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