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