OSDN Git Service

crystaledit: Organize the directory structure
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / renderers / ccrystalrendererdirectwrite.cpp
1 /**
2  * @file  ccrystalrendererdirectdraw.cpp
3  *
4  * @brief Implementation of the CCrystalRendererDirectWrite class
5  */
6
7 #ifdef _WIN64
8 #undef WINVER
9 #define WINVER 0x0a00
10 #include <afxwin.h>
11 #include "ccrystalrendererdirectwrite.h"
12 #include "resource.h"
13 #include <d2d1_3.h>
14 #include <dwrite_3.h>
15 #include <vector>
16 #include <algorithm>
17 #include <utility>
18
19 struct CustomGlyphRun : public DWRITE_GLYPH_RUN
20 {
21         CustomGlyphRun(const DWRITE_GLYPH_RUN& glyphRun, const float *customGlyphAdvances, float charHeight)
22                 : DWRITE_GLYPH_RUN(glyphRun)
23                 , sumCharWidth(0)
24                 , ascent(0)
25         {
26                 glyphAdvances = new float[glyphCount];
27                 DWRITE_FONT_METRICS fontFaceMetrics;
28                 glyphRun.fontFace->GetMetrics(&fontFaceMetrics);
29                 for (unsigned i = 0; i < glyphCount; ++i)
30                 {
31                         const_cast<float*>(glyphAdvances)[i] = customGlyphAdvances[i];
32                         sumCharWidth += glyphAdvances[i];
33                 }
34                 float height = (fontFaceMetrics.ascent + fontFaceMetrics.descent) * fontEmSize / fontFaceMetrics.designUnitsPerEm;
35                 float scaleY = charHeight / height;
36                 if (1.0f > scaleY)
37                         fontEmSize *= scaleY;
38                 ascent = fontFaceMetrics.ascent * fontEmSize / fontFaceMetrics.designUnitsPerEm;
39         }
40
41         CustomGlyphRun(const CustomGlyphRun& other)
42                 : DWRITE_GLYPH_RUN(other)
43                 , sumCharWidth(other.sumCharWidth)
44                 , ascent(0.0f)
45         {
46                 glyphAdvances = new float[other.glyphCount];
47                 for (unsigned i = 0; i < other.glyphCount; ++i)
48                         const_cast<float*>(glyphAdvances)[i] = other.glyphAdvances[i];
49         }
50
51         ~CustomGlyphRun()
52         {
53                 delete[] glyphAdvances;
54         }
55
56         float sumCharWidth;
57         float ascent;
58 };
59
60 struct DrawGlyphRunParams
61 {
62         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)
71         {
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)
77                 {
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];
82                 }
83         }
84
85         DrawGlyphRunParams(const DrawGlyphRunParams &other)
86                 : glyphRun(other.glyphRun)
87                 , fBaselineOriginX(other.fBaselineOriginX)
88                 , fBaselineOriginY(other.fBaselineOriginY)
89                 , measuringMode(other.measuringMode)
90         {
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)
96                 {
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];
101                 }
102         }
103
104         ~DrawGlyphRunParams()
105         {
106                 delete glyphRun.glyphAdvances;
107                 delete glyphRun.glyphIndices;
108                 delete glyphRun.glyphOffsets;
109                 glyphRun.fontFace->Release();
110         }
111
112         FLOAT fBaselineOriginX;
113         FLOAT fBaselineOriginY;
114         DWRITE_MEASURING_MODE measuringMode;
115         DWRITE_GLYPH_RUN glyphRun;
116 };
117
118 class CDrawingContext
119 {
120 public:
121         CDrawingContext(CRenderTarget* pRenderTarget)
122         : m_pRenderTarget(pRenderTarget)
123         {
124         }
125
126         CRenderTarget* m_pRenderTarget;
127         std::vector<DrawGlyphRunParams> m_drawGlyphRunParams;
128 };
129
130 class CCustomTextRenderer : public CCmdTarget
131 {
132         DECLARE_DYNAMIC(CCustomTextRenderer)
133 public:
134         CCustomTextRenderer() = default;
135         virtual ~CCustomTextRenderer() = default;
136         IDWriteTextRenderer* Get();
137 public:
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)
152 };
153
154 inline IDWriteTextRenderer* CCustomTextRenderer::Get()
155 {
156         return &m_xCustomTextRenderer;
157 }
158
159 IMPLEMENT_DYNAMIC(CCustomTextRenderer, CCmdTarget)
160
161 BEGIN_INTERFACE_MAP(CCustomTextRenderer, CCmdTarget)
162         INTERFACE_PART(CCustomTextRenderer, __uuidof(IDWriteTextRenderer), CustomTextRenderer)
163 END_INTERFACE_MAP()
164
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)
169 {
170         CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
171         pDrawingContext->m_drawGlyphRunParams.push_back(
172                 DrawGlyphRunParams{fBaselineOriginX, fBaselineOriginY, measuringMode, *pGlyphRun});
173         return S_OK;
174 }
175
176 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawInlineObject(void* pClientDrawingContext,
177         FLOAT fOriginX, FLOAT fOriginY, IDWriteInlineObject* pInlineObject,
178         BOOL bIsSideways, BOOL bIsRightToLeft,
179         IUnknown* pClientDrawingEffect)
180 {
181         return E_NOTIMPL;
182 }
183
184 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawStrikethrough(void* pClientDrawingContext,
185         FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, const DWRITE_STRIKETHROUGH* pStrikethrough,
186         IUnknown* pClientDrawingEffect)
187 {
188         return E_NOTIMPL;
189 }
190
191 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::DrawUnderline(void* pClientDrawingContext,
192         FLOAT fBaselineOriginX, FLOAT fBaselineOriginY, const DWRITE_UNDERLINE* pUnderline,
193         IUnknown* pClientDrawingEffect)
194 {
195         return E_NOTIMPL;
196 }
197
198 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::GetCurrentTransform(void* pClientDrawingContext, DWRITE_MATRIX* pTransform)
199 {
200         CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
201         pDrawingContext->m_pRenderTarget->GetTransform((D2D1_MATRIX_3X2_F*)pTransform);
202         return S_OK;
203 }
204
205 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::GetPixelsPerDip(void* pClientDrawingContext, FLOAT* pfPixelsPerDip)
206 {
207         CDrawingContext* pDrawingContext = static_cast<CDrawingContext*>(pClientDrawingContext);
208         *pfPixelsPerDip = pDrawingContext->m_pRenderTarget->GetDpi().width / 96.0f;
209         return S_OK;
210 }
211
212 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::IsPixelSnappingDisabled(void* pClientDrawingContext, BOOL* pbIsDisabled)
213 {
214         *pbIsDisabled = FALSE;
215         return S_OK;
216 }
217
218 STDMETHODIMP_(ULONG) CCustomTextRenderer::XCustomTextRenderer::AddRef()
219 {
220         METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
221         return pThis->ExternalAddRef();
222 }
223
224 STDMETHODIMP_(ULONG) CCustomTextRenderer::XCustomTextRenderer::Release()
225 {
226         METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
227         return pThis->ExternalRelease();
228 }
229
230 STDMETHODIMP CCustomTextRenderer::XCustomTextRenderer::QueryInterface(REFIID iid, LPVOID far* ppvObj)
231 {
232         METHOD_PROLOGUE(CCustomTextRenderer, CustomTextRenderer);
233         return pThis->ExternalQueryInterface(&iid, ppvObj);
234 }
235
236 /////////////////////////////////////////////////////////////////////////////
237 // CCrystalRendererDirectWrite construction/destruction
238
239
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())
246 {
247   const auto props = D2D1::RenderTargetProperties(
248       D2D1_RENDER_TARGET_TYPE_DEFAULT,
249       D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
250       0,
251       0,
252       D2D1_RENDER_TARGET_USAGE_NONE,
253       D2D1_FEATURE_LEVEL_DEFAULT
254   );
255
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(),
263           1.0f,
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));
269 }
270
271 CCrystalRendererDirectWrite::~CCrystalRendererDirectWrite ()
272 {
273 }
274
275 void CCrystalRendererDirectWrite::BindDC(const CDC& dc, const CRect& rc)
276 {
277         m_renderTarget.BindDC(dc, rc);
278 }
279
280 void CCrystalRendererDirectWrite::BeginDraw()
281 {
282         m_renderTarget.BeginDraw();
283 }
284
285 bool CCrystalRendererDirectWrite::EndDraw()
286 {
287         return (SUCCEEDED(m_renderTarget.EndDraw()));
288 }
289
290 static D2D1_SIZE_F GetCharWidthHeight(IDWriteTextFormat *pTextFormat)
291 {
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};
297 }
298
299 void CCrystalRendererDirectWrite::SetFont(const LOGFONT &lf)
300 {
301         m_lfBaseFont = lf;
302         for (int nIndex = 0; nIndex < 4; ++nIndex)
303         {
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);
315         }
316         m_pCurrentTextFormat = m_pTextFormat[0].get();
317         m_pFont.reset();
318         m_charSize = ::GetCharWidthHeight(m_pTextFormat[3]->Get());
319 }
320
321 void CCrystalRendererDirectWrite::SwitchFont(bool italic, bool bold)
322 {
323         int nIndex = 0;
324         if (bold)
325                 nIndex |= 1;
326         if (italic)
327                 nIndex |= 2;
328         m_pCurrentTextFormat = m_pTextFormat[nIndex].get();
329 }
330
331 CSize CCrystalRendererDirectWrite::GetCharWidthHeight()
332 {
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));
336 }
337
338 bool CCrystalRendererDirectWrite::GetCharWidth(unsigned start, unsigned end, int * nWidthArray)
339 {
340         if (!m_pFont)
341         {
342                 m_pFont.reset(new CFont());
343                 m_pFont->CreateFontIndirect(&m_lfBaseFont);
344         }
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);
349         return succeeded;
350 }
351
352 void CCrystalRendererDirectWrite::SetTextColor(COLORREF clr)
353 {
354         m_pTextBrush->SetColor(ColorRefToColorF(clr));
355 }
356
357 void CCrystalRendererDirectWrite::SetBkColor(COLORREF clr)
358 {
359         m_pBackgroundBrush->SetColor(ColorRefToColorF(clr));
360 }
361
362 void CCrystalRendererDirectWrite::FillRectangle(const CRect &rc)
363 {
364         m_renderTarget.FillRectangle(CD2DRectF(rc), m_pBackgroundBrush.get());
365 }
366
367 void CCrystalRendererDirectWrite::FillSolidRectangle(const CRect &rc, COLORREF color)
368 {
369         m_pTempBrush->SetColor(ColorRefToColorF(color));
370         m_renderTarget.FillRectangle(CD2DRectF(rc), m_pTempBrush.get());
371 }
372
373 void CCrystalRendererDirectWrite::DrawRoundRectangle(int left, int top, int right, int bottom, int width, int height)
374 {
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());
378 }
379
380 void CCrystalRendererDirectWrite::PushAxisAlignedClip(const CRect & rc)
381 {
382         m_renderTarget.PushAxisAlignedClip(rc);
383 }
384
385 void CCrystalRendererDirectWrite::PopAxisAlignedClip()
386 {
387         m_renderTarget.PopAxisAlignedClip();
388 }
389
390 void CCrystalRendererDirectWrite::DrawMarginIcon(int x, int y, int iconIndex)
391 {
392         if (!m_pIconBitmap)
393         {
394                 m_pIconBitmap.reset(new CD2DBitmap(nullptr, static_cast<UINT>(IDR_MARGIN_ICONS_PNG), _T("IMAGE")));
395                 m_pIconBitmap->Create(&m_renderTarget);
396         }
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);
403 }
404
405 void CCrystalRendererDirectWrite::DrawMarginLineNumber(int x, int y, int number)
406 {
407         TCHAR szNumbers[32];
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());
413 }
414
415 void CCrystalRendererDirectWrite::DrawBoundaryLine(int left, int right, int y)
416 {
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());
421 }
422
423 void CCrystalRendererDirectWrite::DrawLineCursor(int left, int right, int y, int height)
424 {
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);
432 }
433
434 void CCrystalRendererDirectWrite::DrawText(int x, int y, const CRect &rc, const TCHAR *text, size_t len, const int nWidths[])
435 {
436         CD2DRectF rcF(rc);
437
438         m_renderTarget.PushAxisAlignedClip(rcF);
439
440         m_renderTarget.FillRectangle(rcF, m_pBackgroundBrush.get());
441
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)
445         {
446                 CDrawingContext drawingContext{ &m_renderTarget };
447                 CComPtr<IDWriteTextLayout> pTextLayout;
448 #ifdef _UNICODE
449                 AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(text, static_cast<unsigned>(len),
450 #else
451                 USES_CONVERSION;
452                 AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(A2W(text), static_cast<unsigned>(len),
453 #endif
454                         *m_pCurrentTextFormat,
455                         rcF.right - rcF.left, rcF.bottom - rcF.top, &pTextLayout);
456                 pTextLayout->Draw(&drawingContext, m_pTextRenderer->Get(), 0, 0);
457
458                 std::vector<float> customGlyphAdvances(len, m_charSize.width);
459                 for (size_t i = 0, j = 0; i < len; ++i)
460                 {
461                         if (nWidths[i] != 0)
462                                 customGlyphAdvances[j++] = static_cast<float>(nWidths[i]);
463                 }
464
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)
468                 {
469                         indices.push_back({i, drawingContext.m_drawGlyphRunParams[i].fBaselineOriginX, glyphPos});
470                         glyphPos += drawingContext.m_drawGlyphRunParams[i].glyphRun.glyphCount;
471                 }
472                 std::stable_sort(indices.begin(), indices.end(),
473                         [](const DrawGlyphRunIndex & a, const DrawGlyphRunIndex& b) { return a.fBaselineOriginX < b.fBaselineOriginX; });
474
475                 float fBaselineOriginX = static_cast<float>(x);
476                 for (size_t i = 0; i < indices.size(); ++i)
477                 {
478                         if (indices[i].glyphPos >= customGlyphAdvances.size())
479                         {
480                                 TRACE(_T("BUG: indices[i].glyphPos >= customGlyphAdvances.size()\n"));
481                                 break;
482                         }
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,
488                                 fBaselineOriginY,
489                                 param.measuringMode, &customGlyphRun, nullptr, nullptr);
490                         fBaselineOriginX += customGlyphRun.sumCharWidth;
491                 }
492         }
493         m_renderTarget.PopAxisAlignedClip();
494 }
495
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)
500 {
501         IDWriteFactory *pWriteFactory = AfxGetD2DState()->GetWriteFactory();
502         CComQIPtr<IDWriteFactory4> pWriteFactory4(pWriteFactory);
503         CComQIPtr<ID2D1DeviceContext4> pD2dDeviceContext(m_renderTarget);
504         CComPtr<IDWriteColorGlyphRunEnumerator1> glyphRunEnumerator;
505
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)
515         );
516
517         if (!pWriteFactory4)
518         {
519                 m_renderTarget.DrawGlyphRun(
520                         {fBaselineOriginX, fBaselineOriginY},
521                         *pGlyphRun, m_pTextBrush.get(), measuringMode);
522                 return S_OK;
523         }
524
525         HRESULT hr = pWriteFactory4->TranslateColorGlyphRun(
526                 {fBaselineOriginX, fBaselineOriginY},
527                 pGlyphRun, pGlyphRunDescription, supportedFormats,
528                 measuringMode, nullptr, 0, &glyphRunEnumerator);
529         if (hr == DWRITE_E_NOCOLOR)
530         {
531                 m_renderTarget.DrawGlyphRun(
532                         {fBaselineOriginX, fBaselineOriginY},
533                         *pGlyphRun, m_pTextBrush.get(), measuringMode);
534                 return S_OK;
535         }
536
537         for (;;)
538         {
539                 BOOL haveRun;
540                 glyphRunEnumerator->MoveNext(&haveRun);
541                 if (!haveRun)
542                         break;
543
544                 DWRITE_COLOR_GLYPH_RUN1 const* colorRun;
545                 glyphRunEnumerator->GetCurrentRun(&colorRun);
546
547                 D2D1_POINT_2F currentBaselineOrigin = D2D1::Point2F(
548                         colorRun->baselineOriginX,
549                         colorRun->baselineOriginY
550                 );
551
552                 switch (colorRun->glyphImageFormat)
553                 {
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:
558                 {
559                         // This run is bitmap glyphs. Use Direct2D to draw them.
560                         pD2dDeviceContext->DrawColorBitmapGlyphRun(
561                                 colorRun->glyphImageFormat, currentBaselineOrigin,
562                                 &colorRun->glyphRun, measuringMode);
563                 }
564                 break;
565
566                 case DWRITE_GLYPH_IMAGE_FORMATS_SVG:
567                 {
568                         // This run is SVG glyphs. Use Direct2D to draw them.
569                         pD2dDeviceContext->DrawSvgGlyphRun(
570                                 currentBaselineOrigin, &colorRun->glyphRun,
571                                 m_pTextBrush->Get(),
572                                 nullptr, 0, measuringMode);
573                 }
574                 break;
575
576                 case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE:
577                 case DWRITE_GLYPH_IMAGE_FORMATS_CFF:
578                 case DWRITE_GLYPH_IMAGE_FORMATS_COLR:
579                 default:
580                 {
581                         // This run is solid-color outlines, either from non-color
582                         // glyphs or from COLR glyph layers. Use Direct2D to draw them.
583
584                         ID2D1Brush* layerBrush;
585                         if (colorRun->paletteIndex == 0xFFFF)
586                         {
587                                 // This run uses the current text color.
588                                 layerBrush = m_pTextBrush->Get();
589                         }
590                         else
591                         {
592                                 // This run specifies its own color.
593                                 m_pTempBrush->SetColor(colorRun->runColor);
594                                 layerBrush = m_pTempBrush->Get();
595                         }
596
597                         // Draw the run with the selected color.
598                         pD2dDeviceContext->DrawGlyphRun(currentBaselineOrigin, &colorRun->glyphRun,
599                                 colorRun->glyphRunDescription, layerBrush, measuringMode);
600                 }
601                 break;
602                 }
603         }
604         return S_OK;
605 }
606
607 #endif