Port Arabic fallback ligating to share code with GSUB
authorBehdad Esfahbod <behdad@behdad.org>
Wed, 29 Aug 2012 15:11:54 +0000 (11:11 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Wed, 29 Aug 2012 18:01:22 +0000 (14:01 -0400)
This will eventually allow us to skip marks, as well as (fallback)
attach marks to ligature components of fallback-shaped Arabic.
That would be pretty cool.  I kludged GDEF props in, so mark-skipping
works, but the produced ligature id/components will be cleared later
by substitute_start() et al.

Perhaps using a synthetic table for Arabic fallback shaping was a better
idea.  The current approach has way too many layering violations...

src/hb-ot-layout-gsubgpos-private.hh
src/hb-ot-shape-complex-arabic.cc
src/hb-ot-shape.cc

index 5815d5f..00bc563 100644 (file)
@@ -134,6 +134,10 @@ struct hb_apply_context_t
                        has_glyph_classes (gdef.has_glyph_classes ()),
                        digest (*digest_) {}
 
+  void set_lookup_props (unsigned int lookup_props_) {
+    lookup_props = lookup_props_;
+  }
+
   void set_lookup (const Lookup &l) {
     lookup_props = l.get_props ();
   }
index 857bf55..965947a 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "hb-ot-shape-complex-private.hh"
 #include "hb-ot-shape-private.hh"
-
+#include "hb-ot-layout-gsubgpos-private.hh"
 
 
 /* buffer var allocations */
@@ -88,17 +88,6 @@ static hb_codepoint_t get_arabic_shape (hb_codepoint_t u, unsigned int shape)
   return u;
 }
 
-static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second)
-{
-  if (unlikely (!second)) return 0;
-  for (unsigned i = 0; i < ARRAY_LENGTH (ligature_table); i++)
-    if (ligature_table[i].first == first)
-      for (unsigned j = 0; j < ARRAY_LENGTH (ligature_table[i].ligatures); j++)
-       if (ligature_table[i].ligatures[j].second == second)
-         return ligature_table[i].ligatures[j].ligature;
-  return 0;
-}
-
 static const hb_tag_t arabic_features[] =
 {
   HB_TAG('i','n','i','t'),
@@ -257,20 +246,57 @@ arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
       buffer->info[i].codepoint = shaped;
   }
 
+  OT::hb_apply_context_t c (font, buffer, 1/*global mask*/, NULL);
+  c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
+
   /* Mandatory ligatures */
   buffer->clear_output ();
-  for (buffer->idx = 0; buffer->idx + 1 < count;) {
-    hb_codepoint_t ligature = get_ligature (buffer->cur().codepoint,
-                                           buffer->cur(+1).codepoint);
-    if (likely (!ligature) || !(font->get_glyph (ligature, 0, &glyph))) {
-      buffer->next_glyph ();
-      continue;
+  for (buffer->idx = 0; buffer->idx + 1 < count;)
+  {
+    const unsigned int count = 2;
+    unsigned int end_offset;
+    bool is_mark_ligature;
+    unsigned int total_component_count;
+
+    bool matched = false;
+    for (unsigned i = 0; i < ARRAY_LENGTH (ligature_table); i++)
+    {
+      if (ligature_table[i].first != buffer->cur().codepoint)
+        continue;
+      for (unsigned j = 0; j < ARRAY_LENGTH (ligature_table[i].ligatures); j++)
+      {
+       OT::USHORT component;
+       component.set (ligature_table[i].ligatures[j].second);
+       hb_codepoint_t ligature = ligature_table[i].ligatures[j].ligature;
+       if (likely (!OT::match_input (&c, count,
+                                     &component,
+                                     OT::match_glyph,
+                                     NULL,
+                                     &end_offset,
+                                     &is_mark_ligature,
+                                     &total_component_count) ||
+                   !(font->get_glyph (ligature, 0, &glyph))))
+         continue;
+
+       /* Deal, we are forming the ligature. */
+       buffer->merge_clusters (buffer->idx, buffer->idx + end_offset);
+
+       OT::ligate_input (&c,
+                         count,
+                         &component,
+                         ligature,
+                         OT::match_glyph,
+                         NULL,
+                         is_mark_ligature,
+                         total_component_count);
+       matched = true;
+       break;
+      }
+      if (matched)
+        break;
     }
-
-    buffer->replace_glyphs (2, 1, &ligature);
-
-    /* Technically speaking we can skip marks and stuff, like the GSUB path does.
-     * But who cares, we're in fallback! */
+    if (!matched)
+      buffer->next_glyph ();
   }
   for (; buffer->idx < count;)
       buffer->next_glyph ();
index 29076cf..009a25d 100644 (file)
@@ -319,8 +319,10 @@ hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
 static inline void
 hb_ot_substitute_default (hb_ot_shape_context_t *c)
 {
-  if (c->plan->shaper->preprocess_text)
+  if (c->plan->shaper->preprocess_text) {
+    hb_synthesize_glyph_classes (c); /* XXX This is a hack for now. */
     c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
+  }
 
   hb_ot_mirror_chars (c);