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"
12typedef HRESULT  (__stdcall *FuncType_DWriteCreateFactory)(__in DWRITE_FACTORY_TYPE, __in REFIID, __out IUnknown **);
13template <typename InterfaceType>
14inline void SafeRelease(InterfaceType** currentObject)
15{
16    if (*currentObject != NULL) {
17        (*currentObject)->Release();
18        *currentObject = NULL;
19    }
20}
21template <typename InterfaceType>
22inline InterfaceType* SafeAcquire(InterfaceType* newObject)
23{
24    if (newObject != NULL) {
25        newObject->AddRef();
26    }
27    return newObject;
28}
29class CDwFontFileStream : public IDWriteFontFileStream, public CFX_Object
30{
31public:
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    }
44private:
45    ULONG refCount_;
46    void const* resourcePtr_;
47    DWORD resourceSize_;
48};
49class CDwFontFileLoader : public IDWriteFontFileLoader, public CFX_Object
50{
51public:
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    }
69private:
70    CDwFontFileLoader();
71    ULONG refCount_;
72    static IDWriteFontFileLoader* instance_;
73};
74class CDwFontContext : public CFX_Object
75{
76public:
77    CDwFontContext(IDWriteFactory* dwriteFactory);
78    ~CDwFontContext();
79    HRESULT Initialize();
80private:
81    CDwFontContext(CDwFontContext const&);
82    void operator=(CDwFontContext const&);
83    HRESULT hr_;
84    IDWriteFactory* dwriteFactory_;
85};
86class CDwGdiTextRenderer : public CFX_Object
87{
88public:
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    );
105private:
106    CFX_DIBitmap* pBitmap_;
107    IDWriteBitmapRenderTarget* pRenderTarget_;
108    IDWriteRenderingParams* pRenderingParams_;
109};
110CDWriteExt::CDWriteExt()
111{
112    m_hModule = NULL;
113    m_pDWriteFactory = NULL;
114    m_pDwFontContext = NULL;
115    m_pDwTextRenderer = NULL;
116}
117void CDWriteExt::Load()
118{
119}
120void CDWriteExt::Unload()
121{
122    if (m_pDwFontContext) {
123        delete (CDwFontContext*)m_pDwFontContext;
124        m_pDwFontContext = NULL;
125    }
126    SafeRelease((IDWriteFactory**)&m_pDWriteFactory);
127}
128CDWriteExt::~CDWriteExt()
129{
130    Unload();
131}
132LPVOID	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;
174failed:
175    SafeRelease(&pDwFontFile);
176    return NULL;
177}
178FX_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;
220failed:
221    SafeRelease(&pGdiInterop);
222    SafeRelease(&pBitmapRenderTarget);
223    SafeRelease(&pRenderingParams);
224    return FALSE;
225}
226FX_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}
267void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget)
268{
269    if (renderTarget) {
270        delete (CDwGdiTextRenderer*)renderTarget;
271    }
272}
273void CDWriteExt::DwDeleteFont(void* pFont)
274{
275    if (pFont) {
276        SafeRelease((IDWriteFontFace**)&pFont);
277    }
278}
279CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize)
280{
281    refCount_ = 0;
282    resourcePtr_ = fontFileReferenceKey;
283    resourceSize_ = fontFileReferenceKeySize;
284}
285HRESULT 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}
296ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef()
297{
298    return InterlockedIncrement((long*)(&refCount_));
299}
300ULONG STDMETHODCALLTYPE CDwFontFileStream::Release()
301{
302    ULONG newCount = InterlockedDecrement((long*)(&refCount_));
303    if (newCount == 0) {
304        delete this;
305    }
306    return newCount;
307}
308HRESULT 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}
326void STDMETHODCALLTYPE CDwFontFileStream::ReleaseFileFragment(void* fragmentContext)
327{
328}
329HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize)
330{
331    *fileSize = resourceSize_;
332    return S_OK;
333}
334HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime)
335{
336    *lastWriteTime = 0;
337    return E_NOTIMPL;
338}
339IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL;
340CDwFontFileLoader::CDwFontFileLoader() :
341    refCount_(0)
342{
343}
344HRESULT 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}
355ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef()
356{
357    return InterlockedIncrement((long*)(&refCount_));
358}
359ULONG 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}
368HRESULT 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}
386CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory) :
387    hr_(S_FALSE),
388    dwriteFactory_(SafeAcquire(dwriteFactory))
389{
390}
391CDwFontContext::~CDwFontContext()
392{
393    if(dwriteFactory_ && hr_ == S_OK) {
394        dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader());
395    }
396    SafeRelease(&dwriteFactory_);
397}
398HRESULT CDwFontContext::Initialize()
399{
400    if (hr_ == S_FALSE) {
401        return hr_ = dwriteFactory_->RegisterFontFileLoader(CDwFontFileLoader::GetLoader());
402    }
403    return hr_;
404}
405CDwGdiTextRenderer::CDwGdiTextRenderer(CFX_DIBitmap* pBitmap, IDWriteBitmapRenderTarget* bitmapRenderTarget, IDWriteRenderingParams* renderingParams):
406    pBitmap_(pBitmap),
407    pRenderTarget_(SafeAcquire(bitmapRenderTarget)),
408    pRenderingParams_(SafeAcquire(renderingParams))
409{
410}
411CDwGdiTextRenderer::~CDwGdiTextRenderer()
412{
413    SafeRelease(&pRenderTarget_);
414    SafeRelease(&pRenderingParams_);
415}
416STDMETHODIMP 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