@@ -81,6 +81,9 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
8181 num_glyphs++;
8282 }
8383
84+ if (!num_glyphs)
85+ return NULL ;
86+
8487 /* Bubble-sort!
8588 * May not be good-enough for presidential candidate interviews, but good-enough for us... */
8689 hb_bubble_sort (&glyphs[0 ], num_glyphs, OT::GlyphID::cmp, &substitutes[0 ]);
@@ -158,6 +161,9 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
158161 }
159162 }
160163
164+ if (!num_ligatures)
165+ return NULL ;
166+
161167 OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs);
162168 OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs);
163169 OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures);
@@ -198,13 +204,101 @@ struct arabic_fallback_plan_t
198204{
199205 ASSERT_POD ();
200206
207+ unsigned int num_lookups;
208+ bool free_lookups;
209+
201210 hb_mask_t mask_array[ARABIC_NUM_FALLBACK_FEATURES];
202211 OT::SubstLookup *lookup_array[ARABIC_NUM_FALLBACK_FEATURES];
203212 hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_NUM_FALLBACK_FEATURES];
204213};
205214
206215static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
207216
217+ #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_WITH_WIN1256)
218+ #define HB_WITH_WIN1256
219+ #endif
220+
221+ #ifdef HB_WITH_WIN1256
222+ #include " hb-ot-shape-complex-arabic-win1256.hh"
223+ #endif
224+
225+ struct ManifestLookup {
226+ OT::USHORT fallbackType;
227+ OT::OffsetTo<OT::SubstLookup> lookupOffset;
228+ };
229+ typedef OT::ArrayOf<ManifestLookup> Manifest;
230+
231+ static bool
232+ arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
233+ const hb_ot_shape_plan_t *plan,
234+ hb_font_t *font)
235+ {
236+ #ifdef HB_WITH_WIN1256
237+ /* Does this font look like it's Windows-1256-encoded? */
238+ hb_codepoint_t g;
239+ if (!(hb_font_get_glyph (font, 0x0627u , 0 , &g) && g == 199 /* ALEF */ &&
240+ hb_font_get_glyph (font, 0x0644u , 0 , &g) && g == 225 /* LAM */ &&
241+ hb_font_get_glyph (font, 0x0649u , 0 , &g) && g == 236 /* ALEF MAKSURA */ &&
242+ hb_font_get_glyph (font, 0x064Au , 0 , &g) && g == 237 /* YEH */ &&
243+ hb_font_get_glyph (font, 0x0652u , 0 , &g) && g == 250 /* SUKUN */ ))
244+ return false ;
245+
246+ const Manifest &manifest = reinterpret_cast <const Manifest&> (arabic_win1256_gsub_lookups.manifest );
247+ ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData ) / sizeof (ManifestLookup)
248+ <= ARABIC_NUM_FALLBACK_FEATURES);
249+ /* TODO sanitize the table? */
250+
251+ unsigned j = 0 ;
252+ unsigned int count = manifest.len ;
253+ for (unsigned int i = 0 ; i < count; i++)
254+ {
255+ fallback_plan->mask_array [j] = plan->map .get_1_mask (manifest[i].fallbackType );
256+ if (fallback_plan->mask_array [j])
257+ {
258+ fallback_plan->lookup_array [j] = const_cast <OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset ));
259+ if (fallback_plan->lookup_array [j])
260+ {
261+ fallback_plan->accel_array [j].init (*fallback_plan->lookup_array [j]);
262+ j++;
263+ }
264+ }
265+ }
266+
267+ fallback_plan->num_lookups = j;
268+ fallback_plan->free_lookups = false ;
269+
270+ return j > 0 ;
271+ #else
272+ return false ;
273+ #endif
274+ }
275+
276+ static bool
277+ arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
278+ const hb_ot_shape_plan_t *plan,
279+ hb_font_t *font)
280+ {
281+ unsigned int j = 0 ;
282+ for (unsigned int i = 0 ; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
283+ {
284+ fallback_plan->mask_array [j] = plan->map .get_1_mask (arabic_fallback_features[i]);
285+ if (fallback_plan->mask_array [j])
286+ {
287+ fallback_plan->lookup_array [j] = arabic_fallback_synthesize_lookup (plan, font, i);
288+ if (fallback_plan->lookup_array [j])
289+ {
290+ fallback_plan->accel_array [j].init (*fallback_plan->lookup_array [j]);
291+ j++;
292+ }
293+ }
294+ }
295+
296+ fallback_plan->num_lookups = j;
297+ fallback_plan->free_lookups = true ;
298+
299+ return j > 0 ;
300+ }
301+
208302static arabic_fallback_plan_t *
209303arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
210304 hb_font_t *font)
@@ -213,17 +307,21 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
213307 if (unlikely (!fallback_plan))
214308 return const_cast <arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
215309
216- for (unsigned int i = 0 ; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
217- {
218- fallback_plan->mask_array [i] = plan->map .get_1_mask (arabic_fallback_features[i]);
219- if (fallback_plan->mask_array [i]) {
220- fallback_plan->lookup_array [i] = arabic_fallback_synthesize_lookup (plan, font, i);
221- if (fallback_plan->lookup_array [i])
222- fallback_plan->accel_array [i].init (*fallback_plan->lookup_array [i]);
223- }
224- }
310+ fallback_plan->num_lookups = 0 ;
311+ fallback_plan->free_lookups = false ;
312+
313+ /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
314+ * in case the font has cmap entries for the presentation-forms characters. */
315+ if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
316+ return fallback_plan;
225317
226- return fallback_plan;
318+ /* See if this looks like a Windows-1256-encoded font. If it does, use a
319+ * hand-coded GSUB table. */
320+ if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
321+ return fallback_plan;
322+
323+ free (fallback_plan);
324+ return const_cast <arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
227325}
228326
229327static void
@@ -232,11 +330,12 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
232330 if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
233331 return ;
234332
235- for (unsigned int i = 0 ; i < ARABIC_NUM_FALLBACK_FEATURES ; i++)
333+ for (unsigned int i = 0 ; i < fallback_plan-> num_lookups ; i++)
236334 if (fallback_plan->lookup_array [i])
237335 {
238336 fallback_plan->accel_array [i].fini (fallback_plan->lookup_array [i]);
239- free (fallback_plan->lookup_array [i]);
337+ if (fallback_plan->free_lookups )
338+ free (fallback_plan->lookup_array [i]);
240339 }
241340
242341 free (fallback_plan);
@@ -248,7 +347,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
248347 hb_buffer_t *buffer)
249348{
250349 OT::hb_apply_context_t c (0 , font, buffer);
251- for (unsigned int i = 0 ; i < ARABIC_NUM_FALLBACK_FEATURES ; i++)
350+ for (unsigned int i = 0 ; i < fallback_plan-> num_lookups ; i++)
252351 if (fallback_plan->lookup_array [i]) {
253352 c.set_lookup_mask (fallback_plan->mask_array [i]);
254353 hb_ot_layout_substitute_lookup (&c,
0 commit comments