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