Improve performance on Windows especially for non-Latin scripts
authorTor Lillqvist <tml@iki.fi>
Sat, 26 Jun 2010 13:05:13 +0000 (16:05 +0300)
committerTor Lillqvist <tml@iki.fi>
Sat, 26 Jun 2010 13:09:10 +0000 (16:09 +0300)
The use of Uniscribe script caches was decidedly suboptimal. Use one
persistent SCRIPT_CACHE per Win32 font and script.

Patch by by David E. Hollingsworth and Fredrik Corneliusson, from bug

modules/basic/basic-win32.c
pango/pangowin32-private.h
pango/pangowin32.c
pango/pangowin32.def

index 1565a7c..22aafdb 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "pangowin32.h"
 
+extern HFONT _pango_win32_font_get_hfont (PangoFont *font);
+
 #ifndef PANGO_MODULE_PREFIX
 #define PANGO_MODULE_PREFIX _pango_basic_win32
 #endif
@@ -500,8 +502,7 @@ itemize_shape_and_place (PangoFont           *font,
                         wchar_t             *wtext,
                         int                  wlen,
                         const PangoAnalysis *analysis,
-                        PangoGlyphString    *glyphs,
-                        SCRIPT_CACHE        *script_cache)
+                        PangoGlyphString    *glyphs)
 {
   int i;
   int item, nitems, item_step;
@@ -510,6 +511,11 @@ itemize_shape_and_place (PangoFont           *font,
   SCRIPT_STATE state;
   SCRIPT_ITEM items[100];
   double scale = pango_win32_font_get_metrics_factor (font);
+  HFONT hfont = _pango_win32_font_get_hfont (font);
+  static GHashTable *script_cache_hash = NULL;
+
+  if (!script_cache_hash)
+    script_cache_hash = g_hash_table_new (g_int64_hash, g_int64_equal);
 
   memset (&control, 0, sizeof (control));
   memset (&state, 0, sizeof (state));
@@ -556,9 +562,11 @@ itemize_shape_and_place (PangoFont           *font,
       int advances[1000];
       GOFFSET offsets[1000];
       ABC abc;
-      int script = items[item].a.eScript;
+      gint32 script = items[item].a.eScript;
       int ng;
       int char_offset;
+      SCRIPT_CACHE *script_cache;
+      gint64 font_and_script_key;
 
       memset (advances, 0, sizeof (advances));
       memset (offsets, 0, sizeof (offsets));
@@ -584,9 +592,33 @@ itemize_shape_and_place (PangoFont           *font,
                 items[item].a.fNoGlyphIndex ? " fNoGlyphIndex" : "",
                 items[item].iCharPos, items[item+1].iCharPos-1, itemlen);
 #endif
+      /* Create a hash key based on hfont and script engine */
+      font_and_script_key = (((gint64) ((gint32) hfont)) << 32) | script;
+
+      /* Get the script cache for this hfont and script */
+      script_cache = g_hash_table_lookup (script_cache_hash, &font_and_script_key);
+      if (!script_cache)
+       {
+         gint64 *key_n;
+         SCRIPT_CACHE *new_script_cache;
+
+         key_n = g_new (gint64, 1);
+         *key_n = font_and_script_key;
+
+         new_script_cache = g_new0 (SCRIPT_CACHE, 1);
+         script_cache = new_script_cache;
+
+         /* Insert the new value */
+         g_hash_table_insert (script_cache_hash, key_n, new_script_cache);
+
+#ifdef BASIC_WIN32_DEBUGGING
+         if (pango_win32_debug)
+           g_print ("  New SCRIPT_CACHE for font %p and script %d\n", hfont, script);
+#endif
+       }
 
       items[item].a.fRTL = analysis->level % 2;
-      if ((*script_shape) (hdc, &script_cache[script],
+      if ((*script_shape) (hdc, script_cache,
                           wtext + items[item].iCharPos, itemlen,
                           G_N_ELEMENTS (iglyphs),
                           &items[item].a,
@@ -616,7 +648,7 @@ itemize_shape_and_place (PangoFont           *font,
                                 nglyphs, glyphs->log_clusters + ng,
                                 char_offset);
 
-      if ((*script_place) (hdc, &script_cache[script], iglyphs, nglyphs,
+      if ((*script_place) (hdc, script_cache, iglyphs, nglyphs,
                           visattrs, &items[item].a,
                           advances, offsets, &abc))
        {
@@ -676,9 +708,7 @@ uniscribe_shape (PangoFont           *font,
 {
   wchar_t *wtext;
   long wlen;
-  int i;
   gboolean retval = TRUE;
-  SCRIPT_CACHE script_cache[100];
 
   if (!pango_win32_font_select_font (font, hdc))
     return FALSE;
@@ -689,11 +719,7 @@ uniscribe_shape (PangoFont           *font,
 
   if (retval)
     {
-      memset (script_cache, 0, sizeof (script_cache));
-      retval = itemize_shape_and_place (font, hdc, wtext, wlen, analysis, glyphs, script_cache);
-      for (i = 0; i < G_N_ELEMENTS (script_cache); i++)
-       if (script_cache[i])
-         (*script_free_cache)(&script_cache[i]);
+      retval = itemize_shape_and_place (font, hdc, wtext, wlen, analysis, glyphs);
     }
 
   if (retval)
index 9f35823..73df2e9 100644 (file)
@@ -129,11 +129,8 @@ struct _PangoWin32Font
 
   PangoFontMap *fontmap;
 
-  /* Written by pango_win32_get_hfont: */
+  /* Written by _pango_win32_font_get_hfont: */
   HFONT hfont;
-  gint tm_ascent;
-  gint tm_descent;
-  gint tm_overhang;
 
   PangoWin32Face *win32face;
 
@@ -275,6 +272,8 @@ gboolean    _pango_win32_get_name_record        (HDC                 hdc,
                                                     gint                i,
                                                     struct name_record *record);
 
+HFONT          _pango_win32_font_get_hfont         (PangoFont          *font);
+
 extern HDC _pango_win32_hdc;
 extern OSVERSIONINFO _pango_win32_os_version_info;
 extern gboolean _pango_win32_debug;
index 1f8c1d2..30ec8b6 100644 (file)
@@ -74,7 +74,6 @@ static gboolean pango_win32_font_real_select_font      (PangoFont *font,
 static void     pango_win32_font_real_done_font        (PangoFont *font);
 static double   pango_win32_font_real_get_metrics_factor (PangoFont *font);
 
-static HFONT                 pango_win32_get_hfont              (PangoFont        *font);
 static void                  pango_win32_get_item_properties    (PangoItem        *item,
                                                                 PangoUnderline   *uline,
                                                                 PangoAttrColor   *fg_color,
@@ -82,12 +81,11 @@ static void                  pango_win32_get_item_properties    (PangoItem
                                                                 PangoAttrColor   *bg_color,
                                                                 gboolean         *bg_set);
 
-static HFONT
-pango_win32_get_hfont (PangoFont *font)
+HFONT
+_pango_win32_font_get_hfont (PangoFont *font)
 {
   PangoWin32Font *win32font = (PangoWin32Font *)font;
   PangoWin32FontCache *cache;
-  TEXTMETRIC tm;
 
   if (!win32font)
     return NULL;
@@ -105,13 +103,6 @@ pango_win32_get_hfont (PangoFont *font)
          g_free (face_utf8);
          return NULL;
        }
-
-      SelectObject (_pango_win32_hdc, win32font->hfont);
-      GetTextMetrics (_pango_win32_hdc, &tm);
-
-      win32font->tm_overhang = tm.tmOverhang;
-      win32font->tm_descent = tm.tmDescent;
-      win32font->tm_ascent = tm.tmAscent;
     }
 
   return win32font->hfont;
@@ -261,7 +252,7 @@ pango_win32_render (HDC               hdc,
   if (glyphs->num_glyphs == 0)
     return;
 
-  hfont = pango_win32_get_hfont (font);
+  hfont = _pango_win32_font_get_hfont (font);
   if (!hfont)
     return;
 
@@ -440,6 +431,7 @@ pango_win32_font_get_glyph_extents (PangoFont      *font,
   PangoWin32Font *win32font = (PangoWin32Font *)font;
   guint16 glyph_index = glyph;
   GLYPHMETRICS gm;
+  TEXTMETRIC tm;
   guint32 res;
   HFONT hfont;
   MAT2 m = {{0,1}, {0,0}, {0,0}, {0,1}};
@@ -465,7 +457,7 @@ pango_win32_font_get_glyph_extents (PangoFont      *font,
 
       memset (&gm, 0, sizeof (gm));
 
-      hfont = pango_win32_get_hfont (font);
+      hfont = _pango_win32_font_get_hfont (font);
       SelectObject (_pango_win32_hdc, hfont);
       /* FIXME: (Alex) This constant reuse of _pango_win32_hdc is
         not thread-safe */
@@ -491,10 +483,11 @@ pango_win32_font_get_glyph_extents (PangoFont      *font,
       info->ink_rect.y = - PANGO_SCALE * gm.gmptGlyphOrigin.y;
       info->ink_rect.height = PANGO_SCALE * gm.gmBlackBoxY;
 
+      GetTextMetrics (_pango_win32_hdc, &tm);
       info->logical_rect.x = 0;
       info->logical_rect.width = PANGO_SCALE * gm.gmCellIncX;
-      info->logical_rect.y = - PANGO_SCALE * win32font->tm_ascent;
-      info->logical_rect.height = PANGO_SCALE * (win32font->tm_ascent + win32font->tm_descent);
+      info->logical_rect.y = - PANGO_SCALE * tm.tmAscent;
+      info->logical_rect.height = PANGO_SCALE * (tm.tmAscent + tm.tmDescent);
 
       g_hash_table_insert (win32font->glyph_info, GUINT_TO_POINTER(glyph), info);
     }
@@ -562,7 +555,7 @@ pango_win32_font_get_metrics (PangoFont     *font,
       info->sample_str = sample_str;
       info->metrics = metrics = pango_font_metrics_new ();
 
-      hfont = pango_win32_get_hfont (font);
+      hfont = _pango_win32_font_get_hfont (font);
       if (hfont != NULL)
        {
          PangoCoverage *coverage;
@@ -626,7 +619,7 @@ static gboolean
 pango_win32_font_real_select_font (PangoFont *font,
                                   HDC        hdc)
 {
-  HFONT hfont = pango_win32_get_hfont (font);
+  HFONT hfont = _pango_win32_font_get_hfont (font);
 
   if (!hfont)
     return FALSE;
@@ -1611,7 +1604,7 @@ font_has_name_in (PangoFont                       *font,
   if (cjkv == PANGO_WIN32_COVERAGE_UNSPEC)
     return TRUE;
 
-  hfont = pango_win32_get_hfont (font);
+  hfont = _pango_win32_font_get_hfont (font);
   oldhfont = SelectObject (_pango_win32_hdc, hfont);
 
   if (!_pango_win32_get_name_header (_pango_win32_hdc, &header))
index 13b6e8b..ec8e8b2 100644 (file)
@@ -3,6 +3,7 @@ EXPORTS
        _pango_win32_make_matching_logfontw
        _pango_win32_font_get_type
        _pango_win32_font_map_get_type
+       _pango_win32_font_get_hfont
        pango_win32_font_cache_free
        pango_win32_font_cache_load
        pango_win32_font_cache_loadw