To: vim_dev@googlegroups.com Subject: Patch 8.0.1343 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1343 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) Files: appveyor.yml, runtime/doc/options.txt, src/gui_dwrite.cpp, src/gui_dwrite.h, src/gui_w32.c, src/proto/gui_w32.pro *** ../vim-8.0.1342/appveyor.yml 2016-09-25 20:21:58.333062395 +0200 --- appveyor.yml 2017-11-26 14:22:54.513534386 +0100 *************** *** 16,21 **** --- 16,22 ---- before_build: - '"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: - src/appveyor.bat *** ../vim-8.0.1342/runtime/doc/options.txt 2017-11-25 17:58:23.622091808 +0100 --- runtime/doc/options.txt 2017-11-26 14:22:54.517534364 +0100 *************** *** 6049,6059 **** Example: > set encoding=utf-8 ! set gfn=Ricty_Diminished:h12:cSHIFTJIS set rop=type:directx < ! If select a raster font (Courier, Terminal or FixedSys) to ! 'guifont', it fallbacks to be drawn by GDI automatically. Other render types are currently not supported. --- 6154,6187 ---- Example: > set encoding=utf-8 ! set gfn=Ricty_Diminished:h12 set rop=type:directx < ! If select a raster font (Courier, Terminal or FixedSys which ! 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. *** ../vim-8.0.1342/src/gui_dwrite.cpp 2016-03-19 20:48:11.000000000 +0100 --- src/gui_dwrite.cpp 2017-11-26 14:22:54.517534364 +0100 *************** *** 4,9 **** --- 4,10 ---- * * Contributors: * - Ken Takata + * - Yasuhiro Matsumoto * * Copyright (C) 2013 MURAOKA Taro * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. *************** *** 23,29 **** #include #include #include ! #include #include "gui_dwrite.h" --- 24,44 ---- #include #include #include ! ! // 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 #include "gui_dwrite.h" *************** *** 79,94 **** } } - struct GdiTextRendererContext - { - // const fields. - COLORREF color; - FLOAT cellWidth; - - // working fields. - FLOAT offsetX; - }; - static DWRITE_PIXEL_GEOMETRY ToPixelGeometry(int value) { --- 94,99 ---- *************** *** 184,200 **** } } class AdjustedGlyphRun : public DWRITE_GLYPH_RUN { private: FLOAT mDelta; FLOAT *mAdjustedAdvances; public: AdjustedGlyphRun( const DWRITE_GLYPH_RUN *glyphRun, ! FLOAT cellWidth) : DWRITE_GLYPH_RUN(*glyphRun), mDelta(0.0f), mAdjustedAdvances(new FLOAT[glyphRun->glyphCount]) { --- 189,339 ---- } } + 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 &accum) : DWRITE_GLYPH_RUN(*glyphRun), + mAccum(accum), mDelta(0.0f), mAdjustedAdvances(new FLOAT[glyphRun->glyphCount]) { *************** *** 209,253 **** glyphAdvances = mAdjustedAdvances; } ! ~AdjustedGlyphRun(void) { delete[] mAdjustedAdvances; } - FLOAT getDelta(void) const - { - return mDelta; - } - static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth) { ! int cellCount = (int)floor(value / cellWidth + 0.5f); if (cellCount < 1) cellCount = 1; return cellCount * cellWidth; } }; ! class GdiTextRenderer FINAL : public IDWriteTextRenderer { public: ! GdiTextRenderer( ! IDWriteBitmapRenderTarget* bitmapRenderTarget, ! IDWriteRenderingParams* renderingParams) : cRefCount_(0), ! pRenderTarget_(bitmapRenderTarget), ! pRenderingParams_(renderingParams) { - pRenderTarget_->AddRef(); - pRenderingParams_->AddRef(); AddRef(); } // add "virtual" to avoid a compiler warning ! virtual ~GdiTextRenderer() { - SafeRelease(&pRenderTarget_); - SafeRelease(&pRenderingParams_); } IFACEMETHOD(IsPixelSnappingDisabled)( --- 348,391 ---- glyphAdvances = mAdjustedAdvances; } ! ~AdjustedGlyphRun() { + mAccum += mDelta; delete[] mAdjustedAdvances; } static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth) { ! int cellCount = int(floor(value / cellWidth + 0.5f)); if (cellCount < 1) cellCount = 1; return cellCount * cellWidth; } }; ! struct TextRendererContext { ! // const fields. ! COLORREF color; ! FLOAT cellWidth; ! ! // working fields. ! FLOAT offsetX; ! }; ! ! class TextRenderer FINAL : public IDWriteTextRenderer { public: ! TextRenderer( ! DWriteContext* pDWC) : cRefCount_(0), ! pDWC_(pDWC) { AddRef(); } // add "virtual" to avoid a compiler warning ! virtual ~TextRenderer() { } IFACEMETHOD(IsPixelSnappingDisabled)( *************** *** 263,269 **** __out DWRITE_MATRIX* transform) { // forward the render target's transform ! pRenderTarget_->GetCurrentTransform(transform); return S_OK; } --- 401,408 ---- __out DWRITE_MATRIX* transform) { // forward the render target's transform ! pDWC_->mRT->GetTransform( ! reinterpret_cast(transform)); return S_OK; } *************** *** 271,313 **** __maybenull void* clientDrawingContext, __out FLOAT* pixelsPerDip) { ! *pixelsPerDip = pRenderTarget_->GetPixelsPerDip(); 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(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, --- 410,421 ---- __maybenull void* clientDrawingContext, __out FLOAT* pixelsPerDip) { ! float dpiX, unused; ! pDWC_->mRT->GetDpi(&dpiX, &unused); ! *pixelsPerDip = dpiX / 96.0f; return S_OK; } IFACEMETHOD(DrawUnderline)( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, *************** *** 340,345 **** --- 448,516 ---- 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(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,464 **** 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::DWriteContext() : ! mDpiScaleX(1.f), ! mDpiScaleY(1.f), mDrawing(false), mD2D1Factory(NULL), mRT(NULL), mBrush(NULL), mDWriteFactory(NULL), mGdiInterop(NULL), mRenderingParams(NULL), 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(&mD2D1Factory)); --- 556,583 ---- private: long cRefCount_; ! DWriteContext* pDWC_; }; DWriteContext::DWriteContext() : ! mHDC(NULL), mDrawing(false), + mFallbackDC(false), mD2D1Factory(NULL), mRT(NULL), mBrush(NULL), mDWriteFactory(NULL), + mDWriteFactory2(NULL), mGdiInterop(NULL), mRenderingParams(NULL), + mFontCache(8), mTextFormat(NULL), mFontWeight(DWRITE_FONT_WEIGHT_NORMAL), mFontStyle(DWRITE_FONT_STYLE_NORMAL), mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT) { HRESULT hr; hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), NULL, reinterpret_cast(&mD2D1Factory)); *************** *** 497,502 **** --- 616,630 ---- if (SUCCEEDED(hr)) { + DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory2), + reinterpret_cast(&mDWriteFactory2)); + _RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available"); + } + + if (SUCCEEDED(hr)) + { hr = mDWriteFactory->GetGdiInterop(&mGdiInterop); _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop); } *************** *** 515,534 **** SafeRelease(&mRenderingParams); SafeRelease(&mGdiInterop); SafeRelease(&mDWriteFactory); SafeRelease(&mBrush); SafeRelease(&mRT); SafeRelease(&mD2D1Factory); } HRESULT ! DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize) { ! // Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx HRESULT hr = S_OK; IDWriteFont *font = NULL; IDWriteFontFamily *fontFamily = NULL; IDWriteLocalizedStrings *localizedFamilyNames = NULL; if (SUCCEEDED(hr)) { --- 643,666 ---- SafeRelease(&mRenderingParams); SafeRelease(&mGdiInterop); SafeRelease(&mDWriteFactory); + SafeRelease(&mDWriteFactory2); SafeRelease(&mBrush); SafeRelease(&mRT); SafeRelease(&mD2D1Factory); } HRESULT ! DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont, ! IDWriteTextFormat **ppTextFormat) { ! // 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,593 **** if (SUCCEEDED(hr)) { ! // If no font size was passed in use the lfHeight of the LOGFONT. ! 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); ! ! // Convert the cell height (ascent + descent) from design units ! // to ems. ! float cellHeight = static_cast( ! fontMetrics.ascent + fontMetrics.descent) ! / fontMetrics.designUnitsPerEm; ! ! // Divide the font size by the cell height to get the font em ! // size. ! fontSize /= cellHeight; ! } } } --- 693,722 ---- if (SUCCEEDED(hr)) { ! // Use lfHeight of the LOGFONT as font size. ! fontSize = float(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); ! ! // Convert the cell height (ascent + descent) from design units ! // to ems. ! float cellHeight = static_cast( ! fontMetrics.ascent + fontMetrics.descent) ! / fontMetrics.designUnitsPerEm; ! ! // Divide the font size by the cell height to get the font em ! // size. ! fontSize /= cellHeight; } } *************** *** 612,734 **** font->GetStretch(), fontSize, localeName, ! &mTextFormat); } if (SUCCEEDED(hr)) { mFontWeight = static_cast(logFont.lfWeight); mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; } - SafeRelease(&localizedFamilyNames); - SafeRelease(&fontFamily); - SafeRelease(&font); - return hr; } void DWriteContext::SetFont(HFONT hFont) { ! if (mLastHFont != hFont) { ! LOGFONTW lf; ! if (GetObjectW(hFont, sizeof(lf), &lf)) { ! SetFont(lf); ! mLastHFont = hFont; } } } void ! DWriteContext::SetFont(const LOGFONTW &logFont) { ! 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); } void ! DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len, ! int x, int y, int w, int h, int cellWidth, COLORREF color) { ! HRESULT hr = S_OK; ! IDWriteBitmapRenderTarget *bmpRT = NULL; ! ! // Skip when any fonts are not set. ! if (mTextFormat == NULL) return; ! // Check possibility of zero divided error. ! if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f) ! return; ! if (SUCCEEDED(hr)) ! hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT); if (SUCCEEDED(hr)) { ! IDWriteTextLayout *textLayout = NULL; ! ! 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); } ! SafeRelease(&bmpRT); } ! float ! DWriteContext::PixelsToDipsX(int x) { ! return x / mDpiScaleX; } ! float ! DWriteContext::PixelsToDipsY(int y) { ! return y / mDpiScaleY; } void --- 741,905 ---- font->GetStretch(), fontSize, localeName, ! &pTextFormat); } if (SUCCEEDED(hr)) + 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(logFont.lfWeight); mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; } return hr; } void DWriteContext::SetFont(HFONT hFont) { ! FontCache::Item item; ! if (mFontCache.get(hFont, item)) { ! if (item.pTextFormat != NULL) { ! 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::BindDC(HDC hdc, RECT *rect) { ! Flush(); ! mRT->BindDC(hdc, rect); ! mRT->SetTransform(D2D1::IdentityMatrix()); ! mHDC = hdc; ! } ! void ! DWriteContext::AssureDrawing() ! { ! if (mDrawing == false) ! { ! mRT->BeginDraw(); ! mDrawing = true; ! } ! } ! 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; + } ! AssureDrawing(); ! HRESULT hr; ! IDWriteTextLayout *textLayout = NULL; ! ! hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat, ! FLOAT(w), FLOAT(h), &textLayout); if (SUCCEEDED(hr)) { ! DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) }; ! textLayout->SetFontWeight(mFontWeight, textRange); ! textLayout->SetFontStyle(mFontStyle, textRange); ! TextRenderer renderer(this); ! TextRendererContext context = { color, FLOAT(cellWidth), 0.0f }; ! textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y)); } ! SafeRelease(&textLayout); } ! void ! DWriteContext::FillRect(RECT *rc, COLORREF color) { ! AssureDrawing(); ! mRT->FillRectangle( ! D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top), ! FLOAT(rc->right), FLOAT(rc->bottom)), ! SolidBrush(color)); } ! void ! DWriteContext::Flush() { ! if (mDrawing) ! { ! mRT->EndDraw(); ! mDrawing = false; ! } } void *************** *** 757,762 **** --- 928,937 ---- SafeRelease(&mRenderingParams); mRenderingParams = renderingParams; mTextAntialiasMode = textAntialiasMode; + + Flush(); + mRT->SetTextRenderingParams(mRenderingParams); + mRT->SetTextAntialiasMode(mTextAntialiasMode); } } *************** *** 825,863 **** } 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); ! } } 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, --- 1000,1021 ---- } void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect) { ! 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, const WCHAR* text, int len, int x, *************** *** 865,884 **** int w, int h, int cellWidth, ! COLORREF color) { if (ctx != NULL) ! ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color); } void ! DWriteContext_EndDraw(DWriteContext *ctx) { ! if (ctx != NULL && ctx->mRT != NULL) ! { ! ctx->mRT->EndDraw(); ! ctx->mDrawing = false; ! } } void --- 1023,1050 ---- int w, int h, int cellWidth, ! COLORREF color, ! UINT fuOptions, ! CONST RECT *lprc, ! CONST INT * lpDx) { if (ctx != NULL) ! ctx->DrawText(text, len, x, y, w, h, cellWidth, color, ! fuOptions, lprc, lpDx); } void ! DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color) { ! if (ctx != NULL) ! ctx->FillRect(rc, color); ! } ! ! void ! DWriteContext_Flush(DWriteContext *ctx) ! { ! if (ctx != NULL) ! ctx->Flush(); } void *** ../vim-8.0.1342/src/gui_dwrite.h 2014-08-06 14:21:57.000000000 +0200 --- src/gui_dwrite.h 2017-11-26 14:22:54.517534364 +0100 *************** *** 4,9 **** --- 4,10 ---- * * Contributors: * - Ken Takata + * - Yasuhiro Matsumoto * * Copyright (C) 2013 MURAOKA Taro * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. *************** *** 54,65 **** void DWrite_Final(void); DWriteContext *DWriteContext_Open(void); - void DWriteContext_BeginDraw(DWriteContext *ctx); void DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect); void DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont); void DWriteContext_DrawText( DWriteContext *ctx, - HDC hdc, const WCHAR* text, int len, int x, --- 55,64 ---- *************** *** 67,74 **** int w, int h, int cellWidth, ! COLORREF color); ! void DWriteContext_EndDraw(DWriteContext *ctx); void DWriteContext_Close(DWriteContext *ctx); void DWriteContext_SetRenderingParams( --- 66,77 ---- int w, int h, int cellWidth, ! COLORREF color, ! 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_SetRenderingParams( *** ../vim-8.0.1342/src/gui_w32.c 2017-11-25 17:14:29.604189538 +0100 --- src/gui_w32.c 2017-11-26 14:22:54.521534341 +0100 *************** *** 34,61 **** static int s_directx_enabled = 0; static int s_directx_load_attempted = 0; # define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL) #endif #ifdef FEAT_MENU static int gui_mswin_get_menu_height(int fix_window); #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) int gui_mch_set_rendering_options(char_u *s) --- 34,47 ---- static int s_directx_enabled = 0; static int s_directx_load_attempted = 0; # define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL) + static int directx_enabled(void); + static void directx_binddc(void); #endif #ifdef FEAT_MENU static int gui_mswin_get_menu_height(int fix_window); #endif #if defined(FEAT_RENDER_OPTIONS) || defined(PROTO) int gui_mch_set_rendering_options(char_u *s) *************** *** 369,374 **** --- 355,388 ---- # define MyTranslateMessage(x) TranslateMessage(x) #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) /* use of WindowProc depends on wide_WindowProc */ # define MyWindowProc vim_WindowProc *************** *** 589,594 **** --- 603,612 ---- blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime, (TIMERPROC)_OnBlinkTimer); } + #if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_Flush(s_dwc); + #endif } static void *************** *** 1000,1005 **** --- 1018,1036 ---- _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 /* * Find the vimmenu_T with the given id *************** *** 1234,1239 **** --- 1265,1271 ---- HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown); HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown); HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease); + HANDLE_MSG(hwnd, WM_SIZE, _OnSizeTextArea); #ifdef FEAT_BEVAL_GUI case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam); *************** *** 1633,1638 **** --- 1665,1675 ---- { RECT rc; + #if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_Flush(s_dwc); + #endif + /* * Note: InvertRect() excludes right and bottom of rectangle. */ *************** *** 1661,1666 **** --- 1698,1708 ---- HBRUSH hbr; RECT rc; + #if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_Flush(s_dwc); + #endif + /* * Note: FrameRect() excludes right and bottom of rectangle. */ *************** *** 1701,1706 **** --- 1743,1754 ---- rc.top = FILL_Y(gui.row) + gui.char_height - h; rc.right = rc.left + w; rc.bottom = rc.top + h; + + #if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_Flush(s_dwc); + #endif + hbr = CreateSolidBrush(color); FillRect(s_hdc, &rc, hbr); DeleteBrush(hbr); *************** *** 2856,2865 **** out_flush(); /* make sure all output has been processed */ (void)BeginPaint(hwnd, &ps); - #if defined(FEAT_DIRECTX) - if (IS_ENABLE_DIRECTX()) - DWriteContext_BeginDraw(s_dwc); - #endif #ifdef FEAT_MBYTE /* prevent multi-byte characters from misprinting on an invalid --- 2904,2909 ---- *************** *** 2876,2894 **** 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, ps.rcPaint.right - ps.rcPaint.left + 1, ps.rcPaint.bottom - ps.rcPaint.top + 1); } - #if defined(FEAT_DIRECTX) - if (IS_ENABLE_DIRECTX()) - DWriteContext_EndDraw(s_dwc); - #endif EndPaint(hwnd, &ps); } } --- 2920,2930 ---- *************** *** 3010,3015 **** --- 3046,3056 ---- { RECT rc; + #if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_Flush(s_dwc); + #endif + /* * Note: InvertRect() excludes right and bottom of rectangle. */ *************** *** 3082,3087 **** --- 3123,3134 ---- 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.right = FILL_X(gui.scroll_region_right + 1); rc.top = FILL_Y(row); *************** *** 3115,3120 **** --- 3162,3173 ---- 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.right = FILL_X(gui.scroll_region_right + 1); rc.top = FILL_Y(row); *************** *** 6145,6153 **** #endif HPEN hpen, old_pen; 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 --- 6198,6203 ---- *************** *** 6208,6213 **** --- 6258,6268 ---- hbr = hbr_cache[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); SetBkMode(s_hdc, TRANSPARENT); *************** *** 6227,6242 **** #ifdef FEAT_DIRECTX if (IS_ENABLE_DIRECTX()) ! { ! 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 if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width) --- 6282,6288 ---- #ifdef FEAT_DIRECTX if (IS_ENABLE_DIRECTX()) ! DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont); #endif if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width) *************** *** 6347,6358 **** ++clen; } #if defined(FEAT_DIRECTX) ! if (IS_ENABLE_DIRECTX() && font_is_ttf_or_vector) { /* Add one to "cells" for italics. */ ! DWriteContext_DrawText(s_dwc, s_hdc, unicodebuf, wlen, TEXT_X(col), TEXT_Y(row), FILL_X(cells + 1), FILL_Y(1), ! gui.char_width, gui.currFgColor); } else #endif --- 6393,6405 ---- ++clen; } #if defined(FEAT_DIRECTX) ! if (IS_ENABLE_DIRECTX()) { /* Add one to "cells" for italics. */ ! DWriteContext_DrawText(s_dwc, unicodebuf, wlen, TEXT_X(col), TEXT_Y(row), FILL_X(cells + 1), FILL_Y(1), ! gui.char_width, gui.currFgColor, ! foptions, pcliprect, unicodepdy); } else #endif *************** *** 6411,6416 **** --- 6458,6469 ---- 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 */ if (flags & DRAW_UNDERL) { *************** *** 6473,6478 **** --- 6526,6536 ---- BOOL __stdcall GdiFlush(void); # endif + #if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_Flush(s_dwc); + #endif + GdiFlush(); } *************** *** 6481,6486 **** --- 6539,6552 ---- { 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); FillRect(s_hdc, rcp, hbr); DeleteBrush(hbr); *************** *** 8386,8391 **** --- 8452,8462 ---- if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL) return; + #if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_Flush(s_dwc); + #endif + x = TEXT_X(col); y = TEXT_Y(row); w = gui.char_width * 2; *************** *** 8865,8870 **** --- 8936,8946 ---- x = 0; 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++) SetPixel(s_hdc, x+2, y++, gui.currFgColor); *** ../vim-8.0.1342/src/proto/gui_w32.pro 2017-07-23 16:45:05.673761155 +0200 --- src/proto/gui_w32.pro 2017-11-26 14:22:54.521534341 +0100 *************** *** 1,5 **** /* gui_w32.c */ - int directx_enabled(void); int gui_mch_set_rendering_options(char_u *s); int gui_mch_is_blinking(void); int gui_mch_is_blink_off(void); --- 1,4 ---- *** ../vim-8.0.1342/src/version.c 2017-11-25 21:07:25.337679963 +0100 --- src/version.c 2017-11-26 14:25:22.756828762 +0100 *************** *** 773,774 **** --- 773,776 ---- { /* Add new patch number below this line */ + /**/ + 1343, /**/ -- Everyone has a photographic memory. Some don't have film. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///