* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-normalize-private.hh"
-#include "hb-ot-shape-complex-private.hh"
-#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-normalize.hh"
+#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shape.hh"
/*
}
static inline void
-handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
+handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c,
+ unsigned int end,
+ bool short_circuit HB_UNUSED)
{
/* 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 && buffer->successful;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
- /* The next two lines are some ugly lines... But work. */
if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
{
- buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+ hb_codepoint_t unicode = buffer->cur().codepoint;
+ buffer->replace_glyphs (2, 1, &unicode);
}
else
{
decompose_current_character (c, short_circuit);
}
-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))
- decompose_current_character (c, might_short_circuit);
- else
- decompose_multi_char_cluster (c, end, always_short_circuit);
-}
-
static int
compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
_hb_buffer_assert_unicode_vars (buffer);
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
+ if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_AUTO)
+ {
+ if (plan->has_gpos_mark)
+ // https://github.com/harfbuzz/harfbuzz/issues/653#issuecomment-423905920
+ //mode = HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
+ mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
+ else
+ mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
+ }
+
const hb_ot_shape_normalize_context_t c = {
plan,
buffer,
/* First round, decompose */
- buffer->clear_output ();
- count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count && buffer->successful;)
+ bool all_simple = true;
{
- unsigned int end;
- for (end = buffer->idx + 1; end < count; end++)
- if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
- break;
+ buffer->clear_output ();
+ count = buffer->len;
+ buffer->idx = 0;
+ do
+ {
+ unsigned int end;
+ for (end = buffer->idx + 1; end < count; end++)
+ if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
+ break;
- decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
- }
- buffer->swap_buffers ();
+ if (end < count)
+ end--; /* Leave one base for the marks to cluster with. */
+ /* From idx to end are simple clusters. */
+ if (might_short_circuit)
+ {
+ unsigned int done = font->get_nominal_glyphs (end - buffer->idx,
+ &buffer->cur().codepoint,
+ sizeof (buffer->info[0]),
+ &buffer->cur().glyph_index(),
+ sizeof (buffer->info[0]));
+ buffer->next_glyphs (done);
+ }
+ while (buffer->idx < end && buffer->successful)
+ decompose_current_character (&c, might_short_circuit);
- /* Second round, reorder (inplace) */
+ if (buffer->idx == count || !buffer->successful)
+ break;
- count = buffer->len;
- for (unsigned int i = 0; i < count; i++)
- {
- if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
- continue;
+ all_simple = false;
- unsigned int end;
- for (end = i + 1; end < count; end++)
- if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
- break;
+ /* Find all the marks now. */
+ for (end = buffer->idx + 1; end < count; end++)
+ if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))
+ break;
- /* We are going to do a O(n^2). Only do this if the sequence is short. */
- if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) {
- i = end;
- continue;
+ /* idx to end is one non-simple cluster. */
+ decompose_multi_char_cluster (&c, end, always_short_circuit);
}
-
- buffer->sort (i, end, compare_combining_class);
-
- if (plan->shaper->reorder_marks)
- plan->shaper->reorder_marks (plan, buffer, i, end);
-
- i = end;
+ while (buffer->idx < count && buffer->successful);
+ buffer->swap_buffers ();
}
- if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
- mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
- return;
-
- /* Third round, recompose */
-
- /* As noted in the comment earlier, we don't try to combine
- * ccc=0 chars with their previous Starter. */
+ /* Second round, reorder (inplace) */
- buffer->clear_output ();
- count = buffer->len;
- unsigned int starter = 0;
- buffer->next_glyph ();
- while (buffer->idx < count && buffer->successful)
+ if (!all_simple)
{
- hb_codepoint_t composed, glyph;
- 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())))
+ count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
{
- if (/* If there's anything between the starter and this char, they should have CCC
- * smaller than this character's. */
- (starter == buffer->out_len - 1 ||
- info_cc (buffer->prev()) < info_cc (buffer->cur())) &&
- /* And compose. */
- c.compose (&c,
- buffer->out_info[starter].codepoint,
- buffer->cur().codepoint,
- &composed) &&
- /* And the font has glyph for the composite. */
- font->get_nominal_glyph (composed, &glyph))
- {
- /* Composes. */
- buffer->next_glyph (); /* Copy to out-buffer. */
- if (unlikely (!buffer->successful))
- return;
- buffer->merge_out_clusters (starter, buffer->out_len);
- buffer->out_len--; /* Remove the second composable. */
- /* 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);
+ if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
+ continue;
+
+ unsigned int end;
+ for (end = i + 1; end < count; end++)
+ if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
+ break;
+ /* We are going to do a O(n^2). Only do this if the sequence is short. */
+ if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) {
+ i = end;
continue;
}
- }
- /* Blocked, or doesn't compose. */
- buffer->next_glyph ();
+ buffer->sort (i, end, compare_combining_class);
- if (info_cc (buffer->prev()) == 0)
- starter = buffer->out_len - 1;
- }
- buffer->swap_buffers ();
+ if (plan->shaper->reorder_marks)
+ plan->shaper->reorder_marks (plan, buffer, i, end);
+ i = end;
+ }
+ }
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CGJ)
{
/* For all CGJ, check if it prevented any reordering at all.
_hb_glyph_info_unhide (&buffer->info[i]);
}
}
+
+
+ /* Third round, recompose */
+
+ if (!all_simple &&
+ (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS ||
+ mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT))
+ {
+ /* 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 && buffer->successful)
+ {
+ hb_codepoint_t composed, glyph;
+ 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 (/* If there's anything between the starter and this char, they should have CCC
+ * smaller than this character's. */
+ (starter == buffer->out_len - 1 ||
+ info_cc (buffer->prev()) < info_cc (buffer->cur())) &&
+ /* And compose. */
+ c.compose (&c,
+ buffer->out_info[starter].codepoint,
+ buffer->cur().codepoint,
+ &composed) &&
+ /* And the font has glyph for the composite. */
+ font->get_nominal_glyph (composed, &glyph))
+ {
+ /* Composes. */
+ buffer->next_glyph (); /* Copy to out-buffer. */
+ if (unlikely (!buffer->successful))
+ return;
+ buffer->merge_out_clusters (starter, buffer->out_len);
+ buffer->out_len--; /* Remove the second composable. */
+ /* 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);
+
+ continue;
+ }
+ }
+
+ /* Blocked, or doesn't compose. */
+ buffer->next_glyph ();
+
+ if (info_cc (buffer->prev()) == 0)
+ starter = buffer->out_len - 1;
+ }
+ buffer->swap_buffers ();
+ }
}