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