hb-ot-shape-normalize.cc revision 34c22f816808d061a980cffca12de03beb437fa0
1655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod/*
2655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * Copyright © 2011  Google, Inc.
3655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod *
4655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
5655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod *
6655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * Permission is hereby granted, without written agreement and without
7655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
8655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * software and its documentation for any purpose, provided that the
9655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * above copyright notice and the following two paragraphs appear in
10655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * all copies of this software.
11655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod *
12655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * DAMAGE.
17655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod *
18655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod *
24655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod * Google Author(s): Behdad Esfahbod
25655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod */
26655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod
27655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod#include "hb-ot-shape-private.hh"
285d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod#include "hb-ot-shape-complex-private.hh"
29655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod
30655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad EsfahbodHB_BEGIN_DECLS
31655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod
325d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod/*
335d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * HIGHLEVEL DESIGN:
345d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
355d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * This file exports one main function: _hb_ot_shape_normalize().
365d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
375d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * This function closely reflects the Unicode Normalization Algorithm,
385d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * yet it's different.  The shaper an either prefer decomposed (NFD) or
395d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * composed (NFC).
405d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
415d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * In general what happens is that: each grapheme is decomposed in a chain
425d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * of 1:2 decompositions, marks reordered, and then recomposed if desires,
435d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * so far it's like Unicode Normalization.  However, the decomposition and
445d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * recomposition only happens if the font supports the resulting characters.
455d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
465d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * The goals are:
475d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
485d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *   - Try to render all canonically equivalent strings similarly.  To really
495d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     achieve this we have to always do the full decomposition and then
505d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     selectively recompose from there.  It's kinda too expensive though, so
515d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     we skip some cases.  For example, if composed is desired, we simply
525d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     don't touch 1-character clusters that are supported by the font, even
535d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     though their NFC may be different.
545d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
555d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *   - When a font has a precomposed character for a sequence but the 'ccmp'
565d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     feature in the font is not adequate, form use the precomposed character
575d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     which typically has better mark positioning.
585d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
595d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *   - When a font does not support a character but supports its decomposition,
605d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     well, use the decomposition.
615d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *
625d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *   - The Indic shaper requests decomposed output.  This will handle splitting
635d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod *     matra for the Indic shaper.
645d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod */
655d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod
6645412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod
675c6f5982d78e2d7fadc2fbb8b4f3a4be9420c59aBehdad Esfahbodstatic bool
6845412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahboddecompose (hb_ot_shape_context_t *c,
694ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod	   bool shortest,
7045412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod	   hb_codepoint_t ab)
71655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod{
7245412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod  hb_codepoint_t a, b, glyph;
7345412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod
744ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  if (!hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) ||
754ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod      !hb_font_get_glyph (c->font, b, 0, &glyph))
764ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    return FALSE;
7745412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod
784ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  /* XXX handle singleton decompositions */
794ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  bool has_a = hb_font_get_glyph (c->font, a, 0, &glyph);
804ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  if (shortest && has_a) {
814ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    /* Output a and b */
824ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->output_glyph (a);
834ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->output_glyph (b);
844ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    return TRUE;
854ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  }
86655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod
874ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  if (decompose (c, shortest, a)) {
884ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->output_glyph (b);
894ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    return TRUE;
904ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  }
9145412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod
924ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  if (has_a) {
934ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->output_glyph (a);
944ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->output_glyph (b);
9545412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod    return TRUE;
9645412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod  }
9745412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod
984ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  return FALSE;
995c6f5982d78e2d7fadc2fbb8b4f3a4be9420c59aBehdad Esfahbod}
1005c6f5982d78e2d7fadc2fbb8b4f3a4be9420c59aBehdad Esfahbod
10134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbodstatic bool
1024ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahboddecompose_current_glyph (hb_ot_shape_context_t *c,
1034ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod			 bool shortest)
104d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod{
10534c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint)) {
1064ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->skip_glyph ();
10734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    return TRUE;
10834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  } else {
1094ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->next_glyph ();
11034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    return FALSE;
11134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  }
112d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod}
113d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod
11434c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbodstatic bool
1154ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahboddecompose_single_char_cluster (hb_ot_shape_context_t *c,
1164ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod			       bool will_recompose)
1175c6f5982d78e2d7fadc2fbb8b4f3a4be9420c59aBehdad Esfahbod{
1184ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  hb_codepoint_t glyph;
1194ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
1204ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  /* If recomposing and font supports this, we're good to go */
1214ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  if (will_recompose && hb_font_get_glyph (c->font, c->buffer->info[c->buffer->idx].codepoint, 0, &glyph)) {
1224ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    c->buffer->next_glyph ();
12334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    return FALSE;
1244ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  }
1254ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
12634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  return decompose_current_glyph (c, will_recompose);
127655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod}
128655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod
12934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbodstatic bool
1304ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahboddecompose_multi_char_cluster (hb_ot_shape_context_t *c,
1314ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod			      unsigned int end)
132655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod{
13334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  bool changed = FALSE;
13434c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
1355d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod  /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
1364ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  for (unsigned int i = c->buffer->idx; i < end; i++)
137d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod    if (unlikely (is_variation_selector (c->buffer->info[i].codepoint)))
13834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      return changed;
139d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod
1404ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  while (c->buffer->idx < end)
14134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    changed |= decompose_current_glyph (c, FALSE);
14234c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
14334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  return changed;
144655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod}
145655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod
14645412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbodvoid
1475d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod_hb_ot_shape_normalize (hb_ot_shape_context_t *c)
148655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod{
1495d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod  hb_buffer_t *buffer = c->buffer;
1505d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod  bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper);
15134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  bool changed = FALSE;
1524ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  bool has_multichar_clusters = FALSE;
15334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  unsigned int count;
1545d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod
1555d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod  buffer->clear_output ();
1565d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod
15734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
1584ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  /* First round, decompose */
1594ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
16034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  count = buffer->len;
161468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod  for (buffer->idx = 0; buffer->idx < count;)
1625d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod  {
163655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod    unsigned int end;
164468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod    for (end = buffer->idx + 1; end < count; end++)
165468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod      if (buffer->info[buffer->idx].cluster != buffer->info[end].cluster)
166655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod        break;
1675d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod
168468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod    if (buffer->idx + 1 == end)
16934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      changed |= decompose_single_char_cluster (c, recompose);
1704ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    else {
17134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      changed |= decompose_multi_char_cluster (c, end);
1724ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod      has_multichar_clusters = TRUE;
1734ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    }
174655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod  }
175468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod  buffer->swap_buffers ();
1764ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
17734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
1784ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  /* Technically speaking, two characters with ccc=0 may combine.  But all
1794ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod   * those cases are in languages that the indic module handles (which expects
1804ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod   * decomposed), or in Hangul jamo, which again, we want decomposed anyway.
1814ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod   * So we don't bother combining across cluster boundaries. */
1824ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
1834ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  if (!has_multichar_clusters)
1844ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod    return; /* Done! */
1854ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
18634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  if (changed)
18734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class in var1 */
18834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
18934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
1904ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  /* Second round, reorder (inplace) */
1914ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
19234c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  count = buffer->len;
19334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  for (unsigned int i = 0; i < count; i++)
19434c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  {
19534c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    if (buffer->info[i].combining_class() == 0)
19634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      continue;
19734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
19834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    unsigned int end;
19934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    for (end = i + 1; end < count; end++)
20034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      if (buffer->info[end].combining_class() == 0)
20134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod        break;
20234c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
20334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    /* We are going to do a bubble-sort.  Only do this if the
20434c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod     * sequence is short.  Doing it on long sequences can result
20534c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod     * in an O(n^2) DoS. */
20634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    if (end - i > 10) {
20734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      i = end;
20834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      continue;
20934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    }
21034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
21134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    unsigned int k = end - i - 1;
21234c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    do {
21334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      hb_glyph_info_t *pinfo = buffer->info + i;
21434c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      unsigned int new_k = 0;
21534c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
21634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      for (unsigned int j = 0; j < k; j++)
21734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod	if (pinfo[j].combining_class() > pinfo[j+1].combining_class()) {
21834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod	  hb_glyph_info_t t;
21934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod	  t = pinfo[j];
22034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod	  pinfo[j] = pinfo[j + 1];
22134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod	  pinfo[j + 1] = t;
22234c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
22334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod	  new_k = j;
22434c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod	}
22534c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod      k = new_k;
22634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    } while (k);
22734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
22834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod    i = end;
22934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod  }
23034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
2314ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
2324ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  /* Third round, recompose */
23334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
2344ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  if (recompose) {
2354ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
2364ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod
2374ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod  }
23834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod
239655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod}
240655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod
241655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad EsfahbodHB_END_DECLS
242