changeset 97086:c38003f850b5

(uniscribe_shape): Avoid using context if cache is populated. (uniscribe_encode_char): Always use uniscribe. Avoid using context if cache is populated.
author Jason Rumney <jasonr@gnu.org>
date Tue, 29 Jul 2008 16:24:24 +0000
parents fa4823bf5a04
children 535cfa18fb6d
files src/ChangeLog src/w32uniscribe.c
diffstat 2 files changed, 125 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Jul 29 14:46:18 2008 +0000
+++ b/src/ChangeLog	Tue Jul 29 16:24:24 2008 +0000
@@ -1,3 +1,10 @@
+2008-07-29  Jason Rumney  <jasonr@gnu.org>
+
+        * w32uniscribe.c (uniscribe_shape): Avoid using context if cache
+        is populated.
+        (uniscribe_encode_char): Always use uniscribe.
+        Avoid using context if cache is populated.
+
 2008-07-29  Jan Djärv  <jan.h.d@swipnet.se>
 
 	* xmenu.c (Fx_menu_bar_open_internal): Use activate_item signal to
--- a/src/w32uniscribe.c	Tue Jul 29 14:46:18 2008 +0000
+++ b/src/w32uniscribe.c	Tue Jul 29 16:24:24 2008 +0000
@@ -211,10 +211,10 @@
   int *advances;
   GOFFSET *offsets;
   ABC overall_metrics;
-  HDC context;
-  HFONT old_font;
   HRESULT result;
-  struct frame * f;
+  struct frame * f = NULL;
+  HDC context = NULL;
+  HFONT old_font = NULL;
 
   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
   uniscribe_font = (struct uniscribe_font_info *) font;
@@ -248,7 +248,7 @@
 					sizeof (SCRIPT_ITEM) * max_items + 1);
     }
 
-  if (!SUCCEEDED (result))
+  if (FAILED (result))
     {
       xfree (items);
       return Qnil;
@@ -257,10 +257,6 @@
   /* TODO: When we get BIDI support, we need to call ScriptLayout here.
      Requires that we know the surrounding context.  */
 
-  f = XFRAME (selected_frame);
-  context = get_frame_dc (f);
-  old_font = SelectObject (context, FONT_HANDLE(font));
-
   glyphs = alloca (max_glyphs * sizeof (WORD));
   clusters = alloca (nchars * sizeof (WORD));
   attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR));
@@ -272,17 +268,35 @@
       int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1;
       nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
 
+      /* Context may be NULL here, in which case the cache should be
+         used without needing to select the font.  */
       result = ScriptShape (context, &(uniscribe_font->cache),
 			    chars + items[i].iCharPos, nchars_in_run,
 			    max_glyphs - done_glyphs, &(items[i].a),
 			    glyphs, clusters, attributes, &nglyphs);
+
+      if (result == E_PENDING && !context)
+	{
+	  /* This assumes the selected frame is on the same display as the
+	     one we are drawing.  It would be better for the frame to be
+	     passed in.  */
+	  f = XFRAME (selected_frame);
+	  context = get_frame_dc (f);
+	  old_font = SelectObject (context, FONT_HANDLE(font));
+
+	  result = ScriptShape (context, &(uniscribe_font->cache),
+				chars + items[i].iCharPos, nchars_in_run,
+				max_glyphs - done_glyphs, &(items[i].a),
+				glyphs, clusters, attributes, &nglyphs);
+	}
+
       if (result == E_OUTOFMEMORY)
 	{
 	  /* Need a bigger lgstring.  */
 	  lgstring = Qnil;
 	  break;
 	}
-      else if (result) /* Failure.  */
+      else if (FAILED (result))
 	{
 	  /* Can't shape this run - return results so far if any.  */
 	  break;
@@ -298,7 +312,18 @@
 	  result = ScriptPlace (context, &(uniscribe_font->cache),
 				glyphs, nglyphs, attributes, &(items[i].a),
 				advances, offsets, &overall_metrics);
-	  if (SUCCEEDED (result))
+	  if (result == E_PENDING && !context)
+	    {
+	      /* Cache not complete...  */
+	      f = XFRAME (selected_frame);
+	      context = get_frame_dc (f);
+	      old_font = SelectObject (context, FONT_HANDLE(font));
+
+	      result = ScriptPlace (context, &(uniscribe_font->cache),
+				    glyphs, nglyphs, attributes, &(items[i].a),
+				    advances, offsets, &overall_metrics);
+	    }
+          if (SUCCEEDED (result))
 	    {
 	      int j, nclusters, from, to;
 
@@ -357,6 +382,16 @@
 		  result = ScriptGetGlyphABCWidth (context,
 						   &(uniscribe_font->cache),
 						   glyphs[j], &char_metric);
+		  if (result == E_PENDING && !context)
+		    {
+		      /* Cache incomplete... */
+		      f = XFRAME (selected_frame);
+		      context = get_frame_dc (f);
+		      old_font = SelectObject (context, FONT_HANDLE(font));
+		      result = ScriptGetGlyphABCWidth (context,
+						       &(uniscribe_font->cache),
+						       glyphs[j], &char_metric);
+		    }
 
 		  if (SUCCEEDED (result))
 		    {
@@ -382,14 +417,19 @@
 		    }
 		  else
 		    LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
-		}	    }
+		}
+	    }
 	}
       done_glyphs += nglyphs;
     }
 
   xfree (items);
-  SelectObject (context, old_font);
-  release_frame_dc (f, context);
+
+  if (context)
+    {
+      SelectObject (context, old_font);
+      release_frame_dc (f, context);
+    }
 
   if (NILP (lgstring))
     return Qnil;
@@ -405,68 +445,90 @@
      struct font *font;
      int c;
 {
-  HDC context;
-  struct frame *f;
-  HFONT old_font;
+  HDC context = NULL;
+  struct frame *f = NULL;
+  HFONT old_font = NULL;
   unsigned code = FONT_INVALID_CODE;
+  wchar_t ch[2];
+  int len;
+  SCRIPT_ITEM* items;
+  int nitems;
+  struct uniscribe_font_info *uniscribe_font
+    = (struct uniscribe_font_info *)font;
 
-  /* Use selected frame until API is updated to pass the frame.  */
-  f = XFRAME (selected_frame);
-  context = get_frame_dc (f);
-  old_font = SelectObject (context, FONT_HANDLE(font));
-
-  /* There are a number of ways to get glyph indices for BMP characters.
-     The GetGlyphIndices GDI function seems to work best for detecting
-     non-existing glyphs.  */
   if (c < 0x10000)
     {
-      wchar_t ch = (wchar_t) c;
-      WORD index;
-      DWORD retval = GetGlyphIndicesW (context, &ch, 1, &index,
-                                       GGI_MARK_NONEXISTING_GLYPHS);
-      if (retval == 1 && index != 0xFFFF)
-        code = index;
+      ch[0] = (wchar_t) c;
+      len = 1;
+    }
+  else
+    {
+      DWORD surrogate = c - 0x10000;
+
+      /* High surrogate: U+D800 - U+DBFF.  */
+      ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
+      /* Low surrogate: U+DC00 - U+DFFF.  */
+      ch[1] = 0xDC00 + (surrogate & 0x03FF);
+      len = 2;
     }
 
   /* Non BMP characters must be handled by the uniscribe shaping
      engine as GDI functions (except blindly displaying lines of
      unicode text) and the promising looking ScriptGetCMap do not
      convert surrogate pairs to glyph indexes correctly.  */
-  else
     {
-      wchar_t ch[2];
-      SCRIPT_ITEM* items;
-      int nitems;
-      struct uniscribe_font_info *uniscribe_font
-        = (struct uniscribe_font_info *)font;
-      DWORD surrogate = c - 0x10000;
-
-      /* High surrogate: U+D800 - U+DBFF.  */
-      ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
-      /* Low surrogate: U+DC00 - U+DFFF.  */
-      ch[1] = 0xDC00 + (surrogate & 0x03FF);
-
       items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
-      if (SUCCEEDED (ScriptItemize (ch, 2, 2, NULL, NULL, items, &nitems)))
-        {
-          WORD glyphs[2], clusters[2];
-          SCRIPT_VISATTR attrs[2];
+      if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
+	{
+	  HRESULT result;
+          /* Some Indic characters result in more than 1 glyph.  */
+          WORD glyphs[1], clusters[1];
+          SCRIPT_VISATTR attrs[1];
           int nglyphs;
 
-          if (SUCCEEDED (ScriptShape (context, &(uniscribe_font->cache),
-                                      ch, 2, 2, &(items[0].a),
-                                      glyphs, clusters, attrs, &nglyphs))
-              && nglyphs == 1)
+          result = ScriptShape (context, &(uniscribe_font->cache),
+                                ch, len, 20, &(items[0].a),
+                                glyphs, clusters, attrs, &nglyphs);
+
+          if (result == E_PENDING)
+            {
+              /* Use selected frame until API is updated to pass
+                 the frame.  */
+              f = XFRAME (selected_frame);
+              context = get_frame_dc (f);
+              old_font = SelectObject (context, FONT_HANDLE(font));
+              result = ScriptShape (context, &(uniscribe_font->cache),
+                                    ch, len, 2, &(items[0].a),
+                                    glyphs, clusters, attrs, &nglyphs);
+            }
+
+          if (SUCCEEDED (result) && nglyphs == 1)
             {
               code = glyphs[0];
             }
-        }
+          else if (SUCCEEDED (result) || result == E_OUTOFMEMORY)
+            {
+              /* This character produces zero or more than one glyph
+                 when shaped. But we still need the return from here
+                 to be valid for the shaping engine to be invoked
+                 later.  */
+              result = ScriptGetCMap (context, &(uniscribe_font->cache),
+                                      ch, len, 0, glyphs);
+              if (SUCCEEDED (result))
+                return glyphs[0];
+              else
+                return 0; /* notdef - enough in some cases to get the script
+                             engine working, but not others... */
+            }
+	}
     }
+    if (context)
+      {
+	SelectObject (context, old_font);
+	release_frame_dc (f, context);
+      }
 
-  SelectObject (context, old_font);
-  release_frame_dc (f, context);
-
-  return code;
+    return code;
 }
 
 /*