+ unsigned int a = pa->combining_class();
+ unsigned int b = pb->combining_class();
+
+ return a < b ? -1 : a == b ? 0 : +1;
+}
+
+void
+_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 has_multichar_clusters = FALSE;
+ unsigned int count;
+
+ /* 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;)
+ {
+ unsigned int end;
+ for (end = buffer->idx + 1; end < count; end++)
+ if (buffer->info[buffer->idx].cluster != buffer->info[end].cluster)
+ break;
+
+ if (buffer->idx + 1 == end)
+ decompose_single_char_cluster (c, recompose);
+ else {
+ decompose_multi_char_cluster (c, end);
+ has_multichar_clusters = TRUE;
+ }
+ }
+ buffer->swap_buffers ();
+
+
+ /* 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.
+ *
+ * TODO: Am I right about Hangul? If I am, we should add a Hangul module
+ * that requests decomposed. */
+
+ if (!has_multichar_clusters)
+ return; /* Done! */
+
+
+ /* Second round, reorder (inplace) */
+
+ count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (buffer->info[i].combining_class() == 0)
+ continue;