diff options
-rw-r--r-- | pango/pango-bidi-type.c | 69 |
1 files changed, 64 insertions, 5 deletions
diff --git a/pango/pango-bidi-type.c b/pango/pango-bidi-type.c index 55d44e98..9e2d4a9f 100644 --- a/pango/pango-bidi-type.c +++ b/pango/pango-bidi-type.c @@ -137,6 +137,8 @@ pango_log2vis_get_embedding_levels (const gchar *text, FriBidiBracketType *bracket_types; #endif FriBidiLevel max_level; + FriBidiCharType ored_types = 0; + FriBidiCharType anded_strongs = FRIBIDI_TYPE_RLE; G_STATIC_ASSERT (sizeof (FriBidiLevel) == sizeof (guint8)); G_STATIC_ASSERT (sizeof (FriBidiChar) == sizeof (gunichar)); @@ -175,7 +177,12 @@ pango_log2vis_get_embedding_levels (const gchar *text, for (i = 0, p = text; p < text + length; p = g_utf8_next_char(p), i++) { gunichar ch = g_utf8_get_char (p); - bidi_types[i] = fribidi_get_bidi_type (ch); + FriBidiCharType char_type; + char_type = fribidi_get_bidi_type (ch); + bidi_types[i] = char_type; + ored_types |= char_type; + if (FRIBIDI_IS_STRONG (char_type)) + anded_strongs &= char_type; #ifdef USE_FRIBIDI_EX_API if (G_UNLIKELY(bidi_types[i] == FRIBIDI_TYPE_ON)) bracket_types[i] = fribidi_get_bracket (ch); @@ -184,6 +191,58 @@ pango_log2vis_get_embedding_levels (const gchar *text, #endif } + /* Short-circuit (malloc-expensive) FriBidi call for unidirectional + * text. + * + * For details see: + * https://bugzilla.gnome.org/show_bug.cgi?id=590183 + */ + +#ifndef FRIBIDI_IS_ISOLATE +#define FRIBIDI_IS_ISOLATE(x) 0 +#endif + /* The case that all resolved levels will be ltr. + * No isolates, all strongs be LTR, there should be no Arabic numbers + * (or letters for that matter), and one of the following: + * + * o base_dir doesn't have an RTL taste. + * o there are letters, and base_dir is weak. + */ + if (!FRIBIDI_IS_ISOLATE (ored_types) && + !FRIBIDI_IS_RTL (ored_types) && + !FRIBIDI_IS_ARABIC (ored_types) && + (!FRIBIDI_IS_RTL (fribidi_base_dir) || + (FRIBIDI_IS_WEAK (fribidi_base_dir) && + FRIBIDI_IS_LETTER (ored_types)) + )) + { + /* all LTR */ + fribidi_base_dir = FRIBIDI_PAR_LTR; + memset (embedding_levels_list, 0, n_chars); + goto resolved; + } + /* The case that all resolved levels will be RTL is much more complex. + * No isolates, no numbers, all strongs are RTL, and one of + * the following: + * + * o base_dir has an RTL taste (may be weak). + * o there are letters, and base_dir is weak. + */ + else if (!FRIBIDI_IS_ISOLATE (ored_types) && + !FRIBIDI_IS_NUMBER (ored_types) && + FRIBIDI_IS_RTL (anded_strongs) && + (FRIBIDI_IS_RTL (fribidi_base_dir) || + (FRIBIDI_IS_WEAK (fribidi_base_dir) && + FRIBIDI_IS_LETTER (ored_types)) + )) + { + /* all RTL */ + fribidi_base_dir = FRIBIDI_PAR_RTL; + memset (embedding_levels_list, 1, n_chars); + goto resolved; + } + + #ifdef USE_FRIBIDI_EX_API max_level = fribidi_get_par_embedding_levels_ex (bidi_types, bracket_types, n_chars, &fribidi_base_dir, @@ -195,15 +254,15 @@ pango_log2vis_get_embedding_levels (const gchar *text, (FriBidiLevel*)embedding_levels_list); #endif - g_free (bidi_types); - if (G_UNLIKELY(max_level == 0)) { - /* fribidi_get_par_embedding_levels() failed, - * is this the best thing to do? */ + /* fribidi_get_par_embedding_levels() failed. */ memset (embedding_levels_list, 0, length); } +resolved: + g_free (bidi_types); + *pbase_dir = (fribidi_base_dir == FRIBIDI_PAR_LTR) ? PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL; return embedding_levels_list; |