text: // 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_
  #include "../../../include/fxge/fx_ge_win32.h"
  #include "dwrite_int.h"
  #include "../Microsoft SDK/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 : public IDWriteFontFileStream, public CFX_Object
  {
  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 : public IDWriteFontFileLoader, public CFX_Object
  {
  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 CFX_Object
  {
  public:
      CDwFontContext(IDWriteFactory* dwriteFactory);
      ~CDwFontContext();
      HRESULT Initialize();
  private:
      CDwFontContext(CDwFontContext const&);
      void operator=(CDwFontContext const&);
      HRESULT hr_;
      IDWriteFactory* dwriteFactory_;
  };
  class CDwGdiTextRenderer : public CFX_Object
  {
  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
  