| // 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 <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 |