1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/include/fxge/fx_ge.h"
8 
9 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_
10 #include <dwrite.h>
11 
12 #include "core/include/fxge/fx_ge_win32.h"
13 #include "dwrite_int.h"
14 
15 typedef HRESULT(__stdcall* FuncType_DWriteCreateFactory)(
16     __in DWRITE_FACTORY_TYPE,
17     __in REFIID,
18     __out IUnknown**);
19 template <typename InterfaceType>
SafeRelease(InterfaceType ** currentObject)20 inline void SafeRelease(InterfaceType** currentObject) {
21   if (*currentObject) {
22     (*currentObject)->Release();
23     *currentObject = NULL;
24   }
25 }
26 template <typename InterfaceType>
SafeAcquire(InterfaceType * newObject)27 inline InterfaceType* SafeAcquire(InterfaceType* newObject) {
28   if (newObject) {
29     newObject->AddRef();
30   }
31   return newObject;
32 }
33 class CDwFontFileStream final : public IDWriteFontFileStream {
34  public:
35   explicit CDwFontFileStream(void const* fontFileReferenceKey,
36                              UINT32 fontFileReferenceKeySize);
37   virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
38                                                    void** ppvObject);
39   virtual ULONG STDMETHODCALLTYPE AddRef();
40   virtual ULONG STDMETHODCALLTYPE Release();
41   virtual HRESULT STDMETHODCALLTYPE
42   ReadFileFragment(void const** fragmentStart,
43                    UINT64 fileOffset,
44                    UINT64 fragmentSize,
45                    OUT void** fragmentContext);
46   virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
47   virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
48   virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
IsInitialized()49   bool IsInitialized() { return resourcePtr_ != NULL; }
50 
51  private:
52   ULONG refCount_;
53   void const* resourcePtr_;
54   DWORD resourceSize_;
55 };
56 class CDwFontFileLoader final : public IDWriteFontFileLoader {
57  public:
58   virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
59                                                    void** ppvObject);
60   virtual ULONG STDMETHODCALLTYPE AddRef();
61   virtual ULONG STDMETHODCALLTYPE Release();
62   virtual HRESULT STDMETHODCALLTYPE
63   CreateStreamFromKey(void const* fontFileReferenceKey,
64                       UINT32 fontFileReferenceKeySize,
65                       OUT IDWriteFontFileStream** fontFileStream);
66 
GetLoader()67   static IDWriteFontFileLoader* GetLoader() {
68     if (!instance_) {
69       instance_ = new CDwFontFileLoader();
70     }
71     return instance_;
72   }
IsLoaderInitialized()73   static bool IsLoaderInitialized() { return instance_ != NULL; }
74 
75  private:
76   CDwFontFileLoader();
77   ULONG refCount_;
78   static IDWriteFontFileLoader* instance_;
79 };
80 class CDwFontContext {
81  public:
82   CDwFontContext(IDWriteFactory* dwriteFactory);
83   ~CDwFontContext();
84   HRESULT Initialize();
85 
86  private:
87   CDwFontContext(CDwFontContext const&);
88   void operator=(CDwFontContext const&);
89   HRESULT hr_;
90   IDWriteFactory* dwriteFactory_;
91 };
92 class CDwGdiTextRenderer {
93  public:
94   CDwGdiTextRenderer(CFX_DIBitmap* pBitmap,
95                      IDWriteBitmapRenderTarget* bitmapRenderTarget,
96                      IDWriteRenderingParams* renderingParams);
97   ~CDwGdiTextRenderer();
98   HRESULT STDMETHODCALLTYPE DrawGlyphRun(const FX_RECT& text_bbox,
99                                          __in_opt CFX_ClipRgn* pClipRgn,
100                                          __in_opt DWRITE_MATRIX const* pMatrix,
101                                          FLOAT baselineOriginX,
102                                          FLOAT baselineOriginY,
103                                          DWRITE_MEASURING_MODE measuringMode,
104                                          __in DWRITE_GLYPH_RUN const* glyphRun,
105                                          const COLORREF& textColor);
106 
107  private:
108   CFX_DIBitmap* pBitmap_;
109   IDWriteBitmapRenderTarget* pRenderTarget_;
110   IDWriteRenderingParams* pRenderingParams_;
111 };
CDWriteExt()112 CDWriteExt::CDWriteExt() {
113   m_hModule = NULL;
114   m_pDWriteFactory = NULL;
115   m_pDwFontContext = NULL;
116   m_pDwTextRenderer = NULL;
117 }
Load()118 void CDWriteExt::Load() {}
Unload()119 void CDWriteExt::Unload() {
120   if (m_pDwFontContext) {
121     delete (CDwFontContext*)m_pDwFontContext;
122     m_pDwFontContext = NULL;
123   }
124   SafeRelease((IDWriteFactory**)&m_pDWriteFactory);
125 }
~CDWriteExt()126 CDWriteExt::~CDWriteExt() {
127   Unload();
128 }
DwCreateFontFaceFromStream(uint8_t * pData,FX_DWORD size,int simulation_style)129 LPVOID CDWriteExt::DwCreateFontFaceFromStream(uint8_t* pData,
130                                               FX_DWORD size,
131                                               int simulation_style) {
132   IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;
133   IDWriteFontFile* pDwFontFile = NULL;
134   IDWriteFontFace* pDwFontFace = NULL;
135   BOOL isSupportedFontType = FALSE;
136   DWRITE_FONT_FILE_TYPE fontFileType;
137   DWRITE_FONT_FACE_TYPE fontFaceType;
138   UINT32 numberOfFaces;
139   DWRITE_FONT_SIMULATIONS fontStyle =
140       (DWRITE_FONT_SIMULATIONS)(simulation_style & 3);
141   HRESULT hr = S_OK;
142   hr = pDwFactory->CreateCustomFontFileReference(
143       (void const*)pData, (UINT32)size, CDwFontFileLoader::GetLoader(),
144       &pDwFontFile);
145   if (FAILED(hr)) {
146     goto failed;
147   }
148   hr = pDwFontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType,
149                             &numberOfFaces);
150   if (FAILED(hr) || !isSupportedFontType ||
151       fontFaceType == DWRITE_FONT_FACE_TYPE_UNKNOWN) {
152     goto failed;
153   }
154   hr = pDwFactory->CreateFontFace(fontFaceType, 1, &pDwFontFile, 0, fontStyle,
155                                   &pDwFontFace);
156   if (FAILED(hr)) {
157     goto failed;
158   }
159   SafeRelease(&pDwFontFile);
160   return pDwFontFace;
161 failed:
162   SafeRelease(&pDwFontFile);
163   return NULL;
164 }
DwCreateRenderingTarget(CFX_DIBitmap * pBitmap,void ** renderTarget)165 FX_BOOL CDWriteExt::DwCreateRenderingTarget(CFX_DIBitmap* pBitmap,
166                                             void** renderTarget) {
167   if (pBitmap->GetFormat() > FXDIB_Argb) {
168     return FALSE;
169   }
170   IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;
171   IDWriteGdiInterop* pGdiInterop = NULL;
172   IDWriteBitmapRenderTarget* pBitmapRenderTarget = NULL;
173   IDWriteRenderingParams* pRenderingParams = NULL;
174   HRESULT hr = S_OK;
175   hr = pDwFactory->GetGdiInterop(&pGdiInterop);
176   if (FAILED(hr)) {
177     goto failed;
178   }
179   hr = pGdiInterop->CreateBitmapRenderTarget(
180       NULL, pBitmap->GetWidth(), pBitmap->GetHeight(), &pBitmapRenderTarget);
181   if (FAILED(hr)) {
182     goto failed;
183   }
184   hr = pDwFactory->CreateCustomRenderingParams(
185       1.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_RGB,
186       DWRITE_RENDERING_MODE_DEFAULT, &pRenderingParams);
187   if (FAILED(hr)) {
188     goto failed;
189   }
190   hr = pBitmapRenderTarget->SetPixelsPerDip(1.0f);
191   if (FAILED(hr)) {
192     goto failed;
193   }
194   *(CDwGdiTextRenderer**)renderTarget =
195       new CDwGdiTextRenderer(pBitmap, pBitmapRenderTarget, pRenderingParams);
196   SafeRelease(&pGdiInterop);
197   SafeRelease(&pBitmapRenderTarget);
198   SafeRelease(&pRenderingParams);
199   return TRUE;
200 failed:
201   SafeRelease(&pGdiInterop);
202   SafeRelease(&pBitmapRenderTarget);
203   SafeRelease(&pRenderingParams);
204   return FALSE;
205 }
DwRendingString(void * renderTarget,CFX_ClipRgn * pClipRgn,FX_RECT & stringRect,CFX_Matrix * pMatrix,void * font,FX_FLOAT font_size,FX_ARGB text_color,int glyph_count,unsigned short * glyph_indices,FX_FLOAT baselineOriginX,FX_FLOAT baselineOriginY,void * glyph_offsets,FX_FLOAT * glyph_advances)206 FX_BOOL CDWriteExt::DwRendingString(void* renderTarget,
207                                     CFX_ClipRgn* pClipRgn,
208                                     FX_RECT& stringRect,
209                                     CFX_Matrix* pMatrix,
210                                     void* font,
211                                     FX_FLOAT font_size,
212                                     FX_ARGB text_color,
213                                     int glyph_count,
214                                     unsigned short* glyph_indices,
215                                     FX_FLOAT baselineOriginX,
216                                     FX_FLOAT baselineOriginY,
217                                     void* glyph_offsets,
218                                     FX_FLOAT* glyph_advances) {
219   if (!renderTarget) {
220     return TRUE;
221   }
222   CDwGdiTextRenderer* pTextRenderer = (CDwGdiTextRenderer*)renderTarget;
223   DWRITE_MATRIX transform;
224   DWRITE_GLYPH_RUN glyphRun;
225   HRESULT hr = S_OK;
226   if (pMatrix) {
227     transform.m11 = pMatrix->a;
228     transform.m12 = pMatrix->b;
229     transform.m21 = pMatrix->c;
230     transform.m22 = pMatrix->d;
231     transform.dx = pMatrix->e;
232     transform.dy = pMatrix->f;
233   }
234   glyphRun.fontFace = (IDWriteFontFace*)font;
235   glyphRun.fontEmSize = font_size;
236   glyphRun.glyphCount = glyph_count;
237   glyphRun.glyphIndices = glyph_indices;
238   glyphRun.glyphAdvances = glyph_advances;
239   glyphRun.glyphOffsets = (DWRITE_GLYPH_OFFSET*)glyph_offsets;
240   glyphRun.isSideways = FALSE;
241   glyphRun.bidiLevel = 0;
242   hr = pTextRenderer->DrawGlyphRun(
243       stringRect, pClipRgn, pMatrix ? &transform : NULL, baselineOriginX,
244       baselineOriginY, DWRITE_MEASURING_MODE_NATURAL, &glyphRun,
245       RGB(FXARGB_R(text_color), FXARGB_G(text_color), FXARGB_B(text_color)));
246   return SUCCEEDED(hr);
247 }
DwDeleteRenderingTarget(void * renderTarget)248 void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget) {
249   delete (CDwGdiTextRenderer*)renderTarget;
250 }
DwDeleteFont(void * pFont)251 void CDWriteExt::DwDeleteFont(void* pFont) {
252   if (pFont) {
253     SafeRelease((IDWriteFontFace**)&pFont);
254   }
255 }
CDwFontFileStream(void const * fontFileReferenceKey,UINT32 fontFileReferenceKeySize)256 CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey,
257                                      UINT32 fontFileReferenceKeySize) {
258   refCount_ = 0;
259   resourcePtr_ = fontFileReferenceKey;
260   resourceSize_ = fontFileReferenceKeySize;
261 }
QueryInterface(REFIID iid,void ** ppvObject)262 HRESULT STDMETHODCALLTYPE CDwFontFileStream::QueryInterface(REFIID iid,
263                                                             void** ppvObject) {
264   if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
265     *ppvObject = this;
266     AddRef();
267     return S_OK;
268   }
269   *ppvObject = NULL;
270   return E_NOINTERFACE;
271 }
AddRef()272 ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef() {
273   return InterlockedIncrement((long*)(&refCount_));
274 }
Release()275 ULONG STDMETHODCALLTYPE CDwFontFileStream::Release() {
276   ULONG newCount = InterlockedDecrement((long*)(&refCount_));
277   if (newCount == 0) {
278     delete this;
279   }
280   return newCount;
281 }
282 HRESULT STDMETHODCALLTYPE
ReadFileFragment(void const ** fragmentStart,UINT64 fileOffset,UINT64 fragmentSize,OUT void ** fragmentContext)283 CDwFontFileStream::ReadFileFragment(void const** fragmentStart,
284                                     UINT64 fileOffset,
285                                     UINT64 fragmentSize,
286                                     OUT void** fragmentContext) {
287   if (fileOffset <= resourceSize_ &&
288       fragmentSize <= resourceSize_ - fileOffset) {
289     *fragmentStart = static_cast<uint8_t const*>(resourcePtr_) +
290                      static_cast<size_t>(fileOffset);
291     *fragmentContext = NULL;
292     return S_OK;
293   }
294   *fragmentStart = NULL;
295   *fragmentContext = NULL;
296   return E_FAIL;
297 }
298 void STDMETHODCALLTYPE
ReleaseFileFragment(void * fragmentContext)299 CDwFontFileStream::ReleaseFileFragment(void* fragmentContext) {}
GetFileSize(OUT UINT64 * fileSize)300 HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize) {
301   *fileSize = resourceSize_;
302   return S_OK;
303 }
304 HRESULT STDMETHODCALLTYPE
GetLastWriteTime(OUT UINT64 * lastWriteTime)305 CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime) {
306   *lastWriteTime = 0;
307   return E_NOTIMPL;
308 }
309 IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL;
CDwFontFileLoader()310 CDwFontFileLoader::CDwFontFileLoader() : refCount_(0) {}
QueryInterface(REFIID iid,void ** ppvObject)311 HRESULT STDMETHODCALLTYPE CDwFontFileLoader::QueryInterface(REFIID iid,
312                                                             void** ppvObject) {
313   if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
314     *ppvObject = this;
315     AddRef();
316     return S_OK;
317   }
318   *ppvObject = NULL;
319   return E_NOINTERFACE;
320 }
AddRef()321 ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef() {
322   return InterlockedIncrement((long*)(&refCount_));
323 }
Release()324 ULONG STDMETHODCALLTYPE CDwFontFileLoader::Release() {
325   ULONG newCount = InterlockedDecrement((long*)(&refCount_));
326   if (newCount == 0) {
327     instance_ = NULL;
328     delete this;
329   }
330   return newCount;
331 }
CreateStreamFromKey(void const * fontFileReferenceKey,UINT32 fontFileReferenceKeySize,OUT IDWriteFontFileStream ** fontFileStream)332 HRESULT STDMETHODCALLTYPE CDwFontFileLoader::CreateStreamFromKey(
333     void const* fontFileReferenceKey,
334     UINT32 fontFileReferenceKeySize,
335     OUT IDWriteFontFileStream** fontFileStream) {
336   *fontFileStream = NULL;
337   CDwFontFileStream* stream =
338       new CDwFontFileStream(fontFileReferenceKey, fontFileReferenceKeySize);
339   if (!stream->IsInitialized()) {
340     delete stream;
341     return E_FAIL;
342   }
343   *fontFileStream = SafeAcquire(stream);
344   return S_OK;
345 }
CDwFontContext(IDWriteFactory * dwriteFactory)346 CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory)
347     : hr_(S_FALSE), dwriteFactory_(SafeAcquire(dwriteFactory)) {}
~CDwFontContext()348 CDwFontContext::~CDwFontContext() {
349   if (dwriteFactory_ && hr_ == S_OK) {
350     dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader());
351   }
352   SafeRelease(&dwriteFactory_);
353 }
Initialize()354 HRESULT CDwFontContext::Initialize() {
355   if (hr_ == S_FALSE) {
356     return hr_ = dwriteFactory_->RegisterFontFileLoader(
357                CDwFontFileLoader::GetLoader());
358   }
359   return hr_;
360 }
CDwGdiTextRenderer(CFX_DIBitmap * pBitmap,IDWriteBitmapRenderTarget * bitmapRenderTarget,IDWriteRenderingParams * renderingParams)361 CDwGdiTextRenderer::CDwGdiTextRenderer(
362     CFX_DIBitmap* pBitmap,
363     IDWriteBitmapRenderTarget* bitmapRenderTarget,
364     IDWriteRenderingParams* renderingParams)
365     : pBitmap_(pBitmap),
366       pRenderTarget_(SafeAcquire(bitmapRenderTarget)),
367       pRenderingParams_(SafeAcquire(renderingParams)) {}
~CDwGdiTextRenderer()368 CDwGdiTextRenderer::~CDwGdiTextRenderer() {
369   SafeRelease(&pRenderTarget_);
370   SafeRelease(&pRenderingParams_);
371 }
DrawGlyphRun(const FX_RECT & text_bbox,__in_opt CFX_ClipRgn * pClipRgn,__in_opt DWRITE_MATRIX const * pMatrix,FLOAT baselineOriginX,FLOAT baselineOriginY,DWRITE_MEASURING_MODE measuringMode,__in DWRITE_GLYPH_RUN const * glyphRun,const COLORREF & textColor)372 STDMETHODIMP CDwGdiTextRenderer::DrawGlyphRun(
373     const FX_RECT& text_bbox,
374     __in_opt CFX_ClipRgn* pClipRgn,
375     __in_opt DWRITE_MATRIX const* pMatrix,
376     FLOAT baselineOriginX,
377     FLOAT baselineOriginY,
378     DWRITE_MEASURING_MODE measuringMode,
379     __in DWRITE_GLYPH_RUN const* glyphRun,
380     const COLORREF& textColor) {
381   HRESULT hr = S_OK;
382   if (pMatrix) {
383     hr = pRenderTarget_->SetCurrentTransform(pMatrix);
384     if (FAILED(hr)) {
385       return hr;
386     }
387   }
388   HDC hDC = pRenderTarget_->GetMemoryDC();
389   HBITMAP hBitmap = (HBITMAP)::GetCurrentObject(hDC, OBJ_BITMAP);
390   BITMAP bitmap;
391   GetObject(hBitmap, sizeof bitmap, &bitmap);
392   CFX_DIBitmap dib;
393   dib.Create(bitmap.bmWidth, bitmap.bmHeight,
394              bitmap.bmBitsPixel == 24 ? FXDIB_Rgb : FXDIB_Rgb32,
395              (uint8_t*)bitmap.bmBits);
396   dib.CompositeBitmap(text_bbox.left, text_bbox.top, text_bbox.Width(),
397                       text_bbox.Height(), pBitmap_, text_bbox.left,
398                       text_bbox.top, FXDIB_BLEND_NORMAL, NULL);
399   hr = pRenderTarget_->DrawGlyphRun(baselineOriginX, baselineOriginY,
400                                     measuringMode, glyphRun, pRenderingParams_,
401                                     textColor);
402   if (FAILED(hr)) {
403     return hr;
404   }
405   pBitmap_->CompositeBitmap(text_bbox.left, text_bbox.top, text_bbox.Width(),
406                             text_bbox.Height(), &dib, text_bbox.left,
407                             text_bbox.top, FXDIB_BLEND_NORMAL, pClipRgn);
408   return hr;
409 }
410 #endif
411