From: Behdad Esfahbod Date: Tue, 13 Nov 2012 20:35:35 +0000 (-0800) Subject: [Indic] Decompose Sinhala split matras the way old HarfBuzz / Pango did X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0736915b8ed789a209205fec762997af3a8af89c;p=platform%2Fupstream%2FlibHarfBuzzSharp.git [Indic] Decompose Sinhala split matras the way old HarfBuzz / Pango did Had to do some refactoring to make this happen... Under uniscribe bug compatibility mode, we still plit them Uniscrie-style, but Jonathan and I convinced ourselves that there is no harm doing this the Unicode way. This change makes that happen, and unbreaks free Sinhala fonts. --- diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc index 697e54e..cba7933 100644 --- a/src/hb-ot-shape-complex-arabic.cc +++ b/src/hb-ot-shape-complex-arabic.cc @@ -348,6 +348,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = data_destroy_arabic, NULL, /* preprocess_text_arabic */ NULL, /* normalization_preference */ + NULL, /* decompose */ + NULL, /* compose */ setup_masks_arabic, true, /* zero_width_attached_marks */ }; diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc index 60fe3fb..a948d52 100644 --- a/src/hb-ot-shape-complex-indic.cc +++ b/src/hb-ot-shape-complex-indic.cc @@ -1268,11 +1268,81 @@ final_reordering (const hb_ot_shape_plan_t *plan, static hb_ot_shape_normalization_mode_t -normalization_preference_indic (const hb_ot_shape_plan_t *plan) +normalization_preference_indic (const hb_segment_properties_t *props) { return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; } +static hb_bool_t +decompose_indic (hb_unicode_funcs_t *unicode, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b) +{ + switch (ab) + { + /* Don't decompose these. */ + case 0x0931 : return false; + case 0x0B94 : return false; + + + /* + * Decompose split matras that don't have Unicode decompositions. + */ + + case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; + case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; + case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; + case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; + case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; + case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; + case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; + case 0x1925 : *a = 0x1920; *b= 0x1923; return true; + case 0x1926 : *a = 0x1920; *b= 0x1924; return true; + case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; + case 0x1112E : *a = 0x11127; *b= 0x11131; return true; + case 0x1112F : *a = 0x11127; *b= 0x11132; return true; +#if 0 + /* This one has no decomposition in Unicode, but needs no decomposition either. */ + /* case 0x0AC9 : return false; */ + case 0x0B57 : *a = no decomp, -> RIGHT; return true; + case 0x1C29 : *a = no decomp, -> LEFT; return true; + case 0xA9C0 : *a = no decomp, -> RIGHT; return true; + case 0x111BF : *a = no decomp, -> ABOVE; return true; +#endif + } + + if (indic_options ().uniscribe_bug_compatible) + switch (ab) + { + /* These Sinhala ones have Unicode decompositions, but Uniscribe + * decomposes them "Khmer-style". */ + case 0x0DDA : *a = 0x0DD9; *b= 0x0DDA; return true; + case 0x0DDC : *a = 0x0DD9; *b= 0x0DDC; return true; + case 0x0DDD : *a = 0x0DD9; *b= 0x0DDD; return true; + case 0x0DDE : *a = 0x0DD9; *b= 0x0DDE; return true; + } + + return unicode->decompose (ab, a, b); +} + +static hb_bool_t +compose_indic (hb_unicode_funcs_t *unicode, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab) +{ + /* Avoid recomposing split matras. */ + if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (a))) + return false; + + /* Composition-exclusion exceptions that we want to recompose. */ + if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } + + return unicode->compose (a, b, ab); +} + + const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = { "indic", @@ -1282,6 +1352,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = data_destroy_indic, NULL, /* preprocess_text */ normalization_preference_indic, + decompose_indic, + compose_indic, setup_masks_indic, false, /* zero_width_attached_marks */ }; diff --git a/src/hb-ot-shape-complex-misc.cc b/src/hb-ot-shape-complex-misc.cc index 13bc22b..a65de2f 100644 --- a/src/hb-ot-shape-complex-misc.cc +++ b/src/hb-ot-shape-complex-misc.cc @@ -72,9 +72,9 @@ collect_features_default (hb_ot_shape_planner_t *plan) } static hb_ot_shape_normalization_mode_t -normalization_preference_default (const hb_ot_shape_plan_t *plan) +normalization_preference_default (const hb_segment_properties_t *props) { - switch ((hb_tag_t) plan->props.script) + switch ((hb_tag_t) props->script) { /* Unicode-1.1 additions */ case HB_SCRIPT_HANGUL: @@ -83,6 +83,131 @@ normalization_preference_default (const hb_ot_shape_plan_t *plan) return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; } +static hb_bool_t +compose_default (hb_unicode_funcs_t *unicode, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab) +{ + /* Hebrew presentation-form shaping. + * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */ + // Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA; + // note that some letters do not have a dagesh presForm encoded + static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = { + 0xFB30, // ALEF + 0xFB31, // BET + 0xFB32, // GIMEL + 0xFB33, // DALET + 0xFB34, // HE + 0xFB35, // VAV + 0xFB36, // ZAYIN + 0, // HET + 0xFB38, // TET + 0xFB39, // YOD + 0xFB3A, // FINAL KAF + 0xFB3B, // KAF + 0xFB3C, // LAMED + 0, // FINAL MEM + 0xFB3E, // MEM + 0, // FINAL NUN + 0xFB40, // NUN + 0xFB41, // SAMEKH + 0, // AYIN + 0xFB43, // FINAL PE + 0xFB44, // PE + 0, // FINAL TSADI + 0xFB46, // TSADI + 0xFB47, // QOF + 0xFB48, // RESH + 0xFB49, // SHIN + 0xFB4A // TAV + }; + + hb_bool_t found = unicode->compose (a, b, ab); + + if (!found && (b & ~0x7F) == 0x0580) { + // special-case Hebrew presentation forms that are excluded from + // standard normalization, but wanted for old fonts + switch (b) { + case 0x05B4: // HIRIQ + if (a == 0x05D9) { // YOD + *ab = 0xFB1D; + found = true; + } + break; + case 0x05B7: // patah + if (a == 0x05F2) { // YIDDISH YOD YOD + *ab = 0xFB1F; + found = true; + } else if (a == 0x05D0) { // ALEF + *ab = 0xFB2E; + found = true; + } + break; + case 0x05B8: // QAMATS + if (a == 0x05D0) { // ALEF + *ab = 0xFB2F; + found = true; + } + break; + case 0x05B9: // HOLAM + if (a == 0x05D5) { // VAV + *ab = 0xFB4B; + found = true; + } + break; + case 0x05BC: // DAGESH + if (a >= 0x05D0 && a <= 0x05EA) { + *ab = sDageshForms[a - 0x05D0]; + found = (*ab != 0); + } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT + *ab = 0xFB2C; + found = true; + } else if (a == 0xFB2B) { // SHIN WITH SIN DOT + *ab = 0xFB2D; + found = true; + } + break; + case 0x05BF: // RAFE + switch (a) { + case 0x05D1: // BET + *ab = 0xFB4C; + found = true; + break; + case 0x05DB: // KAF + *ab = 0xFB4D; + found = true; + break; + case 0x05E4: // PE + *ab = 0xFB4E; + found = true; + break; + } + break; + case 0x05C1: // SHIN DOT + if (a == 0x05E9) { // SHIN + *ab = 0xFB2A; + found = true; + } else if (a == 0xFB49) { // SHIN WITH DAGESH + *ab = 0xFB2C; + found = true; + } + break; + case 0x05C2: // SIN DOT + if (a == 0x05E9) { // SHIN + *ab = 0xFB2B; + found = true; + } else if (a == 0xFB49) { // SHIN WITH DAGESH + *ab = 0xFB2D; + found = true; + } + break; + } + } + + return found; +} + const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = { "default", @@ -92,6 +217,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = NULL, /* data_destroy */ NULL, /* preprocess_text */ normalization_preference_default, + NULL, /* decompose */ + compose_default, NULL, /* setup_masks */ true, /* zero_width_attached_marks */ }; @@ -203,6 +330,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = NULL, /* data_destroy */ preprocess_text_thai, NULL, /* normalization_preference */ + NULL, /* decompose */ + NULL, /* compose */ NULL, /* setup_masks */ true, /* zero_width_attached_marks */ }; diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh index a45b0f4..477a250 100644 --- a/src/hb-ot-shape-complex-private.hh +++ b/src/hb-ot-shape-complex-private.hh @@ -56,6 +56,7 @@ struct hb_ot_complex_shaper_t /* collect_features() * Called during shape_plan(). * Shapers should use plan->map to add their features and callbacks. + * May be NULL. */ void (*collect_features) (hb_ot_shape_planner_t *plan); @@ -63,6 +64,7 @@ struct hb_ot_complex_shaper_t * Called during shape_plan(). * Shapers should use plan->map to override features and add callbacks after * common features are added. + * May be NULL. */ void (*override_features) (hb_ot_shape_planner_t *plan); @@ -78,13 +80,15 @@ struct hb_ot_complex_shaper_t * Called when the shape_plan is being destroyed. * plan->data is passed here for destruction. * If NULL is returned, means a plan failure. - * May be NULL. */ + * May be NULL. + */ void (*data_destroy) (void *data); /* preprocess_text() * Called during shape(). * Shapers can use to modify text before shaping starts. + * May be NULL. */ void (*preprocess_text) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -93,14 +97,34 @@ struct hb_ot_complex_shaper_t /* normalization_preference() * Called during shape(). + * May be NULL. */ hb_ot_shape_normalization_mode_t - (*normalization_preference) (const hb_ot_shape_plan_t *plan); + (*normalization_preference) (const hb_segment_properties_t *props); + + /* decompose() + * Called during shape()'s normalization. + * May be NULL. + */ + hb_bool_t (*decompose) (hb_unicode_funcs_t *unicode, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b); + + /* compose() + * Called during shape()'s normalization. + * May be NULL. + */ + hb_bool_t (*compose) (hb_unicode_funcs_t *unicode, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab); /* setup_masks() * Called during shape(). * Shapers should use map to get feature masks and set on buffer. * Shapers may NOT modify characters. + * May be NULL. */ void (*setup_masks) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, diff --git a/src/hb-ot-shape-normalize-private.hh b/src/hb-ot-shape-normalize-private.hh index c5fcbea..4b77699 100644 --- a/src/hb-ot-shape-normalize-private.hh +++ b/src/hb-ot-shape-normalize-private.hh @@ -35,6 +35,8 @@ /* buffer var allocations, used during the normalization process */ #define glyph_index() var1.u32 +struct hb_ot_complex_shaper_t; + enum hb_ot_shape_normalization_mode_t { HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED, HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */ @@ -44,8 +46,8 @@ enum hb_ot_shape_normalization_mode_t { HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS }; -HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font, +HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_complex_shaper_t *shaper, hb_buffer_t *buffer, - hb_ot_shape_normalization_mode_t mode); + hb_font_t *font); #endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */ diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc index 18a3f3f..df15f7d 100644 --- a/src/hb-ot-shape-normalize.cc +++ b/src/hb-ot-shape-normalize.cc @@ -25,6 +25,7 @@ */ #include "hb-ot-shape-normalize-private.hh" +#include "hb-ot-shape-complex-private.hh" #include "hb-ot-shape-private.hh" @@ -82,180 +83,23 @@ */ static hb_bool_t -decompose_func (hb_unicode_funcs_t *unicode, - hb_codepoint_t ab, - hb_codepoint_t *a, - hb_codepoint_t *b) +decompose_unicode (hb_unicode_funcs_t *unicode, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b) { - /* XXX FIXME, move these to complex shapers and propagage to normalizer.*/ - switch (ab) { - case 0x0AC9 : return false; - - case 0x0931 : return false; - case 0x0B94 : return false; - - /* These ones have Unicode decompositions, but we do it - * this way to be close to what Uniscribe does. */ - case 0x0DDA : *a = 0x0DD9; *b= 0x0DDA; return true; - case 0x0DDC : *a = 0x0DD9; *b= 0x0DDC; return true; - case 0x0DDD : *a = 0x0DD9; *b= 0x0DDD; return true; - case 0x0DDE : *a = 0x0DD9; *b= 0x0DDE; return true; - - case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; - case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; - case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; - case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; - case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; - case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; - case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; - case 0x1925 : *a = 0x1920; *b= 0x1923; return true; - case 0x1926 : *a = 0x1920; *b= 0x1924; return true; - case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; - case 0x1112E : *a = 0x11127; *b= 0x11131; return true; - case 0x1112F : *a = 0x11127; *b= 0x11132; return true; -#if 0 - case 0x0B57 : *a = 0xno decomp, -> RIGHT; return true; - case 0x1C29 : *a = 0xno decomp, -> LEFT; return true; - case 0xA9C0 : *a = 0xno decomp, -> RIGHT; return true; - case 0x111BF : *a = 0xno decomp, -> ABOVE; return true; -#endif - } return unicode->decompose (ab, a, b); } static hb_bool_t -compose_func (hb_unicode_funcs_t *unicode, - hb_codepoint_t a, - hb_codepoint_t b, - hb_codepoint_t *ab) +compose_unicode (hb_unicode_funcs_t *unicode, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab) { - /* XXX, this belongs to indic normalizer. */ - if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (a))) - return false; - /* XXX, add composition-exclusion exceptions to Indic shaper. */ - if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } - - /* XXX, these belong to the hebew / default shaper. */ - /* Hebrew presentation-form shaping. - * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */ - // Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA; - // note that some letters do not have a dagesh presForm encoded - static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = { - 0xFB30, // ALEF - 0xFB31, // BET - 0xFB32, // GIMEL - 0xFB33, // DALET - 0xFB34, // HE - 0xFB35, // VAV - 0xFB36, // ZAYIN - 0, // HET - 0xFB38, // TET - 0xFB39, // YOD - 0xFB3A, // FINAL KAF - 0xFB3B, // KAF - 0xFB3C, // LAMED - 0, // FINAL MEM - 0xFB3E, // MEM - 0, // FINAL NUN - 0xFB40, // NUN - 0xFB41, // SAMEKH - 0, // AYIN - 0xFB43, // FINAL PE - 0xFB44, // PE - 0, // FINAL TSADI - 0xFB46, // TSADI - 0xFB47, // QOF - 0xFB48, // RESH - 0xFB49, // SHIN - 0xFB4A // TAV - }; - - hb_bool_t found = unicode->compose (a, b, ab); - - if (!found && (b & ~0x7F) == 0x0580) { - // special-case Hebrew presentation forms that are excluded from - // standard normalization, but wanted for old fonts - switch (b) { - case 0x05B4: // HIRIQ - if (a == 0x05D9) { // YOD - *ab = 0xFB1D; - found = true; - } - break; - case 0x05B7: // patah - if (a == 0x05F2) { // YIDDISH YOD YOD - *ab = 0xFB1F; - found = true; - } else if (a == 0x05D0) { // ALEF - *ab = 0xFB2E; - found = true; - } - break; - case 0x05B8: // QAMATS - if (a == 0x05D0) { // ALEF - *ab = 0xFB2F; - found = true; - } - break; - case 0x05B9: // HOLAM - if (a == 0x05D5) { // VAV - *ab = 0xFB4B; - found = true; - } - break; - case 0x05BC: // DAGESH - if (a >= 0x05D0 && a <= 0x05EA) { - *ab = sDageshForms[a - 0x05D0]; - found = (*ab != 0); - } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT - *ab = 0xFB2C; - found = true; - } else if (a == 0xFB2B) { // SHIN WITH SIN DOT - *ab = 0xFB2D; - found = true; - } - break; - case 0x05BF: // RAFE - switch (a) { - case 0x05D1: // BET - *ab = 0xFB4C; - found = true; - break; - case 0x05DB: // KAF - *ab = 0xFB4D; - found = true; - break; - case 0x05E4: // PE - *ab = 0xFB4E; - found = true; - break; - } - break; - case 0x05C1: // SHIN DOT - if (a == 0x05E9) { // SHIN - *ab = 0xFB2A; - found = true; - } else if (a == 0xFB49) { // SHIN WITH DAGESH - *ab = 0xFB2C; - found = true; - } - break; - case 0x05C2: // SIN DOT - if (a == 0x05E9) { // SHIN - *ab = 0xFB2B; - found = true; - } else if (a == 0xFB49) { // SHIN WITH DAGESH - *ab = 0xFB2D; - found = true; - } - break; - } - } - - return found; + return unicode->compose (a, b, ab); } - static inline void set_glyph (hb_glyph_info_t &info, hb_font_t *font) { @@ -283,40 +127,54 @@ skip_char (hb_buffer_t *buffer) buffer->skip_glyph (); } +struct normalize_context_t +{ + hb_buffer_t *buffer; + hb_font_t *font; + hb_bool_t (*decompose) (hb_unicode_funcs_t *unicode, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b); + hb_bool_t (*compose) (hb_unicode_funcs_t *unicode, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab); +}; + /* Returns 0 if didn't decompose, number of resulting characters otherwise. */ static inline unsigned int -decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t ab) +decompose (const normalize_context_t *c, bool shortest, hb_codepoint_t ab) { hb_codepoint_t a, b, a_glyph, b_glyph; - if (!decompose_func (buffer->unicode, ab, &a, &b) || - (b && !font->get_glyph (b, 0, &b_glyph))) + if (!c->decompose (c->buffer->unicode, ab, &a, &b) || + (b && !c->font->get_glyph (b, 0, &b_glyph))) return 0; - bool has_a = font->get_glyph (a, 0, &a_glyph); + bool has_a = c->font->get_glyph (a, 0, &a_glyph); if (shortest && has_a) { /* Output a and b */ - output_char (buffer, a, a_glyph); + output_char (c->buffer, a, a_glyph); if (likely (b)) { - output_char (buffer, b, b_glyph); + output_char (c->buffer, b, b_glyph); return 2; } return 1; } unsigned int ret; - if ((ret = decompose (font, buffer, shortest, a))) { + if ((ret = decompose (c, shortest, a))) { if (b) { - output_char (buffer, b, b_glyph); + output_char (c->buffer, b, b_glyph); return ret + 1; } return ret; } if (has_a) { - output_char (buffer, a, a_glyph); + output_char (c->buffer, a, a_glyph); if (likely (b)) { - output_char (buffer, b, b_glyph); + output_char (c->buffer, b, b_glyph); return 2; } return 1; @@ -327,41 +185,42 @@ decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t a /* Returns 0 if didn't decompose, number of resulting characters otherwise. */ static inline bool -decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer, hb_codepoint_t u) +decompose_compatibility (const normalize_context_t *c, hb_codepoint_t u) { unsigned int len, i; hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN]; hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN]; - len = buffer->unicode->decompose_compatibility (u, decomposed); + len = c->buffer->unicode->decompose_compatibility (u, decomposed); if (!len) return 0; for (i = 0; i < len; i++) - if (!font->get_glyph (decomposed[i], 0, &glyphs[i])) + if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i])) return 0; for (i = 0; i < len; i++) - output_char (buffer, decomposed[i], glyphs[i]); + output_char (c->buffer, decomposed[i], glyphs[i]); return len; } /* Returns true if recomposition may be benefitial. */ static inline bool -decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest) +decompose_current_character (const normalize_context_t *c, bool shortest) { + hb_buffer_t * const buffer = c->buffer; hb_codepoint_t glyph; unsigned int len = 1; /* Kind of a cute waterfall here... */ - if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) + if (shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph)) next_char (buffer, glyph); - else if ((len = decompose (font, buffer, shortest, buffer->cur().codepoint))) + else if ((len = decompose (c, shortest, buffer->cur().codepoint))) skip_char (buffer); - else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) + else if (!shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph)) next_char (buffer, glyph); - else if ((len = decompose_compatibility (font, buffer, buffer->cur().codepoint))) + else if ((len = decompose_compatibility (c, buffer->cur().codepoint))) skip_char (buffer); else next_char (buffer, glyph); /* glyph is initialized in earlier branches. */ @@ -374,49 +233,51 @@ decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest } static inline void -handle_variation_selector_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end) +handle_variation_selector_cluster (const normalize_context_t *c, unsigned int end) { + hb_buffer_t * const buffer = c->buffer; for (; buffer->idx < end - 1;) { if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) { /* The next two lines are some ugly lines... But work. */ - font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()); + c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()); buffer->replace_glyphs (2, 1, &buffer->cur().codepoint); } else { - set_glyph (buffer->cur(), font); + set_glyph (buffer->cur(), c->font); buffer->next_glyph (); } } if (likely (buffer->idx < end)) { - set_glyph (buffer->cur(), font); + set_glyph (buffer->cur(), c->font); buffer->next_glyph (); } } /* Returns true if recomposition may be benefitial. */ static inline bool -decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end) +decompose_multi_char_cluster (const normalize_context_t *c, unsigned int end) { + hb_buffer_t * const buffer = c->buffer; /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ for (unsigned int i = buffer->idx; i < end; i++) if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) { - handle_variation_selector_cluster (font, buffer, end); + handle_variation_selector_cluster (c, end); return false; } while (buffer->idx < end) - decompose_current_character (font, buffer, false); + decompose_current_character (c, false); /* We can be smarter here and only return true if there are at least two ccc!=0 marks. * But does not matter. */ return true; } static inline bool -decompose_cluster (hb_font_t *font, hb_buffer_t *buffer, bool short_circuit, unsigned int end) +decompose_cluster (const normalize_context_t *c, bool short_circuit, unsigned int end) { - if (likely (buffer->idx + 1 == end)) - return decompose_current_character (font, buffer, short_circuit); + if (likely (c->buffer->idx + 1 == end)) + return decompose_current_character (c, short_circuit); else - return decompose_multi_char_cluster (font, buffer, end); + return decompose_multi_char_cluster (c, end); } @@ -431,9 +292,20 @@ compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) void -_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, - hb_ot_shape_normalization_mode_t mode) +_hb_ot_shape_normalize (const hb_ot_complex_shaper_t *shaper, + hb_buffer_t *buffer, + hb_font_t *font) { + hb_ot_shape_normalization_mode_t mode = shaper->normalization_preference ? + shaper->normalization_preference (&buffer->props) : + HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT; + const normalize_context_t c = { + buffer, + font, + shaper->decompose ? shaper->decompose : decompose_unicode, + shaper->compose ? shaper->compose : compose_unicode + }; + bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED && mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; bool can_use_recompose = false; @@ -457,7 +329,7 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, if (buffer->cur().cluster != buffer->info[end].cluster) break; - can_use_recompose = decompose_cluster (font, buffer, short_circuit, end) || can_use_recompose; + can_use_recompose = decompose_cluster (&c, short_circuit, end) || can_use_recompose; } buffer->swap_buffers (); @@ -517,10 +389,10 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, (starter == buffer->out_len - 1 || _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) && /* And compose. */ - compose_func (buffer->unicode, - buffer->out_info[starter].codepoint, - buffer->cur().codepoint, - &composed) && + c.compose (buffer->unicode, + buffer->out_info[starter].codepoint, + buffer->cur().codepoint, + &composed) && /* And the font has glyph for the composite. */ font->get_glyph (composed, 0, &glyph)) { diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index d168ae7..26ec4db 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -362,10 +362,7 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c) HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index); - _hb_ot_shape_normalize (c->font, c->buffer, - c->plan->shaper->normalization_preference ? - c->plan->shaper->normalization_preference (c->plan) : - HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT); + _hb_ot_shape_normalize (c->plan->shaper, c->buffer, c->font); hb_ot_shape_setup_masks (c);