blob: 7a17c4ad093834ad6829a4e29ecb57b173a6b837 [file] [log] [blame]
// 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 FX_FINAL : public IDWriteFontFileStream
{
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 FX_FINAL : public IDWriteFontFileLoader
{
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_ = new CDwFontFileLoader();
}
return instance_;
}
static bool IsLoaderInitialized()
{
return instance_ != NULL;
}
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::~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 = 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_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 = 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,
(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