2 * @file ccrystalrendererdirectdraw.cpp
4 * @brief Implementation of the CCrystalRendererDirectWrite class
11 #include "ccrystalrendererdirectwrite.h"
19 struct CustomGlyphRun : public DWRITE_GLYPH_RUN
21 CustomGlyphRun(const DWRITE_GLYPH_RUN& glyphRun, const float *customGlyphAdvances, float charHeight)
22 : DWRITE_GLYPH_RUN(glyphRun)
26 glyphAdvances = new float[glyphCount];
27 DWRITE_FONT_METRICS fontFaceMetrics;
28 glyphRun.fontFace->GetMetrics(&fontFaceMetrics);
29 for (unsigned i = 0; i < glyphCount; ++i)
31 const_cast<float*>(glyphAdvances)[i] = customGlyphAdvances[i];
32 sumCharWidth += glyphAdvances[i];
34 float height = (fontFaceMetrics.ascent + fontFaceMetrics.descent) * fontEmSize / fontFaceMetrics.designUnitsPerEm;
35 float scaleY = charHeight / height;
38 ascent = fontFaceMetrics.ascent * fontEmSize / fontFaceMetrics.designUnitsPerEm;
41 CustomGlyphRun(const CustomGlyphRun& other)
42 : DWRITE_GLYPH_RUN(other)
43 , sumCharWidth(other.sumCharWidth)
46 glyphAdvances = new float[other.glyphCount];
47 for (unsigned i = 0; i < other.glyphCount; ++i)
48 const_cast<float*>(glyphAdvances)[i] = other.glyphAdvances[i];
53 delete[] glyphAdvances;
60 struct DrawGlyphRunParams
63 float fBaselineOriginXOther,
64 float fBaselineOriginYOther,
65 DWRITE_MEASURING_MODE measuringModeOther,
66 const DWRITE_GLYPH_RUN& glyphRunOther)
67 : glyphRun(glyphRunOther)
68 , fBaselineOriginX(fBaselineOriginXOther)
69 , fBaselineOriginY(fBaselineOriginYOther)
70 , measuringMode(measuringModeOther)
72 glyphRun.glyphAdvances = new FLOAT[glyphRunOther.glyphCount];
73 glyphRun.glyphIndices = new UINT16[glyphRunOther.glyphCount];
74 glyphRun.glyphOffsets = glyphRunOther.glyphOffsets ? new DWRITE_GLYPH_OFFSET[glyphRunOther.glyphCount] : nullptr;
75 glyphRun.fontFace->AddRef();
76 for (unsigned i = 0; i < glyphRunOther.glyphCount; ++i)
78 const_cast<float *>(glyphRun.glyphAdvances)[i] = glyphRunOther.glyphAdvances[i];
79 const_cast<UINT16 *>(glyphRun.glyphIndices)[i] = glyphRunOther.glyphIndices[i];
80 if (glyphRunOther.glyphOffsets)
81 const_cast<DWRITE_GLYPH_OFFSET *>(glyphRun.glyphOffsets)[i] = glyphRunOther.glyphOffsets[i];
85 DrawGlyphRunParams(const DrawGlyphRunParams &other)
86 : glyphRun(other.glyphRun)
87 , fBaselineOriginX(other.fBaselineOriginX)
88 , fBaselineOriginY(other.fBaselineOriginY)
89 , measuringMode(other.measuringMode)
91 glyphRun.glyphAdvances = new FLOAT[other.glyphRun.glyphCount];
92 glyphRun.glyphIndices = new UINT16[other.glyphRun.glyphCount];
93 glyphRun.glyphOffsets = other.glyphRun.glyphOffsets ? new DWRITE_GLYPH_OFFSET[other.glyphRun.glyphCount] : nullptr;
94 glyphRun.fontFace->AddRef();
95 for (unsigned i = 0; i < other.glyphRun.glyphCount; ++i)
97 const_cast<FLOAT *>(glyphRun.glyphAdvances)[i] = other.glyphRun.glyphAdvances[i];
98 const_cast<UINT16 *>(glyphRun.glyphIndices)[i] = other.glyphRun.glyphIndices[i];
99 if (other.glyphRun.glyphOffsets)
100 const_cast<DWRITE_GLYPH_OFFSET *>(glyphRun.glyphOffsets)[i] = other.glyphRun.glyphOffsets[i];
104 ~DrawGlyphRunParams()
106 delete glyphRun.glyphAdvances;
107 delete glyphRun.glyphIndices;
108 delete glyphRun.glyphOffsets;
109 glyphRun.fontFace->Release();
112 FLOAT fBaselineOriginX;
113 FLOAT fBaselineOriginY;
114 DWRITE_MEASURING_MODE measuringMode;
115 DWRITE_GLYPH_RUN glyphRun;
118 class CDrawingContext
121 CDrawingContext(CRenderTarget* pRenderTarget)
122 : m_pRenderTarget(pRenderTarget)
126 CRenderTarget* m_pRenderTarget;
127 std::vector<DrawGlyphRunParams> m_drawGlyphRunParams;
130 class CCustomTextRenderer : public CCmdTarget
132 DECLARE_DYNAMIC(CCustomTextRenderer)
134 CCustomTextRenderer() = default;
135 virtual ~CCustomTextRenderer() = default;
136 IDWriteTextRenderer* Get();
138 DECLARE_INTERFACE_MAP()
139 BEGIN_INTERFACE_PART(CustomTextRenderer, IDWriteTextRenderer)
140 // override IDWriteTextRenderer
141 STDMETHOD(DrawGlyphRun)(void*, FLOAT, FLOAT, DWRITE_MEASURING_MODE, const DWRITE_GLYPH_RUN*,
142 const DWRITE_GLYPH_RUN_DESCRIPTION*, IUnknown*);
143 STDMETHOD(DrawInlineObject)(void*, FLOAT, FLOAT, IDWriteInlineObject*, BOOL, BOOL, IUnknown*);
144 STDMETHOD(DrawStrikethrough)(void*, FLOAT, FLOAT, const DWRITE_STRIKETHROUGH*, IUnknown*);
145 STDMETHOD(DrawUnderline)(void*, FLOAT, FLOAT, const DWRITE_UNDERLINE*, IUnknown*);
146 // override IDWritePixelSnapping
147 STDMETHOD(GetCurrentTransform)(void*, DWRITE_MATRIX*);
148 STDMETHOD(GetPixelsPerDip)(void*, FLOAT*);
149 STDMETHOD(IsPixelSnappingDisabled)(void*, BOOL*);
150 // implementation helpers
151 END_INTERFACE_PART(CustomTextRenderer)
154 inline IDWriteTextRenderer* CCustomTextRenderer::Get()
156 return &m_xCustomTextRenderer;
159 IMPLEMENT_DYNAMIC(CCustomTextRenderer, CCmdTarget)
161 BEGIN_INTERFACE_MAP(CCustomTextRenderer, CCmdTarget)
162 INTERFACE_PART(CCustomTextRenderer, __uuidof(IDWriteTextRenderer), CustomTextRenderer)
165 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawGlyphRun(void* pClientDrawingContext,
166 FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, DWRITE_MEASURING_MODE measuringMode,
167 const DWRITE_GLYPH_RUN* pGlyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION* pGlyphRunDescription,
168 IUnknown* pClientDrawingEffect)
170 CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
171 pDrawingContext->m_drawGlyphRunParams.push_back(
172 DrawGlyphRunParams{fBaselineOriginX, fBaselineOriginY, measuringMode, *pGlyphRun});
176 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawInlineObject(void* pClientDrawingContext,
177 FLOAT fOriginX, FLOAT fOriginY, IDWriteInlineObject* pInlineObject,
178 BOOL bIsSideways, BOOL bIsRightToLeft,
179 IUnknown* pClientDrawingEffect)
184 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawStrikethrough(void* pClientDrawingContext,
185 FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, const DWRITE_STRIKETHROUGH* pStrikethrough,
186 IUnknown* pClientDrawingEffect)
191 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawUnderline(void* pClientDrawingContext,
192 FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, const DWRITE_UNDERLINE* pUnderline,
193 IUnknown* pClientDrawingEffect)
198 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::GetCurrentTransform(void* pClientDrawingContext, DWRITE_MATRIX* pTransform)
200 CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
201 pDrawingContext->m_pRenderTarget->GetTransform((D2D1_MATRIX_3X2_F*)pTransform);
205 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::GetPixelsPerDip(void* pClientDrawingContext, FLOAT* pfPixelsPerDip)
207 CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
208 *pfPixelsPerDip = pDrawingContext->m_pRenderTarget->GetDpi().width / 96.0f;
212 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::IsPixelSnappingDisabled(void* pClientDrawingContext, BOOL* pbIsDisabled)
214 *pbIsDisabled = FALSE;
218 STDMETHODIMP_(ULONG) CCustomTextRenderer::XCustomTextRenderer::AddRef()
220 METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
221 return pThis->ExternalAddRef();
224 STDMETHODIMP_(ULONG) CCustomTextRenderer::XCustomTextRenderer::Release()
226 METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
227 return pThis->ExternalRelease();
230 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::QueryInterface(REFIID iid, LPVOID far* ppvObj)
232 METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
233 return pThis->ExternalQueryInterface(&iid, ppvObj);
236 /////////////////////////////////////////////////////////////////////////////
237 // CCrystalRendererDirectWrite construction/destruction
240 CCrystalRendererDirectWrite::CCrystalRendererDirectWrite(int nRenderingMode)
241 : m_pCurrentTextFormat{ nullptr }, m_charSize{}, m_lfBaseFont{}
242 , m_pTextBrush(new CD2DSolidColorBrush(&m_renderTarget, D2D1::ColorF(D2D1::ColorF::Black)))
243 , m_pTempBrush(new CD2DSolidColorBrush(&m_renderTarget, D2D1::ColorF(D2D1::ColorF::Black)))
244 , m_pBackgroundBrush(new CD2DSolidColorBrush(&m_renderTarget, D2D1::ColorF(D2D1::ColorF::White)))
245 , m_pTextRenderer(new CCustomTextRenderer())
247 const auto props = D2D1::RenderTargetProperties(
248 D2D1_RENDER_TARGET_TYPE_DEFAULT,
249 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
252 D2D1_RENDER_TARGET_USAGE_NONE,
253 D2D1_FEATURE_LEVEL_DEFAULT
256 m_renderTarget.Create(props);
257 IDWriteFactory *pWriteFactory = AfxGetD2DState()->GetWriteFactory();
258 CComPtr<IDWriteRenderingParams> pTextRenderingParams, pTextRenderingParams2;
259 pWriteFactory->CreateRenderingParams(&pTextRenderingParams);
260 pWriteFactory->CreateCustomRenderingParams(
261 pTextRenderingParams->GetGamma(),
262 pTextRenderingParams->GetEnhancedContrast(),
264 pTextRenderingParams->GetPixelGeometry(),
265 static_cast<DWRITE_RENDERING_MODE>(nRenderingMode),
266 &pTextRenderingParams2);
267 m_renderTarget.SetTextRenderingParams(pTextRenderingParams2);
268 m_renderTarget.SetDpi(CD2DSizeF(96.0F, 96.0F));
271 CCrystalRendererDirectWrite::~CCrystalRendererDirectWrite ()
275 void CCrystalRendererDirectWrite::BindDC(const CDC& dc, const CRect& rc)
277 m_renderTarget.BindDC(dc, rc);
280 void CCrystalRendererDirectWrite::BeginDraw()
282 m_renderTarget.BeginDraw();
285 bool CCrystalRendererDirectWrite::EndDraw()
287 return (SUCCEEDED(m_renderTarget.EndDraw()));
290 static D2D1_SIZE_F GetCharWidthHeight(IDWriteTextFormat *pTextFormat)
292 CComPtr<IDWriteTextLayout> pTextLayout;
293 AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(L"W", 1, pTextFormat, 0, 0, &pTextLayout);
294 DWRITE_TEXT_METRICS textMetrics{};
295 pTextLayout->GetMetrics(&textMetrics);
296 return {textMetrics.width, textMetrics.height};
299 void CCrystalRendererDirectWrite::SetFont(const LOGFONT &lf)
302 for (int nIndex = 0; nIndex < 4; ++nIndex)
304 bool bold = (nIndex & 1) != 0;
305 bool italic = (nIndex & 2) != 0;
306 m_pTextFormat[nIndex].reset(new CD2DTextFormat(&m_renderTarget,
307 lf.lfFaceName[0] ? lf.lfFaceName : _T("Courier New"),
308 static_cast<FLOAT>(abs(lf.lfHeight == 0 ? 11 : lf.lfHeight)),
309 bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL,
310 italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL));
311 IDWriteTextFormat *pTextFormat = m_pTextFormat[nIndex]->Get();
312 pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
313 pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
314 pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
316 m_pCurrentTextFormat = m_pTextFormat[0].get();
318 m_charSize = ::GetCharWidthHeight(m_pTextFormat[3]->Get());
321 void CCrystalRendererDirectWrite::SwitchFont(bool italic, bool bold)
328 m_pCurrentTextFormat = m_pTextFormat[nIndex].get();
331 CSize CCrystalRendererDirectWrite::GetCharWidthHeight()
333 if (m_pTextFormat[3] == nullptr)
334 SetFont(m_lfBaseFont);
335 return CSize(static_cast<int>(m_charSize.width + 0.9999), static_cast<int>(m_charSize.height + 0.9999));
338 bool CCrystalRendererDirectWrite::GetCharWidth(unsigned start, unsigned end, int * nWidthArray)
342 m_pFont.reset(new CFont());
343 m_pFont->CreateFontIndirect(&m_lfBaseFont);
345 CClientDC dc (CWnd::GetDesktopWindow());
346 CFont *pOldFont = dc.SelectObject(m_pFont.get());
347 bool succeeded = !!GetCharWidth32(dc.m_hDC, start, end, nWidthArray);
348 dc.SelectObject(pOldFont);
352 void CCrystalRendererDirectWrite::SetTextColor(COLORREF clr)
354 m_pTextBrush->SetColor(ColorRefToColorF(clr));
357 void CCrystalRendererDirectWrite::SetBkColor(COLORREF clr)
359 m_pBackgroundBrush->SetColor(ColorRefToColorF(clr));
362 void CCrystalRendererDirectWrite::FillRectangle(const CRect &rc)
364 m_renderTarget.FillRectangle(CD2DRectF(rc), m_pBackgroundBrush.get());
367 void CCrystalRendererDirectWrite::FillSolidRectangle(const CRect &rc, COLORREF color)
369 m_pTempBrush->SetColor(ColorRefToColorF(color));
370 m_renderTarget.FillRectangle(CD2DRectF(rc), m_pTempBrush.get());
373 void CCrystalRendererDirectWrite::DrawRoundRectangle(int left, int top, int right, int bottom, int width, int height)
375 m_renderTarget.DrawRoundedRectangle(
376 D2D1_ROUNDED_RECT{ {static_cast<float>(left), static_cast<float>(top), static_cast<float>(right), static_cast<float>(bottom)},
377 static_cast<float>(width), static_cast<float>(height) }, m_pTextBrush.get());
380 void CCrystalRendererDirectWrite::PushAxisAlignedClip(const CRect & rc)
382 m_renderTarget.PushAxisAlignedClip(rc);
385 void CCrystalRendererDirectWrite::PopAxisAlignedClip()
387 m_renderTarget.PopAxisAlignedClip();
390 void CCrystalRendererDirectWrite::DrawMarginIcon(int x, int y, int iconIndex)
394 m_pIconBitmap.reset(new CD2DBitmap(nullptr, static_cast<UINT>(IDR_MARGIN_ICONS_PNG), _T("IMAGE")));
395 m_pIconBitmap->Create(&m_renderTarget);
397 auto size = m_pIconBitmap->GetPixelSize();
398 CD2DRectF rcSrc{static_cast<float>(iconIndex * MARGIN_ICON_WIDTH), 0.0f, static_cast<float>((iconIndex + 1) * MARGIN_ICON_WIDTH), static_cast<float>(MARGIN_ICON_HEIGHT)};
399 m_renderTarget.DrawBitmap(m_pIconBitmap.get(),
400 { static_cast<float>(x), static_cast<float>(y),
401 static_cast<float>(x + MARGIN_ICON_WIDTH), static_cast<float>(y + MARGIN_ICON_HEIGHT) },
402 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, &rcSrc);
405 void CCrystalRendererDirectWrite::DrawMarginLineNumber(int x, int y, int number)
408 int len = wsprintf(szNumbers, _T("%d"), number);
409 m_renderTarget.DrawText(szNumbers,
410 { static_cast<float>(x) - m_charSize.width * len - 4, static_cast<float>(y),
411 static_cast<float>(x), static_cast<float>(y + m_charSize.height) },
412 m_pTextBrush.get(), m_pTextFormat[0].get());
415 void CCrystalRendererDirectWrite::DrawBoundaryLine(int left, int right, int y)
417 m_pTempBrush->SetColor(ColorRefToColorF(0));
418 m_renderTarget.DrawLine(
419 { static_cast<float>(left), static_cast<float>(y) },
420 { static_cast<float>(right), static_cast<float>(y) }, m_pTempBrush.get());
423 void CCrystalRendererDirectWrite::DrawLineCursor(int left, int right, int y, int height)
425 m_pTempBrush->SetColor(ColorRefToColorF(0));
426 m_pTempBrush->SetOpacity(0.1f);
427 m_renderTarget.DrawLine(
428 { static_cast<float>(left), static_cast<float>(y) },
429 { static_cast<float>(right), static_cast<float>(y) },
430 m_pTempBrush.get(), static_cast<float>(1));
431 m_pTempBrush->SetOpacity(1.0f);
434 void CCrystalRendererDirectWrite::DrawText(int x, int y, const CRect &rc, const TCHAR *text, size_t len, const int nWidths[])
438 m_renderTarget.PushAxisAlignedClip(rcF);
440 m_renderTarget.FillRectangle(rcF, m_pBackgroundBrush.get());
442 D2D1_COLOR_F textColor = m_pTextBrush->GetColor();
443 D2D1_COLOR_F backColor = m_pBackgroundBrush->GetColor();
444 if (memcmp(&textColor, &backColor, sizeof(D2D1_COLOR_F)) != 0)
446 CDrawingContext drawingContext{ &m_renderTarget };
447 CComPtr<IDWriteTextLayout> pTextLayout;
449 AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(text, static_cast<unsigned>(len),
452 AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(A2W(text), static_cast<unsigned>(len),
454 *m_pCurrentTextFormat,
455 rcF.right - rcF.left, rcF.bottom - rcF.top, &pTextLayout);
456 pTextLayout->Draw(&drawingContext, m_pTextRenderer->Get(), 0, 0);
458 std::vector<float> customGlyphAdvances(len, m_charSize.width);
459 for (size_t i = 0, j = 0; i < len; ++i)
462 customGlyphAdvances[j++] = static_cast<float>(nWidths[i]);
465 struct DrawGlyphRunIndex { size_t i; float fBaselineOriginX; size_t glyphPos; };
466 std::vector<DrawGlyphRunIndex> indices;
467 for (size_t i = 0, glyphPos = 0; i < drawingContext.m_drawGlyphRunParams.size(); ++i)
469 indices.push_back({i, drawingContext.m_drawGlyphRunParams[i].fBaselineOriginX, glyphPos});
470 glyphPos += drawingContext.m_drawGlyphRunParams[i].glyphRun.glyphCount;
472 std::stable_sort(indices.begin(), indices.end(),
473 [](const DrawGlyphRunIndex & a, const DrawGlyphRunIndex& b) { return a.fBaselineOriginX < b.fBaselineOriginX; });
475 float fBaselineOriginX = static_cast<float>(x);
476 for (size_t i = 0; i < indices.size(); ++i)
478 if (indices[i].glyphPos >= customGlyphAdvances.size())
480 TRACE(_T("BUG: indices[i].glyphPos >= customGlyphAdvances.size()\n"));
483 DrawGlyphRunParams& param = drawingContext.m_drawGlyphRunParams[indices[i].i];
484 CustomGlyphRun customGlyphRun(param.glyphRun, &customGlyphAdvances[indices[i].glyphPos], m_charSize.height);
485 float fBaselineOriginY = y + customGlyphRun.ascent;
486 DrawGlyphRun(&drawingContext,
487 (customGlyphRun.bidiLevel & 1) ? (fBaselineOriginX + customGlyphRun.sumCharWidth) : fBaselineOriginX,
489 param.measuringMode, &customGlyphRun, nullptr, nullptr);
490 fBaselineOriginX += customGlyphRun.sumCharWidth;
493 m_renderTarget.PopAxisAlignedClip();
496 STDMETHODIMP CCrystalRendererDirectWrite::DrawGlyphRun(void* pClientDrawingContext,
497 FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, DWRITE_MEASURING_MODE measuringMode,
498 const DWRITE_GLYPH_RUN* pGlyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION* pGlyphRunDescription,
499 IUnknown* pClientDrawingEffect)
501 IDWriteFactory *pWriteFactory = AfxGetD2DState()->GetWriteFactory();
502 CComQIPtr<IDWriteFactory4> pWriteFactory4(pWriteFactory);
503 CComQIPtr<ID2D1DeviceContext4> pD2dDeviceContext(m_renderTarget);
504 CComPtr<IDWriteColorGlyphRunEnumerator1> glyphRunEnumerator;
506 DWRITE_GLYPH_IMAGE_FORMATS supportedFormats = static_cast<DWRITE_GLYPH_IMAGE_FORMATS>(
507 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE) |
508 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_CFF) |
509 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_COLR) |
510 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_SVG) |
511 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_PNG) |
512 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_JPEG)|
513 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_TIFF) |
514 static_cast<int>(DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8)
519 m_renderTarget.DrawGlyphRun(
520 {fBaselineOriginX, fBaselineOriginY},
521 *pGlyphRun, m_pTextBrush.get(), measuringMode);
525 HRESULT hr = pWriteFactory4->TranslateColorGlyphRun(
526 {fBaselineOriginX, fBaselineOriginY},
527 pGlyphRun, pGlyphRunDescription, supportedFormats,
528 measuringMode, nullptr, 0, &glyphRunEnumerator);
529 if (hr == DWRITE_E_NOCOLOR)
531 m_renderTarget.DrawGlyphRun(
532 {fBaselineOriginX, fBaselineOriginY},
533 *pGlyphRun, m_pTextBrush.get(), measuringMode);
540 glyphRunEnumerator->MoveNext(&haveRun);
544 DWRITE_COLOR_GLYPH_RUN1 const* colorRun;
545 glyphRunEnumerator->GetCurrentRun(&colorRun);
547 D2D1_POINT_2F currentBaselineOrigin = D2D1::Point2F(
548 colorRun->baselineOriginX,
549 colorRun->baselineOriginY
552 switch (colorRun->glyphImageFormat)
554 case DWRITE_GLYPH_IMAGE_FORMATS_PNG:
555 case DWRITE_GLYPH_IMAGE_FORMATS_JPEG:
556 case DWRITE_GLYPH_IMAGE_FORMATS_TIFF:
557 case DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8:
559 // This run is bitmap glyphs. Use Direct2D to draw them.
560 pD2dDeviceContext->DrawColorBitmapGlyphRun(
561 colorRun->glyphImageFormat, currentBaselineOrigin,
562 &colorRun->glyphRun, measuringMode);
566 case DWRITE_GLYPH_IMAGE_FORMATS_SVG:
568 // This run is SVG glyphs. Use Direct2D to draw them.
569 pD2dDeviceContext->DrawSvgGlyphRun(
570 currentBaselineOrigin, &colorRun->glyphRun,
572 nullptr, 0, measuringMode);
576 case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE:
577 case DWRITE_GLYPH_IMAGE_FORMATS_CFF:
578 case DWRITE_GLYPH_IMAGE_FORMATS_COLR:
581 // This run is solid-color outlines, either from non-color
582 // glyphs or from COLR glyph layers. Use Direct2D to draw them.
584 ID2D1Brush* layerBrush;
585 if (colorRun->paletteIndex == 0xFFFF)
587 // This run uses the current text color.
588 layerBrush = m_pTextBrush->Get();
592 // This run specifies its own color.
593 m_pTempBrush->SetColor(colorRun->runColor);
594 layerBrush = m_pTempBrush->Get();
597 // Draw the run with the selected color.
598 pD2dDeviceContext->DrawGlyphRun(currentBaselineOrigin, &colorRun->glyphRun,
599 colorRun->glyphRunDescription, layerBrush, measuringMode);