// 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 "core/fxge/include/fx_ge.h"
|
|
#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_DESKTOP_
|
#include <dwrite.h>
|
|
#include "core/fxge/include/fx_ge_win32.h"
|
#include "core/fxge/win32/dwrite_int.h"
|
|
typedef HRESULT(__stdcall* FuncType_DWriteCreateFactory)(
|
__in DWRITE_FACTORY_TYPE,
|
__in REFIID,
|
__out IUnknown**);
|
template <typename InterfaceType>
|
inline void SafeRelease(InterfaceType** currentObject) {
|
if (*currentObject) {
|
(*currentObject)->Release();
|
*currentObject = nullptr;
|
}
|
}
|
template <typename InterfaceType>
|
inline InterfaceType* SafeAcquire(InterfaceType* newObject) {
|
if (newObject) {
|
newObject->AddRef();
|
}
|
return newObject;
|
}
|
|
class CDwFontFileStream final : public IDWriteFontFileStream {
|
public:
|
explicit CDwFontFileStream(void const* fontFileReferenceKey,
|
UINT32 fontFileReferenceKeySize);
|
|
// IUnknown.
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
|
void** ppvObject) override;
|
ULONG STDMETHODCALLTYPE AddRef() override;
|
ULONG STDMETHODCALLTYPE Release() override;
|
|
// IDWriteFontFileStream.
|
HRESULT STDMETHODCALLTYPE
|
ReadFileFragment(void const** fragmentStart,
|
UINT64 fileOffset,
|
UINT64 fragmentSize,
|
OUT void** fragmentContext) override;
|
void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext) override;
|
HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize) override;
|
HRESULT STDMETHODCALLTYPE
|
GetLastWriteTime(OUT UINT64* lastWriteTime) override;
|
|
bool IsInitialized() { return !!resourcePtr_; }
|
|
private:
|
ULONG refCount_;
|
void const* resourcePtr_;
|
DWORD resourceSize_;
|
};
|
|
class CDwFontFileLoader final : public IDWriteFontFileLoader {
|
public:
|
// IUnknown.
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
|
void** ppvObject) override;
|
ULONG STDMETHODCALLTYPE AddRef() override;
|
ULONG STDMETHODCALLTYPE Release() override;
|
|
// IDWriteFontFileLoader.
|
HRESULT STDMETHODCALLTYPE
|
CreateStreamFromKey(void const* fontFileReferenceKey,
|
UINT32 fontFileReferenceKeySize,
|
OUT IDWriteFontFileStream** fontFileStream) override;
|
|
static IDWriteFontFileLoader* GetLoader() {
|
if (!instance_) {
|
instance_ = new CDwFontFileLoader();
|
}
|
return instance_;
|
}
|
static bool IsLoaderInitialized() { return !!instance_; }
|
|
private:
|
CDwFontFileLoader();
|
ULONG refCount_;
|
static IDWriteFontFileLoader* instance_;
|
};
|
|
class CDwFontContext {
|
public:
|
CDwFontContext(IDWriteFactory* dwriteFactory);
|
~CDwFontContext();
|
|
HRESULT Initialize();
|
|
private:
|
CDwFontContext(CDwFontContext const&);
|
void operator=(CDwFontContext const&);
|
HRESULT hr_;
|
IDWriteFactory* dwriteFactory_;
|
};
|
|
class CDwGdiTextRenderer {
|
public:
|
CDwGdiTextRenderer(CFX_DIBitmap* pBitmap,
|
IDWriteBitmapRenderTarget* bitmapRenderTarget,
|
IDWriteRenderingParams* renderingParams);
|
~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(nullptr),
|
m_pDWriteFactory(nullptr),
|
m_pDwFontContext(nullptr),
|
m_pDwTextRenderer(nullptr) {}
|
|
void CDWriteExt::Load() {}
|
|
void CDWriteExt::Unload() {
|
if (m_pDwFontContext) {
|
delete (CDwFontContext*)m_pDwFontContext;
|
m_pDwFontContext = nullptr;
|
}
|
SafeRelease((IDWriteFactory**)&m_pDWriteFactory);
|
}
|
|
CDWriteExt::~CDWriteExt() {
|
Unload();
|
}
|
|
LPVOID CDWriteExt::DwCreateFontFaceFromStream(uint8_t* pData,
|
uint32_t size,
|
int simulation_style) {
|
IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;
|
IDWriteFontFile* pDwFontFile = nullptr;
|
IDWriteFontFace* pDwFontFace = nullptr;
|
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 nullptr;
|
}
|
|
FX_BOOL CDWriteExt::DwCreateRenderingTarget(CFX_DIBitmap* pBitmap,
|
void** renderTarget) {
|
if (pBitmap->GetFormat() > FXDIB_Argb) {
|
return FALSE;
|
}
|
IDWriteFactory* pDwFactory = (IDWriteFactory*)m_pDWriteFactory;
|
IDWriteGdiInterop* pGdiInterop = nullptr;
|
IDWriteBitmapRenderTarget* pBitmapRenderTarget = nullptr;
|
IDWriteRenderingParams* pRenderingParams = nullptr;
|
HRESULT hr = S_OK;
|
hr = pDwFactory->GetGdiInterop(&pGdiInterop);
|
if (FAILED(hr)) {
|
goto failed;
|
}
|
hr = pGdiInterop->CreateBitmapRenderTarget(
|
nullptr, 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 =
|
new CDwGdiTextRenderer(pBitmap, pBitmapRenderTarget, pRenderingParams);
|
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_Matrix* 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) {
|
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 : nullptr, baselineOriginX,
|
baselineOriginY, DWRITE_MEASURING_MODE_NATURAL, &glyphRun,
|
RGB(FXARGB_R(text_color), FXARGB_G(text_color), FXARGB_B(text_color)));
|
return SUCCEEDED(hr);
|
}
|
|
void CDWriteExt::DwDeleteRenderingTarget(void* 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;
|
}
|
*ppvObject = nullptr;
|
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<uint8_t const*>(resourcePtr_) +
|
static_cast<size_t>(fileOffset);
|
*fragmentContext = nullptr;
|
return S_OK;
|
}
|
*fragmentStart = nullptr;
|
*fragmentContext = nullptr;
|
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_ = nullptr;
|
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;
|
}
|
*ppvObject = nullptr;
|
return E_NOINTERFACE;
|
}
|
|
ULONG STDMETHODCALLTYPE CDwFontFileLoader::AddRef() {
|
return InterlockedIncrement((long*)(&refCount_));
|
}
|
|
ULONG STDMETHODCALLTYPE CDwFontFileLoader::Release() {
|
ULONG newCount = InterlockedDecrement((long*)(&refCount_));
|
if (newCount == 0) {
|
instance_ = nullptr;
|
delete this;
|
}
|
return newCount;
|
}
|
|
HRESULT STDMETHODCALLTYPE CDwFontFileLoader::CreateStreamFromKey(
|
void const* fontFileReferenceKey,
|
UINT32 fontFileReferenceKeySize,
|
OUT IDWriteFontFileStream** fontFileStream) {
|
*fontFileStream = nullptr;
|
CDwFontFileStream* stream =
|
new CDwFontFileStream(fontFileReferenceKey, fontFileReferenceKeySize);
|
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,
|
(uint8_t*)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, nullptr);
|
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
|