diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh index 56b3a4f61..2cf90b7b5 100644 --- a/src/hb-ot-layout-gpos-table.hh +++ b/src/hb-ot-layout-gpos-table.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009,2010 Red Hat, Inc. - * Copyright © 2010,2012 Google, Inc. + * Copyright © 2010,2012,2013 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -1429,7 +1429,18 @@ struct PosLookup : Lookup inline const PosLookupSubTable& get_subtable (unsigned int i) const { return this+CastR > (subTable)[i]; } - inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const + inline bool is_reverse (void) const + { + return false; + } + + inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + return TRACE_RETURN (true); + } + + inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); c->set_recurse_func (NULL); @@ -1461,31 +1472,6 @@ struct PosLookup : Lookup static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); - inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const - { - bool ret = false; - - if (unlikely (!c->buffer->len || !c->lookup_mask)) - return false; - - c->set_recurse_func (apply_recurse_func); - c->set_lookup (*this); - - c->buffer->idx = 0; - - while (c->buffer->idx < c->buffer->len) - { - if (digest->may_have (c->buffer->cur().codepoint) && - (c->buffer->cur().mask & c->lookup_mask) && - apply_once (c)) - ret = true; - else - c->buffer->idx++; - } - - return ret; - } - template static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 3b6635bf9..6ab1a2b92 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009,2010 Red Hat, Inc. - * Copyright © 2010,2012 Google, Inc. + * Copyright © 2010,2012,2013 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -37,6 +37,12 @@ namespace OT { struct SingleSubstFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -115,6 +121,12 @@ struct SingleSubstFormat1 struct SingleSubstFormat2 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -251,6 +263,13 @@ struct SingleSubst struct Sequence { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + /* For len==0 we don't do anything, so it's harmless. */ + return TRACE_RETURN (substitute.len <= 1); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -315,6 +334,18 @@ struct Sequence struct MultipleSubstFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + /* Some tools generate MultipleSubst with each substitute having length 1! + * So, check them. */ + unsigned int count = sequence.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+sequence[i]).is_inplace (c)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -440,6 +471,12 @@ typedef ArrayOf AlternateSet; /* Array of alternate GlyphIDs--in struct AlternateSubstFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -760,6 +797,12 @@ struct LigatureSet struct LigatureSubstFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + return TRACE_RETURN (false); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -908,6 +951,12 @@ struct ExtensionSubst : Extension struct ReverseChainSingleSubstFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1145,6 +1194,13 @@ struct SubstLookup : Lookup return lookup_type_is_reverse (type); } + inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + c->set_recurse_func (dispatch_recurse_func); + return TRACE_RETURN (dispatch (c)); + } + inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1152,7 +1208,7 @@ struct SubstLookup : Lookup return TRACE_RETURN (dispatch (c)); } - inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const + inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); c->set_recurse_func (dispatch_recurse_func); @@ -1191,54 +1247,6 @@ struct SubstLookup : Lookup } static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); - inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const - { - bool ret = false; - - if (unlikely (!c->buffer->len || !c->lookup_mask)) - return false; - - c->set_recurse_func (apply_recurse_func); - c->set_lookup (*this); - - if (likely (!is_reverse ())) - { - /* in/out forward substitution */ - c->buffer->clear_output (); - c->buffer->idx = 0; - - while (c->buffer->idx < c->buffer->len) - { - if (digest->may_have (c->buffer->cur().codepoint) && - (c->buffer->cur().mask & c->lookup_mask) && - apply_once (c)) - ret = true; - else - c->buffer->next_glyph (); - } - if (ret) - c->buffer->swap_buffers (); - } - else - { - /* in-place backward substitution */ - c->buffer->remove_output (); - c->buffer->idx = c->buffer->len - 1; - do - { - if (digest->may_have (c->buffer->cur().codepoint) && - (c->buffer->cur().mask & c->lookup_mask) && - apply_once (c)) - ret = true; - else - c->buffer->idx--; - - } - while ((int) c->buffer->idx >= 0); - } - - return ret; - } inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, unsigned int i) diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh index f46b3782e..9fc638b75 100644 --- a/src/hb-ot-layout-gsubgpos-private.hh +++ b/src/hb-ot-layout-gsubgpos-private.hh @@ -44,6 +44,55 @@ namespace OT { ""); + +#ifndef HB_DEBUG_IS_INPLACE +#define HB_DEBUG_IS_INPLACE (HB_DEBUG+0) +#endif + +#define TRACE_IS_INPLACE(this) \ + hb_auto_trace_t trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + ""); + +struct hb_is_inplace_context_t +{ + inline const char *get_name (void) { return "IS_INPLACE"; } + static const unsigned int max_debug_depth = HB_DEBUG_IS_INPLACE; + typedef bool return_t; + typedef return_t (*recurse_func_t) (hb_is_inplace_context_t *c, unsigned int lookup_index); + template + inline return_t dispatch (const T &obj) { return obj.is_inplace (this); } + static return_t default_return_value (void) { return true; } + bool stop_sublookup_iteration (return_t r) const { return !r; } + + return_t recurse (unsigned int lookup_index) + { + if (unlikely (nesting_level_left == 0 || !recurse_func)) + return default_return_value (); + + nesting_level_left--; + bool ret = recurse_func (this, lookup_index); + nesting_level_left++; + return ret; + } + + hb_face_t *face; + recurse_func_t recurse_func; + unsigned int nesting_level_left; + unsigned int debug_depth; + + hb_is_inplace_context_t (hb_face_t *face_, + unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : + face (face_), + recurse_func (NULL), + nesting_level_left (nesting_level_left_), + debug_depth (0) {} + + void set_recurse_func (recurse_func_t func) { recurse_func = func; } +}; + + + #ifndef HB_DEBUG_CLOSURE #define HB_DEBUG_CLOSURE (HB_DEBUG+0) #endif @@ -158,7 +207,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 +327,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 +340,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 (); } @@ -1096,6 +1151,17 @@ static inline bool context_apply_lookup (hb_apply_context_t *c, struct Rule { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + const LookupRecord *lookupRecord = &StructAtOffset (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); + unsigned int count = lookupCount; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookupRecord[i].lookupListIndex)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1155,6 +1221,16 @@ struct Rule struct RuleSet { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if (!(this+rule[i]).is_inplace (c)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1211,6 +1287,16 @@ struct RuleSet struct ContextFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1297,6 +1383,16 @@ struct ContextFormat1 struct ContextFormat2 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1392,6 +1488,17 @@ struct ContextFormat2 struct ContextFormat3 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + const LookupRecord *lookupRecord = &StructAtOffset (coverage, coverage[0].static_size * glyphCount); + unsigned int count = lookupCount; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookupRecord[i].lookupListIndex)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1633,6 +1740,19 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c, struct ChainRule { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + const HeadlessArrayOf &input = StructAfter > (backtrack); + const ArrayOf &lookahead = StructAfter > (input); + const ArrayOf &lookup = StructAfter > (lookahead); + unsigned int count = lookup.len; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookup.array[i].lookupListIndex)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1718,6 +1838,16 @@ struct ChainRule struct ChainRuleSet { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + if (!(this+rule[i]).is_inplace (c)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { TRACE_CLOSURE (this); @@ -1771,6 +1901,16 @@ struct ChainRuleSet struct ChainContextFormat1 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1854,6 +1994,16 @@ struct ChainContextFormat1 struct ChainContextFormat2 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+ruleSet[i]).is_inplace (c)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); @@ -1978,6 +2128,20 @@ struct ChainContextFormat2 struct ChainContextFormat3 { + inline bool is_inplace (hb_is_inplace_context_t *c) const + { + TRACE_IS_INPLACE (this); + const OffsetArrayOf &input = StructAfter > (backtrack); + const OffsetArrayOf &lookahead = StructAfter > (input); + const ArrayOf &lookup = StructAfter > (lookahead); + + unsigned int count = lookup.len; + for (unsigned int i = 0; i < count; i++) + if (!c->recurse (lookup.array[i].lookupListIndex)) + return TRACE_RETURN (false); + return TRACE_RETURN (true); + } + inline void closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 4866c4191..a9de35690 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -202,12 +202,19 @@ HB_INTERNAL void hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer); -HB_INTERNAL hb_bool_t -hb_ot_layout_substitute_lookup (hb_font_t *font, - hb_buffer_t *buffer, - unsigned int lookup_index, - hb_mask_t mask, - hb_bool_t auto_zwj); + +struct hb_ot_layout_lookup_accelerator_t; + +namespace OT { + struct hb_apply_context_t; + struct SubstLookup; +} + +HB_INTERNAL void +hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c, + const OT::SubstLookup &lookup, + const hb_ot_layout_lookup_accelerator_t &accel); + /* Should be called after all the substitute_lookup's are done */ HB_INTERNAL void @@ -220,13 +227,6 @@ HB_INTERNAL void hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer); -HB_INTERNAL hb_bool_t -hb_ot_layout_position_lookup (hb_font_t *font, - hb_buffer_t *buffer, - unsigned int lookup_index, - hb_mask_t mask, - hb_bool_t auto_zwj); - /* Should be called after all the position_lookup's are done */ HB_INTERNAL void hb_ot_layout_position_finish (hb_font_t *font, @@ -244,6 +244,23 @@ namespace OT { struct GPOS; } +struct hb_ot_layout_lookup_accelerator_t +{ + template + inline void init (const TLookup &lookup) + { + digest.init (); + lookup.add_coverage (&digest); + } + + template + inline void fini (const TLookup &lookup) + { + } + + hb_set_digest_t digest; +}; + struct hb_ot_layout_t { hb_blob_t *gdef_blob; @@ -257,8 +274,8 @@ struct hb_ot_layout_t unsigned int gsub_lookup_count; unsigned int gpos_lookup_count; - hb_set_digest_t *gsub_digests; - hb_set_digest_t *gpos_digests; + hb_ot_layout_lookup_accelerator_t *gsub_accels; + hb_ot_layout_lookup_accelerator_t *gpos_accels; }; diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index c80ca7d7f..355f51c92 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -2,7 +2,7 @@ * Copyright © 1998-2004 David Turner and Werner Lemberg * Copyright © 2006 Behdad Esfahbod * Copyright © 2007,2008,2009 Red Hat, Inc. - * Copyright © 2012 Google, Inc. + * Copyright © 2012,2013 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -34,6 +34,8 @@ #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-map-private.hh" + #include #include @@ -59,26 +61,20 @@ _hb_ot_layout_create (hb_face_t *face) layout->gsub_lookup_count = layout->gsub->get_lookup_count (); layout->gpos_lookup_count = layout->gpos->get_lookup_count (); - layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t)); - layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t)); + layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); + layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t)); - if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) || - (layout->gpos_lookup_count && !layout->gpos_digests))) + if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) || + (layout->gpos_lookup_count && !layout->gpos_accels))) { _hb_ot_layout_destroy (layout); return NULL; } for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) - { - layout->gsub_digests[i].init (); - layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]); - } + layout->gsub_accels[i].init (layout->gsub->get_lookup (i)); for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) - { - layout->gpos_digests[i].init (); - layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]); - } + layout->gpos_accels[i].init (layout->gpos->get_lookup (i)); return layout; } @@ -90,8 +86,13 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout) hb_blob_destroy (layout->gsub_blob); hb_blob_destroy (layout->gpos_blob); - free (layout->gsub_digests); - free (layout->gpos_digests); + for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) + layout->gsub_accels[i].fini (layout->gsub->get_lookup (i)); + for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) + layout->gpos_accels[i].fini (layout->gpos->get_lookup (i)); + + free (layout->gsub_accels); + free (layout->gpos_accels); free (layout); } @@ -613,13 +614,13 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, case HB_OT_TAG_GSUB: { const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); - l.collect_glyphs_lookup (&c); + l.collect_glyphs (&c); return; } case HB_OT_TAG_GPOS: { const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index); - l.collect_glyphs_lookup (&c); + l.collect_glyphs (&c); return; } } @@ -659,7 +660,7 @@ hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); - return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]); + return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest); } void @@ -668,22 +669,6 @@ hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) OT::GSUB::substitute_start (font, buffer); } -hb_bool_t -hb_ot_layout_substitute_lookup (hb_font_t *font, - hb_buffer_t *buffer, - unsigned int lookup_index, - hb_mask_t mask, - hb_bool_t auto_zwj) -{ - if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false; - - OT::hb_apply_context_t c (0, font, buffer, mask, auto_zwj); - - const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index); - - return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]); -} - void hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer) { @@ -718,22 +703,6 @@ hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) OT::GPOS::position_start (font, buffer); } -hb_bool_t -hb_ot_layout_position_lookup (hb_font_t *font, - hb_buffer_t *buffer, - unsigned int lookup_index, - hb_mask_t mask, - hb_bool_t auto_zwj) -{ - if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false; - - OT::hb_apply_context_t c (1, font, buffer, mask, auto_zwj); - - const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index); - - return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]); -} - void hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer) { @@ -784,3 +753,158 @@ hb_ot_layout_get_size_params (hb_face_t *face, return false; } + + +/* + * Parts of different types are implemented here such that they have direct + * access to GSUB/GPOS lookups. + */ + + +struct GSUBProxy +{ + static const unsigned int table_index = 0; + typedef OT::SubstLookup Lookup; + + GSUBProxy (hb_face_t *face) : + table (*hb_ot_layout_from_face (face)->gsub), + accels (hb_ot_layout_from_face (face)->gsub_accels) {} + + const OT::GSUB &table; + const hb_ot_layout_lookup_accelerator_t *accels; +}; + +struct GPOSProxy +{ + static const unsigned int table_index = 1; + typedef OT::PosLookup Lookup; + + GPOSProxy (hb_face_t *face) : + table (*hb_ot_layout_from_face (face)->gpos), + accels (hb_ot_layout_from_face (face)->gpos_accels) {} + + const OT::GPOS &table; + const hb_ot_layout_lookup_accelerator_t *accels; +}; + + +template +static inline bool apply_once (OT::hb_apply_context_t *c, + const Lookup &lookup) +{ + if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props)) + return false; + return lookup.dispatch (c); +} + +template +static inline bool +apply_string (OT::hb_apply_context_t *c, + const typename Proxy::Lookup &lookup, + const hb_ot_layout_lookup_accelerator_t &accel) +{ + bool ret = false; + OT::hb_is_inplace_context_t inplace_c (c->face); + bool inplace = lookup.is_inplace (&inplace_c); + + if (unlikely (!c->buffer->len || !c->lookup_mask)) + return false; + + c->set_lookup (lookup); + + if (likely (!lookup.is_reverse ())) + { + /* in/out forward substitution/positioning */ + if (Proxy::table_index == 0) + c->buffer->clear_output (); + c->buffer->idx = 0; + + while (c->buffer->idx < c->buffer->len) + { + if (accel.digest.may_have (c->buffer->cur().codepoint) && + (c->buffer->cur().mask & c->lookup_mask) && + apply_once (c, lookup)) + ret = true; + else + c->buffer->next_glyph (); + } + if (ret) + { + if (!inplace) + c->buffer->swap_buffers (); + else + assert (!c->buffer->has_separate_output ()); + } + } + else + { + /* in-place backward substitution/positioning */ + if (Proxy::table_index == 0) + c->buffer->remove_output (); + c->buffer->idx = c->buffer->len - 1; + do + { + if (accel.digest.may_have (c->buffer->cur().codepoint) && + (c->buffer->cur().mask & c->lookup_mask) && + apply_once (c, lookup)) + ret = true; + else + c->buffer->idx--; + + } + while ((int) c->buffer->idx >= 0); + } + + return ret; +} + +template +inline void hb_ot_map_t::apply (const Proxy &proxy, + const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) const +{ + const unsigned int table_index = proxy.table_index; + unsigned int i = 0; + OT::hb_apply_context_t c (table_index, font, buffer); + c.set_recurse_func (Proxy::Lookup::apply_recurse_func); + + for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) { + const stage_map_t *stage = &stages[table_index][stage_index]; + for (; i < stage->last_lookup; i++) + { + unsigned int lookup_index = lookups[table_index][i].index; + c.set_lookup_mask (lookups[table_index][i].mask); + c.set_auto_zwj (lookups[table_index][i].auto_zwj); + apply_string (&c, + proxy.table.get_lookup (lookup_index), + proxy.accels[lookup_index]); + } + + if (stage->pause_func) + { + buffer->clear_output (); + stage->pause_func (plan, font, buffer); + } + } +} + +void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const +{ + GSUBProxy proxy (font->face); + apply (proxy, plan, font, buffer); +} + +void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const +{ + GPOSProxy proxy (font->face); + apply (proxy, plan, font, buffer); +} + +HB_INTERNAL void +hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c, + const OT::SubstLookup &lookup, + const hb_ot_layout_lookup_accelerator_t &accel) +{ + apply_string (c, lookup, accel); +} diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh index 5ed54a6ca..0e718a6f1 100644 --- a/src/hb-ot-map-private.hh +++ b/src/hb-ot-map-private.hh @@ -118,10 +118,9 @@ struct hb_ot_map_t } HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const; - HB_INTERNAL inline void apply (unsigned int table_index, - const struct hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) const; + template + HB_INTERNAL inline void apply (const Proxy &proxy, + const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc index dd26afc8e..43856fa37 100644 --- a/src/hb-ot-map.cc +++ b/src/hb-ot-map.cc @@ -102,49 +102,6 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, info->stage[1] = current_stage[1]; } -inline void hb_ot_map_t::apply (unsigned int table_index, - const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) const -{ - unsigned int i = 0; - - for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) { - const stage_map_t *stage = &stages[table_index][stage_index]; - for (; i < stage->last_lookup; i++) - switch (table_index) - { - case 0: - hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, - lookups[table_index][i].mask, - lookups[table_index][i].auto_zwj); - break; - - case 1: - hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, - lookups[table_index][i].mask, - lookups[table_index][i].auto_zwj); - break; - } - - if (stage->pause_func) - { - buffer->clear_output (); - stage->pause_func (plan, font, buffer); - } - } -} - -void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const -{ - apply (0, plan, font, buffer); -} - -void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const -{ - apply (1, plan, font, buffer); -} - void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const { diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh index 996e40e8d..6b2b87e3f 100644 --- a/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/src/hb-ot-shape-complex-arabic-fallback.hh @@ -199,7 +199,7 @@ struct arabic_fallback_plan_t hb_mask_t mask_array[ARABIC_NUM_FALLBACK_FEATURES]; OT::SubstLookup *lookup_array[ARABIC_NUM_FALLBACK_FEATURES]; - hb_set_digest_t digest_array[ARABIC_NUM_FALLBACK_FEATURES]; + hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_NUM_FALLBACK_FEATURES]; }; static const arabic_fallback_plan_t arabic_fallback_plan_nil = {}; @@ -214,12 +214,11 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) { - fallback_plan->digest_array[i].init (); fallback_plan->mask_array[i] = plan->map.get_1_mask (arabic_fallback_features[i]); if (fallback_plan->mask_array[i]) { fallback_plan->lookup_array[i] = arabic_fallback_synthesize_lookup (plan, font, i); if (fallback_plan->lookup_array[i]) - fallback_plan->lookup_array[i]->add_coverage (&fallback_plan->digest_array[i]); + fallback_plan->accel_array[i].init (*fallback_plan->lookup_array[i]); } } @@ -234,7 +233,10 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan) for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) if (fallback_plan->lookup_array[i]) + { + fallback_plan->accel_array[i].fini (fallback_plan->lookup_array[i]); free (fallback_plan->lookup_array[i]); + } free (fallback_plan); } @@ -244,10 +246,13 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, hb_font_t *font, hb_buffer_t *buffer) { + OT::hb_apply_context_t c (0, font, buffer); for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) if (fallback_plan->lookup_array[i]) { - OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i], true/*auto_zwj*/); - fallback_plan->lookup_array[i]->apply_string (&c, &fallback_plan->digest_array[i]); + c.set_lookup_mask (fallback_plan->mask_array[i]); + hb_ot_layout_substitute_lookup (&c, + *fallback_plan->lookup_array[i], + fallback_plan->accel_array[i]); } } diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc index 334182544..284d030d5 100644 --- a/src/hb-ot-shape-fallback.cc +++ b/src/hb-ot-shape-fallback.cc @@ -420,7 +420,8 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ? HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n')); - OT::hb_apply_context_t c (1, font, buffer, kern_mask, true/*auto_zwj*/); + OT::hb_apply_context_t c (1, font, buffer); + c.set_lookup_mask (kern_mask); c.set_lookup_props (OT::LookupFlag::IgnoreMarks); for (buffer->idx = 0; buffer->idx < count;)