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