Index: third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh |
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh |
index f46b3782ec71218709eb73aee3eebbff02427f0b..bdd773e36b9030ff0425c9956722ed225370446f 100644 |
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh |
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh |
@@ -43,7 +43,6 @@ namespace OT { |
(&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
""); |
- |
#ifndef HB_DEBUG_CLOSURE |
#define HB_DEBUG_CLOSURE (HB_DEBUG+0) |
#endif |
@@ -158,7 +157,13 @@ struct hb_collect_glyphs_context_t |
/* Note that GPOS sets recurse_func to NULL already, so it doesn't get |
* past the previous check. For GSUB, we only want to collect the output |
- * glyphs in the recursion. If output is not requested, we can go home now. */ |
+ * glyphs in the recursion. If output is not requested, we can go home now. |
+ * |
+ * Note further, that the above is not exactly correct. A recursed lookup |
+ * is allowed to match input that is not matched in the context, but that's |
+ * not how most fonts are built. It's possible to relax that and recurse |
+ * with all sets here if it proves to be an issue. |
+ */ |
if (output == hb_set_get_empty ()) |
return HB_VOID; |
@@ -272,14 +277,12 @@ struct hb_apply_context_t |
hb_apply_context_t (unsigned int table_index_, |
hb_font_t *font_, |
- hb_buffer_t *buffer_, |
- hb_mask_t lookup_mask_, |
- bool auto_zwj_) : |
+ hb_buffer_t *buffer_) : |
table_index (table_index_), |
font (font_), face (font->face), buffer (buffer_), |
direction (buffer_->props.direction), |
- lookup_mask (lookup_mask_), |
- auto_zwj (auto_zwj_), |
+ lookup_mask (1), |
+ auto_zwj (true), |
recurse_func (NULL), |
nesting_level_left (MAX_NESTING_LEVEL), |
lookup_props (0), |
@@ -287,6 +290,8 @@ struct hb_apply_context_t |
has_glyph_classes (gdef.has_glyph_classes ()), |
debug_depth (0) {} |
+ inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } |
+ inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } |
inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } |
inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } |
@@ -346,7 +351,7 @@ struct hb_apply_context_t |
{ |
unsigned int property; |
- property = info.glyph_props(); |
+ property = _hb_glyph_info_get_glyph_props (&info); |
if (!c->match_properties (info.codepoint, property, lookup_props)) |
return SKIP_YES; |
@@ -354,7 +359,7 @@ struct hb_apply_context_t |
if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && |
(ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && |
(ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && |
- !is_a_ligature (info))) |
+ !_hb_glyph_info_ligated (&info))) |
return SKIP_MAYBE; |
return SKIP_NO; |
@@ -555,36 +560,47 @@ struct hb_apply_context_t |
{ |
unsigned int property; |
- property = info->glyph_props(); |
+ property = _hb_glyph_info_get_glyph_props (info); |
return match_properties (info->codepoint, property, lookup_props); |
} |
- inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const |
+ inline void _set_glyph_props (hb_codepoint_t glyph_index, |
+ unsigned int class_guess = 0, |
+ bool ligature = false) const |
{ |
+ unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & |
+ HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; |
+ add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; |
+ if (ligature) |
+ add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; |
if (likely (has_glyph_classes)) |
- buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index); |
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); |
else if (class_guess) |
- buffer->cur().glyph_props() = class_guess; |
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); |
} |
- inline void output_glyph (hb_codepoint_t glyph_index, |
- unsigned int class_guess = 0) const |
+ inline void replace_glyph (hb_codepoint_t glyph_index) const |
{ |
- set_class (glyph_index, class_guess); |
- buffer->output_glyph (glyph_index); |
+ _set_glyph_props (glyph_index); |
+ buffer->replace_glyph (glyph_index); |
} |
- inline void replace_glyph (hb_codepoint_t glyph_index, |
- unsigned int class_guess = 0) const |
+ inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const |
{ |
- set_class (glyph_index, class_guess); |
+ _set_glyph_props (glyph_index); |
+ buffer->cur().codepoint = glyph_index; |
+ } |
+ inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index, |
+ unsigned int class_guess) const |
+ { |
+ _set_glyph_props (glyph_index, class_guess, true); |
buffer->replace_glyph (glyph_index); |
} |
- inline void replace_glyph_inplace (hb_codepoint_t glyph_index, |
- unsigned int class_guess = 0) const |
+ inline void output_glyph (hb_codepoint_t glyph_index, |
+ unsigned int class_guess) const |
{ |
- set_class (glyph_index, class_guess); |
- buffer->cur().codepoint = glyph_index; |
+ _set_glyph_props (glyph_index, class_guess); |
+ buffer->output_glyph (glyph_index); |
} |
}; |
@@ -697,13 +713,18 @@ static inline bool match_input (hb_apply_context_t *c, |
const USHORT input[], /* Array of input values--start with second glyph */ |
match_func_t match_func, |
const void *match_data, |
- unsigned int *end_offset = NULL, |
+ unsigned int *end_offset, |
+ unsigned int match_positions[MAX_CONTEXT_LENGTH], |
bool *p_is_mark_ligature = NULL, |
unsigned int *p_total_component_count = NULL) |
{ |
TRACE_APPLY (NULL); |
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); |
+ if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false); |
+ |
+ hb_buffer_t *buffer = c->buffer; |
+ |
+ hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1); |
skippy_iter.set_match_func (match_func, match_data, input); |
if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); |
@@ -725,20 +746,23 @@ static inline bool match_input (hb_apply_context_t *c, |
* ligate with a conjunct...) |
*/ |
- bool is_mark_ligature = !!(c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); |
+ bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); |
unsigned int total_component_count = 0; |
- total_component_count += get_lig_num_comps (c->buffer->cur()); |
+ total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
- unsigned int first_lig_id = get_lig_id (c->buffer->cur()); |
- unsigned int first_lig_comp = get_lig_comp (c->buffer->cur()); |
+ unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
+ unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); |
+ match_positions[0] = buffer->idx; |
for (unsigned int i = 1; i < count; i++) |
{ |
if (!skippy_iter.next ()) return TRACE_RETURN (false); |
- unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]); |
- unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]); |
+ match_positions[i] = skippy_iter.idx; |
+ |
+ unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); |
+ unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); |
if (first_lig_id && first_lig_comp) { |
/* If first component was attached to a previous ligature component, |
@@ -754,12 +778,11 @@ static inline bool match_input (hb_apply_context_t *c, |
return TRACE_RETURN (false); |
} |
- is_mark_ligature = is_mark_ligature && (c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); |
- total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]); |
+ is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); |
+ total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); |
} |
- if (end_offset) |
- *end_offset = skippy_iter.idx - c->buffer->idx + 1; |
+ *end_offset = skippy_iter.idx - buffer->idx + 1; |
if (p_is_mark_ligature) |
*p_is_mark_ligature = is_mark_ligature; |
@@ -770,17 +793,18 @@ static inline bool match_input (hb_apply_context_t *c, |
return TRACE_RETURN (true); |
} |
static inline void ligate_input (hb_apply_context_t *c, |
- unsigned int count, /* Including the first glyph (not matched) */ |
- const USHORT input[], /* Array of input values--start with second glyph */ |
- match_func_t match_func, |
- const void *match_data, |
+ unsigned int count, /* Including the first glyph */ |
+ unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ |
+ unsigned int match_length, |
hb_codepoint_t lig_glyph, |
bool is_mark_ligature, |
unsigned int total_component_count) |
{ |
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); |
- skippy_iter.set_match_func (match_func, match_data, input); |
- if (skippy_iter.has_no_chance ()) return; |
+ TRACE_APPLY (NULL); |
+ |
+ hb_buffer_t *buffer = c->buffer; |
+ |
+ buffer->merge_clusters (buffer->idx, buffer->idx + match_length); |
/* |
* - If it *is* a mark ligature, we don't allocate a new ligature id, and leave |
@@ -811,44 +835,49 @@ static inline void ligate_input (hb_apply_context_t *c, |
*/ |
unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; |
- unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer); |
- unsigned int last_lig_id = get_lig_id (c->buffer->cur()); |
- unsigned int last_num_components = get_lig_num_comps (c->buffer->cur()); |
+ unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer); |
+ unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
+ unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
unsigned int components_so_far = last_num_components; |
if (!is_mark_ligature) |
- set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count); |
- c->replace_glyph (lig_glyph, klass); |
+ { |
+ _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); |
+ if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
+ { |
+ _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER); |
+ _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0); |
+ } |
+ } |
+ c->replace_glyph_with_ligature (lig_glyph, klass); |
for (unsigned int i = 1; i < count; i++) |
{ |
- if (!skippy_iter.next ()) return; |
- |
- while (c->buffer->idx < skippy_iter.idx) |
+ while (buffer->idx < match_positions[i]) |
{ |
if (!is_mark_ligature) { |
unsigned int new_lig_comp = components_so_far - last_num_components + |
- MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components); |
- set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp); |
+ MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components); |
+ _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp); |
} |
- c->buffer->next_glyph (); |
+ buffer->next_glyph (); |
} |
- last_lig_id = get_lig_id (c->buffer->cur()); |
- last_num_components = get_lig_num_comps (c->buffer->cur()); |
+ last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
+ last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
components_so_far += last_num_components; |
/* Skip the base glyph */ |
- c->buffer->idx++; |
+ buffer->idx++; |
} |
if (!is_mark_ligature && last_lig_id) { |
/* Re-adjust components for any marks following. */ |
- for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) { |
- if (last_lig_id == get_lig_id (c->buffer->info[i])) { |
+ for (unsigned int i = buffer->idx; i < buffer->len; i++) { |
+ if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { |
unsigned int new_lig_comp = components_so_far - last_num_components + |
- MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components); |
- set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp); |
+ MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components); |
+ _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); |
} else |
break; |
} |
@@ -918,102 +947,87 @@ static inline void recurse_lookups (context_t *c, |
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) |
{ |
for (unsigned int i = 0; i < lookupCount; i++) |
- c->recurse (lookupRecord->lookupListIndex); |
+ c->recurse (lookupRecord[i].lookupListIndex); |
} |
static inline bool apply_lookup (hb_apply_context_t *c, |
unsigned int count, /* Including the first glyph */ |
- const USHORT input[], /* Array of input values--start with second glyph */ |
- match_func_t match_func, |
- const void *match_data, |
+ unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ |
unsigned int lookupCount, |
- const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) |
+ const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ |
+ unsigned int match_length) |
{ |
TRACE_APPLY (NULL); |
- unsigned int end = c->buffer->len; |
- if (unlikely (count == 0 || c->buffer->idx + count > end)) |
- return TRACE_RETURN (false); |
+ hb_buffer_t *buffer = c->buffer; |
+ unsigned int end; |
- /* TODO We don't support lookupRecord arrays that are not increasing: |
- * Should be easy for in_place ones at least. */ |
- |
- /* Note: If sublookup is reverse, it will underflow after the first loop |
- * and we jump out of it. Not entirely disastrous. So we don't check |
- * for reverse lookup here. |
- */ |
+ /* All positions are distance from beginning of *output* buffer. |
+ * Adjust. */ |
+ { |
+ unsigned int bl = buffer->backtrack_len (); |
+ end = bl + match_length; |
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); |
- skippy_iter.set_match_func (match_func, match_data, input); |
- uint8_t syllable = c->buffer->cur().syllable(); |
+ int delta = bl - buffer->idx; |
+ /* Convert positions to new indexing. */ |
+ for (unsigned int j = 0; j < count; j++) |
+ match_positions[j] += delta; |
+ } |
- unsigned int i = 0; |
- if (lookupCount && 0 == lookupRecord->sequenceIndex) |
+ for (unsigned int i = 0; i < lookupCount; i++) |
{ |
- unsigned int old_pos = c->buffer->idx; |
+ unsigned int idx = lookupRecord[i].sequenceIndex; |
+ if (idx >= count) |
+ continue; |
- /* Apply a lookup */ |
- bool done = c->recurse (lookupRecord->lookupListIndex); |
+ buffer->move_to (match_positions[idx]); |
- lookupRecord++; |
- lookupCount--; |
- /* Err, this is wrong if the lookup jumped over some glyphs */ |
- i += c->buffer->idx - old_pos; |
+ unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); |
+ if (!c->recurse (lookupRecord[i].lookupListIndex)) |
+ continue; |
- if (!done) |
- goto not_applied; |
- else |
- { |
- /* Reinitialize iterator. */ |
- hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i); |
- tmp.set_syllable (syllable); |
- skippy_iter = tmp; |
- } |
- } |
- else |
- { |
- not_applied: |
- /* No lookup applied for this index */ |
- c->buffer->next_glyph (); |
- i++; |
- } |
- while (i < count) |
- { |
- if (!skippy_iter.next ()) return TRACE_RETURN (true); |
- while (c->buffer->idx < skippy_iter.idx) |
- c->buffer->next_glyph (); |
+ unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); |
+ int delta = new_len - orig_len; |
- if (lookupCount && i == lookupRecord->sequenceIndex) |
- { |
- unsigned int old_pos = c->buffer->idx; |
+ if (!delta) |
+ continue; |
- /* Apply a lookup */ |
- bool done = c->recurse (lookupRecord->lookupListIndex); |
+ /* Recursed lookup changed buffer len. Adjust. */ |
- lookupRecord++; |
- lookupCount--; |
- /* Err, this is wrong if the lookup jumped over some glyphs */ |
- i += c->buffer->idx - old_pos; |
+ /* end can't go back past the current match position. */ |
+ end = MAX ((int) match_positions[idx] + 1, int (end) + delta); |
- if (!done) |
- goto not_applied2; |
- else |
- { |
- /* Reinitialize iterator. */ |
- hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i); |
- tmp.set_syllable (syllable); |
- skippy_iter = tmp; |
- } |
+ unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ |
+ |
+ if (delta > 0) |
+ { |
+ if (unlikely (delta + count > MAX_CONTEXT_LENGTH)) |
+ break; |
} |
else |
{ |
- not_applied2: |
- /* No lookup applied for this index */ |
- c->buffer->next_glyph (); |
- i++; |
+ /* NOTE: delta is negative. */ |
+ delta = MAX (delta, (int) next - (int) count); |
+ next -= delta; |
} |
+ |
+ /* Shift! */ |
+ memmove (match_positions + next + delta, match_positions + next, |
+ (count - next) * sizeof (match_positions[0])); |
+ next += delta; |
+ count += delta; |
+ |
+ /* Fill in new entries. */ |
+ for (unsigned int j = idx + 1; j < next; j++) |
+ match_positions[j] = match_positions[j - 1] + 1; |
+ |
+ /* And fixup the rest. */ |
+ for (; next < count; next++) |
+ match_positions[next] += delta; |
} |
+ buffer->move_to (end); |
+ |
return TRACE_RETURN (true); |
} |
@@ -1085,13 +1099,16 @@ static inline bool context_apply_lookup (hb_apply_context_t *c, |
const LookupRecord lookupRecord[], |
ContextApplyLookupContext &lookup_context) |
{ |
+ unsigned int match_length = 0; |
+ unsigned int match_positions[MAX_CONTEXT_LENGTH]; |
return match_input (c, |
inputCount, input, |
- lookup_context.funcs.match, lookup_context.match_data) |
+ lookup_context.funcs.match, lookup_context.match_data, |
+ &match_length, match_positions) |
&& apply_lookup (c, |
- inputCount, input, |
- lookup_context.funcs.match, lookup_context.match_data, |
- lookupCount, lookupRecord); |
+ inputCount, match_positions, |
+ lookupCount, lookupRecord, |
+ match_length); |
} |
struct Rule |
@@ -1554,7 +1571,7 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c, |
&& intersects_array (c, |
inputCount ? inputCount - 1 : 0, input, |
lookup_context.funcs.intersects, lookup_context.intersects_data[1]) |
- && intersects_array (c, |
+ && intersects_array (c, |
lookaheadCount, lookahead, |
lookup_context.funcs.intersects, lookup_context.intersects_data[2])) |
recurse_lookups (c, |
@@ -1613,22 +1630,23 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c, |
const LookupRecord lookupRecord[], |
ChainContextApplyLookupContext &lookup_context) |
{ |
- unsigned int lookahead_offset = 0; |
+ unsigned int match_length = 0; |
+ unsigned int match_positions[MAX_CONTEXT_LENGTH]; |
return match_input (c, |
inputCount, input, |
lookup_context.funcs.match, lookup_context.match_data[1], |
- &lookahead_offset) |
+ &match_length, match_positions) |
&& match_backtrack (c, |
backtrackCount, backtrack, |
lookup_context.funcs.match, lookup_context.match_data[0]) |
&& match_lookahead (c, |
lookaheadCount, lookahead, |
lookup_context.funcs.match, lookup_context.match_data[2], |
- lookahead_offset) |
+ match_length) |
&& apply_lookup (c, |
- inputCount, input, |
- lookup_context.funcs.match, lookup_context.match_data[1], |
- lookupCount, lookupRecord); |
+ inputCount, match_positions, |
+ lookupCount, lookupRecord, |
+ match_length); |
} |
struct ChainRule |