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

From: Tom Seddon <[email-masked]>
Date: Tue, 26 Nov 2013 21:50:02 +0000

On 26 Nov 2013, at 20:48, Eli Zaretskii <[email-masked]> wrote:

> OK.  So what other function(s) can be used for this purpose?
> 
> If there are no good alternatives, I guess we will go with
> GetCharABCWidthsFloatW anyway, since the situation cannot become worse
> than it is already.

I've changed it to GetCharWidth32, which is in the list on that MSDN page - see patch below. I've checked this against all bitmap fonts on my system and it produces the same results (and emacs looks to behave the same, including in terms of performance).

This function only works for bitmap fonts, but hopefully if GetGlyphOutlineW ever fails, the reason is that the font is a bitmap one! (And if not, and GetCharWidth32 fails too, there's the same fallback as before in the form of GetTextExtentPoint32.)

> Btw, I used your recipe, but didn't see any significant slowdown with
> fixed.fon (also, the file bigline.txt is missing, I just used the
> 16384 thingy instead.

Agh, my mistake - I should have included start-slow.el, not start-bigline.el. Sorry. start-slow.el looks like this:

(set-face-attribute 'default nil :font "fixed")
(switch-to-buffer (find-file "usb.ids"))
(goto-char (point-max))

Maybe that will show up the problem? But it sounds rather like your computer just doesn't suffer from this issue, for whatever reason...

Thanks,

--Tom

P.S. my two PCs are as follows, and unpatched emacs performs poorly on both of them when using bitmap fonts:

- 3.4GHz Core i7 desktop, 16GB RAM, GeForce 560Ti, Windows 7
- 2.53GHz Core 2 Duo laptop, 8GB RAM, GeForce 9400M, Windows 7 (this is a Macbook Pro - the performance is also bad running in a VM)

So this could be something to do with NVidia display drivers on Windows 7, I suppose? Though I'd expect the VM to have its own drivers, suggesting that it might not actually be the graphics card vendor...

-----------------------------------

From 09fe3b0c0eb07c5ada87aee0864fa1d9478fdcf1 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 GetCharWidth32W if GetGlyphOutlineW fails.

The previous fallback - which will still be used if GetCharWidth32W
fails - was to call GetTextExtentPoint32W. This can be rather slow,
mainly due to having to create a DC for it each time - but not to say
that using the cache isn't cheaper than GetTextExtentPoint32W anyway.
---
 src/w32font.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/src/w32font.c b/src/w32font.c
index 5c5a15c..08316ec 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_width_32_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 * GetCharWidth32W_Proc) (
+   HDC hdc,
+   UINT uFirstChar,
+   UINT uLastChar,
+   LPINT lpBuffer);
 
 /* 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_width_32_w (HDC hdc, UINT uFirstChar,
+					 UINT uLastChar, LPINT lpBuffer)
+{
+  static GetCharWidth32W_Proc s_pfn_Get_Char_Width_32W = NULL;
+  HMODULE hm_unicows = NULL;
+  if (g_b_init_get_char_width_32_w == 0)
+    {
+      g_b_init_get_char_width_32_w = 1;
+      hm_unicows = w32_load_unicows_or_gdi32 ();
+      if (hm_unicows)
+	s_pfn_Get_Char_Width_32W = (GetCharWidth32W_Proc)
+	  GetProcAddress (hm_unicows, "GetCharWidth32W");
+    }
+  eassert (s_pfn_Get_Char_Width_32W != NULL);
+  return s_pfn_Get_Char_Width_32W (hdc, uFirstChar, uLastChar, lpBuffer);
+}
+
 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;
+  INT width;
 
   if (w32_font->glyph_idx)
     options |= GGO_GLYPH_INDEX;
@@ -2454,6 +2478,13 @@ compute_metrics (HDC dc, struct w32font_info *w32_font, unsigned int code,
       metrics->width = gm.gmCellIncX;
       metrics->status = W32METRIC_SUCCESS;
     }
+  else if (get_char_width_32_w (dc, code, code, &width) != 0)
+    {
+      metrics->lbearing = 0;
+      metrics->rbearing = width;
+      metrics->width = width;
+      metrics->status = W32METRIC_SUCCESS;
+    }
   else
     metrics->status = W32METRIC_FAIL;
 }
-- 
1.8.1.msysgit.1