Merge to XFA: Remove more cruft from fx_system.h
[pdfium.git] / core / src / fxge / win32 / fx_win32_dwrite.cpp
index d4c9620..022325b 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../../include/fxge/fx_ge.h"\r
-#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_\r
-#include "../../../include/fxge/fx_ge_win32.h"\r
-#include "dwrite_int.h"\r
-#include "../Microsoft SDK/include/DWrite.h"\r
-typedef HRESULT  (__stdcall *FuncType_DWriteCreateFactory)(__in DWRITE_FACTORY_TYPE, __in REFIID, __out IUnknown **);\r
-template <typename InterfaceType>\r
-inline void SafeRelease(InterfaceType** currentObject)\r
-{\r
-    if (*currentObject != NULL) {\r
-        (*currentObject)->Release();\r
-        *currentObject = NULL;\r
-    }\r
-}\r
-template <typename InterfaceType>\r
-inline InterfaceType* SafeAcquire(InterfaceType* newObject)\r
-{\r
-    if (newObject != NULL) {\r
-        newObject->AddRef();\r
-    }\r
-    return newObject;\r
-}\r
-class CDwFontFileStream : public IDWriteFontFileStream, public CFX_Object\r
-{\r
-public:\r
-    explicit CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize);\r
-    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);\r
-    virtual ULONG   STDMETHODCALLTYPE AddRef();\r
-    virtual ULONG   STDMETHODCALLTYPE Release();\r
-    virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, OUT void** fragmentContext);\r
-    virtual void    STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);\r
-    virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);\r
-    virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);\r
-    bool IsInitialized()\r
-    {\r
-        return resourcePtr_ != NULL;\r
-    }\r
-private:\r
-    ULONG refCount_;\r
-    void const* resourcePtr_;\r
-    DWORD resourceSize_;\r
-};\r
-class CDwFontFileLoader : public IDWriteFontFileLoader, public CFX_Object\r
-{\r
-public:\r
-    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);\r
-    virtual ULONG STDMETHODCALLTYPE AddRef();\r
-    virtual ULONG STDMETHODCALLTYPE Release();\r
-    virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize, OUT IDWriteFontFileStream** fontFileStream);\r
-\r
-    static IDWriteFontFileLoader* GetLoader()\r
-    {\r
-        if (instance_ == NULL) {\r
-            instance_ = FX_NEW CDwFontFileLoader();\r
-            return instance_;\r
-        }\r
-        return instance_;\r
-    }\r
-    static bool IsLoaderInitialized()\r
-    {\r
-        return instance_ != NULL;\r
-    }\r
-private:\r
-    CDwFontFileLoader();\r
-    ULONG refCount_;\r
-    static IDWriteFontFileLoader* instance_;\r
-};\r
-class CDwFontContext : public CFX_Object\r
-{\r
-public:\r
-    CDwFontContext(IDWriteFactory* dwriteFactory);\r
-    ~CDwFontContext();\r
-    HRESULT Initialize();\r
-private:\r
-    CDwFontContext(CDwFontContext const&);\r
-    void operator=(CDwFontContext const&);\r
-    HRESULT hr_;\r
-    IDWriteFactory* dwriteFactory_;\r
-};\r
-class CDwGdiTextRenderer : public CFX_Object\r
-{\r
-public:\r
-    CDwGdiTextRenderer(\r
-        CFX_DIBitmap* pBitmap,\r
-        IDWriteBitmapRenderTarget* bitmapRenderTarget,\r
-        IDWriteRenderingParams* renderingParams\r
-    );\r
-    CDwGdiTextRenderer::~CDwGdiTextRenderer();\r
-    HRESULT STDMETHODCALLTYPE DrawGlyphRun(\r
-        const FX_RECT& text_bbox,\r
-        __in_opt CFX_ClipRgn* pClipRgn,\r
-        __in_opt DWRITE_MATRIX const* pMatrix,\r
-        FLOAT baselineOriginX,\r
-        FLOAT baselineOriginY,\r
-        DWRITE_MEASURING_MODE measuringMode,\r
-        __in DWRITE_GLYPH_RUN const* glyphRun,\r
-        const COLORREF& textColor\r
-    );\r
-private:\r
-    CFX_DIBitmap* pBitmap_;\r
-    IDWriteBitmapRenderTarget* pRenderTarget_;\r
-    IDWriteRenderingParams* pRenderingParams_;\r
-};\r
-CDWriteExt::CDWriteExt()\r
-{\r
-    m_hModule = NULL;\r
-    m_pDWriteFactory = NULL;\r
-    m_pDwFontContext = NULL;\r
-    m_pDwTextRenderer = NULL;\r
-}\r
-void CDWriteExt::Load()\r
-{\r
-}\r
-void CDWriteExt::Unload()\r
-{\r
-    if (m_pDwFontContext) {\r
-        delete (CDwFontContext*)m_pDwFontContext;\r
-        m_pDwFontContext = NULL;\r
-    }\r
-    SafeRelease((IDWriteFactory**)&m_pDWriteFactory);\r
-}\r
-CDWriteExt::~CDWriteExt()\r
-{\r
-    Unload();\r
-}\r
-LPVOID CDWriteExt::DwCreateFontFaceFromStream(FX_LPBYTE pData, FX_DWORD size, int simulation_style)\r
-{\r
-    IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;\r
-    IDWriteFontFile* pDwFontFile = NULL;\r
-    IDWriteFontFace* pDwFontFace = NULL;\r
-    BOOL isSupportedFontType = FALSE;\r
-    DWRITE_FONT_FILE_TYPE fontFileType;\r
-    DWRITE_FONT_FACE_TYPE fontFaceType;\r
-    UINT32 numberOfFaces;\r
-    DWRITE_FONT_SIMULATIONS fontStyle = (DWRITE_FONT_SIMULATIONS)(simulation_style & 3);\r
-    HRESULT hr = S_OK;\r
-    hr = pDwFactory->CreateCustomFontFileReference(\r
-             (void const*)pData,\r
-             (UINT32)size,\r
-             CDwFontFileLoader::GetLoader(),\r
-             &pDwFontFile\r
-         );\r
-    if (FAILED(hr)) {\r
-        goto failed;\r
-    }\r
-    hr = pDwFontFile->Analyze(\r
-             &isSupportedFontType,\r
-             &fontFileType,\r
-             &fontFaceType,\r
-             &numberOfFaces\r
-         );\r
-    if (FAILED(hr) || !isSupportedFontType || fontFaceType == DWRITE_FONT_FACE_TYPE_UNKNOWN) {\r
-        goto failed;\r
-    }\r
-    hr = pDwFactory->CreateFontFace(\r
-             fontFaceType,\r
-             1,\r
-             &pDwFontFile,\r
-             0,\r
-             fontStyle,\r
-             &pDwFontFace\r
-         );\r
-    if (FAILED(hr)) {\r
-        goto failed;\r
-    }\r
-    SafeRelease(&pDwFontFile);\r
-    return pDwFontFace;\r
-failed:\r
-    SafeRelease(&pDwFontFile);\r
-    return NULL;\r
-}\r
-FX_BOOL CDWriteExt::DwCreateRenderingTarget(CFX_DIBitmap* pBitmap, void** renderTarget)\r
-{\r
-    if (pBitmap->GetFormat() > FXDIB_Argb) {\r
-        return FALSE;\r
-    }\r
-    IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;\r
-    IDWriteGdiInterop* pGdiInterop = NULL;\r
-    IDWriteBitmapRenderTarget* pBitmapRenderTarget = NULL;\r
-    IDWriteRenderingParams* pRenderingParams = NULL;\r
-    HRESULT hr = S_OK;\r
-    hr = pDwFactory->GetGdiInterop(&pGdiInterop);\r
-    if (FAILED(hr)) {\r
-        goto failed;\r
-    }\r
-    hr = pGdiInterop->CreateBitmapRenderTarget(NULL, pBitmap->GetWidth(), pBitmap->GetHeight(),\r
-            &pBitmapRenderTarget);\r
-    if (FAILED(hr)) {\r
-        goto failed;\r
-    }\r
-    hr = pDwFactory->CreateCustomRenderingParams(\r
-             1.0f,\r
-             0.0f,\r
-             1.0f,\r
-             DWRITE_PIXEL_GEOMETRY_RGB,\r
-             DWRITE_RENDERING_MODE_DEFAULT,\r
-             &pRenderingParams\r
-         );\r
-    if (FAILED(hr)) {\r
-        goto failed;\r
-    }\r
-    hr = pBitmapRenderTarget->SetPixelsPerDip(1.0f);\r
-    if (FAILED(hr)) {\r
-        goto failed;\r
-    }\r
-    *(CDwGdiTextRenderer**)renderTarget = FX_NEW CDwGdiTextRenderer(pBitmap, pBitmapRenderTarget, pRenderingParams);\r
-    if (*(CDwGdiTextRenderer**)renderTarget == NULL) {\r
-        goto failed;\r
-    }\r
-    SafeRelease(&pGdiInterop);\r
-    SafeRelease(&pBitmapRenderTarget);\r
-    SafeRelease(&pRenderingParams);\r
-    return TRUE;\r
-failed:\r
-    SafeRelease(&pGdiInterop);\r
-    SafeRelease(&pBitmapRenderTarget);\r
-    SafeRelease(&pRenderingParams);\r
-    return FALSE;\r
-}\r
-FX_BOOL        CDWriteExt::DwRendingString(void* renderTarget, CFX_ClipRgn* pClipRgn, FX_RECT& stringRect, CFX_AffineMatrix* pMatrix,\r
-                                    void *font, FX_FLOAT font_size, FX_ARGB text_color,\r
-                                    int glyph_count, unsigned short* glyph_indices,\r
-                                    FX_FLOAT baselineOriginX, FX_FLOAT baselineOriginY,\r
-                                    void* glyph_offsets,\r
-                                    FX_FLOAT* glyph_advances)\r
-{\r
-    if (renderTarget == NULL) {\r
-        return TRUE;\r
-    }\r
-    CDwGdiTextRenderer* pTextRenderer = (CDwGdiTextRenderer*)renderTarget;\r
-    DWRITE_MATRIX transform;\r
-    DWRITE_GLYPH_RUN glyphRun;\r
-    HRESULT hr = S_OK;\r
-    if (pMatrix) {\r
-        transform.m11 = pMatrix->a;\r
-        transform.m12 = pMatrix->b;\r
-        transform.m21 = pMatrix->c;\r
-        transform.m22 = pMatrix->d;\r
-        transform.dx = pMatrix->e;\r
-        transform.dy = pMatrix->f;\r
-    }\r
-    glyphRun.fontFace = (IDWriteFontFace*)font;\r
-    glyphRun.fontEmSize = font_size;\r
-    glyphRun.glyphCount = glyph_count;\r
-    glyphRun.glyphIndices = glyph_indices;\r
-    glyphRun.glyphAdvances = glyph_advances;\r
-    glyphRun.glyphOffsets = (DWRITE_GLYPH_OFFSET*)glyph_offsets;\r
-    glyphRun.isSideways = FALSE;\r
-    glyphRun.bidiLevel = 0;\r
-    hr = pTextRenderer->DrawGlyphRun(\r
-             stringRect,\r
-             pClipRgn,\r
-             pMatrix ? &transform : NULL,\r
-             baselineOriginX, baselineOriginY,\r
-             DWRITE_MEASURING_MODE_NATURAL,\r
-             &glyphRun,\r
-             RGB(FXARGB_R(text_color), FXARGB_G(text_color), FXARGB_B(text_color))\r
-         );\r
-    return SUCCEEDED(hr) ? TRUE : FALSE;\r
-}\r
-void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget)\r
-{\r
-    if (renderTarget) {\r
-        delete (CDwGdiTextRenderer*)renderTarget;\r
-    }\r
-}\r
-void CDWriteExt::DwDeleteFont(void* pFont)\r
-{\r
-    if (pFont) {\r
-        SafeRelease((IDWriteFontFace**)&pFont);\r
-    }\r
-}\r
-CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize)\r
-{\r
-    refCount_ = 0;\r
-    resourcePtr_ = fontFileReferenceKey;\r
-    resourceSize_ = fontFileReferenceKeySize;\r
-}\r
-HRESULT STDMETHODCALLTYPE CDwFontFileStream::QueryInterface(REFIID iid, void** ppvObject)\r
-{\r
-    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {\r
-        *ppvObject = this;\r
-        AddRef();\r
-        return S_OK;\r
-    } else {\r
-        *ppvObject = NULL;\r
-        return E_NOINTERFACE;\r
-    }\r
-}\r
-ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef()\r
-{\r
-    return InterlockedIncrement((long*)(&refCount_));\r
-}\r
-ULONG STDMETHODCALLTYPE CDwFontFileStream::Release()\r
-{\r
-    ULONG newCount = InterlockedDecrement((long*)(&refCount_));\r
-    if (newCount == 0) {\r
-        delete this;\r
-    }\r
-    return newCount;\r
-}\r
-HRESULT STDMETHODCALLTYPE CDwFontFileStream::ReadFileFragment(\r
-    void const** fragmentStart,\r
-    UINT64 fileOffset,\r
-    UINT64 fragmentSize,\r
-    OUT void** fragmentContext\r
-)\r
-{\r
-    if (fileOffset <= resourceSize_ &&\r
-            fragmentSize <= resourceSize_ - fileOffset) {\r
-        *fragmentStart = static_cast<FX_BYTE const*>(resourcePtr_) + static_cast<size_t>(fileOffset);\r
-        *fragmentContext = NULL;\r
-        return S_OK;\r
-    } else {\r
-        *fragmentStart = NULL;\r
-        *fragmentContext = NULL;\r
-        return E_FAIL;\r
-    }\r
-}\r
-void STDMETHODCALLTYPE CDwFontFileStream::ReleaseFileFragment(void* fragmentContext)\r
-{\r
-}\r
-HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize)\r
-{\r
-    *fileSize = resourceSize_;\r
-    return S_OK;\r
-}\r
-HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime)\r
-{\r
-    *lastWriteTime = 0;\r
-    return E_NOTIMPL;\r
-}\r
-IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL;\r
-CDwFontFileLoader::CDwFontFileLoader() :\r
-    refCount_(0)\r
-{\r
-}\r
-HRESULT STDMETHODCALLTYPE CDwFontFileLoader::QueryInterface(REFIID iid, void** ppvObject)\r
-{\r
-    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {\r
-        *ppvObject = this;\r
-        AddRef();\r
-        return S_OK;\r
-    } else {\r
-        *ppvObject = NULL;\r
-        return E_NOINTERFACE;\r
-    }\r
-}\r
-ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef()\r
-{\r
-    return InterlockedIncrement((long*)(&refCount_));\r
-}\r
-ULONG STDMETHODCALLTYPE CDwFontFileLoader::Release()\r
-{\r
-    ULONG newCount = InterlockedDecrement((long*)(&refCount_));\r
-    if (newCount == 0) {\r
-        instance_ = NULL;\r
-        delete this;\r
-    }\r
-    return newCount;\r
-}\r
-HRESULT STDMETHODCALLTYPE CDwFontFileLoader::CreateStreamFromKey(\r
-    void const* fontFileReferenceKey,\r
-    UINT32 fontFileReferenceKeySize,\r
-    OUT IDWriteFontFileStream** fontFileStream\r
-)\r
-{\r
-    *fontFileStream = NULL;\r
-    CDwFontFileStream* stream = FX_NEW CDwFontFileStream(fontFileReferenceKey, fontFileReferenceKeySize);\r
-    if (stream == NULL)        {\r
-        return E_OUTOFMEMORY;\r
-    }\r
-    if (!stream->IsInitialized()) {\r
-        delete stream;\r
-        return E_FAIL;\r
-    }\r
-    *fontFileStream = SafeAcquire(stream);\r
-    return S_OK;\r
-}\r
-CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory) :\r
-    hr_(S_FALSE),\r
-    dwriteFactory_(SafeAcquire(dwriteFactory))\r
-{\r
-}\r
-CDwFontContext::~CDwFontContext()\r
-{\r
-    if(dwriteFactory_ && hr_ == S_OK) {\r
-        dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader());\r
-    }\r
-    SafeRelease(&dwriteFactory_);\r
-}\r
-HRESULT CDwFontContext::Initialize()\r
-{\r
-    if (hr_ == S_FALSE) {\r
-        return hr_ = dwriteFactory_->RegisterFontFileLoader(CDwFontFileLoader::GetLoader());\r
-    }\r
-    return hr_;\r
-}\r
-CDwGdiTextRenderer::CDwGdiTextRenderer(CFX_DIBitmap* pBitmap, IDWriteBitmapRenderTarget* bitmapRenderTarget, IDWriteRenderingParams* renderingParams):\r
-    pBitmap_(pBitmap),\r
-    pRenderTarget_(SafeAcquire(bitmapRenderTarget)),\r
-    pRenderingParams_(SafeAcquire(renderingParams))\r
-{\r
-}\r
-CDwGdiTextRenderer::~CDwGdiTextRenderer()\r
-{\r
-    SafeRelease(&pRenderTarget_);\r
-    SafeRelease(&pRenderingParams_);\r
-}\r
-STDMETHODIMP CDwGdiTextRenderer::DrawGlyphRun(\r
-    const FX_RECT& text_bbox,\r
-    __in_opt CFX_ClipRgn* pClipRgn,\r
-    __in_opt DWRITE_MATRIX const* pMatrix,\r
-    FLOAT baselineOriginX,\r
-    FLOAT baselineOriginY,\r
-    DWRITE_MEASURING_MODE measuringMode,\r
-    __in DWRITE_GLYPH_RUN const* glyphRun,\r
-    const COLORREF& textColor\r
-)\r
-{\r
-    HRESULT hr = S_OK;\r
-    if (pMatrix) {\r
-        hr = pRenderTarget_->SetCurrentTransform(pMatrix);\r
-        if (FAILED(hr)) {\r
-            return hr;\r
-        }\r
-    }\r
-    HDC hDC = pRenderTarget_->GetMemoryDC();\r
-    HBITMAP hBitmap = (HBITMAP)::GetCurrentObject(hDC, OBJ_BITMAP);\r
-    BITMAP bitmap;\r
-    GetObject(hBitmap, sizeof bitmap, &bitmap);\r
-    CFX_DIBitmap dib;\r
-    dib.Create(\r
-        bitmap.bmWidth,\r
-        bitmap.bmHeight,\r
-        bitmap.bmBitsPixel == 24 ? FXDIB_Rgb : FXDIB_Rgb32,\r
-        (FX_LPBYTE)bitmap.bmBits\r
-    );\r
-    dib.CompositeBitmap(\r
-        text_bbox.left,\r
-        text_bbox.top,\r
-        text_bbox.Width(),\r
-        text_bbox.Height(),\r
-        pBitmap_,\r
-        text_bbox.left,\r
-        text_bbox.top,\r
-        FXDIB_BLEND_NORMAL,\r
-        NULL\r
-    );\r
-    hr = pRenderTarget_->DrawGlyphRun(\r
-             baselineOriginX,\r
-             baselineOriginY,\r
-             measuringMode,\r
-             glyphRun,\r
-             pRenderingParams_,\r
-             textColor\r
-         );\r
-    if (FAILED(hr)) {\r
-        return hr;\r
-    }\r
-    pBitmap_->CompositeBitmap(\r
-        text_bbox.left,\r
-        text_bbox.top,\r
-        text_bbox.Width(),\r
-        text_bbox.Height(),\r
-        &dib,\r
-        text_bbox.left,\r
-        text_bbox.top,\r
-        FXDIB_BLEND_NORMAL,\r
-        pClipRgn\r
-    );\r
-    return hr;\r
-}\r
-#endif\r
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "../../../include/fxge/fx_ge.h"
+#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_
+#include "../../../include/fxge/fx_ge_win32.h"
+#include "dwrite_int.h"
+#include <dwrite.h>
+typedef HRESULT  (__stdcall *FuncType_DWriteCreateFactory)(__in DWRITE_FACTORY_TYPE, __in REFIID, __out IUnknown **);
+template <typename InterfaceType>
+inline void SafeRelease(InterfaceType** currentObject)
+{
+    if (*currentObject != NULL) {
+        (*currentObject)->Release();
+        *currentObject = NULL;
+    }
+}
+template <typename InterfaceType>
+inline InterfaceType* SafeAcquire(InterfaceType* newObject)
+{
+    if (newObject != NULL) {
+        newObject->AddRef();
+    }
+    return newObject;
+}
+class CDwFontFileStream final : public IDWriteFontFileStream
+{
+public:
+    explicit CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize);
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
+    virtual ULONG   STDMETHODCALLTYPE AddRef();
+    virtual ULONG   STDMETHODCALLTYPE Release();
+    virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, OUT void** fragmentContext);
+    virtual void    STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
+    virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
+    virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
+    bool IsInitialized()
+    {
+        return resourcePtr_ != NULL;
+    }
+private:
+    ULONG refCount_;
+    void const* resourcePtr_;
+    DWORD resourceSize_;
+};
+class CDwFontFileLoader final : public IDWriteFontFileLoader
+{
+public:
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
+    virtual ULONG STDMETHODCALLTYPE AddRef();
+    virtual ULONG STDMETHODCALLTYPE Release();
+    virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize, OUT IDWriteFontFileStream** fontFileStream);
+
+    static IDWriteFontFileLoader* GetLoader()
+    {
+        if (instance_ == NULL) {
+            instance_ = FX_NEW CDwFontFileLoader();
+            return instance_;
+        }
+        return instance_;
+    }
+    static bool IsLoaderInitialized()
+    {
+        return instance_ != NULL;
+    }
+private:
+    CDwFontFileLoader();
+    ULONG refCount_;
+    static IDWriteFontFileLoader* instance_;
+};
+class CDwFontContext 
+{
+public:
+    CDwFontContext(IDWriteFactory* dwriteFactory);
+    ~CDwFontContext();
+    HRESULT Initialize();
+private:
+    CDwFontContext(CDwFontContext const&);
+    void operator=(CDwFontContext const&);
+    HRESULT hr_;
+    IDWriteFactory* dwriteFactory_;
+};
+class CDwGdiTextRenderer 
+{
+public:
+    CDwGdiTextRenderer(
+        CFX_DIBitmap* pBitmap,
+        IDWriteBitmapRenderTarget* bitmapRenderTarget,
+        IDWriteRenderingParams* renderingParams
+    );
+    CDwGdiTextRenderer::~CDwGdiTextRenderer();
+    HRESULT STDMETHODCALLTYPE 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
+    );
+private:
+    CFX_DIBitmap* pBitmap_;
+    IDWriteBitmapRenderTarget* pRenderTarget_;
+    IDWriteRenderingParams* pRenderingParams_;
+};
+CDWriteExt::CDWriteExt()
+{
+    m_hModule = NULL;
+    m_pDWriteFactory = NULL;
+    m_pDwFontContext = NULL;
+    m_pDwTextRenderer = NULL;
+}
+void CDWriteExt::Load()
+{
+}
+void CDWriteExt::Unload()
+{
+    if (m_pDwFontContext) {
+        delete (CDwFontContext*)m_pDwFontContext;
+        m_pDwFontContext = NULL;
+    }
+    SafeRelease((IDWriteFactory**)&m_pDWriteFactory);
+}
+CDWriteExt::~CDWriteExt()
+{
+    Unload();
+}
+LPVOID CDWriteExt::DwCreateFontFaceFromStream(FX_LPBYTE pData, FX_DWORD size, int simulation_style)
+{
+    IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;
+    IDWriteFontFile* pDwFontFile = NULL;
+    IDWriteFontFace* pDwFontFace = NULL;
+    BOOL isSupportedFontType = FALSE;
+    DWRITE_FONT_FILE_TYPE fontFileType;
+    DWRITE_FONT_FACE_TYPE fontFaceType;
+    UINT32 numberOfFaces;
+    DWRITE_FONT_SIMULATIONS fontStyle = (DWRITE_FONT_SIMULATIONS)(simulation_style & 3);
+    HRESULT hr = S_OK;
+    hr = pDwFactory->CreateCustomFontFileReference(
+             (void const*)pData,
+             (UINT32)size,
+             CDwFontFileLoader::GetLoader(),
+             &pDwFontFile
+         );
+    if (FAILED(hr)) {
+        goto failed;
+    }
+    hr = pDwFontFile->Analyze(
+             &isSupportedFontType,
+             &fontFileType,
+             &fontFaceType,
+             &numberOfFaces
+         );
+    if (FAILED(hr) || !isSupportedFontType || fontFaceType == DWRITE_FONT_FACE_TYPE_UNKNOWN) {
+        goto failed;
+    }
+    hr = pDwFactory->CreateFontFace(
+             fontFaceType,
+             1,
+             &pDwFontFile,
+             0,
+             fontStyle,
+             &pDwFontFace
+         );
+    if (FAILED(hr)) {
+        goto failed;
+    }
+    SafeRelease(&pDwFontFile);
+    return pDwFontFace;
+failed:
+    SafeRelease(&pDwFontFile);
+    return NULL;
+}
+FX_BOOL CDWriteExt::DwCreateRenderingTarget(CFX_DIBitmap* pBitmap, void** renderTarget)
+{
+    if (pBitmap->GetFormat() > FXDIB_Argb) {
+        return FALSE;
+    }
+    IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;
+    IDWriteGdiInterop* pGdiInterop = NULL;
+    IDWriteBitmapRenderTarget* pBitmapRenderTarget = NULL;
+    IDWriteRenderingParams* pRenderingParams = NULL;
+    HRESULT hr = S_OK;
+    hr = pDwFactory->GetGdiInterop(&pGdiInterop);
+    if (FAILED(hr)) {
+        goto failed;
+    }
+    hr = pGdiInterop->CreateBitmapRenderTarget(NULL, pBitmap->GetWidth(), pBitmap->GetHeight(),
+            &pBitmapRenderTarget);
+    if (FAILED(hr)) {
+        goto failed;
+    }
+    hr = pDwFactory->CreateCustomRenderingParams(
+             1.0f,
+             0.0f,
+             1.0f,
+             DWRITE_PIXEL_GEOMETRY_RGB,
+             DWRITE_RENDERING_MODE_DEFAULT,
+             &pRenderingParams
+         );
+    if (FAILED(hr)) {
+        goto failed;
+    }
+    hr = pBitmapRenderTarget->SetPixelsPerDip(1.0f);
+    if (FAILED(hr)) {
+        goto failed;
+    }
+    *(CDwGdiTextRenderer**)renderTarget = FX_NEW CDwGdiTextRenderer(pBitmap, pBitmapRenderTarget, pRenderingParams);
+    if (*(CDwGdiTextRenderer**)renderTarget == NULL) {
+        goto failed;
+    }
+    SafeRelease(&pGdiInterop);
+    SafeRelease(&pBitmapRenderTarget);
+    SafeRelease(&pRenderingParams);
+    return TRUE;
+failed:
+    SafeRelease(&pGdiInterop);
+    SafeRelease(&pBitmapRenderTarget);
+    SafeRelease(&pRenderingParams);
+    return FALSE;
+}
+FX_BOOL        CDWriteExt::DwRendingString(void* renderTarget, CFX_ClipRgn* pClipRgn, FX_RECT& stringRect, CFX_AffineMatrix* 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)
+{
+    if (renderTarget == NULL) {
+        return TRUE;
+    }
+    CDwGdiTextRenderer* pTextRenderer = (CDwGdiTextRenderer*)renderTarget;
+    DWRITE_MATRIX transform;
+    DWRITE_GLYPH_RUN glyphRun;
+    HRESULT hr = S_OK;
+    if (pMatrix) {
+        transform.m11 = pMatrix->a;
+        transform.m12 = pMatrix->b;
+        transform.m21 = pMatrix->c;
+        transform.m22 = pMatrix->d;
+        transform.dx = pMatrix->e;
+        transform.dy = pMatrix->f;
+    }
+    glyphRun.fontFace = (IDWriteFontFace*)font;
+    glyphRun.fontEmSize = font_size;
+    glyphRun.glyphCount = glyph_count;
+    glyphRun.glyphIndices = glyph_indices;
+    glyphRun.glyphAdvances = glyph_advances;
+    glyphRun.glyphOffsets = (DWRITE_GLYPH_OFFSET*)glyph_offsets;
+    glyphRun.isSideways = FALSE;
+    glyphRun.bidiLevel = 0;
+    hr = pTextRenderer->DrawGlyphRun(
+             stringRect,
+             pClipRgn,
+             pMatrix ? &transform : NULL,
+             baselineOriginX, baselineOriginY,
+             DWRITE_MEASURING_MODE_NATURAL,
+             &glyphRun,
+             RGB(FXARGB_R(text_color), FXARGB_G(text_color), FXARGB_B(text_color))
+         );
+    return SUCCEEDED(hr) ? TRUE : FALSE;
+}
+void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget)
+{
+    if (renderTarget) {
+        delete (CDwGdiTextRenderer*)renderTarget;
+    }
+}
+void CDWriteExt::DwDeleteFont(void* pFont)
+{
+    if (pFont) {
+        SafeRelease((IDWriteFontFace**)&pFont);
+    }
+}
+CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize)
+{
+    refCount_ = 0;
+    resourcePtr_ = fontFileReferenceKey;
+    resourceSize_ = fontFileReferenceKeySize;
+}
+HRESULT STDMETHODCALLTYPE CDwFontFileStream::QueryInterface(REFIID iid, void** ppvObject)
+{
+    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
+        *ppvObject = this;
+        AddRef();
+        return S_OK;
+    } else {
+        *ppvObject = NULL;
+        return E_NOINTERFACE;
+    }
+}
+ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef()
+{
+    return InterlockedIncrement((long*)(&refCount_));
+}
+ULONG STDMETHODCALLTYPE CDwFontFileStream::Release()
+{
+    ULONG newCount = InterlockedDecrement((long*)(&refCount_));
+    if (newCount == 0) {
+        delete this;
+    }
+    return newCount;
+}
+HRESULT STDMETHODCALLTYPE CDwFontFileStream::ReadFileFragment(
+    void const** fragmentStart,
+    UINT64 fileOffset,
+    UINT64 fragmentSize,
+    OUT void** fragmentContext
+)
+{
+    if (fileOffset <= resourceSize_ &&
+            fragmentSize <= resourceSize_ - fileOffset) {
+        *fragmentStart = static_cast<FX_BYTE const*>(resourcePtr_) + static_cast<size_t>(fileOffset);
+        *fragmentContext = NULL;
+        return S_OK;
+    } else {
+        *fragmentStart = NULL;
+        *fragmentContext = NULL;
+        return E_FAIL;
+    }
+}
+void STDMETHODCALLTYPE CDwFontFileStream::ReleaseFileFragment(void* fragmentContext)
+{
+}
+HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize)
+{
+    *fileSize = resourceSize_;
+    return S_OK;
+}
+HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime)
+{
+    *lastWriteTime = 0;
+    return E_NOTIMPL;
+}
+IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL;
+CDwFontFileLoader::CDwFontFileLoader() :
+    refCount_(0)
+{
+}
+HRESULT STDMETHODCALLTYPE CDwFontFileLoader::QueryInterface(REFIID iid, void** ppvObject)
+{
+    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
+        *ppvObject = this;
+        AddRef();
+        return S_OK;
+    } else {
+        *ppvObject = NULL;
+        return E_NOINTERFACE;
+    }
+}
+ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef()
+{
+    return InterlockedIncrement((long*)(&refCount_));
+}
+ULONG STDMETHODCALLTYPE CDwFontFileLoader::Release()
+{
+    ULONG newCount = InterlockedDecrement((long*)(&refCount_));
+    if (newCount == 0) {
+        instance_ = NULL;
+        delete this;
+    }
+    return newCount;
+}
+HRESULT STDMETHODCALLTYPE CDwFontFileLoader::CreateStreamFromKey(
+    void const* fontFileReferenceKey,
+    UINT32 fontFileReferenceKeySize,
+    OUT IDWriteFontFileStream** fontFileStream
+)
+{
+    *fontFileStream = NULL;
+    CDwFontFileStream* stream = FX_NEW CDwFontFileStream(fontFileReferenceKey, fontFileReferenceKeySize);
+    if (stream == NULL)        {
+        return E_OUTOFMEMORY;
+    }
+    if (!stream->IsInitialized()) {
+        delete stream;
+        return E_FAIL;
+    }
+    *fontFileStream = SafeAcquire(stream);
+    return S_OK;
+}
+CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory) :
+    hr_(S_FALSE),
+    dwriteFactory_(SafeAcquire(dwriteFactory))
+{
+}
+CDwFontContext::~CDwFontContext()
+{
+    if(dwriteFactory_ && hr_ == S_OK) {
+        dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader());
+    }
+    SafeRelease(&dwriteFactory_);
+}
+HRESULT CDwFontContext::Initialize()
+{
+    if (hr_ == S_FALSE) {
+        return hr_ = dwriteFactory_->RegisterFontFileLoader(CDwFontFileLoader::GetLoader());
+    }
+    return hr_;
+}
+CDwGdiTextRenderer::CDwGdiTextRenderer(CFX_DIBitmap* pBitmap, IDWriteBitmapRenderTarget* bitmapRenderTarget, IDWriteRenderingParams* renderingParams):
+    pBitmap_(pBitmap),
+    pRenderTarget_(SafeAcquire(bitmapRenderTarget)),
+    pRenderingParams_(SafeAcquire(renderingParams))
+{
+}
+CDwGdiTextRenderer::~CDwGdiTextRenderer()
+{
+    SafeRelease(&pRenderTarget_);
+    SafeRelease(&pRenderingParams_);
+}
+STDMETHODIMP CDwGdiTextRenderer::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
+)
+{
+    HRESULT hr = S_OK;
+    if (pMatrix) {
+        hr = pRenderTarget_->SetCurrentTransform(pMatrix);
+        if (FAILED(hr)) {
+            return hr;
+        }
+    }
+    HDC hDC = pRenderTarget_->GetMemoryDC();
+    HBITMAP hBitmap = (HBITMAP)::GetCurrentObject(hDC, OBJ_BITMAP);
+    BITMAP bitmap;
+    GetObject(hBitmap, sizeof bitmap, &bitmap);
+    CFX_DIBitmap dib;
+    dib.Create(
+        bitmap.bmWidth,
+        bitmap.bmHeight,
+        bitmap.bmBitsPixel == 24 ? FXDIB_Rgb : FXDIB_Rgb32,
+        (FX_LPBYTE)bitmap.bmBits
+    );
+    dib.CompositeBitmap(
+        text_bbox.left,
+        text_bbox.top,
+        text_bbox.Width(),
+        text_bbox.Height(),
+        pBitmap_,
+        text_bbox.left,
+        text_bbox.top,
+        FXDIB_BLEND_NORMAL,
+        NULL
+    );
+    hr = pRenderTarget_->DrawGlyphRun(
+             baselineOriginX,
+             baselineOriginY,
+             measuringMode,
+             glyphRun,
+             pRenderingParams_,
+             textColor
+         );
+    if (FAILED(hr)) {
+        return hr;
+    }
+    pBitmap_->CompositeBitmap(
+        text_bbox.left,
+        text_bbox.top,
+        text_bbox.Width(),
+        text_bbox.Height(),
+        &dib,
+        text_bbox.left,
+        text_bbox.top,
+        FXDIB_BLEND_NORMAL,
+        pClipRgn
+    );
+    return hr;
+}
+#endif