diff options
author | Behdad Esfahbod <behdad@behdad.org> | 2009-11-17 16:20:42 -0500 |
---|---|---|
committer | Behdad Esfahbod <behdad@behdad.org> | 2009-11-17 16:21:11 -0500 |
commit | 4ccabeffc20f899163bf610356871afb197e9bf8 (patch) | |
tree | 629478f89f68fc763f55cbc53bd8d1d25160c610 | |
parent | 718c533d28cb760e45c7b874420b14003445a9c1 (diff) | |
download | pango-4ccabeffc20f899163bf610356871afb197e9bf8.tar.gz |
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.
-rw-r--r-- | modules/indic/indic-fc.c | 1 | ||||
-rw-r--r-- | modules/khmer/khmer-fc.c | 1 | ||||
-rw-r--r-- | modules/thai/thai-fc.c | 1 | ||||
-rw-r--r-- | modules/tibetan/tibetan-fc.c | 1 | ||||
-rw-r--r-- | pango/glyphstring.c | 2 | ||||
-rw-r--r-- | pango/pango-engine.c | 3 | ||||
-rw-r--r-- | pango/pango-impl-utils.h | 26 | ||||
-rw-r--r-- | pango/pango-ot-buffer.c | 23 | ||||
-rw-r--r-- | 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 6ba90c1a..3a232be4 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 04c5c830..14357d78 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 66dccbb4..837a0286 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 51600fc8..4e894165 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 923a9360..0382eb6e 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 974e2d5a..50ba7f40 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 3ef3a0c4..6d6c8ff2 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 a4aacc3a..533c3102 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 0dd56a8e..1513b028 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); + } } |