Skip to content

Instantly share code, notes, and snippets.

@k-takata
Created January 16, 2013 12:36
Show Gist options
  • Save k-takata/4546842 to your computer and use it in GitHub Desktop.
Save k-takata/4546842 to your computer and use it in GitHub Desktop.
additional patch No.5 for vim-kaoriya-vim-mq-ex / patch-direct_write.diff (Use GDI compatible layouts.)
diff --git a/src/gui_dwrite.cpp b/src/gui_dwrite.cpp
--- a/src/gui_dwrite.cpp
+++ b/src/gui_dwrite.cpp
@@ -14,6 +14,10 @@
#include "gui_dwrite.h"
+extern "C" {
+#include "vim.h"
+}
+
#ifdef __MINGW32__
# define __maybenull SAL__maybenull
# define __in SAL__in
@@ -39,10 +43,13 @@
public:
GdiTextRenderer(
IDWriteBitmapRenderTarget* bitmapRenderTarget,
- IDWriteRenderingParams* renderingParams) :
+ IDWriteRenderingParams* renderingParams,
+ FLOAT dpiScaleX) :
cRefCount_(0),
pRenderTarget_(bitmapRenderTarget),
- pRenderingParams_(renderingParams)
+ pRenderingParams_(renderingParams),
+ dpiScaleX_(dpiScaleX),
+ offset_(0.0)
{
pRenderTarget_->AddRef();
pRenderingParams_->AddRef();
@@ -97,14 +104,31 @@
// Pass on the drawing call to the render target to do the real work.
RECT dirtyRect = {0};
+ // Adjust glyphAdvances and baselineOriginX to fit with the layout of
+ // GDI. Using CreateGdiCompatibleTextLayout() is not enough.
+ DWRITE_GLYPH_RUN glyphRunAdj = *glyphRun;
+ FLOAT* glyphAdvances = new FLOAT[glyphRun->glyphCount];
+ glyphRunAdj.glyphAdvances = glyphAdvances;
+ FLOAT delta = 0.0;
+ for (int i = 0; i < glyphRun->glyphCount; i++) {
+ if (glyphRun->glyphAdvances[i] > gui.char_width * 1.5 / dpiScaleX_)
+ glyphAdvances[i] = gui.char_width * 2 / dpiScaleX_;
+ else
+ glyphAdvances[i] = gui.char_width / dpiScaleX_;
+ delta += glyphAdvances[i] - glyphRun->glyphAdvances[i];
+ }
+
hr = pRenderTarget_->DrawGlyphRun(
- baselineOriginX,
+ baselineOriginX + offset_,
baselineOriginY,
measuringMode,
- glyphRun,
+ &glyphRunAdj,
pRenderingParams_,
context->color,
&dirtyRect);
+ offset_ += delta;
+
+ delete [] glyphAdvances;
return hr;
}
@@ -188,6 +212,8 @@
unsigned long cRefCount_;
IDWriteBitmapRenderTarget* pRenderTarget_;
IDWriteRenderingParams* pRenderingParams_;
+ FLOAT dpiScaleX_;
+ FLOAT offset_;
};
struct DWriteContext {
@@ -477,9 +503,15 @@
HDC memdc = bmpRT->GetMemoryDC();
BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY);
+#if 1
+ hr = mDWriteFactory->CreateTextLayout(
+ text, len, mTextFormat, static_cast<FLOAT>(w),
+ static_cast<FLOAT>(h), &textLayout);
+#else
hr = mDWriteFactory->CreateGdiCompatibleTextLayout(
text, len, mTextFormat, static_cast<FLOAT>(w),
static_cast<FLOAT>(h), mDpiScaleX, NULL, TRUE, &textLayout);
+#endif
if (SUCCEEDED(hr))
{
@@ -493,7 +525,7 @@
if (SUCCEEDED(hr))
{
GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT,
- mRenderingParams);
+ mRenderingParams, mDpiScaleX);
GdiTextRendererContext data = { color };
textLayout->Draw(&data, renderer, 0, 0);
SafeRelease(&renderer);
@k-takata
Copy link
Author

このコードを書き起こすに当たって、参考にした資料(URLとか)ってあったら教えてください。

ないです。

CreateGdiCompatibleTextLayout を使わない理由を教えてください。

CreateGdiCompatibleTextLayout を使っても CreateTextLayout を使っても、glyphAdvances の値を上書きしてしまっているので、同じ結果になっているはずです。(少なくとも私には判別できませんでした。)
measuringMode の値が違っているかもしれませんので、サブピクセルレベルでは配置が異なっている可能性がありますが、未確認です。

本来は Layout のほうをカスタムしてやるんじゃないかなぁ、というのが直感。

そういうやり方を探してはいるのですが、見つかってないです。

あと offset_ に差 (delta) が蓄積してんだけど、
Yが異なる=不要な offset_ が適用されることは無いのかしら?

行が異なる場合はoffset_が0に初期化されるので問題ないです。
一回の textLayout->Draw() の呼び出しで、DrawGlyphRun() が複数回呼ばれるので、それを補正しているのが offset_ です。

@k-takata
Copy link
Author

GdiTextRendererContext を経由して参照したほうが良い。
今のままでは結合が強くなりすぎてる。

それはそうですね。

@koron
Copy link

koron commented Jan 16, 2013

Thanks! んでは、続きは私の方で取り込んでみます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment