Implement the Unicode Canonical Composition algorithm
authorBehdad Esfahbod <behdad@behdad.org>
Sat, 23 Jul 2011 00:22:49 +0000 (20:22 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Sat, 23 Jul 2011 00:22:49 +0000 (20:22 -0400)
Fallback normalization is complete and working now!

src/hb-ot-shape-normalize.cc

index 66afaa6..6f8abb8 100644 (file)
@@ -154,11 +154,16 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   bool has_multichar_clusters = FALSE;
   unsigned int count;
 
-  buffer->clear_output ();
+  /* We do a farily straightforward yet custom normalization process in three
+   * separate rounds: decompose, reorder, recompose (if desired).  Currently
+   * this makes two buffer swaps.  We can make it faster by moving the last
+   * two rounds into the inner loop for the first round, but it's more readable
+   * this way. */
 
 
   /* First round, decompose */
 
+  buffer->clear_output ();
   count = buffer->len;
   for (buffer->idx = 0; buffer->idx < count;)
   {
@@ -180,7 +185,10 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   /* Technically speaking, two characters with ccc=0 may combine.  But all
    * those cases are in languages that the indic module handles (which expects
    * decomposed), or in Hangul jamo, which again, we want decomposed anyway.
-   * So we don't bother combining across cluster boundaries. */
+   * So we don't bother combining across cluster boundaries.
+   *
+   * TODO: Am I right about Hangul?  If I am, we should add a Hangul module
+   * that requests decomposed. */
 
   if (!has_multichar_clusters)
     return; /* Done! */
@@ -231,12 +239,47 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
   }
 
 
+  if (!recompose)
+    return;
+
   /* Third round, recompose */
 
-  if (recompose) {
+  /* As noted in the comment earlier, we don't try to combine
+   * ccc=0 chars with their previous Starter. */
 
+  buffer->clear_output ();
+  count = buffer->len;
+  unsigned int starter = 0;
+  buffer->next_glyph ();
+  while (buffer->idx < count)
+  {
+    if (buffer->info[buffer->idx].combining_class() == 0) {
+      starter = buffer->out_len;
+      buffer->next_glyph ();
+      continue;
+    }
+
+    hb_codepoint_t composed, glyph;
+    if ((buffer->out_info[buffer->out_len - 1].combining_class() >=
+        buffer->info[buffer->idx].combining_class()) ||
+       !hb_unicode_compose (c->buffer->unicode,
+                            buffer->out_info[starter].codepoint,
+                            buffer->info[buffer->idx].codepoint,
+                            &composed) ||
+       !hb_font_get_glyph (c->font, composed, 0, &glyph))
+    {
+      /* Blocked, or doesn't compose. */
+      buffer->next_glyph ();
+      continue;
+    }
+
+    /* Composes. Modify starter and carry on. */
+    buffer->out_info[starter].codepoint = composed;
+    hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
 
+    buffer->skip_glyph ();
   }
+  buffer->swap_buffers ();
 
 }