hb-ot-shape-normalize.cc revision c7dfe316f8c0fc04b7976fca5e58eb46d91b4821
1655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod/* 211138ccff71f442da1fcf64faa0e1d22e083e775Behdad Esfahbod * Copyright © 2011,2012 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 2711138ccff71f442da1fcf64faa0e1d22e083e775Behdad Esfahbod#include "hb-ot-shape-normalize-private.hh" 280736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod#include "hb-ot-shape-complex-private.hh" 29655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod#include "hb-ot-shape-private.hh" 30655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod 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, 38c346671b6b9b05fa51b95c16212eb29ac69510faBehdad Esfahbod * yet it's different. 39c346671b6b9b05fa51b95c16212eb29ac69510faBehdad Esfahbod * 40c346671b6b9b05fa51b95c16212eb29ac69510faBehdad Esfahbod * Each shaper specifies whether it prefers decomposed (NFD) or composed (NFC). 41c346671b6b9b05fa51b95c16212eb29ac69510faBehdad Esfahbod * The logic however tries to use whatever the font can support. 425d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * 435d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * In general what happens is that: each grapheme is decomposed in a chain 44947c9a778c0d4b428b58806f98c34ede59b7439cBehdad Esfahbod * of 1:2 decompositions, marks reordered, and then recomposed if desired, 455d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * so far it's like Unicode Normalization. However, the decomposition and 465d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * recomposition only happens if the font supports the resulting characters. 475d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * 485d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * The goals are: 495d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * 505d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * - Try to render all canonically equivalent strings similarly. To really 515d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * achieve this we have to always do the full decomposition and then 525d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * selectively recompose from there. It's kinda too expensive though, so 535d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * we skip some cases. For example, if composed is desired, we simply 545d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * don't touch 1-character clusters that are supported by the font, even 555d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * though their NFC may be different. 565d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * 575d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * - When a font has a precomposed character for a sequence but the 'ccmp' 58947c9a778c0d4b428b58806f98c34ede59b7439cBehdad Esfahbod * feature in the font is not adequate, use the precomposed character 595d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * which typically has better mark positioning. 605d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * 6155deff7595ef357d000fef83559c74c9f8acad00Behdad Esfahbod * - When a font does not support a combining mark, but supports it precomposed 62c346671b6b9b05fa51b95c16212eb29ac69510faBehdad Esfahbod * with previous base, use that. This needs the itemizer to have this 63e3b2e077f549b04779c08a9fedb1f35b9f11075cBehdad Esfahbod * knowledge too. We need to provide assistance to the itemizer. 6455deff7595ef357d000fef83559c74c9f8acad00Behdad Esfahbod * 655d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * - When a font does not support a character but supports its decomposition, 66378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod * well, use the decomposition (preferring the canonical decomposition, but 6784186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * falling back to the compatibility decomposition if necessary). The 6884186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * compatibility decomposition is really nice to have, for characters like 6984186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * ellipsis, or various-sized space characters. 705d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod * 7184186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * - The complex shapers can customize the compose and decompose functions to 7284186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * offload some of their requirements to the normalizer. For example, the 7384186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * Indic shaper may want to disallow recomposing of two matras. 7484186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * 7584186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * - We try compatibility decomposition if decomposing through canonical 7684186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * decomposition alone failed to find a sequence that the font supports. 7784186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * We don't try compatibility decomposition recursively during the canonical 7884186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * decomposition phase. This has minimal impact. There are only a handful 7984186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * of Greek letter that have canonical decompositions that include characters 8084186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * with compatibility decomposition. Those can be found using this command: 8184186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * 8284186a64004e5dcd2ce98b564d0e0a09aa5d68b2Behdad Esfahbod * egrep "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt 835d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod */ 845d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod 85eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 86eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_unicode (const hb_ot_shape_normalize_context_t *c, 870736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t ab, 880736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *a, 890736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *b) 90428dfcab6634ff264570a0a5d715efb8048c3db5Behdad Esfahbod{ 91eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->decompose (ab, a, b); 92428dfcab6634ff264570a0a5d715efb8048c3db5Behdad Esfahbod} 93428dfcab6634ff264570a0a5d715efb8048c3db5Behdad Esfahbod 94eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodstatic bool 95eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbodcompose_unicode (const hb_ot_shape_normalize_context_t *c, 960736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t a, 970736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t b, 980736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_codepoint_t *ab) 99428dfcab6634ff264570a0a5d715efb8048c3db5Behdad Esfahbod{ 100eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod return c->unicode->compose (a, b, ab); 101428dfcab6634ff264570a0a5d715efb8048c3db5Behdad Esfahbod} 102428dfcab6634ff264570a0a5d715efb8048c3db5Behdad Esfahbod 103b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbodstatic inline void 104b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbodset_glyph (hb_glyph_info_t &info, hb_font_t *font) 105b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod{ 10607d682806349aee81f53114778ce0beb23909ed7Behdad Esfahbod font->get_glyph (info.codepoint, 0, &info.glyph_index()); 107b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod} 108b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod 1098d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbodstatic inline void 110b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbodoutput_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph) 111c311d852080b50ffc85e80168de62abb05a6be59Behdad Esfahbod{ 112b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod buffer->cur().glyph_index() = glyph; 1138d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod buffer->output_glyph (unichar); 11499c2695759a6af855d565f4994bbdf220570bb48Behdad Esfahbod _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode); 115c311d852080b50ffc85e80168de62abb05a6be59Behdad Esfahbod} 11645412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod 1178d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbodstatic inline void 118b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbodnext_char (hb_buffer_t *buffer, hb_codepoint_t glyph) 1198d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod{ 120b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod buffer->cur().glyph_index() = glyph; 1218d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod buffer->next_glyph (); 1228d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod} 1238d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod 1248d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbodstatic inline void 1258d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbodskip_char (hb_buffer_t *buffer) 1268d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod{ 1278d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod buffer->skip_glyph (); 1288d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod} 1298d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod 130f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod/* Returns 0 if didn't decompose, number of resulting characters otherwise. */ 131f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbodstatic inline unsigned int 132eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab) 133655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod{ 134b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod hb_codepoint_t a, b, a_glyph, b_glyph; 135ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod hb_buffer_t * const buffer = c->buffer; 136ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod hb_font_t * const font = c->font; 13745412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod 138eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod if (!c->decompose (c, ab, &a, &b) || 139ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod (b && !font->get_glyph (b, 0, &b_glyph))) 140f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 0; 14145412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod 142ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod bool has_a = font->get_glyph (a, 0, &a_glyph); 1434ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod if (shortest && has_a) { 1444ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod /* Output a and b */ 145ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod output_char (buffer, a, a_glyph); 146f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod if (likely (b)) { 147ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod output_char (buffer, b, b_glyph); 148f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 2; 149f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod } 150f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 1; 1514ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod } 152655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod 153f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod unsigned int ret; 1540736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if ((ret = decompose (c, shortest, a))) { 155f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod if (b) { 156ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod output_char (buffer, b, b_glyph); 157f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return ret + 1; 158f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod } 159f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return ret; 1604ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod } 16145412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod 1624ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod if (has_a) { 163ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod output_char (buffer, a, a_glyph); 164f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod if (likely (b)) { 165ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod output_char (buffer, b, b_glyph); 166f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 2; 167f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod } 168f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 1; 16945412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod } 17045412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbod 171f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 0; 1725c6f5982d78e2d7fadc2fbb8b4f3a4be9420c59aBehdad Esfahbod} 1735c6f5982d78e2d7fadc2fbb8b4f3a4be9420c59aBehdad Esfahbod 174f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod/* Returns 0 if didn't decompose, number of resulting characters otherwise. */ 175a88a62f70f87563725d47b9b6824565e5d6b78abBehdad Esfahbodstatic inline unsigned int 176eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u) 177d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod{ 178378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod unsigned int len, i; 179378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN]; 180b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN]; 181378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 1820736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod len = c->buffer->unicode->decompose_compatibility (u, decomposed); 183378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod if (!len) 184f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 0; 185378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 186378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod for (i = 0; i < len; i++) 1870736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i])) 188f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return 0; 189378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 190378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod for (i = 0; i < len; i++) 1910736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod output_char (c->buffer, decomposed[i], glyphs[i]); 192378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod 193f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod return len; 194d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod} 195d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod 1966e74c64211b6aaac48bae8c87f9420d8dc03fd93Behdad Esfahbodstatic inline void 197eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahboddecompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest) 1985c6f5982d78e2d7fadc2fbb8b4f3a4be9420c59aBehdad Esfahbod{ 1990736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_buffer_t * const buffer = c->buffer; 2001eff4350239b0768e1042b52db9fb1c0d266f96aBehdad Esfahbod hb_codepoint_t u = buffer->cur().codepoint; 2014ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod hb_codepoint_t glyph; 2024ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod 203378d279bbf692195c4654e312dae854ab3be04cfBehdad Esfahbod /* Kind of a cute waterfall here... */ 2041eff4350239b0768e1042b52db9fb1c0d266f96aBehdad Esfahbod if (shortest && c->font->get_glyph (u, 0, &glyph)) 205b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod next_char (buffer, glyph); 2061eff4350239b0768e1042b52db9fb1c0d266f96aBehdad Esfahbod else if (decompose (c, shortest, u)) 2078d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod skip_char (buffer); 2081eff4350239b0768e1042b52db9fb1c0d266f96aBehdad Esfahbod else if (!shortest && c->font->get_glyph (u, 0, &glyph)) 209b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod next_char (buffer, glyph); 2101eff4350239b0768e1042b52db9fb1c0d266f96aBehdad Esfahbod else if (decompose_compatibility (c, u)) 2118d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod skip_char (buffer); 21207d682806349aee81f53114778ce0beb23909ed7Behdad Esfahbod else 21307d682806349aee81f53114778ce0beb23909ed7Behdad Esfahbod next_char (buffer, glyph); /* glyph is initialized in earlier branches. */ 214b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod} 215b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod 216b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbodstatic inline void 2178fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbodhandle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit) 218b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod{ 2198fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ 2200736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_buffer_t * const buffer = c->buffer; 221ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod hb_font_t * const font = c->font; 222b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod for (; buffer->idx < end - 1;) { 223b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) { 224b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod /* The next two lines are some ugly lines... But work. */ 225ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index())) 22679d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod { 22779d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod buffer->replace_glyphs (2, 1, &buffer->cur().codepoint); 22879d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod } 22979d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod else 23079d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod { 23179d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod /* Just pass on the two characters separately, let GSUB do its magic. */ 232ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod set_glyph (buffer->cur(), font); 23379d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod buffer->next_glyph (); 234ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod set_glyph (buffer->cur(), font); 23579d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod buffer->next_glyph (); 23679d1007a501fd63c0ba4d51038c513e6b8b94740Behdad Esfahbod } 237c7a84917208528040aaf9ad0a9a0b26aabeabc9cBehdad Esfahbod /* Skip any further variation selectors. */ 238c7a84917208528040aaf9ad0a9a0b26aabeabc9cBehdad Esfahbod while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint))) 239c7a84917208528040aaf9ad0a9a0b26aabeabc9cBehdad Esfahbod { 240ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod set_glyph (buffer->cur(), font); 241c7a84917208528040aaf9ad0a9a0b26aabeabc9cBehdad Esfahbod buffer->next_glyph (); 242c7a84917208528040aaf9ad0a9a0b26aabeabc9cBehdad Esfahbod } 243b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod } else { 244ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod set_glyph (buffer->cur(), font); 245b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod buffer->next_glyph (); 246b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod } 247b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod } 248b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod if (likely (buffer->idx < end)) { 249ac8cd511911c7dca6222d14fa758bff75d601567Behdad Esfahbod set_glyph (buffer->cur(), font); 250b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod buffer->next_glyph (); 251b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod } 252655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod} 253655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod 2546e74c64211b6aaac48bae8c87f9420d8dc03fd93Behdad Esfahbodstatic inline void 2558fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahboddecompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit) 256655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod{ 2570736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_buffer_t * const buffer = c->buffer; 25811138ccff71f442da1fcf64faa0e1d22e083e775Behdad Esfahbod for (unsigned int i = buffer->idx; i < end; i++) 259208f70f0553d73d2908b21b9552298029482a8b9Behdad Esfahbod if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) { 2608fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod handle_variation_selector_cluster (c, end, short_circuit); 2616e74c64211b6aaac48bae8c87f9420d8dc03fd93Behdad Esfahbod return; 262af913c5788e600e36d29f44fe4e77db84cf8c442Behdad Esfahbod } 263d6b9c6d20041b4f4fa11befc179aee757c41904dBehdad Esfahbod 26411138ccff71f442da1fcf64faa0e1d22e083e775Behdad Esfahbod while (buffer->idx < end) 2658fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod decompose_current_character (c, short_circuit); 266f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod} 267f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod 2686e74c64211b6aaac48bae8c87f9420d8dc03fd93Behdad Esfahbodstatic inline void 2698fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahboddecompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit) 270f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod{ 2710736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod if (likely (c->buffer->idx + 1 == end)) 2728fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod decompose_current_character (c, might_short_circuit); 273f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod else 2748fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod decompose_multi_char_cluster (c, end, always_short_circuit); 275655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod} 276655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod 277f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod 27845d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbodstatic int 27945d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbodcompare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) 28045d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod{ 281d1deaa2f5bd028e8076265cba92cffa4fa2834acBehdad Esfahbod unsigned int a = _hb_glyph_info_get_modified_combining_class (pa); 282d1deaa2f5bd028e8076265cba92cffa4fa2834acBehdad Esfahbod unsigned int b = _hb_glyph_info_get_modified_combining_class (pb); 28345d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 28445d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod return a < b ? -1 : a == b ? 0 : +1; 28545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod} 28645d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod 287f4cb4762986a28634fa7de9b706f9d37859b881eBehdad Esfahbod 28845412523dc295cb5ee12e096bfacb282cc925843Behdad Esfahbodvoid 289eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod_hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, 2900736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_buffer_t *buffer, 2910736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod hb_font_t *font) 292655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod{ 2938f3eebf7ee4005f9a8efaafcb7f4058cc0a3756eBehdad Esfahbod _hb_buffer_assert_unicode_vars (buffer); 2948f3eebf7ee4005f9a8efaafcb7f4058cc0a3756eBehdad Esfahbod 2953d6ca0d32e5c6597acfcf59301cb1905586ddb52Behdad Esfahbod hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference; 296eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod const hb_ot_shape_normalize_context_t c = { 297eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod plan, 2980736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod buffer, 2990736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod font, 300eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod buffer->unicode, 301eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode, 302eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod plan->shaper->compose ? plan->shaper->compose : compose_unicode 3030736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod }; 3040736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod 3058fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE; 3068fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod bool might_short_circuit = always_short_circuit || 3078fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod (mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED && 3088fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT); 30934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod unsigned int count; 3105d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod 311c311d852080b50ffc85e80168de62abb05a6be59Behdad Esfahbod /* We do a fairly straightforward yet custom normalization process in three 3125389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod * separate rounds: decompose, reorder, recompose (if desired). Currently 3135389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod * this makes two buffer swaps. We can make it faster by moving the last 3145389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod * two rounds into the inner loop for the first round, but it's more readable 3155389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod * this way. */ 3165d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod 31734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 3184ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod /* First round, decompose */ 3194ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod 3205389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod buffer->clear_output (); 32134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod count = buffer->len; 322468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod for (buffer->idx = 0; buffer->idx < count;) 3235d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod { 324655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod unsigned int end; 325468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod for (end = buffer->idx + 1; end < count; end++) 326c7dfe316f8c0fc04b7976fca5e58eb46d91b4821jfkthame if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))) 327655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod break; 3285d90a342e319068716429bf7af76c3896b61a0e5Behdad Esfahbod 3298fc1f7fe74a25bf8549f5edd79c7da6b720eb064Behdad Esfahbod decompose_cluster (&c, end, might_short_circuit, always_short_circuit); 330655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod } 331468e9cb25c9bc14781b7013e447d763f93bf76a3Behdad Esfahbod buffer->swap_buffers (); 3324ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod 33334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 3344ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod /* Second round, reorder (inplace) */ 3354ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod 33634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod count = buffer->len; 33734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod for (unsigned int i = 0; i < count; i++) 33834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod { 339d1deaa2f5bd028e8076265cba92cffa4fa2834acBehdad Esfahbod if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) 34034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod continue; 34134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 34234c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod unsigned int end; 34334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod for (end = i + 1; end < count; end++) 344d1deaa2f5bd028e8076265cba92cffa4fa2834acBehdad Esfahbod if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0) 34534c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod break; 34634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 34734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod /* We are going to do a bubble-sort. Only do this if the 34834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod * sequence is short. Doing it on long sequences can result 34934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod * in an O(n^2) DoS. */ 35034c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod if (end - i > 10) { 35134c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod i = end; 35234c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod continue; 35334c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod } 35434c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 35545d6f29f15f1d2323bcaa2498aed23ff0c8a1567Behdad Esfahbod hb_bubble_sort (buffer->info + i, end - i, compare_combining_class); 35634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 35734c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod i = end; 35834c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod } 35934c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 3604ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod 36108cf5d75ef0c75095173dec822ccb07defaaa6c2Behdad Esfahbod if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE || 36208cf5d75ef0c75095173dec822ccb07defaaa6c2Behdad Esfahbod mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED) 3635389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod return; 3645389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod 3654ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod /* Third round, recompose */ 36634c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 3675389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod /* As noted in the comment earlier, we don't try to combine 3685389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod * ccc=0 chars with their previous Starter. */ 3694ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod 3705389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod buffer->clear_output (); 3715389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod count = buffer->len; 3725389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod unsigned int starter = 0; 373b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod buffer->next_glyph (); 3745389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod while (buffer->idx < count) 3755389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod { 3765389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod hb_codepoint_t composed, glyph; 377269de14dda7a86a20917fa9ea6a5864929c41364Behdad Esfahbod if (/* We don't try to compose a non-mark character with it's preceding starter. 378269de14dda7a86a20917fa9ea6a5864929c41364Behdad Esfahbod * This is both an optimization to avoid trying to compose every two neighboring 379269de14dda7a86a20917fa9ea6a5864929c41364Behdad Esfahbod * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul 380269de14dda7a86a20917fa9ea6a5864929c41364Behdad Esfahbod * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */ 381269de14dda7a86a20917fa9ea6a5864929c41364Behdad Esfahbod HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) && 382968318455304804dc53045e8ba0cd4d76800c02dBehdad Esfahbod /* If there's anything between the starter and this char, they should have CCC 383968318455304804dc53045e8ba0cd4d76800c02dBehdad Esfahbod * smaller than this character's. */ 384968318455304804dc53045e8ba0cd4d76800c02dBehdad Esfahbod (starter == buffer->out_len - 1 || 38599c2695759a6af855d565f4994bbdf220570bb48Behdad Esfahbod _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) && 386968318455304804dc53045e8ba0cd4d76800c02dBehdad Esfahbod /* And compose. */ 387eba312c8d1b2bbe8cb9b6414e843e78d2c521aa4Behdad Esfahbod c.compose (&c, 3880736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod buffer->out_info[starter].codepoint, 3890736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod buffer->cur().codepoint, 3900736915b8ed789a209205fec762997af3a8af89cBehdad Esfahbod &composed) && 391968318455304804dc53045e8ba0cd4d76800c02dBehdad Esfahbod /* And the font has glyph for the composite. */ 3928fbfda920e0b3bb4ab7afb732826026964b79be9Behdad Esfahbod font->get_glyph (composed, 0, &glyph)) 3935389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod { 394bc8357ea7b4c0d7c715aae353176434fb9460205Behdad Esfahbod /* Composes. */ 395b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod buffer->next_glyph (); /* Copy to out-buffer. */ 396bc8357ea7b4c0d7c715aae353176434fb9460205Behdad Esfahbod if (unlikely (buffer->in_error)) 397bc8357ea7b4c0d7c715aae353176434fb9460205Behdad Esfahbod return; 398bc8357ea7b4c0d7c715aae353176434fb9460205Behdad Esfahbod buffer->merge_out_clusters (starter, buffer->out_len); 3998d1eef3f32fb539de2a72804fa3834acc18daab5Behdad Esfahbod buffer->out_len--; /* Remove the second composable. */ 40064426ec73a987bfe1e71a293ee195f268897e8d6Behdad Esfahbod /* Modify starter and carry on. */ 40164426ec73a987bfe1e71a293ee195f268897e8d6Behdad Esfahbod buffer->out_info[starter].codepoint = composed; 40264426ec73a987bfe1e71a293ee195f268897e8d6Behdad Esfahbod buffer->out_info[starter].glyph_index() = glyph; 403d1deaa2f5bd028e8076265cba92cffa4fa2834acBehdad Esfahbod _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode); 404e02d9257863b49e33ab5942971266349d3c548f6Behdad Esfahbod 4055389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod continue; 4065389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod } 4075389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod 408e02d9257863b49e33ab5942971266349d3c548f6Behdad Esfahbod /* Blocked, or doesn't compose. */ 409b00321ea78793d9b3592b5173a9800e6322424feBehdad Esfahbod buffer->next_glyph (); 410968318455304804dc53045e8ba0cd4d76800c02dBehdad Esfahbod 41199c2695759a6af855d565f4994bbdf220570bb48Behdad Esfahbod if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0) 412968318455304804dc53045e8ba0cd4d76800c02dBehdad Esfahbod starter = buffer->out_len - 1; 4134ff0d2d9dfc4f7e4880a4e964ca9872624508ea0Behdad Esfahbod } 4145389ff4dbc46c76c9483e3c95f22524b60e21166Behdad Esfahbod buffer->swap_buffers (); 41534c22f816808d061a980cffca12de03beb437fa0Behdad Esfahbod 416655586fe5e1fadf2a2ef7826e61ee9a445ffa37aBehdad Esfahbod} 417