[pango] Bug 596614 - Pango application receives SIGSEGV on pasting text with U+202E



commit 4ccabeffc20f899163bf610356871afb197e9bf8
Author: Behdad Esfahbod <behdad behdad org>
Date:   Tue Nov 17 16:20:42 2009 -0500

    Bug 596614 - Pango application receives SIGSEGV on pasting text with U+202E
    
    Fixed all modules to reverse glyphs if run is rtl.  Except for Hangul module.
    Fixed pango_shape() to detect that, warn, and reverse.

 modules/indic/indic-fc.c     |    1 +
 modules/khmer/khmer-fc.c     |    1 +
 modules/thai/thai-fc.c       |    1 +
 modules/tibetan/tibetan-fc.c |    1 +
 pango/glyphstring.c          |    2 --
 pango/pango-engine.c         |    3 +++
 pango/pango-impl-utils.h     |   26 +++++++++++++++++++++++++-
 pango/pango-ot-buffer.c      |   23 ++---------------------
 pango/shape.c                |   34 +++++++++++++++++++++++++++++++---
 9 files changed, 65 insertions(+), 27 deletions(-)
---
diff --git a/modules/indic/indic-fc.c b/modules/indic/indic-fc.c
index 6ba90c1..3a232be 100644
--- a/modules/indic/indic-fc.c
+++ b/modules/indic/indic-fc.c
@@ -252,6 +252,7 @@ indic_engine_shape (PangoEngineShape *engine,
 
   pango_glyph_string_set_size (glyphs, n_glyphs);
   buffer = pango_ot_buffer_new (fc_font);
+  pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
 
   set_glyphs(font, wc_out, tags, n_glyphs, buffer,
 	     (indic_shape_engine->classTable->scriptFlags & SF_PROCESS_ZWJ) != 0);
diff --git a/modules/khmer/khmer-fc.c b/modules/khmer/khmer-fc.c
index 04c5c83..14357d7 100644
--- a/modules/khmer/khmer-fc.c
+++ b/modules/khmer/khmer-fc.c
@@ -481,6 +481,7 @@ khmer_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
     return;
 
   buffer = pango_ot_buffer_new (fc_font);
+  pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
 
   wcs = g_utf8_to_ucs4_fast (text, length, &n_chars);
 
diff --git a/modules/thai/thai-fc.c b/modules/thai/thai-fc.c
index 66dccbb..837a028 100644
--- a/modules/thai/thai-fc.c
+++ b/modules/thai/thai-fc.c
@@ -298,6 +298,7 @@ thai_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
   thai_set_glyphs (font_info, text, length, analysis->script, glyphs); 
 
   buffer = pango_ot_buffer_new (PANGO_FC_FONT (font));
+  pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
 
   for (i = 0; i < glyphs->num_glyphs; i++)
     pango_ot_buffer_add_glyph (buffer,
diff --git a/modules/tibetan/tibetan-fc.c b/modules/tibetan/tibetan-fc.c
index 51600fc..4e89416 100644
--- a/modules/tibetan/tibetan-fc.c
+++ b/modules/tibetan/tibetan-fc.c
@@ -443,6 +443,7 @@ tibetan_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
     return;
 
   buffer = pango_ot_buffer_new (fc_font);
+  pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
 
   wcs = g_utf8_to_ucs4_fast (text, length, &n_chars);
 
diff --git a/pango/glyphstring.c b/pango/glyphstring.c
index 923a936..0382eb6 100644
--- a/pango/glyphstring.c
+++ b/pango/glyphstring.c
@@ -659,5 +659,3 @@ pango_glyph_string_x_to_index (PangoGlyphString *glyphs,
 	}
     }
 }
-
-
diff --git a/pango/pango-engine.c b/pango/pango-engine.c
index 974e2d5..50ba7f4 100644
--- a/pango/pango-engine.c
+++ b/pango/pango-engine.c
@@ -140,6 +140,9 @@ fallback_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
 
       p = g_utf8_next_char (p);
     }
+
+  if (analysis->level & 1)
+    pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs);
 }
 
 static PangoCoverageLevel
diff --git a/pango/pango-impl-utils.h b/pango/pango-impl-utils.h
index 3ef3a0c..6d6c8ff 100644
--- a/pango/pango-impl-utils.h
+++ b/pango/pango-impl-utils.h
@@ -150,7 +150,31 @@ pango_utf8_strlen (const gchar *p, gssize max)
   return len;
 }
 
+
+/* To be made public at some point */
+
+static G_GNUC_UNUSED void
+pango_glyph_string_reverse_range (PangoGlyphString *glyphs,
+				  int start, int end)
+{
+  int i, j;
+
+  for (i = start, j = end - 1; i < j; i++, j--)
+    {
+      PangoGlyphInfo glyph_info;
+      gint log_cluster;
+
+      glyph_info = glyphs->glyphs[i];
+      glyphs->glyphs[i] = glyphs->glyphs[j];
+      glyphs->glyphs[j] = glyph_info;
+
+      log_cluster = glyphs->log_clusters[i];
+      glyphs->log_clusters[i] = glyphs->log_clusters[j];
+      glyphs->log_clusters[j] = log_cluster;
+    }
+}
+
+
 G_END_DECLS
 
 #endif /* __PANGO_IMPL_UTILS_H__ */
-
diff --git a/pango/pango-ot-buffer.c b/pango/pango-ot-buffer.c
index a4aacc3..533c310 100644
--- a/pango/pango-ot-buffer.c
+++ b/pango/pango-ot-buffer.c
@@ -23,6 +23,7 @@
 
 #include "pango-ot-private.h"
 #include "pangofc-private.h"
+#include "pango-impl-utils.h"
 
 /* cache a single hb_buffer_t */
 static hb_buffer_t *cached_buffer = NULL;
@@ -204,26 +205,6 @@ pango_ot_buffer_get_glyphs (const PangoOTBuffer  *buffer,
 }
 
 static void
-swap_range (PangoGlyphString *glyphs, int start, int end)
-{
-  int i, j;
-
-  for (i = start, j = end - 1; i < j; i++, j--)
-    {
-      PangoGlyphInfo glyph_info;
-      gint log_cluster;
-
-      glyph_info = glyphs->glyphs[i];
-      glyphs->glyphs[i] = glyphs->glyphs[j];
-      glyphs->glyphs[j] = glyph_info;
-
-      log_cluster = glyphs->log_clusters[i];
-      glyphs->log_clusters[i] = glyphs->log_clusters[j];
-      glyphs->log_clusters[j] = log_cluster;
-    }
-}
-
-static void
 apply_gpos_ltr (PangoGlyphString    *glyphs,
 		hb_glyph_position_t *positions,
 		gboolean             is_hinted)
@@ -389,7 +370,7 @@ pango_ot_buffer_output (const PangoOTBuffer *buffer,
   if (buffer->rtl)
     {
       /* Swap all glyphs */
-      swap_range (glyphs, 0, glyphs->num_glyphs);
+      pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs);
     }
 
   positions = hb_buffer_get_glyph_positions (buffer->buffer);
diff --git a/pango/shape.c b/pango/shape.c
index 0dd56a8..1513b02 100644
--- a/pango/shape.c
+++ b/pango/shape.c
@@ -108,20 +108,21 @@ pango_shape (const gchar      *text,
   else
     glyphs->num_glyphs = 0;
 
-  if (!glyphs->num_glyphs)
+  if (G_UNLIKELY (!glyphs->num_glyphs))
     {
       PangoEngineShape *fallback_engine = _pango_get_fallback_shaper ();
 
       _pango_engine_shape_shape (fallback_engine, analysis->font,
 				 text, length, analysis, glyphs);
+      if (G_UNLIKELY (!glyphs->num_glyphs))
+        return;
     }
 
   /* make sure last_cluster is invalid */
   last_cluster = glyphs->log_clusters[0] - 1;
   for (i = 0; i < glyphs->num_glyphs; i++)
     {
-     /* Set glyphs[i].attr.is_cluster_start based on log_clusters[]
-      */
+      /* Set glyphs[i].attr.is_cluster_start based on log_clusters[] */
       if (glyphs->log_clusters[i] != last_cluster)
 	{
 	  glyphs->glyphs[i].attr.is_cluster_start = TRUE;
@@ -141,4 +142,31 @@ pango_shape (const gchar      *text,
 	  glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width;
 	}
     }
+
+  /* Make sure glyphstring direction conforms to analysis->level */
+  if (G_UNLIKELY ((analysis->level & 1) &&
+		  glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1]))
+    {
+      /* Warn once per shaper */
+      static GQuark warned_quark = 0;
+
+      if (!warned_quark)
+	warned_quark = g_quark_from_static_string ("pango-shape-warned");
+
+      if (analysis->shape_engine && !g_object_get_qdata (G_OBJECT (analysis->shape_engine), warned_quark))
+	{
+	  GType engine_type = G_OBJECT_TYPE (analysis->shape_engine);
+	  const char *engine_name = g_type_name (engine_type);
+	  if (!engine_name)
+	    engine_name = "(unknown)";
+
+	  g_warning ("Expected RTL run but shape-engine='%s' returned LTR. Fixing.", engine_name);
+
+	  g_object_set_qdata_full (G_OBJECT (analysis->shape_engine), warned_quark,
+				   GINT_TO_POINTER (1), NULL);
+	}
+
+      /* *Fix* it so we don't crash later */
+      pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs);
+    }
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]