remove Microsoft SDK
[pdfium.git] / core / src / fxge / win32 / fx_win32_dwrite.cpp
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>
14 inline void SafeRelease(InterfaceType** currentObject)
15 {
16     if (*currentObject != NULL) {
17         (*currentObject)->Release();
18         *currentObject = NULL;
19     }
20 }
21 template <typename InterfaceType>
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);
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
57     static IDWriteFontFileLoader* GetLoader()
58     {
59         if (instance_ == NULL) {
60             instance_ = FX_NEW CDwFontFileLoader();
61             return instance_;
62         }
63         return instance_;
64     }
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 };
110 CDWriteExt::CDWriteExt()
111 {
112     m_hModule = NULL;
113     m_pDWriteFactory = NULL;
114     m_pDwFontContext = NULL;
115     m_pDwTextRenderer = NULL;
116 }
117 void CDWriteExt::Load()
118 {
119 }
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 }
128 CDWriteExt::~CDWriteExt()
129 {
130     Unload();
131 }
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 }
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 }
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 }
267 void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget)
268 {
269     if (renderTarget) {
270         delete (CDwGdiTextRenderer*)renderTarget;
271     }
272 }
273 void CDWriteExt::DwDeleteFont(void* pFont)
274 {
275     if (pFont) {
276         SafeRelease((IDWriteFontFace**)&pFont);
277     }
278 }
279 CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize)
280 {
281     refCount_ = 0;
282     resourcePtr_ = fontFileReferenceKey;
283     resourceSize_ = fontFileReferenceKeySize;
284 }
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 }
296 ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef()
297 {
298     return InterlockedIncrement((long*)(&refCount_));
299 }
300 ULONG STDMETHODCALLTYPE CDwFontFileStream::Release()
301 {
302     ULONG newCount = InterlockedDecrement((long*)(&refCount_));
303     if (newCount == 0) {
304         delete this;
305     }
306     return newCount;
307 }
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 }
326 void STDMETHODCALLTYPE CDwFontFileStream::ReleaseFileFragment(void* fragmentContext)
327 {
328 }
329 HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize)
330 {
331     *fileSize = resourceSize_;
332     return S_OK;
333 }
334 HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime)
335 {
336     *lastWriteTime = 0;
337     return E_NOTIMPL;
338 }
339 IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL;
340 CDwFontFileLoader::CDwFontFileLoader() :
341     refCount_(0)
342 {
343 }
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 }
355 ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef()
356 {
357     return InterlockedIncrement((long*)(&refCount_));
358 }
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 }
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 }
386 CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory) :
387     hr_(S_FALSE),
388     dwriteFactory_(SafeAcquire(dwriteFactory))
389 {
390 }
391 CDwFontContext::~CDwFontContext()
392 {
393     if(dwriteFactory_ && hr_ == S_OK) {
394         dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader());
395     }
396     SafeRelease(&dwriteFactory_);
397 }
398 HRESULT CDwFontContext::Initialize()
399 {
400     if (hr_ == S_FALSE) {
401         return hr_ = dwriteFactory_->RegisterFontFileLoader(CDwFontFileLoader::GetLoader());
402     }
403     return hr_;
404 }
405 CDwGdiTextRenderer::CDwGdiTextRenderer(CFX_DIBitmap* pBitmap, IDWriteBitmapRenderTarget* bitmapRenderTarget, IDWriteRenderingParams* renderingParams):
406     pBitmap_(pBitmap),
407     pRenderTarget_(SafeAcquire(bitmapRenderTarget)),
408     pRenderingParams_(SafeAcquire(renderingParams))
409 {
410 }
411 CDwGdiTextRenderer::~CDwGdiTextRenderer()
412 {
413     SafeRelease(&pRenderTarget_);
414     SafeRelease(&pRenderingParams_);
415 }
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