[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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
/* 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 @@
* 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 @@
* 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 @@
/* 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 @@
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 @@
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 @@
/* 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 @@
}
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 @@
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 @@
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 @@
(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_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);