Bug 664125 - Zero-width spaces cause missing characters
authorKristian Rietveld <kris@lanedo.com>
Sat, 26 Nov 2011 16:27:43 +0000 (17:27 +0100)
committerKristian Rietveld <kris@lanedo.com>
Thu, 19 Jan 2012 16:20:23 +0000 (17:20 +0100)
This is fixed by using the characters obtained from CoreText's mapping from
glyphs back to the original string instead of blindly iterating over the
original gchar string. Take notice that we have to convert these indices
from the mapping back to a byte index in the original UTF8 string.

Zero-width spaces are already removed from the list of CGGlyphs, so we were
mismatching CGGlyphs and characters from the original string. Using
CoreText's list of string indices instead eliminates the mismatches.

modules/basic/basic-coretext.c

index 8dc3dba..991743e 100644 (file)
@@ -76,7 +76,6 @@ basic_engine_shape (PangoEngineShape    *engine,
                    const PangoAnalysis *analysis,
                    PangoGlyphString    *glyphs)
 {
-  const char *p;
   char *copy;
   CTLineRef line;
   CFStringRef cstr;
@@ -88,6 +87,7 @@ basic_engine_shape (PangoEngineShape    *engine,
   CTRunRef run;
   CTRunStatus run_status;
   CFIndex i, glyph_count;
+  CFIndex *indices = NULL;
   const CGGlyph *cgglyphs;
 
   CFTypeRef keys[] = {
@@ -128,7 +128,9 @@ basic_engine_shape (PangoEngineShape    *engine,
   glyph_count = CTRunGetGlyphCount (run);
   cgglyphs = CTRunGetGlyphsPtr (run);
 
-  p = text;
+  indices = malloc (sizeof (CFIndex *) * glyph_count);
+  CTRunGetStringIndices (run, CFRangeMake (0, glyph_count), indices);
+
   pango_glyph_string_set_size (glyphs, glyph_count);
   coverage = pango_font_get_coverage (PANGO_FONT (cfont),
                                       analysis->language);
@@ -138,12 +140,7 @@ basic_engine_shape (PangoEngineShape    *engine,
       CFIndex real_i, prev_i;
       gunichar wc;
       gunichar mirrored_ch;
-
-      wc = g_utf8_get_char (p);
-
-      if (analysis->level % 2)
-       if (pango_get_mirror_char (wc, &mirrored_ch))
-         wc = mirrored_ch;
+      PangoCoverageLevel result;
 
       if (run_status & kCTRunStatusRightToLeft)
         {
@@ -156,53 +153,50 @@ basic_engine_shape (PangoEngineShape    *engine,
           prev_i = real_i - 1;
         }
 
+      wc = CFStringGetCharacterAtIndex (cstr, indices[real_i]);
+
+      if (analysis->level % 2)
+       if (pango_get_mirror_char (wc, &mirrored_ch))
+         wc = mirrored_ch;
+
       if (wc == 0xa0)  /* non-break-space */
        wc = 0x20;
 
-      if (pango_is_zero_width (wc))
-       {
-         set_glyph (font, glyphs, real_i, p - text, PANGO_GLYPH_EMPTY);
-       }
-      else
-       {
-          PangoCoverageLevel result;
+      result = pango_coverage_get (coverage, wc);
 
-          result = pango_coverage_get (coverage, wc);
+      if (result != PANGO_COVERAGE_NONE)
+        {
+          set_glyph (font, glyphs, real_i,
+                     g_utf8_offset_to_pointer (text, indices[real_i]) - text,
+                     cgglyphs[real_i]);
 
-          if (result != PANGO_COVERAGE_NONE)
+          if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK)
             {
-              set_glyph (font, glyphs, real_i, p - text, cgglyphs[real_i]);
-
-              if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK)
+              if (i > 0)
                 {
-                  if (i > 0)
-                    {
-                      PangoRectangle logical_rect, ink_rect;
-
-                      glyphs->glyphs[real_i].geometry.width = MAX (glyphs->glyphs[prev_i].geometry.width,
-                                                                   glyphs->glyphs[prev_i].geometry.width);
-                      glyphs->glyphs[prev_i].geometry.width = 0;
-                      glyphs->log_clusters[real_i] = glyphs->log_clusters[prev_i];
-
-                      /* Some heuristics to try to guess how overstrike glyphs are
-                       * done and compensate
-                       */
-                      pango_font_get_glyph_extents (font, glyphs->glyphs[real_i].glyph, &ink_rect, &logical_rect);
-                      if (logical_rect.width == 0 && ink_rect.x == 0)
-                        glyphs->glyphs[real_i].geometry.x_offset = (glyphs->glyphs[real_i].geometry.width - ink_rect.width) / 2;
-                    }
+                  PangoRectangle logical_rect, ink_rect;
+
+                  glyphs->glyphs[real_i].geometry.width = MAX (glyphs->glyphs[prev_i].geometry.width,
+                                                               glyphs->glyphs[real_i].geometry.width);
+                  glyphs->glyphs[prev_i].geometry.width = 0;
+                  glyphs->log_clusters[real_i] = glyphs->log_clusters[prev_i];
+
+                  /* Some heuristics to try to guess how overstrike glyphs are
+                   * done and compensate
+                   */
+                  pango_font_get_glyph_extents (font, glyphs->glyphs[real_i].glyph, &ink_rect, &logical_rect);
+                  if (logical_rect.width == 0 && ink_rect.x == 0)
+                    glyphs->glyphs[real_i].geometry.x_offset = (glyphs->glyphs[real_i].geometry.width - ink_rect.width) / 2;
                 }
             }
-          else
-            {
-              set_glyph (font, glyphs, real_i, p - text,
-                         PANGO_GET_UNKNOWN_GLYPH (wc));
-            }
         }
-
-      p = g_utf8_next_char (p);
+      else
+        set_glyph (font, glyphs, real_i,
+                   g_utf8_offset_to_pointer (text, indices[real_i]) - text,
+                   PANGO_GET_UNKNOWN_GLYPH (wc));
     }
 
+  free (indices);
   CFRelease (line);
   CFRelease (attstr);
   CFRelease (cstr);