decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
{
hb_codepoint_t a, b, a_glyph, b_glyph;
+ hb_buffer_t * const buffer = c->buffer;
+ hb_font_t * const font = c->font;
if (!c->decompose (c, ab, &a, &b) ||
- (b && !c->font->get_glyph (b, 0, &b_glyph)))
+ (b && !font->get_glyph (b, 0, &b_glyph)))
return 0;
- bool has_a = c->font->get_glyph (a, 0, &a_glyph);
+ bool has_a = font->get_glyph (a, 0, &a_glyph);
if (shortest && has_a) {
/* Output a and b */
- output_char (c->buffer, a, a_glyph);
+ output_char (buffer, a, a_glyph);
if (likely (b)) {
- output_char (c->buffer, b, b_glyph);
+ output_char (buffer, b, b_glyph);
return 2;
}
return 1;
unsigned int ret;
if ((ret = decompose (c, shortest, a))) {
if (b) {
- output_char (c->buffer, b, b_glyph);
+ output_char (buffer, b, b_glyph);
return ret + 1;
}
return ret;
}
if (has_a) {
- output_char (c->buffer, a, a_glyph);
+ output_char (buffer, a, a_glyph);
if (likely (b)) {
- output_char (c->buffer, b, b_glyph);
+ output_char (buffer, b, b_glyph);
return 2;
}
return 1;
}
/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
-static inline bool
+static inline unsigned int
decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u)
{
unsigned int len, i;
return len;
}
-/* Returns true if recomposition may be benefitial. */
-static inline bool
+static inline void
decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
{
hb_buffer_t * const buffer = c->buffer;
hb_codepoint_t glyph;
- unsigned int len = 1;
/* Kind of a cute waterfall here... */
if (shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
next_char (buffer, glyph);
- else if ((len = decompose (c, shortest, buffer->cur().codepoint)))
+ else if (decompose (c, shortest, buffer->cur().codepoint))
skip_char (buffer);
else if (!shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
next_char (buffer, glyph);
- else if ((len = decompose_compatibility (c, buffer->cur().codepoint)))
+ else if (decompose_compatibility (c, buffer->cur().codepoint))
skip_char (buffer);
else
next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
-
- /*
- * A recomposition would only be useful if we decomposed into at least three
- * characters...
- */
- return len > 2;
}
static inline void
-handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
+handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
+ /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
hb_buffer_t * const buffer = c->buffer;
+ hb_font_t * const font = c->font;
for (; buffer->idx < end - 1;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
/* The next two lines are some ugly lines... But work. */
- c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index());
- buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+ if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+ {
+ buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+ }
+ else
+ {
+ /* Just pass on the two characters separately, let GSUB do its magic. */
+ set_glyph (buffer->cur(), font);
+ buffer->next_glyph ();
+ set_glyph (buffer->cur(), font);
+ buffer->next_glyph ();
+ }
+ /* Skip any further variation selectors. */
+ while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+ {
+ set_glyph (buffer->cur(), font);
+ buffer->next_glyph ();
+ }
} else {
- set_glyph (buffer->cur(), c->font);
+ set_glyph (buffer->cur(), font);
buffer->next_glyph ();
}
}
if (likely (buffer->idx < end)) {
- set_glyph (buffer->cur(), c->font);
+ set_glyph (buffer->cur(), font);
buffer->next_glyph ();
}
}
-/* Returns true if recomposition may be benefitial. */
-static inline bool
-decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
+static inline void
+decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
hb_buffer_t * const buffer = c->buffer;
- /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
for (unsigned int i = buffer->idx; i < end; i++)
if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
- handle_variation_selector_cluster (c, end);
- return false;
+ handle_variation_selector_cluster (c, end, short_circuit);
+ return;
}
while (buffer->idx < end)
- decompose_current_character (c, false);
- /* We can be smarter here and only return true if there are at least two ccc!=0 marks.
- * But does not matter. */
- return true;
+ decompose_current_character (c, short_circuit);
}
-static inline bool
-decompose_cluster (const hb_ot_shape_normalize_context_t *c, bool short_circuit, unsigned int end)
+static inline void
+decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit)
{
if (likely (c->buffer->idx + 1 == end))
- return decompose_current_character (c, short_circuit);
+ decompose_current_character (c, might_short_circuit);
else
- return decompose_multi_char_cluster (c, end);
+ decompose_multi_char_cluster (c, end, always_short_circuit);
}
hb_buffer_t *buffer,
hb_font_t *font)
{
- hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference ?
- plan->shaper->normalization_preference (&buffer->props) :
- HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT;
+ _hb_buffer_assert_unicode_vars (buffer);
+
+ hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
const hb_ot_shape_normalize_context_t c = {
plan,
buffer,
plan->shaper->compose ? plan->shaper->compose : compose_unicode
};
- bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
- mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
- bool can_use_recompose = false;
+ bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
+ bool might_short_circuit = always_short_circuit ||
+ (mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
+ mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT);
unsigned int count;
/* We do a fairly straightforward yet custom normalization process in three
if (buffer->cur().cluster != buffer->info[end].cluster)
break;
- can_use_recompose = decompose_cluster (&c, short_circuit, end) || can_use_recompose;
+ decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
}
buffer->swap_buffers ();
- if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !can_use_recompose)
- return; /* Done! */
-
-
/* Second round, reorder (inplace) */
count = buffer->len;
}
- if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
+ if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
+ mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
return;
/* Third round, recompose */
while (buffer->idx < count)
{
hb_codepoint_t composed, glyph;
- if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't try to
- * compose a CCC=0 character with it's preceding starter. */
- (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL ||
- _hb_glyph_info_get_modified_combining_class (&buffer->cur()) != 0) &&
+ if (/* We don't try to compose a non-mark character with it's preceding starter.
+ * This is both an optimization to avoid trying to compose every two neighboring
+ * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul
+ * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
+ HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) &&
/* If there's anything between the starter and this char, they should have CCC
* smaller than this character's. */
(starter == buffer->out_len - 1 ||
return;
buffer->merge_out_clusters (starter, buffer->out_len);
buffer->out_len--; /* Remove the second composable. */
- buffer->out_info[starter].codepoint = composed; /* Modify starter and carry on. */
- set_glyph (buffer->out_info[starter], font);
+ /* Modify starter and carry on. */
+ buffer->out_info[starter].codepoint = composed;
+ buffer->out_info[starter].glyph_index() = glyph;
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
continue;