Subject: bug#6364: [PATCH] Use GetCharABCWidthsFloatW if GetGlyphOutlineW fails.

From: Tom Seddon <[email-masked]>
Date: Tue, 26 Nov 2013 00:35:05 +0000

Please find below a patch to improve the poor scrolling performance when using bitmap fonts. #14721 (http://debbugs.gnu.org/cgi/bugreport.cgi?bug=14721) and and 14307 (http://debbugs.gnu.org/cgi/bugreport.cgi?bug=14307) may also be affected. The patch has been tested against emacs 24.3. It applied cleanly to git head (22687e54e0e4d7c73c098417478574a55393fe2c) but I haven't built it.

Performance with particularly long lines is still rather poor, but general responsiveness is much improved. (Once the buffer is fontified, emacs can now usually keep up if I hold down PgUp, PgDn, C-s, etc.)

(I settled on GetCharABCWidthsFloatW because it works for bitmap fonts and TrueType fonts alike. But the key thing is simply not to create a DC each time w32font_text_extents is called, so there are various other functions that could be called instead if preferred.)

--Tom

From ccedd16f6bd2027145b9e172346d2c3b31c811df Mon Sep 17 00:00:00 2001
From: Tom Seddon <tom@tmbp-w7>
Date: Mon, 25 Nov 2013 22:19:47 +0000
Subject: [PATCH] Use GetCharABCWidthsFloatW if GetGlyphOutlineW fails.

The previous fallback - which will still be used if
GetCharABCWidthsFloatW fails - was to call GetTextExtentPoint32W. This
can be rather slow due to having to create a DC for it each time.
---
 src/w32font.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/src/w32font.c b/src/w32font.c
index 5c5a15c..3577dfa 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -149,6 +149,7 @@ static BOOL g_b_init_get_outline_metrics_w;
 static BOOL g_b_init_get_text_metrics_w;
 static BOOL g_b_init_get_glyph_outline_w;
 static BOOL g_b_init_get_glyph_outline_w;
+static BOOL g_b_init_get_char_abc_widths_float_w;
 
 typedef UINT (WINAPI * GetOutlineTextMetricsW_Proc) (
    HDC hdc,
@@ -165,6 +166,11 @@ typedef DWORD (WINAPI * GetGlyphOutlineW_Proc) (
    DWORD cbBuffer,
    LPVOID lpvBuffer,
    const MAT2 *lpmat2);
+typedef BOOL (WINAPI * GetCharABCWidthsFloatW_Proc) (
+   HDC hdc,
+   UINT uFirstChar,
+   UINT uLastChar,
+   LPABCFLOAT lpabc);
 
 /* Several "wide" functions we use to support the font backends are
    unavailable on Windows 9X, unless UNICOWS.DLL is installed (their
@@ -274,6 +280,23 @@ get_glyph_outline_w (HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm,
 				   lpvBuffer, lpmat2);
 }
 
+static DWORD WINAPI get_char_abc_widths_float_w (HDC hdc, UINT uFirstChar,
+						 UINT uLastChar, LPABCFLOAT lpabc)
+{
+  static GetCharABCWidthsFloatW_Proc s_pfn_Get_Char_ABC_Widths_FloatW = NULL;
+  HMODULE hm_unicows = NULL;
+  if (g_b_init_get_char_abc_widths_float_w == 0)
+    {
+      g_b_init_get_char_abc_widths_float_w = 1;
+      hm_unicows = w32_load_unicows_or_gdi32 ();
+      if (hm_unicows)
+	s_pfn_Get_Char_ABC_Widths_FloatW = (GetCharABCWidthsFloatW_Proc)
+	  GetProcAddress (hm_unicows, "GetCharABCWidthsFloatW");
+    }
+  eassert (s_pfn_Get_Char_ABC_Widths_FloatW != NULL);
+  return s_pfn_Get_Char_ABC_Widths_FloatW (hdc, uFirstChar, uLastChar, lpabc);
+}
+
 static int
 memq_no_quit (Lisp_Object elt, Lisp_Object list)
 {
@@ -2438,6 +2461,7 @@ compute_metrics (HDC dc, struct w32font_info *w32_font, unsigned int code,
   GLYPHMETRICS gm;
   MAT2 transform;
   unsigned int options = GGO_METRICS;
+  ABCFLOAT abc;
 
   if (w32_font->glyph_idx)
     options |= GGO_GLYPH_INDEX;
@@ -2454,6 +2478,14 @@ compute_metrics (HDC dc, struct w32font_info *w32_font, unsigned int code,
       metrics->width = gm.gmCellIncX;
       metrics->status = W32METRIC_SUCCESS;
     }
+  else if (get_char_abc_widths_float_w (dc, code, code, &abc) != 0)
+    {
+      int width = (int) (abc.abcfA + abc.abcfB + abc.abcfC);
+      metrics->lbearing = 0;
+      metrics->rbearing = width;
+      metrics->width = width;
+      metrics->status = W32METRIC_SUCCESS;
+    }
   else
     metrics->status = W32METRIC_FAIL;
 }
-- 
1.8.1.msysgit.1