Home | History | Annotate | Download | only in win32
      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>
     20 inline void SafeRelease(InterfaceType** currentObject) {
     21   if (*currentObject) {
     22     (*currentObject)->Release();
     23     *currentObject = NULL;
     24   }
     25 }
     26 template <typename InterfaceType>
     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);
     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 
     67   static IDWriteFontFileLoader* GetLoader() {
     68     if (!instance_) {
     69       instance_ = new CDwFontFileLoader();
     70     }
     71     return instance_;
     72   }
     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 };
    112 CDWriteExt::CDWriteExt() {
    113   m_hModule = NULL;
    114   m_pDWriteFactory = NULL;
    115   m_pDwFontContext = NULL;
    116   m_pDwTextRenderer = NULL;
    117 }
    118 void CDWriteExt::Load() {}
    119 void CDWriteExt::Unload() {
    120   if (m_pDwFontContext) {
    121     delete (CDwFontContext*)m_pDwFontContext;
    122     m_pDwFontContext = NULL;
    123   }
    124   SafeRelease((IDWriteFactory**)&m_pDWriteFactory);
    125 }
    126 CDWriteExt::~CDWriteExt() {
    127   Unload();
    128 }
    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 }
    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 }
    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 }
    248 void CDWriteExt::DwDeleteRenderingTarget(void* renderTarget) {
    249   delete (CDwGdiTextRenderer*)renderTarget;
    250 }
    251 void CDWriteExt::DwDeleteFont(void* pFont) {
    252   if (pFont) {
    253     SafeRelease((IDWriteFontFace**)&pFont);
    254   }
    255 }
    256 CDwFontFileStream::CDwFontFileStream(void const* fontFileReferenceKey,
    257                                      UINT32 fontFileReferenceKeySize) {
    258   refCount_ = 0;
    259   resourcePtr_ = fontFileReferenceKey;
    260   resourceSize_ = fontFileReferenceKeySize;
    261 }
    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 }
    272 ULONG STDMETHODCALLTYPE CDwFontFileStream::AddRef() {
    273   return InterlockedIncrement((long*)(&refCount_));
    274 }
    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
    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
    299 CDwFontFileStream::ReleaseFileFragment(void* fragmentContext) {}
    300 HRESULT STDMETHODCALLTYPE CDwFontFileStream::GetFileSize(OUT UINT64* fileSize) {
    301   *fileSize = resourceSize_;
    302   return S_OK;
    303 }
    304 HRESULT STDMETHODCALLTYPE
    305 CDwFontFileStream::GetLastWriteTime(OUT UINT64* lastWriteTime) {
    306   *lastWriteTime = 0;
    307   return E_NOTIMPL;
    308 }
    309 IDWriteFontFileLoader* CDwFontFileLoader::instance_ = NULL;
    310 CDwFontFileLoader::CDwFontFileLoader() : refCount_(0) {}
    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 }
    321 ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef() {
    322   return InterlockedIncrement((long*)(&refCount_));
    323 }
    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 }
    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 }
    346 CDwFontContext::CDwFontContext(IDWriteFactory* dwriteFactory)
    347     : hr_(S_FALSE), dwriteFactory_(SafeAcquire(dwriteFactory)) {}
    348 CDwFontContext::~CDwFontContext() {
    349   if (dwriteFactory_ && hr_ == S_OK) {
    350     dwriteFactory_->UnregisterFontFileLoader(CDwFontFileLoader::GetLoader());
    351   }
    352   SafeRelease(&dwriteFactory_);
    353 }
    354 HRESULT CDwFontContext::Initialize() {
    355   if (hr_ == S_FALSE) {
    356     return hr_ = dwriteFactory_->RegisterFontFileLoader(
    357                CDwFontFileLoader::GetLoader());
    358   }
    359   return hr_;
    360 }
    361 CDwGdiTextRenderer::CDwGdiTextRenderer(
    362     CFX_DIBitmap* pBitmap,
    363     IDWriteBitmapRenderTarget* bitmapRenderTarget,
    364     IDWriteRenderingParams* renderingParams)
    365     : pBitmap_(pBitmap),
    366       pRenderTarget_(SafeAcquire(bitmapRenderTarget)),
    367       pRenderingParams_(SafeAcquire(renderingParams)) {}
    368 CDwGdiTextRenderer::~CDwGdiTextRenderer() {
    369   SafeRelease(&pRenderTarget_);
    370   SafeRelease(&pRenderingParams_);
    371 }
    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