mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-06 14:19:45 +00:00
Compare commits
1 Commits
v1.21.2361
...
dev/lhecke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ade1583ac |
@@ -53,7 +53,7 @@ Settings::Settings() :
|
||||
_fUseWindowSizePixels(false),
|
||||
// window size pixels initialized below
|
||||
_fInterceptCopyPaste(0),
|
||||
_fUseDx(UseDx::Disabled),
|
||||
_fUseDx(UseDx::AtlasEngine),
|
||||
_fCopyColor(false)
|
||||
{
|
||||
_dwScreenBufferSize.X = 80;
|
||||
|
||||
@@ -35,7 +35,8 @@ AtlasEngine::AtlasEngine()
|
||||
#endif
|
||||
|
||||
THROW_IF_FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(_p.dwriteFactory), reinterpret_cast<::IUnknown**>(_p.dwriteFactory.addressof())));
|
||||
_p.dwriteFactory4 = _p.dwriteFactory.try_query<IDWriteFactory4>();
|
||||
_p.dwriteFactory.try_query_to(_p.dwriteFactory4.addressof());
|
||||
_p.dwriteFactory.try_query_to(_p.dwriteFactory8.addressof());
|
||||
|
||||
THROW_IF_FAILED(_p.dwriteFactory->GetSystemFontFallback(_p.systemFontFallback.addressof()));
|
||||
_p.systemFontFallback1 = _p.systemFontFallback.try_query<IDWriteFontFallback1>();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <dwrite_3.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <d3d11_2.h>
|
||||
#include <dxgi1_3.h>
|
||||
|
||||
|
||||
@@ -28,28 +28,93 @@ void Microsoft::Console::Render::Atlas::GlyphRunAccumulateBounds(const ID2D1Devi
|
||||
}
|
||||
}
|
||||
|
||||
wil::com_ptr<IDWriteColorGlyphRunEnumerator1> Microsoft::Console::Render::Atlas::TranslateColorGlyphRun(IDWriteFactory4* dwriteFactory4, D2D_POINT_2F baselineOrigin, const DWRITE_GLYPH_RUN* glyphRun) noexcept
|
||||
wil::com_ptr<IDWriteColorGlyphRunEnumerator1> Microsoft::Console::Render::Atlas::TranslateColorGlyphRun(IDWriteFactory4* dwriteFactory4, IDWriteFactory8* dwriteFactory8, D2D_POINT_2F baselineOrigin, const DWRITE_GLYPH_RUN* glyphRun)
|
||||
{
|
||||
static constexpr auto formats =
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_CFF |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_COLR |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_SVG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_PNG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
|
||||
|
||||
wil::com_ptr<IDWriteColorGlyphRunEnumerator1> enumerator;
|
||||
|
||||
if (dwriteFactory4)
|
||||
if (dwriteFactory8)
|
||||
{
|
||||
static constexpr auto formats =
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_CFF |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_COLR |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_SVG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_PNG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8 |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE;
|
||||
|
||||
std::ignore = dwriteFactory8->TranslateColorGlyphRun(baselineOrigin, glyphRun, nullptr, formats, DWRITE_PAINT_FEATURE_LEVEL_COLR_V1, DWRITE_MEASURING_MODE_NATURAL, nullptr, 0, enumerator.addressof());
|
||||
}
|
||||
else if (dwriteFactory4)
|
||||
{
|
||||
static constexpr auto formats =
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_CFF |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_COLR |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_SVG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_PNG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
|
||||
DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
|
||||
|
||||
std::ignore = dwriteFactory4->TranslateColorGlyphRun(baselineOrigin, glyphRun, nullptr, formats, DWRITE_MEASURING_MODE_NATURAL, nullptr, 0, enumerator.addressof());
|
||||
}
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
void Microsoft::Console::Render::Atlas::DrawColorGlyphRunEnumerator(ID2D1DeviceContext4* d2dRenderTarget4, ID2D1DeviceContext7* d2dRenderTarget7, IDWriteColorGlyphRunEnumerator1* enumerator, ID2D1SolidColorBrush* emojiBrush, ID2D1SolidColorBrush* foregroundBrush)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
BOOL hasRun;
|
||||
THROW_IF_FAILED(enumerator->MoveNext(&hasRun));
|
||||
if (!hasRun)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const DWRITE_COLOR_GLYPH_RUN1* colorGlyphRun = nullptr;
|
||||
THROW_IF_FAILED(enumerator->GetCurrentRun(&colorGlyphRun));
|
||||
|
||||
ID2D1Brush* runBrush = nullptr;
|
||||
if (colorGlyphRun->paletteIndex == /*DWRITE_NO_PALETTE_INDEX*/ 0xffff)
|
||||
{
|
||||
runBrush = foregroundBrush;
|
||||
}
|
||||
else
|
||||
{
|
||||
emojiBrush->SetColor(&colorGlyphRun->runColor);
|
||||
runBrush = emojiBrush;
|
||||
}
|
||||
|
||||
const D2D1_POINT_2F origin{ colorGlyphRun->baselineOriginX, colorGlyphRun->baselineOriginY };
|
||||
|
||||
switch (static_cast<int>(colorGlyphRun->glyphImageFormat))
|
||||
{
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_NONE:
|
||||
break;
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_PNG:
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_JPEG:
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_TIFF:
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8:
|
||||
d2dRenderTarget4->DrawColorBitmapGlyphRun(colorGlyphRun->glyphImageFormat, origin, &colorGlyphRun->glyphRun, colorGlyphRun->measuringMode, D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT);
|
||||
break;
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_SVG:
|
||||
d2dRenderTarget4->DrawSvgGlyphRun(origin, &colorGlyphRun->glyphRun, runBrush, nullptr, 0, colorGlyphRun->measuringMode);
|
||||
break;
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE:
|
||||
d2dRenderTarget7->DrawPaintGlyphRun(origin, &colorGlyphRun->glyphRun, runBrush, 0, colorGlyphRun->measuringMode);
|
||||
break;
|
||||
default:
|
||||
d2dRenderTarget4->DrawGlyphRun(origin, &colorGlyphRun->glyphRun, colorGlyphRun->glyphRunDescription, runBrush, colorGlyphRun->measuringMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Microsoft::Console::Render::Atlas::ColorGlyphRunMoveNext(IDWriteColorGlyphRunEnumerator1* enumerator)
|
||||
{
|
||||
BOOL hasRun;
|
||||
@@ -70,7 +135,7 @@ void Microsoft::Console::Render::Atlas::ColorGlyphRunAccumulateBounds(const ID2D
|
||||
GlyphRunAccumulateBounds(d2dRenderTarget, baselineOrigin, &colorGlyphRun->glyphRun, bounds);
|
||||
}
|
||||
|
||||
void Microsoft::Console::Render::Atlas::ColorGlyphRunDraw(ID2D1DeviceContext4* d2dRenderTarget4, ID2D1SolidColorBrush* emojiBrush, ID2D1SolidColorBrush* foregroundBrush, const DWRITE_COLOR_GLYPH_RUN1* colorGlyphRun) noexcept
|
||||
void Microsoft::Console::Render::Atlas::ColorGlyphRunDraw(ID2D1DeviceContext4* d2dRenderTarget4, ID2D1DeviceContext7* d2dRenderTarget7, ID2D1SolidColorBrush* emojiBrush, ID2D1SolidColorBrush* foregroundBrush, const DWRITE_COLOR_GLYPH_RUN1* colorGlyphRun) noexcept
|
||||
{
|
||||
ID2D1Brush* runBrush = nullptr;
|
||||
if (colorGlyphRun->paletteIndex == /*DWRITE_NO_PALETTE_INDEX*/ 0xffff)
|
||||
@@ -85,7 +150,7 @@ void Microsoft::Console::Render::Atlas::ColorGlyphRunDraw(ID2D1DeviceContext4* d
|
||||
|
||||
const D2D1_POINT_2F baselineOrigin{ colorGlyphRun->baselineOriginX, colorGlyphRun->baselineOriginY };
|
||||
|
||||
switch (colorGlyphRun->glyphImageFormat)
|
||||
switch (static_cast<int>(colorGlyphRun->glyphImageFormat))
|
||||
{
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_NONE:
|
||||
break;
|
||||
@@ -98,6 +163,9 @@ void Microsoft::Console::Render::Atlas::ColorGlyphRunDraw(ID2D1DeviceContext4* d
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_SVG:
|
||||
d2dRenderTarget4->DrawSvgGlyphRun(baselineOrigin, &colorGlyphRun->glyphRun, runBrush, nullptr, 0, colorGlyphRun->measuringMode);
|
||||
break;
|
||||
case DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE:
|
||||
d2dRenderTarget7->DrawPaintGlyphRun(baselineOrigin, &colorGlyphRun->glyphRun, runBrush, 0, colorGlyphRun->measuringMode);
|
||||
break;
|
||||
default:
|
||||
d2dRenderTarget4->DrawGlyphRun(baselineOrigin, &colorGlyphRun->glyphRun, colorGlyphRun->glyphRunDescription, runBrush, colorGlyphRun->measuringMode);
|
||||
break;
|
||||
|
||||
@@ -77,9 +77,10 @@ namespace Microsoft::Console::Render::Atlas
|
||||
inline constexpr D2D1_RECT_F GlyphRunEmptyBounds{ 1e38f, 1e38f, -1e38f, -1e38f };
|
||||
void GlyphRunAccumulateBounds(const ID2D1DeviceContext* d2dRenderTarget, D2D1_POINT_2F baselineOrigin, const DWRITE_GLYPH_RUN* glyphRun, D2D1_RECT_F& bounds);
|
||||
|
||||
wil::com_ptr<IDWriteColorGlyphRunEnumerator1> TranslateColorGlyphRun(IDWriteFactory4* dwriteFactory4, D2D_POINT_2F baselineOrigin, const DWRITE_GLYPH_RUN* glyphRun) noexcept;
|
||||
wil::com_ptr<IDWriteColorGlyphRunEnumerator1> TranslateColorGlyphRun(IDWriteFactory4* dwriteFactory4, IDWriteFactory8* dwriteFactory8, D2D_POINT_2F baselineOrigin, const DWRITE_GLYPH_RUN* glyphRun);
|
||||
void DrawColorGlyphRunEnumerator(ID2D1DeviceContext4* d2dRenderTarget4, ID2D1DeviceContext7* d2dRenderTarget7, IDWriteColorGlyphRunEnumerator1* enumerator, ID2D1SolidColorBrush* emojiBrush, ID2D1SolidColorBrush* foregroundBrush);
|
||||
bool ColorGlyphRunMoveNext(IDWriteColorGlyphRunEnumerator1* enumerator);
|
||||
const DWRITE_COLOR_GLYPH_RUN1* ColorGlyphRunGetCurrentRun(IDWriteColorGlyphRunEnumerator1* enumerator);
|
||||
void ColorGlyphRunAccumulateBounds(const ID2D1DeviceContext* d2dRenderTarget, const DWRITE_COLOR_GLYPH_RUN1* colorGlyphRun, D2D1_RECT_F& bounds);
|
||||
void ColorGlyphRunDraw(ID2D1DeviceContext4* d2dRenderTarget4, ID2D1SolidColorBrush* emojiBrush, ID2D1SolidColorBrush* foregroundBrush, const DWRITE_COLOR_GLYPH_RUN1* colorGlyphRun) noexcept;
|
||||
void ColorGlyphRunDraw(ID2D1DeviceContext4* d2dRenderTarget4, ID2D1DeviceContext7* d2dRenderTarget7, ID2D1SolidColorBrush* emojiBrush, ID2D1SolidColorBrush* foregroundBrush, const DWRITE_COLOR_GLYPH_RUN1* colorGlyphRun) noexcept;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ void BackendD2D::ReleaseResources() noexcept
|
||||
{
|
||||
_renderTarget.reset();
|
||||
_renderTarget4.reset();
|
||||
_renderTarget7.reset();
|
||||
// Ensure _handleSettingsUpdate() is called so that _renderTarget gets recreated.
|
||||
_generation = {};
|
||||
}
|
||||
@@ -85,6 +86,7 @@ void BackendD2D::_handleSettingsUpdate(const RenderingPayload& p)
|
||||
// ID2D1RenderTarget and ID2D1DeviceContext are the same and I'm tired of pretending they're not.
|
||||
THROW_IF_FAILED(p.d2dFactory->CreateDxgiSurfaceRenderTarget(buffer.query<IDXGISurface>().get(), &props, reinterpret_cast<ID2D1RenderTarget**>(_renderTarget.addressof())));
|
||||
_renderTarget.query_to(_renderTarget4.addressof());
|
||||
_renderTarget.query_to(_renderTarget7.addressof());
|
||||
|
||||
_renderTarget->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
|
||||
_renderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
@@ -220,17 +222,7 @@ void BackendD2D::_drawText(RenderingPayload& p)
|
||||
if (glyphRun.fontFace)
|
||||
{
|
||||
D2D1_RECT_F bounds = GlyphRunEmptyBounds;
|
||||
|
||||
if (const auto enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), baselineOrigin, &glyphRun))
|
||||
{
|
||||
while (ColorGlyphRunMoveNext(enumerator.get()))
|
||||
{
|
||||
const auto colorGlyphRun = ColorGlyphRunGetCurrentRun(enumerator.get());
|
||||
ColorGlyphRunDraw(_renderTarget4.get(), _emojiBrush.get(), brush, colorGlyphRun);
|
||||
ColorGlyphRunAccumulateBounds(_renderTarget.get(), colorGlyphRun, bounds);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
_renderTarget->DrawGlyphRun(baselineOrigin, &glyphRun, brush, DWRITE_MEASURING_MODE_NATURAL);
|
||||
GlyphRunAccumulateBounds(_renderTarget.get(), baselineOrigin, &glyphRun, bounds);
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace Microsoft::Console::Render::Atlas
|
||||
|
||||
wil::com_ptr<ID2D1DeviceContext> _renderTarget;
|
||||
wil::com_ptr<ID2D1DeviceContext4> _renderTarget4; // Optional. Supported since Windows 10 14393.
|
||||
wil::com_ptr<ID2D1DeviceContext7> _renderTarget7; // Optional. Supported since Windows 11 <unknown>. 25357 maybe?
|
||||
wil::com_ptr<ID2D1StrokeStyle> _dottedStrokeStyle;
|
||||
wil::com_ptr<ID2D1Bitmap> _backgroundBitmap;
|
||||
wil::com_ptr<ID2D1BitmapBrush> _backgroundBrush;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <shader_ps.h>
|
||||
#include <shader_vs.h>
|
||||
|
||||
#include <wincodec.h>
|
||||
|
||||
#include "dwrite.h"
|
||||
#include "../../types/inc/ColorFix.hpp"
|
||||
|
||||
@@ -24,6 +26,7 @@ TIL_FAST_MATH_BEGIN
|
||||
|
||||
// This code packs various data into smaller-than-int types to save both CPU and GPU memory. This warning would force
|
||||
// us to add dozens upon dozens of gsl::narrow_cast<>s throughout the file which is more annoying than helpful.
|
||||
#pragma warning(disable : 4100)
|
||||
#pragma warning(disable : 4242) // '=': conversion from '...' to '...', possible loss of data
|
||||
#pragma warning(disable : 4244) // 'initializing': conversion from '...' to '...', possible loss of data
|
||||
#pragma warning(disable : 4267) // 'argument': conversion from '...' to '...', possible loss of data
|
||||
@@ -42,6 +45,149 @@ TIL_FAST_MATH_BEGIN
|
||||
|
||||
using namespace Microsoft::Console::Render::Atlas;
|
||||
|
||||
class SharedWicBitmap sealed : public IWICBitmap, public IWICBitmapLock
|
||||
{
|
||||
public:
|
||||
static HRESULT Create(_In_ u32 width, _In_ u32 height, _In_ u32 stride, _In_ WICPixelFormatGUID const& pixelFormat, _In_opt_ u8* pBuffer, _Outptr_ SharedWicBitmap** ppWICBitmap)
|
||||
{
|
||||
if (pBuffer == nullptr)
|
||||
{
|
||||
const u32 size = stride * height;
|
||||
pBuffer = new u8[size]{};
|
||||
}
|
||||
|
||||
*ppWICBitmap = new SharedWicBitmap(width, height, stride, pixelFormat, pBuffer, pBuffer != nullptr);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppvObject) override
|
||||
{
|
||||
if (__uuidof(IUnknown) == riid)
|
||||
{
|
||||
*ppvObject = static_cast<IUnknown*>(static_cast<IWICBitmap*>(this));
|
||||
}
|
||||
else if (__uuidof(IWICBitmap) == riid)
|
||||
{
|
||||
*ppvObject = static_cast<IWICBitmap*>(this);
|
||||
}
|
||||
else if (__uuidof(IWICBitmapLock) == riid)
|
||||
{
|
||||
*ppvObject = static_cast<IWICBitmapLock*>(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() override
|
||||
{
|
||||
return ++m_refCount;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release() override
|
||||
{
|
||||
u32 newRefCount = --m_refCount;
|
||||
if (newRefCount == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
return newRefCount;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetSize(_Out_ UINT* pWidth, _Out_ UINT* pHeight) override
|
||||
{
|
||||
*pWidth = m_width;
|
||||
*pHeight = m_height;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetStride(_Out_ UINT* pStride) override
|
||||
{
|
||||
*pStride = m_stride;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetPixelFormat(_Out_ WICPixelFormatGUID* pPixelFormat) override
|
||||
{
|
||||
*pPixelFormat = m_pixelFormat;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetResolution(_Out_ double* pDpiX, _Out_ double* pDpiY) override
|
||||
{
|
||||
*pDpiX = 96.0;
|
||||
*pDpiY = 96.0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP SetResolution(double dpiX, double dpiY) override
|
||||
{
|
||||
assert(false);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CopyPalette(_In_opt_ IWICPalette* pIPalette) override
|
||||
{
|
||||
assert(false);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP SetPalette(_In_opt_ IWICPalette* pIPalette) override
|
||||
{
|
||||
assert(false);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP CopyPixels(_In_opt_ const WICRect* prc, UINT cbStride, UINT cbBufferSize, _Out_writes_all_(cbBufferSize) BYTE* pbBuffer) override
|
||||
{
|
||||
assert(false);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP Lock(_In_opt_ const WICRect* prcLock, DWORD flags, _Outptr_result_maybenull_ IWICBitmapLock** ppILock) override
|
||||
{
|
||||
*ppILock = this;
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP GetDataPointer(_Out_ UINT* pcbBufferSize, _Outptr_result_buffer_all_maybenull_(*pcbBufferSize) BYTE** ppData) override
|
||||
{
|
||||
*pcbBufferSize = m_stride * m_height;
|
||||
*ppData = m_pBuffer;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_refCount;
|
||||
u32 m_width;
|
||||
u32 m_height;
|
||||
u32 m_stride;
|
||||
WICPixelFormatGUID m_pixelFormat;
|
||||
u8* m_pBuffer;
|
||||
bool m_usesSharedMemory;
|
||||
|
||||
SharedWicBitmap(_In_ u32 width, _In_ u32 height, _In_ u32 stride, _In_ WICPixelFormatGUID pixelFormat, _In_ u8* pBuffer, _In_ bool usesSharedMemory) :
|
||||
m_refCount(1), m_width(width), m_height(height), m_stride(stride), m_pixelFormat(pixelFormat), m_pBuffer(pBuffer), m_usesSharedMemory(usesSharedMemory)
|
||||
{
|
||||
}
|
||||
|
||||
~SharedWicBitmap()
|
||||
{
|
||||
if (!m_usesSharedMemory)
|
||||
{
|
||||
delete[] m_pBuffer;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::hash<u16>
|
||||
{
|
||||
@@ -191,6 +337,22 @@ BackendD3D::BackendD3D(const RenderingPayload& p)
|
||||
THROW_IF_FAILED(p.device->CreateBlendState(&desc, _blendState.addressof()));
|
||||
}
|
||||
|
||||
SharedWicBitmap* pSharedWicBitmap = nullptr;
|
||||
THROW_IF_FAILED(SharedWicBitmap::Create(1, 1, 4, GUID_WICPixelFormat8bppAlpha, nullptr, &pSharedWicBitmap));
|
||||
|
||||
const auto renderTargetProperties = D2D1::RenderTargetProperties(
|
||||
D2D1_RENDER_TARGET_TYPE_SOFTWARE,
|
||||
D2D1::PixelFormat(DXGI_FORMAT_A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
|
||||
96.0f,
|
||||
96.0f,
|
||||
D2D1_RENDER_TARGET_USAGE_NONE,
|
||||
D2D1_FEATURE_LEVEL_DEFAULT);
|
||||
|
||||
wil::com_ptr<ID2D1RenderTarget> renderTarget;
|
||||
THROW_IF_FAILED(p.d2dFactory->CreateWicBitmapRenderTarget(pSharedWicBitmap, &renderTargetProperties, renderTarget.addressof()));
|
||||
renderTarget.query_to(_d2dRenderTarget4WIC.addressof());
|
||||
renderTarget.query_to(_d2dRenderTarget7WIC.addressof());
|
||||
|
||||
#ifndef NDEBUG
|
||||
_sourceDirectory = std::filesystem::path{ __FILE__ }.parent_path();
|
||||
_sourceCodeWatcher = wil::make_folder_change_reader_nothrow(_sourceDirectory.c_str(), false, wil::FolderChangeEvents::FileName | wil::FolderChangeEvents::LastWriteTime, [this](wil::FolderChangeEvent, PCWSTR path) {
|
||||
@@ -742,6 +904,7 @@ void BackendD3D::_resizeGlyphAtlas(const RenderingPayload& p, const u16 u, const
|
||||
{
|
||||
_d2dRenderTarget.reset();
|
||||
_d2dRenderTarget4.reset();
|
||||
_d2dRenderTarget7.reset();
|
||||
_glyphAtlas.reset();
|
||||
_glyphAtlasView.reset();
|
||||
|
||||
@@ -769,6 +932,7 @@ void BackendD3D::_resizeGlyphAtlas(const RenderingPayload& p, const u16 u, const
|
||||
// ID2D1RenderTarget and ID2D1DeviceContext are the same and I'm tired of pretending they're not.
|
||||
THROW_IF_FAILED(p.d2dFactory->CreateDxgiSurfaceRenderTarget(surface.get(), &props, reinterpret_cast<ID2D1RenderTarget**>(_d2dRenderTarget.addressof())));
|
||||
_d2dRenderTarget.try_query_to(_d2dRenderTarget4.addressof());
|
||||
_d2dRenderTarget.try_query_to(_d2dRenderTarget7.addressof());
|
||||
|
||||
_d2dRenderTarget->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
|
||||
// We don't really use D2D for anything except DWrite, but it
|
||||
@@ -1254,7 +1418,7 @@ bool BackendD3D::_drawGlyph(const RenderingPayload& p, const AtlasFontFaceEntryI
|
||||
#endif
|
||||
|
||||
const auto lineRendition = static_cast<LineRendition>(fontFaceEntry.lineRendition);
|
||||
const auto needsTransform = lineRendition != LineRendition::SingleWidth;
|
||||
auto needsTransform = lineRendition != LineRendition::SingleWidth;
|
||||
|
||||
static constexpr D2D1_MATRIX_3X2_F identityTransform{ .m11 = 1, .m22 = 1 };
|
||||
D2D1_MATRIX_3X2_F transform = identityTransform;
|
||||
@@ -1298,24 +1462,39 @@ bool BackendD3D::_drawGlyph(const RenderingPayload& p, const AtlasFontFaceEntryI
|
||||
}
|
||||
});
|
||||
|
||||
auto enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), p.dwriteFactory8.get(), {}, &glyphRun);
|
||||
isColorGlyph = !!enumerator;
|
||||
|
||||
if (!enumerator)
|
||||
{
|
||||
const auto enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), {}, &glyphRun);
|
||||
THROW_IF_FAILED(_d2dRenderTarget4->GetGlyphRunWorldBounds({}, &glyphRun, DWRITE_MEASURING_MODE_NATURAL, &bounds));
|
||||
}
|
||||
else
|
||||
{
|
||||
wil::com_ptr<ID2D1SolidColorBrush> emojiBrush;
|
||||
wil::com_ptr<ID2D1SolidColorBrush> brush;
|
||||
|
||||
if (!enumerator)
|
||||
{
|
||||
THROW_IF_FAILED(_d2dRenderTarget->GetGlyphRunWorldBounds({}, &glyphRun, DWRITE_MEASURING_MODE_NATURAL, &bounds));
|
||||
}
|
||||
else
|
||||
{
|
||||
isColorGlyph = true;
|
||||
_d2dRenderTarget4->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
|
||||
static constexpr D2D1_COLOR_F color{ 1, 1, 1, 1 };
|
||||
THROW_IF_FAILED(_d2dRenderTarget4WIC->CreateSolidColorBrush(&color, nullptr, emojiBrush.put()));
|
||||
THROW_IF_FAILED(_d2dRenderTarget4WIC->CreateSolidColorBrush(&color, nullptr, brush.put()));
|
||||
|
||||
while (ColorGlyphRunMoveNext(enumerator.get()))
|
||||
{
|
||||
const auto colorGlyphRun = ColorGlyphRunGetCurrentRun(enumerator.get());
|
||||
ColorGlyphRunAccumulateBounds(_d2dRenderTarget.get(), colorGlyphRun, bounds);
|
||||
}
|
||||
}
|
||||
wil::com_ptr<ID2D1CommandList> commandList;
|
||||
THROW_IF_FAILED(_d2dRenderTarget4WIC->CreateCommandList(commandList.addressof()));
|
||||
|
||||
wil::com_ptr<ID2D1Image> previousTarget;
|
||||
_d2dRenderTarget4WIC->GetTarget(previousTarget.addressof());
|
||||
|
||||
_d2dRenderTarget4WIC->SetTarget(commandList.get());
|
||||
const auto cleanup = wil::scope_exit([&]() {
|
||||
_d2dRenderTarget4WIC->SetTarget(previousTarget.get());
|
||||
});
|
||||
|
||||
_d2dRenderTarget4WIC->BeginDraw();
|
||||
DrawColorGlyphRunEnumerator(_d2dRenderTarget4WIC.get(), _d2dRenderTarget7WIC.get(), enumerator.get(), emojiBrush.get(), brush.get());
|
||||
THROW_IF_FAILED(_d2dRenderTarget4WIC->EndDraw());
|
||||
|
||||
THROW_IF_FAILED(commandList->Close());
|
||||
THROW_IF_FAILED(_d2dRenderTarget4WIC->GetImageWorldBounds(commandList.get(), &bounds));
|
||||
}
|
||||
|
||||
// Overhangs for box glyphs can produce unsightly effects, where the antialiased edges of horizontal
|
||||
@@ -1386,18 +1565,14 @@ bool BackendD3D::_drawGlyph(const RenderingPayload& p, const AtlasFontFaceEntryI
|
||||
_d2dRenderTarget->SetTransform(&transform);
|
||||
}
|
||||
|
||||
if (!isColorGlyph)
|
||||
if (!enumerator)
|
||||
{
|
||||
_d2dRenderTarget->DrawGlyphRun(baselineOrigin, &glyphRun, _brush.get(), DWRITE_MEASURING_MODE_NATURAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), baselineOrigin, &glyphRun);
|
||||
while (ColorGlyphRunMoveNext(enumerator.get()))
|
||||
{
|
||||
const auto colorGlyphRun = ColorGlyphRunGetCurrentRun(enumerator.get());
|
||||
ColorGlyphRunDraw(_d2dRenderTarget4.get(), _emojiBrush.get(), _brush.get(), colorGlyphRun);
|
||||
}
|
||||
enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), p.dwriteFactory8.get(), baselineOrigin, &glyphRun);
|
||||
DrawColorGlyphRunEnumerator(_d2dRenderTarget4.get(), _d2dRenderTarget7.get(), enumerator.get(), _emojiBrush.get(), _brush.get());
|
||||
}
|
||||
|
||||
// Ligatures are drawn with strict cell-wise foreground color, while other text allows colors to overhang
|
||||
|
||||
@@ -263,9 +263,12 @@ namespace Microsoft::Console::Render::Atlas
|
||||
stbrp_context _rectPacker{};
|
||||
til::CoordType _ligatureOverhangTriggerLeft = 0;
|
||||
til::CoordType _ligatureOverhangTriggerRight = 0;
|
||||
|
||||
|
||||
wil::com_ptr<ID2D1DeviceContext> _d2dRenderTarget;
|
||||
wil::com_ptr<ID2D1DeviceContext4> _d2dRenderTarget4; // Optional. Supported since Windows 10 14393.
|
||||
wil::com_ptr<ID2D1DeviceContext7> _d2dRenderTarget7; // Optional. Supported since Windows 11 <unknown>. 25357 maybe?
|
||||
wil::com_ptr<ID2D1DeviceContext4> _d2dRenderTarget4WIC;
|
||||
wil::com_ptr<ID2D1DeviceContext7> _d2dRenderTarget7WIC;
|
||||
wil::com_ptr<ID2D1SolidColorBrush> _emojiBrush;
|
||||
wil::com_ptr<ID2D1SolidColorBrush> _brush;
|
||||
wil::com_ptr<ID2D1Bitmap1> _softFontBitmap;
|
||||
|
||||
@@ -7,6 +7,107 @@
|
||||
|
||||
#include "../../renderer/inc/IRenderEngine.hpp"
|
||||
|
||||
// vvvv copied out of microsoft.windows.sdk.cpp.10.0.25363-preview vvvv
|
||||
|
||||
#define DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE static_cast<DWRITE_GLYPH_IMAGE_FORMATS>(0x00000100)
|
||||
|
||||
enum DWRITE_PAINT_FEATURE_LEVEL
|
||||
{
|
||||
DWRITE_PAINT_FEATURE_LEVEL_NONE = 0,
|
||||
DWRITE_PAINT_FEATURE_LEVEL_COLR_V0 = 1,
|
||||
DWRITE_PAINT_FEATURE_LEVEL_COLR_V1 = 2
|
||||
};
|
||||
|
||||
interface DWRITE_DECLARE_INTERFACE("EE0A7FB5-DEF4-4C23-A454-C9C7DC878398") IDWriteFactory8 : public IDWriteFactory7
|
||||
{
|
||||
/// <summary>
|
||||
/// Translates a glyph run to a sequence of color glyph runs, which can be
|
||||
/// rendered to produce a color representation of the original "base" run.
|
||||
/// </summary>
|
||||
/// <param name="baselineOriginX">Horizontal and vertical origin of the base glyph run in
|
||||
/// pre-transform coordinates.</param>
|
||||
/// <param name="glyphRun">Pointer to the original "base" glyph run.</param>
|
||||
/// <param name="glyphRunDescription">Optional glyph run description.</param>
|
||||
/// <param name="desiredGlyphImageFormats">Which data formats TranslateColorGlyphRun
|
||||
/// should split the runs into.</param>
|
||||
/// <param name="paintFeatureLevel">Paint feature level supported by the caller. Used
|
||||
/// when desiredGlyphImageFormats includes DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE. See
|
||||
/// DWRITE_PAINT_FEATURE_LEVEL for more information.</param>
|
||||
/// <param name="measuringMode">Measuring mode, needed to compute the origins
|
||||
/// of each glyph.</param>
|
||||
/// <param name="worldToDeviceTransform">Matrix converting from the client's
|
||||
/// coordinate space to device coordinates (pixels), i.e., the world transform
|
||||
/// multiplied by any DPI scaling.</param>
|
||||
/// <param name="colorPaletteIndex">Zero-based index of the color palette to use.
|
||||
/// Valid indices are less than the number of palettes in the font, as returned
|
||||
/// by IDWriteFontFace2::GetColorPaletteCount.</param>
|
||||
/// <param name="colorEnumerator">If the function succeeds, receives a pointer
|
||||
/// to an enumerator object that can be used to obtain the color glyph runs.
|
||||
/// If the base run has no color glyphs, then the output pointer is NULL
|
||||
/// and the method returns DWRITE_E_NOCOLOR.</param>
|
||||
/// <returns>
|
||||
/// Returns DWRITE_E_NOCOLOR if the font has no color information, the glyph run
|
||||
/// does not contain any color glyphs, or the specified color palette index
|
||||
/// is out of range. In this case, the client should render the original glyph
|
||||
/// run. Otherwise, returns a standard HRESULT error code.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The old IDWriteFactory2::TranslateColorGlyphRun is equivalent to passing
|
||||
/// DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE|CFF|COLR.
|
||||
/// </remarks>
|
||||
STDMETHOD(TranslateColorGlyphRun)
|
||||
(
|
||||
D2D1_POINT_2F baselineOrigin,
|
||||
_In_ DWRITE_GLYPH_RUN const* glyphRun,
|
||||
_In_opt_ DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
DWRITE_GLYPH_IMAGE_FORMATS desiredGlyphImageFormats,
|
||||
DWRITE_PAINT_FEATURE_LEVEL paintFeatureLevel,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
_In_opt_ DWRITE_MATRIX const* worldAndDpiTransform,
|
||||
UINT32 colorPaletteIndex,
|
||||
_COM_Outptr_ IDWriteColorGlyphRunEnumerator1** colorEnumerator) PURE;
|
||||
};
|
||||
|
||||
interface DX_DECLARE_INTERFACE("ec891cf7-9b69-4851-9def-4e0915771e62") ID2D1DeviceContext7 : public ID2D1DeviceContext6
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the maximum paint feature level supported by DrawPaintGlyphRun.
|
||||
/// </summary>
|
||||
STDMETHOD_(DWRITE_PAINT_FEATURE_LEVEL, GetPaintFeatureLevel)
|
||||
() PURE;
|
||||
|
||||
/// <summary>
|
||||
/// Draws a color glyph run that has the format of
|
||||
/// DWRITE_GLYPH_IMAGE_FORMATS_COLR_PAINT_TREE.
|
||||
/// </summary>
|
||||
/// <param name="colorPaletteIndex">The index used to select a color palette within
|
||||
/// a color font. Note that this not the same as the paletteIndex in the
|
||||
/// DWRITE_COLOR_GLYPH_RUN struct, which is not relevant for paint glyphs.</param>
|
||||
STDMETHOD_(void, DrawPaintGlyphRun)
|
||||
(
|
||||
D2D1_POINT_2F baselineOrigin,
|
||||
_In_ CONST DWRITE_GLYPH_RUN* glyphRun,
|
||||
_In_opt_ ID2D1Brush* defaultFillBrush = NULL,
|
||||
UINT32 colorPaletteIndex = 0,
|
||||
DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL) PURE;
|
||||
|
||||
/// <summary>
|
||||
/// Draws a glyph run, using color representations of glyphs if available.
|
||||
/// </summary>
|
||||
STDMETHOD_(void, DrawGlyphRunWithColorSupport)
|
||||
(
|
||||
D2D1_POINT_2F baselineOrigin,
|
||||
_In_ CONST DWRITE_GLYPH_RUN* glyphRun,
|
||||
_In_opt_ CONST DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription,
|
||||
_In_opt_ ID2D1Brush* foregroundBrush,
|
||||
_In_opt_ ID2D1SvgGlyphStyle* svgGlyphStyle,
|
||||
UINT32 colorPaletteIndex = 0,
|
||||
DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL,
|
||||
D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION bitmapSnapOption = D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT) PURE;
|
||||
}; // interface ID2D1DeviceContext7
|
||||
|
||||
// ^^^^ copied out of microsoft.windows.sdk.cpp.10.0.25363-preview ^^^^
|
||||
|
||||
namespace Microsoft::Console::Render::Atlas
|
||||
{
|
||||
#define ATLAS_FLAG_OPS(type, underlying) \
|
||||
@@ -462,7 +563,8 @@ namespace Microsoft::Console::Render::Atlas
|
||||
//// Parameters which are constant across backends.
|
||||
wil::com_ptr<ID2D1Factory> d2dFactory;
|
||||
wil::com_ptr<IDWriteFactory2> dwriteFactory;
|
||||
wil::com_ptr<IDWriteFactory4> dwriteFactory4; // optional, might be nullptr
|
||||
wil::com_ptr<IDWriteFactory4> dwriteFactory4; // Optional. Supported since Windows 10 14393.
|
||||
wil::com_ptr<IDWriteFactory8> dwriteFactory8; // Optional. Supported since Windows 11 <unknown>. 25357 maybe?
|
||||
wil::com_ptr<IDWriteFontFallback> systemFontFallback;
|
||||
wil::com_ptr<IDWriteFontFallback1> systemFontFallback1; // optional, might be nullptr
|
||||
wil::com_ptr<IDWriteTextAnalyzer1> textAnalyzer;
|
||||
|
||||
Reference in New Issue
Block a user