Index: third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh |
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh |
index 2d8488e1513956119064f483ef4223d96b275005..e5b7ed489c053179312434c03a71c080727186b9 100644 |
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh |
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh |
@@ -33,6 +33,8 @@ |
#include "hb-ot-layout-gsub-table.hh" |
+/* Features ordered the same as the entries in shaping_table rows, |
+ * followed by rlig. Don't change. */ |
static const hb_tag_t arabic_fallback_features[] = |
{ |
HB_TAG('i','n','i','t'), |
@@ -42,16 +44,6 @@ static const hb_tag_t arabic_fallback_features[] = |
HB_TAG('r','l','i','g'), |
}; |
-/* Same order as the fallback feature array */ |
-enum { |
- FALLBACK_INIT, |
- FALLBACK_MEDI, |
- FALLBACK_FINA, |
- FALLBACK_ISOL, |
- FALLBACK_RLIG, |
- ARABIC_NUM_FALLBACK_FEATURES |
-}; |
- |
static OT::SubstLookup * |
arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED, |
hb_font_t *font, |
@@ -80,6 +72,9 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS |
num_glyphs++; |
} |
+ if (!num_glyphs) |
+ return NULL; |
+ |
/* Bubble-sort! |
* May not be good-enough for presidential candidate interviews, but good-enough for us... */ |
hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]); |
@@ -157,6 +152,9 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN |
} |
} |
+ if (!num_ligatures) |
+ return NULL; |
+ |
OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs); |
OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs); |
OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures); |
@@ -193,17 +191,108 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan, |
return arabic_fallback_synthesize_lookup_ligature (plan, font); |
} |
+#define ARABIC_FALLBACK_MAX_LOOKUPS 5 |
+ |
struct arabic_fallback_plan_t |
{ |
ASSERT_POD (); |
- hb_mask_t mask_array[ARABIC_NUM_FALLBACK_FEATURES]; |
- OT::SubstLookup *lookup_array[ARABIC_NUM_FALLBACK_FEATURES]; |
- hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_NUM_FALLBACK_FEATURES]; |
+ unsigned int num_lookups; |
+ bool free_lookups; |
+ |
+ hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS]; |
+ OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS]; |
+ hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; |
}; |
static const arabic_fallback_plan_t arabic_fallback_plan_nil = {}; |
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_WITH_WIN1256) |
+#define HB_WITH_WIN1256 |
+#endif |
+ |
+#ifdef HB_WITH_WIN1256 |
+#include "hb-ot-shape-complex-arabic-win1256.hh" |
+#endif |
+ |
+struct ManifestLookup { |
+ OT::Tag tag; |
+ OT::OffsetTo<OT::SubstLookup> lookupOffset; |
+}; |
+typedef OT::ArrayOf<ManifestLookup> Manifest; |
+ |
+static bool |
+arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan, |
+ const hb_ot_shape_plan_t *plan, |
+ hb_font_t *font) |
+{ |
+#ifdef HB_WITH_WIN1256 |
+ /* Does this font look like it's Windows-1256-encoded? */ |
+ hb_codepoint_t g; |
+ if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ && |
+ hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ && |
+ hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ && |
+ hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ && |
+ hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */)) |
+ return false; |
+ |
+ const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest); |
+ ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup) |
+ <= ARABIC_FALLBACK_MAX_LOOKUPS); |
+ /* TODO sanitize the table? */ |
+ |
+ unsigned j = 0; |
+ unsigned int count = manifest.len; |
+ for (unsigned int i = 0; i < count; i++) |
+ { |
+ fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag); |
+ if (fallback_plan->mask_array[j]) |
+ { |
+ fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset)); |
+ if (fallback_plan->lookup_array[j]) |
+ { |
+ fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]); |
+ j++; |
+ } |
+ } |
+ } |
+ |
+ fallback_plan->num_lookups = j; |
+ fallback_plan->free_lookups = false; |
+ |
+ return j > 0; |
+#else |
+ return false; |
+#endif |
+} |
+ |
+static bool |
+arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan, |
+ const hb_ot_shape_plan_t *plan, |
+ hb_font_t *font) |
+{ |
+ ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS); |
+ unsigned int j = 0; |
+ for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++) |
+ { |
+ fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]); |
+ if (fallback_plan->mask_array[j]) |
+ { |
+ fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i); |
+ if (fallback_plan->lookup_array[j]) |
+ { |
+ fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]); |
+ j++; |
+ } |
+ } |
+ } |
+ |
+ fallback_plan->num_lookups = j; |
+ fallback_plan->free_lookups = true; |
+ |
+ return j > 0; |
+} |
+ |
static arabic_fallback_plan_t * |
arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, |
hb_font_t *font) |
@@ -212,17 +301,21 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, |
if (unlikely (!fallback_plan)) |
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil); |
- for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) |
- { |
- fallback_plan->mask_array[i] = plan->map.get_1_mask (arabic_fallback_features[i]); |
- if (fallback_plan->mask_array[i]) { |
- fallback_plan->lookup_array[i] = arabic_fallback_synthesize_lookup (plan, font, i); |
- if (fallback_plan->lookup_array[i]) |
- fallback_plan->accel_array[i].init (*fallback_plan->lookup_array[i]); |
- } |
- } |
+ fallback_plan->num_lookups = 0; |
+ fallback_plan->free_lookups = false; |
+ |
+ /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms, |
+ * in case the font has cmap entries for the presentation-forms characters. */ |
+ if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font)) |
+ return fallback_plan; |
- return fallback_plan; |
+ /* See if this looks like a Windows-1256-encoded font. If it does, use a |
+ * hand-coded GSUB table. */ |
+ if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font)) |
+ return fallback_plan; |
+ |
+ free (fallback_plan); |
+ return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil); |
} |
static void |
@@ -231,11 +324,12 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan) |
if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil) |
return; |
- for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) |
+ for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) |
if (fallback_plan->lookup_array[i]) |
{ |
fallback_plan->accel_array[i].fini (fallback_plan->lookup_array[i]); |
- free (fallback_plan->lookup_array[i]); |
+ if (fallback_plan->free_lookups) |
+ free (fallback_plan->lookup_array[i]); |
} |
free (fallback_plan); |
@@ -247,7 +341,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, |
hb_buffer_t *buffer) |
{ |
OT::hb_apply_context_t c (0, font, buffer); |
- for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) |
+ for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) |
if (fallback_plan->lookup_array[i]) { |
c.set_lookup_mask (fallback_plan->mask_array[i]); |
hb_ot_layout_substitute_lookup (&c, |