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