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