mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.0.1343: MS-Windows: does not show colored emojis
Problem: MS-Windows: does not show colored emojis. Solution: Implement colored emojis. Improve drawing speed. Make 'taamode' work. (Taro Muraoka, Yasuhiro Matsumoto, Ken Takata, close #2375)
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* Contributors:
|
||||
* - Ken Takata
|
||||
* - Yasuhiro Matsumoto
|
||||
*
|
||||
* Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
|
||||
* THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
|
||||
@@ -23,7 +24,21 @@
|
||||
#include <math.h>
|
||||
#include <d2d1.h>
|
||||
#include <d2d1helper.h>
|
||||
#include <dwrite.h>
|
||||
|
||||
// Disable these macros to compile with old VC and newer SDK (V8.1 or later).
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1700)
|
||||
# define _COM_Outptr_ __out
|
||||
# define _In_reads_(s)
|
||||
# define _In_reads_opt_(s)
|
||||
# define _Maybenull_
|
||||
# define _Out_writes_(s)
|
||||
# define _Out_writes_opt_(s)
|
||||
# define _Out_writes_to_(x, y)
|
||||
# define _Out_writes_to_opt_(x, y)
|
||||
# define _Outptr_
|
||||
#endif
|
||||
|
||||
#include <dwrite_2.h>
|
||||
|
||||
#include "gui_dwrite.h"
|
||||
|
||||
@@ -79,16 +94,6 @@ template <class T> inline void SafeRelease(T **ppT)
|
||||
}
|
||||
}
|
||||
|
||||
struct GdiTextRendererContext
|
||||
{
|
||||
// const fields.
|
||||
COLORREF color;
|
||||
FLOAT cellWidth;
|
||||
|
||||
// working fields.
|
||||
FLOAT offsetX;
|
||||
};
|
||||
|
||||
static DWRITE_PIXEL_GEOMETRY
|
||||
ToPixelGeometry(int value)
|
||||
{
|
||||
@@ -184,17 +189,151 @@ ToInt(DWRITE_RENDERING_MODE value)
|
||||
}
|
||||
}
|
||||
|
||||
class FontCache {
|
||||
public:
|
||||
struct Item {
|
||||
HFONT hFont;
|
||||
IDWriteTextFormat* pTextFormat;
|
||||
DWRITE_FONT_WEIGHT fontWeight;
|
||||
DWRITE_FONT_STYLE fontStyle;
|
||||
Item() : hFont(NULL), pTextFormat(NULL) {}
|
||||
};
|
||||
|
||||
private:
|
||||
int mSize;
|
||||
Item *mItems;
|
||||
|
||||
public:
|
||||
FontCache(int size = 2) :
|
||||
mSize(size),
|
||||
mItems(new Item[size])
|
||||
{
|
||||
}
|
||||
|
||||
~FontCache()
|
||||
{
|
||||
for (int i = 0; i < mSize; ++i)
|
||||
SafeRelease(&mItems[i].pTextFormat);
|
||||
delete[] mItems;
|
||||
}
|
||||
|
||||
bool get(HFONT hFont, Item &item)
|
||||
{
|
||||
int n = find(hFont);
|
||||
if (n < 0)
|
||||
return false;
|
||||
item = mItems[n];
|
||||
slide(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
void put(const Item& item)
|
||||
{
|
||||
int n = find(item.hFont);
|
||||
if (n < 0)
|
||||
n = mSize - 1;
|
||||
if (mItems[n].pTextFormat != item.pTextFormat)
|
||||
{
|
||||
SafeRelease(&mItems[n].pTextFormat);
|
||||
item.pTextFormat->AddRef();
|
||||
}
|
||||
mItems[n] = item;
|
||||
slide(n);
|
||||
}
|
||||
|
||||
private:
|
||||
int find(HFONT hFont)
|
||||
{
|
||||
for (int i = 0; i < mSize; ++i)
|
||||
{
|
||||
if (mItems[i].hFont == hFont)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void slide(int nextTop)
|
||||
{
|
||||
if (nextTop == 0)
|
||||
return;
|
||||
Item tmp = mItems[nextTop];
|
||||
for (int i = nextTop - 1; i >= 0; --i)
|
||||
mItems[i + 1] = mItems[i];
|
||||
mItems[0] = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
struct DWriteContext {
|
||||
HDC mHDC;
|
||||
bool mDrawing;
|
||||
bool mFallbackDC;
|
||||
|
||||
ID2D1Factory *mD2D1Factory;
|
||||
|
||||
ID2D1DCRenderTarget *mRT;
|
||||
ID2D1SolidColorBrush *mBrush;
|
||||
|
||||
IDWriteFactory *mDWriteFactory;
|
||||
IDWriteFactory2 *mDWriteFactory2;
|
||||
|
||||
IDWriteGdiInterop *mGdiInterop;
|
||||
IDWriteRenderingParams *mRenderingParams;
|
||||
|
||||
FontCache mFontCache;
|
||||
IDWriteTextFormat *mTextFormat;
|
||||
DWRITE_FONT_WEIGHT mFontWeight;
|
||||
DWRITE_FONT_STYLE mFontStyle;
|
||||
|
||||
D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
|
||||
|
||||
// METHODS
|
||||
|
||||
DWriteContext();
|
||||
|
||||
virtual ~DWriteContext();
|
||||
|
||||
HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
|
||||
IDWriteTextFormat **ppTextFormat);
|
||||
|
||||
HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
|
||||
|
||||
void SetFont(HFONT hFont);
|
||||
|
||||
void BindDC(HDC hdc, RECT *rect);
|
||||
|
||||
void AssureDrawing();
|
||||
|
||||
ID2D1Brush* SolidBrush(COLORREF color);
|
||||
|
||||
void DrawText(const WCHAR* text, int len,
|
||||
int x, int y, int w, int h, int cellWidth, COLORREF color,
|
||||
UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx);
|
||||
|
||||
void FillRect(RECT *rc, COLORREF color);
|
||||
|
||||
void Flush();
|
||||
|
||||
void SetRenderingParams(
|
||||
const DWriteRenderingParams *params);
|
||||
|
||||
DWriteRenderingParams *GetRenderingParams(
|
||||
DWriteRenderingParams *params);
|
||||
};
|
||||
|
||||
class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
|
||||
{
|
||||
private:
|
||||
FLOAT &mAccum;
|
||||
FLOAT mDelta;
|
||||
FLOAT *mAdjustedAdvances;
|
||||
|
||||
public:
|
||||
AdjustedGlyphRun(
|
||||
const DWRITE_GLYPH_RUN *glyphRun,
|
||||
FLOAT cellWidth) :
|
||||
FLOAT cellWidth,
|
||||
FLOAT &accum) :
|
||||
DWRITE_GLYPH_RUN(*glyphRun),
|
||||
mAccum(accum),
|
||||
mDelta(0.0f),
|
||||
mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
|
||||
{
|
||||
@@ -209,45 +348,44 @@ public:
|
||||
glyphAdvances = mAdjustedAdvances;
|
||||
}
|
||||
|
||||
~AdjustedGlyphRun(void)
|
||||
~AdjustedGlyphRun()
|
||||
{
|
||||
mAccum += mDelta;
|
||||
delete[] mAdjustedAdvances;
|
||||
}
|
||||
|
||||
FLOAT getDelta(void) const
|
||||
{
|
||||
return mDelta;
|
||||
}
|
||||
|
||||
static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
|
||||
{
|
||||
int cellCount = (int)floor(value / cellWidth + 0.5f);
|
||||
int cellCount = int(floor(value / cellWidth + 0.5f));
|
||||
if (cellCount < 1)
|
||||
cellCount = 1;
|
||||
return cellCount * cellWidth;
|
||||
}
|
||||
};
|
||||
|
||||
class GdiTextRenderer FINAL : public IDWriteTextRenderer
|
||||
struct TextRendererContext {
|
||||
// const fields.
|
||||
COLORREF color;
|
||||
FLOAT cellWidth;
|
||||
|
||||
// working fields.
|
||||
FLOAT offsetX;
|
||||
};
|
||||
|
||||
class TextRenderer FINAL : public IDWriteTextRenderer
|
||||
{
|
||||
public:
|
||||
GdiTextRenderer(
|
||||
IDWriteBitmapRenderTarget* bitmapRenderTarget,
|
||||
IDWriteRenderingParams* renderingParams) :
|
||||
TextRenderer(
|
||||
DWriteContext* pDWC) :
|
||||
cRefCount_(0),
|
||||
pRenderTarget_(bitmapRenderTarget),
|
||||
pRenderingParams_(renderingParams)
|
||||
pDWC_(pDWC)
|
||||
{
|
||||
pRenderTarget_->AddRef();
|
||||
pRenderingParams_->AddRef();
|
||||
AddRef();
|
||||
}
|
||||
|
||||
// add "virtual" to avoid a compiler warning
|
||||
virtual ~GdiTextRenderer()
|
||||
virtual ~TextRenderer()
|
||||
{
|
||||
SafeRelease(&pRenderTarget_);
|
||||
SafeRelease(&pRenderingParams_);
|
||||
}
|
||||
|
||||
IFACEMETHOD(IsPixelSnappingDisabled)(
|
||||
@@ -263,7 +401,8 @@ public:
|
||||
__out DWRITE_MATRIX* transform)
|
||||
{
|
||||
// forward the render target's transform
|
||||
pRenderTarget_->GetCurrentTransform(transform);
|
||||
pDWC_->mRT->GetTransform(
|
||||
reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -271,43 +410,12 @@ public:
|
||||
__maybenull void* clientDrawingContext,
|
||||
__out FLOAT* pixelsPerDip)
|
||||
{
|
||||
*pixelsPerDip = pRenderTarget_->GetPixelsPerDip();
|
||||
float dpiX, unused;
|
||||
pDWC_->mRT->GetDpi(&dpiX, &unused);
|
||||
*pixelsPerDip = dpiX / 96.0f;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(DrawGlyphRun)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
__in DWRITE_GLYPH_RUN const* glyphRun,
|
||||
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
IUnknown* clientDrawingEffect)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
GdiTextRendererContext *context =
|
||||
reinterpret_cast<GdiTextRendererContext*>(clientDrawingContext);
|
||||
|
||||
AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth);
|
||||
|
||||
// Pass on the drawing call to the render target to do the real work.
|
||||
RECT dirtyRect = {0};
|
||||
|
||||
hr = pRenderTarget_->DrawGlyphRun(
|
||||
baselineOriginX + context->offsetX,
|
||||
baselineOriginY,
|
||||
measuringMode,
|
||||
&adjustedGlyphRun,
|
||||
pRenderingParams_,
|
||||
context->color,
|
||||
&dirtyRect);
|
||||
|
||||
context->offsetX += adjustedGlyphRun.getDelta();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
IFACEMETHOD(DrawUnderline)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
@@ -340,6 +448,69 @@ public:
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
IFACEMETHOD(DrawGlyphRun)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
__in DWRITE_GLYPH_RUN const* glyphRun,
|
||||
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
IUnknown* clientDrawingEffect)
|
||||
{
|
||||
TextRendererContext *context =
|
||||
reinterpret_cast<TextRendererContext*>(clientDrawingContext);
|
||||
|
||||
AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
|
||||
context->offsetX);
|
||||
|
||||
if (pDWC_->mDWriteFactory2 != NULL)
|
||||
{
|
||||
IDWriteColorGlyphRunEnumerator *enumerator = NULL;
|
||||
HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
|
||||
baselineOriginX + context->offsetX,
|
||||
baselineOriginY,
|
||||
&adjustedGlyphRun,
|
||||
NULL,
|
||||
DWRITE_MEASURING_MODE_GDI_NATURAL,
|
||||
NULL,
|
||||
0,
|
||||
&enumerator);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Draw by IDWriteFactory2 for color emoji
|
||||
BOOL hasRun = TRUE;
|
||||
enumerator->MoveNext(&hasRun);
|
||||
while (hasRun)
|
||||
{
|
||||
const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
|
||||
enumerator->GetCurrentRun(&colorGlyphRun);
|
||||
|
||||
pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
|
||||
pDWC_->mRT->DrawGlyphRun(
|
||||
D2D1::Point2F(
|
||||
colorGlyphRun->baselineOriginX,
|
||||
colorGlyphRun->baselineOriginY),
|
||||
&colorGlyphRun->glyphRun,
|
||||
pDWC_->mBrush,
|
||||
DWRITE_MEASURING_MODE_NATURAL);
|
||||
enumerator->MoveNext(&hasRun);
|
||||
}
|
||||
SafeRelease(&enumerator);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw by IDWriteFactory (without color emoji)
|
||||
pDWC_->mRT->DrawGlyphRun(
|
||||
D2D1::Point2F(
|
||||
baselineOriginX + context->offsetX,
|
||||
baselineOriginY),
|
||||
&adjustedGlyphRun,
|
||||
pDWC_->SolidBrush(context->color),
|
||||
DWRITE_MEASURING_MODE_NATURAL);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
public:
|
||||
IFACEMETHOD_(unsigned long, AddRef) ()
|
||||
{
|
||||
@@ -385,80 +556,28 @@ public:
|
||||
|
||||
private:
|
||||
long cRefCount_;
|
||||
IDWriteBitmapRenderTarget* pRenderTarget_;
|
||||
IDWriteRenderingParams* pRenderingParams_;
|
||||
};
|
||||
|
||||
struct DWriteContext {
|
||||
FLOAT mDpiScaleX;
|
||||
FLOAT mDpiScaleY;
|
||||
bool mDrawing;
|
||||
|
||||
ID2D1Factory *mD2D1Factory;
|
||||
|
||||
ID2D1DCRenderTarget *mRT;
|
||||
ID2D1SolidColorBrush *mBrush;
|
||||
|
||||
IDWriteFactory *mDWriteFactory;
|
||||
IDWriteGdiInterop *mGdiInterop;
|
||||
IDWriteRenderingParams *mRenderingParams;
|
||||
IDWriteTextFormat *mTextFormat;
|
||||
|
||||
HFONT mLastHFont;
|
||||
DWRITE_FONT_WEIGHT mFontWeight;
|
||||
DWRITE_FONT_STYLE mFontStyle;
|
||||
|
||||
D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
|
||||
|
||||
// METHODS
|
||||
|
||||
DWriteContext();
|
||||
|
||||
virtual ~DWriteContext();
|
||||
|
||||
HRESULT SetLOGFONT(const LOGFONTW &logFont, float fontSize);
|
||||
|
||||
void SetFont(HFONT hFont);
|
||||
|
||||
void SetFont(const LOGFONTW &logFont);
|
||||
|
||||
void DrawText(HDC hdc, const WCHAR* text, int len,
|
||||
int x, int y, int w, int h, int cellWidth, COLORREF color);
|
||||
|
||||
float PixelsToDipsX(int x);
|
||||
|
||||
float PixelsToDipsY(int y);
|
||||
|
||||
void SetRenderingParams(
|
||||
const DWriteRenderingParams *params);
|
||||
|
||||
DWriteRenderingParams *GetRenderingParams(
|
||||
DWriteRenderingParams *params);
|
||||
DWriteContext* pDWC_;
|
||||
};
|
||||
|
||||
DWriteContext::DWriteContext() :
|
||||
mDpiScaleX(1.f),
|
||||
mDpiScaleY(1.f),
|
||||
mHDC(NULL),
|
||||
mDrawing(false),
|
||||
mFallbackDC(false),
|
||||
mD2D1Factory(NULL),
|
||||
mRT(NULL),
|
||||
mBrush(NULL),
|
||||
mDWriteFactory(NULL),
|
||||
mDWriteFactory2(NULL),
|
||||
mGdiInterop(NULL),
|
||||
mRenderingParams(NULL),
|
||||
mFontCache(8),
|
||||
mTextFormat(NULL),
|
||||
mLastHFont(NULL),
|
||||
mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
|
||||
mFontStyle(DWRITE_FONT_STYLE_NORMAL),
|
||||
mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
HDC screen = ::GetDC(0);
|
||||
mDpiScaleX = ::GetDeviceCaps(screen, LOGPIXELSX) / 96.0f;
|
||||
mDpiScaleY = ::GetDeviceCaps(screen, LOGPIXELSY) / 96.0f;
|
||||
::ReleaseDC(0, screen);
|
||||
|
||||
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
|
||||
__uuidof(ID2D1Factory), NULL,
|
||||
reinterpret_cast<void**>(&mD2D1Factory));
|
||||
@@ -495,6 +614,15 @@ DWriteContext::DWriteContext() :
|
||||
mDWriteFactory);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DWriteCreateFactory(
|
||||
DWRITE_FACTORY_TYPE_SHARED,
|
||||
__uuidof(IDWriteFactory2),
|
||||
reinterpret_cast<IUnknown**>(&mDWriteFactory2));
|
||||
_RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
|
||||
@@ -515,20 +643,24 @@ DWriteContext::~DWriteContext()
|
||||
SafeRelease(&mRenderingParams);
|
||||
SafeRelease(&mGdiInterop);
|
||||
SafeRelease(&mDWriteFactory);
|
||||
SafeRelease(&mDWriteFactory2);
|
||||
SafeRelease(&mBrush);
|
||||
SafeRelease(&mRT);
|
||||
SafeRelease(&mD2D1Factory);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
|
||||
DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
|
||||
IDWriteTextFormat **ppTextFormat)
|
||||
{
|
||||
// Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx
|
||||
// Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
|
||||
HRESULT hr = S_OK;
|
||||
IDWriteTextFormat *pTextFormat = NULL;
|
||||
|
||||
IDWriteFont *font = NULL;
|
||||
IDWriteFontFamily *fontFamily = NULL;
|
||||
IDWriteLocalizedStrings *localizedFamilyNames = NULL;
|
||||
float fontSize = 0;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
@@ -561,33 +693,30 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// If no font size was passed in use the lfHeight of the LOGFONT.
|
||||
if (fontSize == 0)
|
||||
// Use lfHeight of the LOGFONT as font size.
|
||||
fontSize = float(logFont.lfHeight);
|
||||
|
||||
if (fontSize < 0)
|
||||
{
|
||||
// Convert from pixels to DIPs.
|
||||
fontSize = PixelsToDipsY(logFont.lfHeight);
|
||||
if (fontSize < 0)
|
||||
{
|
||||
// Negative lfHeight represents the size of the em unit.
|
||||
fontSize = -fontSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Positive lfHeight represents the cell height (ascent +
|
||||
// descent).
|
||||
DWRITE_FONT_METRICS fontMetrics;
|
||||
font->GetMetrics(&fontMetrics);
|
||||
// Negative lfHeight represents the size of the em unit.
|
||||
fontSize = -fontSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Positive lfHeight represents the cell height (ascent +
|
||||
// descent).
|
||||
DWRITE_FONT_METRICS fontMetrics;
|
||||
font->GetMetrics(&fontMetrics);
|
||||
|
||||
// Convert the cell height (ascent + descent) from design units
|
||||
// to ems.
|
||||
float cellHeight = static_cast<float>(
|
||||
fontMetrics.ascent + fontMetrics.descent)
|
||||
/ fontMetrics.designUnitsPerEm;
|
||||
// Convert the cell height (ascent + descent) from design units
|
||||
// to ems.
|
||||
float cellHeight = static_cast<float>(
|
||||
fontMetrics.ascent + fontMetrics.descent)
|
||||
/ fontMetrics.designUnitsPerEm;
|
||||
|
||||
// Divide the font size by the cell height to get the font em
|
||||
// size.
|
||||
fontSize /= cellHeight;
|
||||
}
|
||||
// Divide the font size by the cell height to get the font em
|
||||
// size.
|
||||
fontSize /= cellHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,123 +741,165 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
|
||||
font->GetStretch(),
|
||||
fontSize,
|
||||
localeName,
|
||||
&mTextFormat);
|
||||
&pTextFormat);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
|
||||
mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
|
||||
: DWRITE_FONT_STYLE_NORMAL;
|
||||
}
|
||||
hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = pTextFormat->SetParagraphAlignment(
|
||||
DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
|
||||
|
||||
SafeRelease(&localizedFamilyNames);
|
||||
SafeRelease(&fontFamily);
|
||||
SafeRelease(&font);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
*ppTextFormat = pTextFormat;
|
||||
else
|
||||
SafeRelease(&pTextFormat);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
IDWriteTextFormat *pTextFormat = NULL;
|
||||
|
||||
hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
SafeRelease(&mTextFormat);
|
||||
mTextFormat = pTextFormat;
|
||||
mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
|
||||
mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
|
||||
: DWRITE_FONT_STYLE_NORMAL;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext::SetFont(HFONT hFont)
|
||||
{
|
||||
if (mLastHFont != hFont)
|
||||
FontCache::Item item;
|
||||
if (mFontCache.get(hFont, item))
|
||||
{
|
||||
LOGFONTW lf;
|
||||
if (GetObjectW(hFont, sizeof(lf), &lf))
|
||||
if (item.pTextFormat != NULL)
|
||||
{
|
||||
SetFont(lf);
|
||||
mLastHFont = hFont;
|
||||
item.pTextFormat->AddRef();
|
||||
SafeRelease(&mTextFormat);
|
||||
mTextFormat = item.pTextFormat;
|
||||
mFontWeight = item.fontWeight;
|
||||
mFontStyle = item.fontStyle;
|
||||
mFallbackDC = false;
|
||||
}
|
||||
else
|
||||
mFallbackDC = true;
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
LOGFONTW lf;
|
||||
if (GetObjectW(hFont, sizeof(lf), &lf))
|
||||
hr = SetFontByLOGFONT(lf);
|
||||
|
||||
item.hFont = hFont;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
item.pTextFormat = mTextFormat;
|
||||
item.fontWeight = mFontWeight;
|
||||
item.fontStyle = mFontStyle;
|
||||
}
|
||||
mFontCache.put(item);
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext::SetFont(const LOGFONTW &logFont)
|
||||
DWriteContext::BindDC(HDC hdc, RECT *rect)
|
||||
{
|
||||
SafeRelease(&mTextFormat);
|
||||
mLastHFont = NULL;
|
||||
|
||||
HRESULT hr = SetLOGFONT(logFont, 0.f);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = mTextFormat->SetParagraphAlignment(
|
||||
DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = mTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
|
||||
Flush();
|
||||
mRT->BindDC(hdc, rect);
|
||||
mRT->SetTransform(D2D1::IdentityMatrix());
|
||||
mHDC = hdc;
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len,
|
||||
int x, int y, int w, int h, int cellWidth, COLORREF color)
|
||||
DWriteContext::AssureDrawing()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
IDWriteBitmapRenderTarget *bmpRT = NULL;
|
||||
if (mDrawing == false)
|
||||
{
|
||||
mRT->BeginDraw();
|
||||
mDrawing = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip when any fonts are not set.
|
||||
if (mTextFormat == NULL)
|
||||
ID2D1Brush*
|
||||
DWriteContext::SolidBrush(COLORREF color)
|
||||
{
|
||||
mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
|
||||
UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
|
||||
return mBrush;
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext::DrawText(const WCHAR* text, int len,
|
||||
int x, int y, int w, int h, int cellWidth, COLORREF color,
|
||||
UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx)
|
||||
{
|
||||
if (mFallbackDC)
|
||||
{
|
||||
Flush();
|
||||
ExtTextOutW(mHDC, x, y, fuOptions, lprc, text, len, lpDx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check possibility of zero divided error.
|
||||
if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
|
||||
return;
|
||||
AssureDrawing();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT);
|
||||
HRESULT hr;
|
||||
IDWriteTextLayout *textLayout = NULL;
|
||||
|
||||
hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
|
||||
FLOAT(w), FLOAT(h), &textLayout);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IDWriteTextLayout *textLayout = NULL;
|
||||
DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
|
||||
textLayout->SetFontWeight(mFontWeight, textRange);
|
||||
textLayout->SetFontStyle(mFontStyle, textRange);
|
||||
|
||||
HDC memdc = bmpRT->GetMemoryDC();
|
||||
BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY);
|
||||
|
||||
hr = mDWriteFactory->CreateGdiCompatibleTextLayout(
|
||||
text, len, mTextFormat, PixelsToDipsX(w),
|
||||
PixelsToDipsY(h), mDpiScaleX, NULL, TRUE, &textLayout);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len };
|
||||
textLayout->SetFontWeight(mFontWeight, textRange);
|
||||
textLayout->SetFontStyle(mFontStyle, textRange);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT,
|
||||
mRenderingParams);
|
||||
GdiTextRendererContext data = {
|
||||
color,
|
||||
PixelsToDipsX(cellWidth),
|
||||
0.0f
|
||||
};
|
||||
textLayout->Draw(&data, renderer, 0, 0);
|
||||
SafeRelease(&renderer);
|
||||
}
|
||||
|
||||
BitBlt(hdc, x, y, w, h, memdc, 0, 0, SRCCOPY);
|
||||
|
||||
SafeRelease(&textLayout);
|
||||
TextRenderer renderer(this);
|
||||
TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
|
||||
textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
|
||||
}
|
||||
|
||||
SafeRelease(&bmpRT);
|
||||
SafeRelease(&textLayout);
|
||||
}
|
||||
|
||||
float
|
||||
DWriteContext::PixelsToDipsX(int x)
|
||||
void
|
||||
DWriteContext::FillRect(RECT *rc, COLORREF color)
|
||||
{
|
||||
return x / mDpiScaleX;
|
||||
AssureDrawing();
|
||||
mRT->FillRectangle(
|
||||
D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
|
||||
FLOAT(rc->right), FLOAT(rc->bottom)),
|
||||
SolidBrush(color));
|
||||
}
|
||||
|
||||
float
|
||||
DWriteContext::PixelsToDipsY(int y)
|
||||
void
|
||||
DWriteContext::Flush()
|
||||
{
|
||||
return y / mDpiScaleY;
|
||||
if (mDrawing)
|
||||
{
|
||||
mRT->EndDraw();
|
||||
mDrawing = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -757,6 +928,10 @@ DWriteContext::SetRenderingParams(
|
||||
SafeRelease(&mRenderingParams);
|
||||
mRenderingParams = renderingParams;
|
||||
mTextAntialiasMode = textAntialiasMode;
|
||||
|
||||
Flush();
|
||||
mRT->SetTextRenderingParams(mRenderingParams);
|
||||
mRT->SetTextAntialiasMode(mTextAntialiasMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,40 +999,23 @@ DWriteContext_Open(void)
|
||||
return new DWriteContext();
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext_BeginDraw(DWriteContext *ctx)
|
||||
{
|
||||
if (ctx != NULL && ctx->mRT != NULL)
|
||||
{
|
||||
ctx->mRT->BeginDraw();
|
||||
ctx->mRT->SetTransform(D2D1::IdentityMatrix());
|
||||
ctx->mDrawing = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
|
||||
{
|
||||
if (ctx != NULL && ctx->mRT != NULL)
|
||||
{
|
||||
ctx->mRT->BindDC(hdc, rect);
|
||||
ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode);
|
||||
}
|
||||
if (ctx != NULL)
|
||||
ctx->BindDC(hdc, rect);
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
|
||||
{
|
||||
if (ctx != NULL)
|
||||
{
|
||||
ctx->SetFont(hFont);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext_DrawText(
|
||||
DWriteContext *ctx,
|
||||
HDC hdc,
|
||||
const WCHAR* text,
|
||||
int len,
|
||||
int x,
|
||||
@@ -865,20 +1023,28 @@ DWriteContext_DrawText(
|
||||
int w,
|
||||
int h,
|
||||
int cellWidth,
|
||||
COLORREF color)
|
||||
COLORREF color,
|
||||
UINT fuOptions,
|
||||
CONST RECT *lprc,
|
||||
CONST INT * lpDx)
|
||||
{
|
||||
if (ctx != NULL)
|
||||
ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color);
|
||||
ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
|
||||
fuOptions, lprc, lpDx);
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext_EndDraw(DWriteContext *ctx)
|
||||
DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
|
||||
{
|
||||
if (ctx != NULL && ctx->mRT != NULL)
|
||||
{
|
||||
ctx->mRT->EndDraw();
|
||||
ctx->mDrawing = false;
|
||||
}
|
||||
if (ctx != NULL)
|
||||
ctx->FillRect(rc, color);
|
||||
}
|
||||
|
||||
void
|
||||
DWriteContext_Flush(DWriteContext *ctx)
|
||||
{
|
||||
if (ctx != NULL)
|
||||
ctx->Flush();
|
||||
}
|
||||
|
||||
void
|
||||
|
Reference in New Issue
Block a user