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