// 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 typedef HRESULT (__stdcall *FuncType_DWriteCreateFactory)(__in DWRITE_FACTORY_TYPE, __in REFIID, __out IUnknown **); template inline void SafeRelease(InterfaceType** currentObject) { if (*currentObject != NULL) { (*currentObject)->Release(); *currentObject = NULL; } } template 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(resourcePtr_) + static_cast(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