0
0
mirror of https://github.com/vim/vim.git synced 2025-07-04 23:07:33 -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:
Bram Moolenaar 2017-11-26 14:29:32 +01:00
parent fb1db0e355
commit d7ccc4d81d
7 changed files with 572 additions and 302 deletions

View File

@ -16,6 +16,7 @@ matrix:
before_build: before_build:
- '"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release' - '"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release'
- 'set INCLUDE=%INCLUDE%C:\Program Files (x86)\Windows Kits\8.1\Include\um'
build_script: build_script:
- src/appveyor.bat - src/appveyor.bat

View File

@ -6154,11 +6154,34 @@ A jump table for the options with a short description can be found at |Q_op|.
Example: > Example: >
set encoding=utf-8 set encoding=utf-8
set gfn=Ricty_Diminished:h12:cSHIFTJIS set gfn=Ricty_Diminished:h12
set rop=type:directx set rop=type:directx
< <
If select a raster font (Courier, Terminal or FixedSys) to If select a raster font (Courier, Terminal or FixedSys which
'guifont', it fallbacks to be drawn by GDI automatically. have ".fon" extension in file name) to 'guifont', it will be
drawn by GDI as a fallback. This fallback will cause
significant slow down on drawing.
NOTE: It is known that some fonts and options combination
causes trouble on drawing glyphs.
- 'rendmode:5' and 'renmode:6' will not work with some
special made fonts (True-Type fonts which includes only
bitmap glyphs).
- 'taamode:3' will not work with some vector fonts.
NOTE: With this option, you can display colored emoji
(emoticon) in Windows 8.1 or later. To display colored emoji,
there are some conditions which you should notice.
- If your font includes non-colored emoji already, it will
be used.
- If your font doesn't have emoji, the system chooses an
alternative symbol font. On Windows 10, "Segoe UI Emoji"
will be used.
- When this alternative font didn't have fixed width glyph,
emoji might be rendered beyond the bounding box of drawing
cell.
Other render types are currently not supported. Other render types are currently not supported.

View File

@ -4,6 +4,7 @@
* *
* Contributors: * Contributors:
* - Ken Takata * - Ken Takata
* - Yasuhiro Matsumoto
* *
* Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com> * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
* THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
@ -23,7 +24,21 @@
#include <math.h> #include <math.h>
#include <d2d1.h> #include <d2d1.h>
#include <d2d1helper.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" #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 static DWRITE_PIXEL_GEOMETRY
ToPixelGeometry(int value) 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 class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
{ {
private: private:
FLOAT &mAccum;
FLOAT mDelta; FLOAT mDelta;
FLOAT *mAdjustedAdvances; FLOAT *mAdjustedAdvances;
public: public:
AdjustedGlyphRun( AdjustedGlyphRun(
const DWRITE_GLYPH_RUN *glyphRun, const DWRITE_GLYPH_RUN *glyphRun,
FLOAT cellWidth) : FLOAT cellWidth,
FLOAT &accum) :
DWRITE_GLYPH_RUN(*glyphRun), DWRITE_GLYPH_RUN(*glyphRun),
mAccum(accum),
mDelta(0.0f), mDelta(0.0f),
mAdjustedAdvances(new FLOAT[glyphRun->glyphCount]) mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
{ {
@ -209,45 +348,44 @@ public:
glyphAdvances = mAdjustedAdvances; glyphAdvances = mAdjustedAdvances;
} }
~AdjustedGlyphRun(void) ~AdjustedGlyphRun()
{ {
mAccum += mDelta;
delete[] mAdjustedAdvances; delete[] mAdjustedAdvances;
} }
FLOAT getDelta(void) const
{
return mDelta;
}
static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth) 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) if (cellCount < 1)
cellCount = 1; cellCount = 1;
return cellCount * cellWidth; 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: public:
GdiTextRenderer( TextRenderer(
IDWriteBitmapRenderTarget* bitmapRenderTarget, DWriteContext* pDWC) :
IDWriteRenderingParams* renderingParams) :
cRefCount_(0), cRefCount_(0),
pRenderTarget_(bitmapRenderTarget), pDWC_(pDWC)
pRenderingParams_(renderingParams)
{ {
pRenderTarget_->AddRef();
pRenderingParams_->AddRef();
AddRef(); AddRef();
} }
// add "virtual" to avoid a compiler warning // add "virtual" to avoid a compiler warning
virtual ~GdiTextRenderer() virtual ~TextRenderer()
{ {
SafeRelease(&pRenderTarget_);
SafeRelease(&pRenderingParams_);
} }
IFACEMETHOD(IsPixelSnappingDisabled)( IFACEMETHOD(IsPixelSnappingDisabled)(
@ -263,7 +401,8 @@ public:
__out DWRITE_MATRIX* transform) __out DWRITE_MATRIX* transform)
{ {
// forward the render target's transform // forward the render target's transform
pRenderTarget_->GetCurrentTransform(transform); pDWC_->mRT->GetTransform(
reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
return S_OK; return S_OK;
} }
@ -271,43 +410,12 @@ public:
__maybenull void* clientDrawingContext, __maybenull void* clientDrawingContext,
__out FLOAT* pixelsPerDip) __out FLOAT* pixelsPerDip)
{ {
*pixelsPerDip = pRenderTarget_->GetPixelsPerDip(); float dpiX, unused;
pDWC_->mRT->GetDpi(&dpiX, &unused);
*pixelsPerDip = dpiX / 96.0f;
return S_OK; 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)( IFACEMETHOD(DrawUnderline)(
__maybenull void* clientDrawingContext, __maybenull void* clientDrawingContext,
FLOAT baselineOriginX, FLOAT baselineOriginX,
@ -340,6 +448,69 @@ public:
return E_NOTIMPL; 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: public:
IFACEMETHOD_(unsigned long, AddRef) () IFACEMETHOD_(unsigned long, AddRef) ()
{ {
@ -385,80 +556,28 @@ public:
private: private:
long cRefCount_; long cRefCount_;
IDWriteBitmapRenderTarget* pRenderTarget_; DWriteContext* pDWC_;
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::DWriteContext() : DWriteContext::DWriteContext() :
mDpiScaleX(1.f), mHDC(NULL),
mDpiScaleY(1.f),
mDrawing(false), mDrawing(false),
mFallbackDC(false),
mD2D1Factory(NULL), mD2D1Factory(NULL),
mRT(NULL), mRT(NULL),
mBrush(NULL), mBrush(NULL),
mDWriteFactory(NULL), mDWriteFactory(NULL),
mDWriteFactory2(NULL),
mGdiInterop(NULL), mGdiInterop(NULL),
mRenderingParams(NULL), mRenderingParams(NULL),
mFontCache(8),
mTextFormat(NULL), mTextFormat(NULL),
mLastHFont(NULL),
mFontWeight(DWRITE_FONT_WEIGHT_NORMAL), mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
mFontStyle(DWRITE_FONT_STYLE_NORMAL), mFontStyle(DWRITE_FONT_STYLE_NORMAL),
mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT) mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
{ {
HRESULT hr; 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, hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory), NULL, __uuidof(ID2D1Factory), NULL,
reinterpret_cast<void**>(&mD2D1Factory)); reinterpret_cast<void**>(&mD2D1Factory));
@ -495,6 +614,15 @@ DWriteContext::DWriteContext() :
mDWriteFactory); 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)) if (SUCCEEDED(hr))
{ {
hr = mDWriteFactory->GetGdiInterop(&mGdiInterop); hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
@ -515,20 +643,24 @@ DWriteContext::~DWriteContext()
SafeRelease(&mRenderingParams); SafeRelease(&mRenderingParams);
SafeRelease(&mGdiInterop); SafeRelease(&mGdiInterop);
SafeRelease(&mDWriteFactory); SafeRelease(&mDWriteFactory);
SafeRelease(&mDWriteFactory2);
SafeRelease(&mBrush); SafeRelease(&mBrush);
SafeRelease(&mRT); SafeRelease(&mRT);
SafeRelease(&mD2D1Factory); SafeRelease(&mD2D1Factory);
} }
HRESULT 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; HRESULT hr = S_OK;
IDWriteTextFormat *pTextFormat = NULL;
IDWriteFont *font = NULL; IDWriteFont *font = NULL;
IDWriteFontFamily *fontFamily = NULL; IDWriteFontFamily *fontFamily = NULL;
IDWriteLocalizedStrings *localizedFamilyNames = NULL; IDWriteLocalizedStrings *localizedFamilyNames = NULL;
float fontSize = 0;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -561,33 +693,30 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
// If no font size was passed in use the lfHeight of the LOGFONT. // Use lfHeight of the LOGFONT as font size.
if (fontSize == 0) fontSize = float(logFont.lfHeight);
if (fontSize < 0)
{ {
// Convert from pixels to DIPs. // Negative lfHeight represents the size of the em unit.
fontSize = PixelsToDipsY(logFont.lfHeight); fontSize = -fontSize;
if (fontSize < 0) }
{ else
// Negative lfHeight represents the size of the em unit. {
fontSize = -fontSize; // Positive lfHeight represents the cell height (ascent +
} // descent).
else DWRITE_FONT_METRICS fontMetrics;
{ font->GetMetrics(&fontMetrics);
// Positive lfHeight represents the cell height (ascent +
// descent).
DWRITE_FONT_METRICS fontMetrics;
font->GetMetrics(&fontMetrics);
// Convert the cell height (ascent + descent) from design units // Convert the cell height (ascent + descent) from design units
// to ems. // to ems.
float cellHeight = static_cast<float>( float cellHeight = static_cast<float>(
fontMetrics.ascent + fontMetrics.descent) fontMetrics.ascent + fontMetrics.descent)
/ fontMetrics.designUnitsPerEm; / fontMetrics.designUnitsPerEm;
// Divide the font size by the cell height to get the font em // Divide the font size by the cell height to get the font em
// size. // size.
fontSize /= cellHeight; fontSize /= cellHeight;
}
} }
} }
@ -612,123 +741,165 @@ DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
font->GetStretch(), font->GetStretch(),
fontSize, fontSize,
localeName, localeName,
&mTextFormat); &pTextFormat);
} }
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC if (SUCCEEDED(hr))
: DWRITE_FONT_STYLE_NORMAL; hr = pTextFormat->SetParagraphAlignment(
} DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
if (SUCCEEDED(hr))
hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
SafeRelease(&localizedFamilyNames); SafeRelease(&localizedFamilyNames);
SafeRelease(&fontFamily); SafeRelease(&fontFamily);
SafeRelease(&font); 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; return hr;
} }
void void
DWriteContext::SetFont(HFONT hFont) DWriteContext::SetFont(HFONT hFont)
{ {
if (mLastHFont != hFont) FontCache::Item item;
if (mFontCache.get(hFont, item))
{ {
LOGFONTW lf; if (item.pTextFormat != NULL)
if (GetObjectW(hFont, sizeof(lf), &lf))
{ {
SetFont(lf); item.pTextFormat->AddRef();
mLastHFont = hFont; 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 void
DWriteContext::SetFont(const LOGFONTW &logFont) DWriteContext::BindDC(HDC hdc, RECT *rect)
{ {
SafeRelease(&mTextFormat); Flush();
mLastHFont = NULL; mRT->BindDC(hdc, rect);
mRT->SetTransform(D2D1::IdentityMatrix());
HRESULT hr = SetLOGFONT(logFont, 0.f); mHDC = hdc;
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);
} }
void void
DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len, DWriteContext::AssureDrawing()
int x, int y, int w, int h, int cellWidth, COLORREF color)
{ {
HRESULT hr = S_OK; if (mDrawing == false)
IDWriteBitmapRenderTarget *bmpRT = NULL; {
mRT->BeginDraw();
mDrawing = true;
}
}
// Skip when any fonts are not set. ID2D1Brush*
if (mTextFormat == NULL) 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; return;
}
// Check possibility of zero divided error. AssureDrawing();
if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
return;
if (SUCCEEDED(hr)) HRESULT hr;
hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT); IDWriteTextLayout *textLayout = NULL;
hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
FLOAT(w), FLOAT(h), &textLayout);
if (SUCCEEDED(hr)) 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(); TextRenderer renderer(this);
BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY); TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
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);
} }
SafeRelease(&bmpRT); SafeRelease(&textLayout);
} }
float void
DWriteContext::PixelsToDipsX(int x) 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 void
DWriteContext::PixelsToDipsY(int y) DWriteContext::Flush()
{ {
return y / mDpiScaleY; if (mDrawing)
{
mRT->EndDraw();
mDrawing = false;
}
} }
void void
@ -757,6 +928,10 @@ DWriteContext::SetRenderingParams(
SafeRelease(&mRenderingParams); SafeRelease(&mRenderingParams);
mRenderingParams = renderingParams; mRenderingParams = renderingParams;
mTextAntialiasMode = textAntialiasMode; mTextAntialiasMode = textAntialiasMode;
Flush();
mRT->SetTextRenderingParams(mRenderingParams);
mRT->SetTextAntialiasMode(mTextAntialiasMode);
} }
} }
@ -824,40 +999,23 @@ DWriteContext_Open(void)
return new DWriteContext(); 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 void
DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect) DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
{ {
if (ctx != NULL && ctx->mRT != NULL) if (ctx != NULL)
{ ctx->BindDC(hdc, rect);
ctx->mRT->BindDC(hdc, rect);
ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode);
}
} }
void void
DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont) DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
{ {
if (ctx != NULL) if (ctx != NULL)
{
ctx->SetFont(hFont); ctx->SetFont(hFont);
}
} }
void void
DWriteContext_DrawText( DWriteContext_DrawText(
DWriteContext *ctx, DWriteContext *ctx,
HDC hdc,
const WCHAR* text, const WCHAR* text,
int len, int len,
int x, int x,
@ -865,20 +1023,28 @@ DWriteContext_DrawText(
int w, int w,
int h, int h,
int cellWidth, int cellWidth,
COLORREF color) COLORREF color,
UINT fuOptions,
CONST RECT *lprc,
CONST INT * lpDx)
{ {
if (ctx != NULL) 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 void
DWriteContext_EndDraw(DWriteContext *ctx) DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
{ {
if (ctx != NULL && ctx->mRT != NULL) if (ctx != NULL)
{ ctx->FillRect(rc, color);
ctx->mRT->EndDraw(); }
ctx->mDrawing = false;
} void
DWriteContext_Flush(DWriteContext *ctx)
{
if (ctx != NULL)
ctx->Flush();
} }
void void

View File

@ -4,6 +4,7 @@
* *
* Contributors: * Contributors:
* - Ken Takata * - Ken Takata
* - Yasuhiro Matsumoto
* *
* Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com> * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
* THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
@ -54,12 +55,10 @@ void DWrite_Init(void);
void DWrite_Final(void); void DWrite_Final(void);
DWriteContext *DWriteContext_Open(void); DWriteContext *DWriteContext_Open(void);
void DWriteContext_BeginDraw(DWriteContext *ctx);
void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect); void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect);
void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont); void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont);
void DWriteContext_DrawText( void DWriteContext_DrawText(
DWriteContext *ctx, DWriteContext *ctx,
HDC hdc,
const WCHAR* text, const WCHAR* text,
int len, int len,
int x, int x,
@ -67,8 +66,12 @@ void DWriteContext_DrawText(
int w, int w,
int h, int h,
int cellWidth, int cellWidth,
COLORREF color); COLORREF color,
void DWriteContext_EndDraw(DWriteContext *ctx); UINT fuOptions,
CONST RECT *lprc,
CONST INT * lpDx);
void DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color);
void DWriteContext_Flush(DWriteContext *ctx);
void DWriteContext_Close(DWriteContext *ctx); void DWriteContext_Close(DWriteContext *ctx);
void DWriteContext_SetRenderingParams( void DWriteContext_SetRenderingParams(

View File

@ -34,28 +34,14 @@ static DWriteContext *s_dwc = NULL;
static int s_directx_enabled = 0; static int s_directx_enabled = 0;
static int s_directx_load_attempted = 0; static int s_directx_load_attempted = 0;
# define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL) # define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL)
static int directx_enabled(void);
static void directx_binddc(void);
#endif #endif
#ifdef FEAT_MENU #ifdef FEAT_MENU
static int gui_mswin_get_menu_height(int fix_window); static int gui_mswin_get_menu_height(int fix_window);
#endif #endif
#if defined(FEAT_DIRECTX) || defined(PROTO)
int
directx_enabled(void)
{
if (s_dwc != NULL)
return 1;
else if (s_directx_load_attempted)
return 0;
/* load DirectX */
DWrite_Init();
s_directx_load_attempted = 1;
s_dwc = DWriteContext_Open();
return s_dwc != NULL ? 1 : 0;
}
#endif
#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO) #if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
int int
gui_mch_set_rendering_options(char_u *s) gui_mch_set_rendering_options(char_u *s)
@ -369,6 +355,34 @@ static int allow_scrollbar = FALSE;
# define MyTranslateMessage(x) TranslateMessage(x) # define MyTranslateMessage(x) TranslateMessage(x)
#endif #endif
#if defined(FEAT_DIRECTX)
static int
directx_enabled(void)
{
if (s_dwc != NULL)
return 1;
else if (s_directx_load_attempted)
return 0;
/* load DirectX */
DWrite_Init();
s_directx_load_attempted = 1;
s_dwc = DWriteContext_Open();
directx_binddc();
return s_dwc != NULL ? 1 : 0;
}
static void
directx_binddc(void)
{
if (s_textArea != NULL)
{
RECT rect;
GetClientRect(s_textArea, &rect);
DWriteContext_BindDC(s_dwc, s_hdc, &rect);
}
}
#endif
#if defined(FEAT_MBYTE) || defined(GLOBAL_IME) #if defined(FEAT_MBYTE) || defined(GLOBAL_IME)
/* use of WindowProc depends on wide_WindowProc */ /* use of WindowProc depends on wide_WindowProc */
# define MyWindowProc vim_WindowProc # define MyWindowProc vim_WindowProc
@ -589,6 +603,10 @@ _OnBlinkTimer(
blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime, blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
(TIMERPROC)_OnBlinkTimer); (TIMERPROC)_OnBlinkTimer);
} }
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
} }
static void static void
@ -1000,6 +1018,19 @@ _OnMouseMoveOrRelease(
_OnMouseEvent(button, x, y, FALSE, keyFlags); _OnMouseEvent(button, x, y, FALSE, keyFlags);
} }
static void
_OnSizeTextArea(
HWND hwnd UNUSED,
UINT state UNUSED,
int cx UNUSED,
int cy UNUSED)
{
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
directx_binddc();
#endif
}
#ifdef FEAT_MENU #ifdef FEAT_MENU
/* /*
* Find the vimmenu_T with the given id * Find the vimmenu_T with the given id
@ -1234,6 +1265,7 @@ _TextAreaWndProc(
HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown); HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown);
HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown); HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown);
HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease); HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease);
HANDLE_MSG(hwnd, WM_SIZE, _OnSizeTextArea);
#ifdef FEAT_BEVAL_GUI #ifdef FEAT_BEVAL_GUI
case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam); case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam);
@ -1633,6 +1665,11 @@ gui_mch_invert_rectangle(
{ {
RECT rc; RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/* /*
* Note: InvertRect() excludes right and bottom of rectangle. * Note: InvertRect() excludes right and bottom of rectangle.
*/ */
@ -1661,6 +1698,11 @@ gui_mch_draw_hollow_cursor(guicolor_T color)
HBRUSH hbr; HBRUSH hbr;
RECT rc; RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/* /*
* Note: FrameRect() excludes right and bottom of rectangle. * Note: FrameRect() excludes right and bottom of rectangle.
*/ */
@ -1701,6 +1743,12 @@ gui_mch_draw_part_cursor(
rc.top = FILL_Y(gui.row) + gui.char_height - h; rc.top = FILL_Y(gui.row) + gui.char_height - h;
rc.right = rc.left + w; rc.right = rc.left + w;
rc.bottom = rc.top + h; rc.bottom = rc.top + h;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
hbr = CreateSolidBrush(color); hbr = CreateSolidBrush(color);
FillRect(s_hdc, &rc, hbr); FillRect(s_hdc, &rc, hbr);
DeleteBrush(hbr); DeleteBrush(hbr);
@ -2856,10 +2904,6 @@ _OnPaint(
out_flush(); /* make sure all output has been processed */ out_flush(); /* make sure all output has been processed */
(void)BeginPaint(hwnd, &ps); (void)BeginPaint(hwnd, &ps);
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_BeginDraw(s_dwc);
#endif
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
/* prevent multi-byte characters from misprinting on an invalid /* prevent multi-byte characters from misprinting on an invalid
@ -2876,19 +2920,11 @@ _OnPaint(
if (!IsRectEmpty(&ps.rcPaint)) if (!IsRectEmpty(&ps.rcPaint))
{ {
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_BindDC(s_dwc, s_hdc, &ps.rcPaint);
#endif
gui_redraw(ps.rcPaint.left, ps.rcPaint.top, gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left + 1, ps.rcPaint.right - ps.rcPaint.left + 1,
ps.rcPaint.bottom - ps.rcPaint.top + 1); ps.rcPaint.bottom - ps.rcPaint.top + 1);
} }
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_EndDraw(s_dwc);
#endif
EndPaint(hwnd, &ps); EndPaint(hwnd, &ps);
} }
} }
@ -3010,6 +3046,11 @@ gui_mch_flash(int msec)
{ {
RECT rc; RECT rc;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
/* /*
* Note: InvertRect() excludes right and bottom of rectangle. * Note: InvertRect() excludes right and bottom of rectangle.
*/ */
@ -3082,6 +3123,12 @@ gui_mch_delete_lines(
intel_gpu_workaround(); intel_gpu_workaround();
#if defined(FEAT_DIRECTX)
// Commit drawing queue before ScrollWindowEx.
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
rc.left = FILL_X(gui.scroll_region_left); rc.left = FILL_X(gui.scroll_region_left);
rc.right = FILL_X(gui.scroll_region_right + 1); rc.right = FILL_X(gui.scroll_region_right + 1);
rc.top = FILL_Y(row); rc.top = FILL_Y(row);
@ -3115,6 +3162,12 @@ gui_mch_insert_lines(
intel_gpu_workaround(); intel_gpu_workaround();
#if defined(FEAT_DIRECTX)
// Commit drawing queue before ScrollWindowEx.
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
rc.left = FILL_X(gui.scroll_region_left); rc.left = FILL_X(gui.scroll_region_left);
rc.right = FILL_X(gui.scroll_region_right + 1); rc.right = FILL_X(gui.scroll_region_right + 1);
rc.top = FILL_Y(row); rc.top = FILL_Y(row);
@ -6145,9 +6198,6 @@ gui_mch_draw_string(
#endif #endif
HPEN hpen, old_pen; HPEN hpen, old_pen;
int y; int y;
#ifdef FEAT_DIRECTX
int font_is_ttf_or_vector = 0;
#endif
/* /*
* Italic and bold text seems to have an extra row of pixels at the bottom * Italic and bold text seems to have an extra row of pixels at the bottom
@ -6208,6 +6258,11 @@ gui_mch_draw_string(
hbr = hbr_cache[brush_lru]; hbr = hbr_cache[brush_lru];
brush_lru = !brush_lru; brush_lru = !brush_lru;
} }
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_FillRect(s_dwc, &rc, gui.currBgColor);
#endif
FillRect(s_hdc, &rc, hbr); FillRect(s_hdc, &rc, hbr);
SetBkMode(s_hdc, TRANSPARENT); SetBkMode(s_hdc, TRANSPARENT);
@ -6227,16 +6282,7 @@ gui_mch_draw_string(
#ifdef FEAT_DIRECTX #ifdef FEAT_DIRECTX
if (IS_ENABLE_DIRECTX()) if (IS_ENABLE_DIRECTX())
{ DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
TEXTMETRIC tm;
GetTextMetrics(s_hdc, &tm);
if (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR))
{
font_is_ttf_or_vector = 1;
DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
}
}
#endif #endif
if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width) if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
@ -6347,12 +6393,13 @@ gui_mch_draw_string(
++clen; ++clen;
} }
#if defined(FEAT_DIRECTX) #if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX() && font_is_ttf_or_vector) if (IS_ENABLE_DIRECTX())
{ {
/* Add one to "cells" for italics. */ /* Add one to "cells" for italics. */
DWriteContext_DrawText(s_dwc, s_hdc, unicodebuf, wlen, DWriteContext_DrawText(s_dwc, unicodebuf, wlen,
TEXT_X(col), TEXT_Y(row), FILL_X(cells + 1), FILL_Y(1), TEXT_X(col), TEXT_Y(row), FILL_X(cells + 1), FILL_Y(1),
gui.char_width, gui.currFgColor); gui.char_width, gui.currFgColor,
foptions, pcliprect, unicodepdy);
} }
else else
#endif #endif
@ -6411,6 +6458,12 @@ gui_mch_draw_string(
foptions, pcliprect, (char *)text, len, padding); foptions, pcliprect, (char *)text, len, padding);
} }
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX() &&
(flags & (DRAW_UNDERL | DRAW_STRIKE | DRAW_UNDERC | DRAW_CURSOR)))
DWriteContext_Flush(s_dwc);
#endif
/* Underline */ /* Underline */
if (flags & DRAW_UNDERL) if (flags & DRAW_UNDERL)
{ {
@ -6473,6 +6526,11 @@ gui_mch_flush(void)
BOOL __stdcall GdiFlush(void); BOOL __stdcall GdiFlush(void);
# endif # endif
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
GdiFlush(); GdiFlush();
} }
@ -6481,6 +6539,14 @@ clear_rect(RECT *rcp)
{ {
HBRUSH hbr; HBRUSH hbr;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
{
DWriteContext_FillRect(s_dwc, rcp, gui.back_pixel);
return;
}
#endif
hbr = CreateSolidBrush(gui.back_pixel); hbr = CreateSolidBrush(gui.back_pixel);
FillRect(s_hdc, rcp, hbr); FillRect(s_hdc, rcp, hbr);
DeleteBrush(hbr); DeleteBrush(hbr);
@ -8386,6 +8452,11 @@ gui_mch_drawsign(int row, int col, int typenr)
if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL) if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL)
return; return;
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
x = TEXT_X(col); x = TEXT_X(col);
y = TEXT_Y(row); y = TEXT_Y(row);
w = gui.char_width * 2; w = gui.char_width * 2;
@ -8865,6 +8936,11 @@ netbeans_draw_multisign_indicator(int row)
x = 0; x = 0;
y = TEXT_Y(row); y = TEXT_Y(row);
#if defined(FEAT_DIRECTX)
if (IS_ENABLE_DIRECTX())
DWriteContext_Flush(s_dwc);
#endif
for (i = 0; i < gui.char_height - 3; i++) for (i = 0; i < gui.char_height - 3; i++)
SetPixel(s_hdc, x+2, y++, gui.currFgColor); SetPixel(s_hdc, x+2, y++, gui.currFgColor);

View File

@ -1,5 +1,4 @@
/* gui_w32.c */ /* gui_w32.c */
int directx_enabled(void);
int gui_mch_set_rendering_options(char_u *s); int gui_mch_set_rendering_options(char_u *s);
int gui_mch_is_blinking(void); int gui_mch_is_blinking(void);
int gui_mch_is_blink_off(void); int gui_mch_is_blink_off(void);

View File

@ -771,6 +771,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1343,
/**/ /**/
1342, 1342,
/**/ /**/