[OT] Add shape_plan to Arabic shaper
authorBehdad Esfahbod <behdad@behdad.org>
Sat, 11 Aug 2012 22:20:28 +0000 (18:20 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Sat, 11 Aug 2012 22:20:54 +0000 (18:20 -0400)
src/hb-ot-shape-complex-arabic.cc

index 2a96b7d..e0db41c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2010  Google, Inc.
+ * Copyright © 2010,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -99,7 +99,7 @@ static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second)
   return 0;
 }
 
-static const hb_tag_t arabic_syriac_features[] =
+static const hb_tag_t arabic_features[] =
 {
   HB_TAG('i','n','i','t'),
   HB_TAG('m','e','d','i'),
@@ -127,9 +127,7 @@ enum {
 
   NONE,
 
-  COMMON_NUM_FEATURES = 4,
-  SYRIAC_NUM_FEATURES = 7,
-  TOTAL_NUM_FEATURES = NONE
+  ARABIC_NUM_FEATURES = NONE
 };
 
 static const struct arabic_state_table_entry {
@@ -184,9 +182,8 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
 
   map->add_gsub_pause (NULL);
 
-  unsigned int num_features = plan->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
-  for (unsigned int i = 0; i < num_features; i++)
-    map->add_bool_feature (arabic_syriac_features[i], false);
+  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
+    map->add_bool_feature (arabic_features[i], false);
 
   map->add_gsub_pause (NULL);
 
@@ -200,10 +197,51 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
   map->add_bool_feature (HB_TAG('c','s','w','h'));
 }
 
+struct arabic_shape_plan_t
+{
+  ASSERT_POD ();
+
+  bool do_fallback;
+  hb_mask_t mask_array[ARABIC_NUM_FEATURES];
+};
+
+static void *
+data_create_arabic (const hb_ot_shape_plan_t *plan)
+{
+  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
+  if (unlikely (!arabic_plan))
+    return NULL;
+
+  hb_mask_t total_masks = 0;
+  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
+    arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
+    total_masks |= arabic_plan->mask_array[i];
+  }
+
+  /* Pitfalls:
+   * - This path fires if user force-set init/medi/fina/isol off,
+   * - If font does not declare script 'arab', well, what to do?
+   *   Most probably it's safe to assume that init/medi/fina/isol
+   *   still mean Arabic shaping, although they do not have to.
+   */
+  arabic_plan->do_fallback = 0 == total_masks;
+
+  return arabic_plan;
+}
+
+static void
+data_destroy_arabic (void *data)
+{
+  free (data);
+}
 
 static void
 arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
 {
+  /* Only Arabic has presentation forms encoded in Unicode. */
+  if (buffer->props.script != HB_SCRIPT_ARABIC)
+    return;
+
   unsigned int count = buffer->len;
   hb_codepoint_t glyph;
 
@@ -240,6 +278,8 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
                    hb_buffer_t              *buffer,
                    hb_font_t                *font)
 {
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+
   unsigned int count = buffer->len;
   unsigned int prev = 0, state = 0;
 
@@ -265,28 +305,12 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
     state = entry->next_state;
   }
 
-  hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0};
-  hb_mask_t total_masks = 0;
-  unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
-  for (unsigned int i = 0; i < num_masks; i++) {
-    mask_array[i] = plan->map.get_1_mask (arabic_syriac_features[i]);
-    total_masks |= mask_array[i];
-  }
-
-  if (total_masks) {
+  if (likely (!arabic_plan->do_fallback)) {
     /* Has OpenType tables */
     for (unsigned int i = 0; i < count; i++)
-      buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()];
-  } else if (buffer->props.script == HB_SCRIPT_ARABIC) {
-    /* Fallback Arabic shaping to Presentation Forms */
-    /* Pitfalls:
-     * - This path fires if user force-set init/medi/fina/isol off,
-     * - If font does not declare script 'arab', well, what to do?
-     *   Most probably it's safe to assume that init/medi/fina/isol
-     *   still mean Arabic shaping, although they do not have to.
-     */
+      buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()];
+  } else
     arabic_fallback_shape (font, buffer);
-  }
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
@@ -296,8 +320,8 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
   "arabic",
   collect_features_arabic,
   NULL, /* override_features */
-  NULL, /* data_create */
-  NULL, /* data_destroy */
+  data_create_arabic,
+  data_destroy_arabic,
   NULL, /* normalization_preference */
   setup_masks_arabic,
   true, /* zero_width_attached_marks */