[Indic] Reorder matras
[profile/ivi/org.tizen.video-player.git] / src / hb-ot-shape-normalize.cc
index 66afaa6..e2fd91c 100644 (file)
@@ -63,6 +63,15 @@ HB_BEGIN_DECLS
  *     matra for the Indic shaper.
  */
 
+static void
+output_glyph (hb_ot_shape_context_t *c,
+             hb_codepoint_t glyph)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  buffer->output_glyph (glyph);
+  hb_glyph_info_set_unicode_props (&buffer->out_info[buffer->out_len - 1], buffer->unicode);
+}
 
 static bool
 decompose (hb_ot_shape_context_t *c,
@@ -78,42 +87,39 @@ decompose (hb_ot_shape_context_t *c,
   bool has_a = hb_font_get_glyph (c->font, a, 0, &glyph);
   if (shortest && has_a) {
     /* Output a and b */
-    c->buffer->output_glyph (a);
+    output_glyph (c, a);
     if (b)
-      c->buffer->output_glyph (b);
+      output_glyph (c, b);
     return TRUE;
   }
 
   if (decompose (c, shortest, a)) {
     if (b)
-      c->buffer->output_glyph (b);
+      output_glyph (c, b);
     return TRUE;
   }
 
   if (has_a) {
-    c->buffer->output_glyph (a);
+    output_glyph (c, a);
     if (b)
-      c->buffer->output_glyph (b);
+      output_glyph (c, b);
     return TRUE;
   }
 
   return FALSE;
 }
 
-static bool
+static void
 decompose_current_glyph (hb_ot_shape_context_t *c,
                         bool shortest)
 {
-  if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint)) {
+  if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint))
     c->buffer->skip_glyph ();
-    return TRUE;
-  } else {
+  else
     c->buffer->next_glyph ();
-    return FALSE;
-  }
 }
 
-static bool
+static void
 decompose_single_char_cluster (hb_ot_shape_context_t *c,
                               bool will_recompose)
 {
@@ -122,27 +128,32 @@ decompose_single_char_cluster (hb_ot_shape_context_t *c,
   /* If recomposing and font supports this, we're good to go */
   if (will_recompose && hb_font_get_glyph (c->font, c->buffer->info[c->buffer->idx].codepoint, 0, &glyph)) {
     c->buffer->next_glyph ();
-    return FALSE;
+    return;
   }
 
-  return decompose_current_glyph (c, will_recompose);
+  decompose_current_glyph (c, will_recompose);
 }
 
-static bool
+static void
 decompose_multi_char_cluster (hb_ot_shape_context_t *c,
                              unsigned int end)
 {
-  bool changed = FALSE;
-
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
   for (unsigned int i = c->buffer->idx; i < end; i++)
     if (unlikely (is_variation_selector (c->buffer->info[i].codepoint)))
-      return changed;
+      return;
 
   while (c->buffer->idx < end)
-    changed |= decompose_current_glyph (c, FALSE);
+    decompose_current_glyph (c, FALSE);
+}
+
+static int
+compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+{
+  unsigned int a = pa->combining_class();
+  unsigned int b = pb->combining_class();
 
-  return changed;
+  return a < b ? -1 : a == b ? 0 : +1;
 }
 
 void
@@ -150,15 +161,19 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
 {
   hb_buffer_t *buffer = c->buffer;
   bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper);
-  bool changed = FALSE;
   bool has_multichar_clusters = FALSE;
   unsigned int count;
 
-  buffer->clear_output ();
+  /* We do a fairly 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;)
   {
@@ -168,9 +183,9 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
         break;
 
     if (buffer->idx + 1 == end)
-      changed |= decompose_single_char_cluster (c, recompose);
+      decompose_single_char_cluster (c, recompose);
     else {
-      changed |= decompose_multi_char_cluster (c, end);
+      decompose_multi_char_cluster (c, end);
       has_multichar_clusters = TRUE;
     }
   }
@@ -180,14 +195,14 @@ _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! */
 
-  if (changed)
-    _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class in var1 */
-
 
   /* Second round, reorder (inplace) */
 
@@ -210,33 +225,53 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c)
       continue;
     }
 
-    unsigned int k = end - i - 1;
-    do {
-      hb_glyph_info_t *pinfo = buffer->info + i;
-      unsigned int new_k = 0;
-
-      for (unsigned int j = 0; j < k; j++)
-       if (pinfo[j].combining_class() > pinfo[j+1].combining_class()) {
-         hb_glyph_info_t t;
-         t = pinfo[j];
-         pinfo[j] = pinfo[j + 1];
-         pinfo[j + 1] = t;
-
-         new_k = j;
-       }
-      k = new_k;
-    } while (k);
+    hb_bubble_sort (buffer->info + i, end - i, compare_combining_class);
 
     i = end;
   }
 
 
+  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 ();
 
 }