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