From 66bf7ce4e3135535c110a917178b84c4a2b1d11f Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 17 May 2009 08:28:42 -0400 Subject: [PATCH] [HB] Move Context matching logic out of GSUB --- src/hb-ot-layout-gdef-private.h | 2 - src/hb-ot-layout-gsub-private.h | 331 +--------------------------------- src/hb-ot-layout-gsubgpos-private.h | 347 ++++++++++++++++++++++++++++++++++++ 3 files changed, 352 insertions(+), 328 deletions(-) create mode 100644 src/hb-ot-layout-gsubgpos-private.h diff --git a/src/hb-ot-layout-gdef-private.h b/src/hb-ot-layout-gdef-private.h index 1b811dd..36471a8 100644 --- a/src/hb-ot-layout-gdef-private.h +++ b/src/hb-ot-layout-gdef-private.h @@ -27,8 +27,6 @@ #ifndef HB_OT_LAYOUT_GDEF_PRIVATE_H #define HB_OT_LAYOUT_GDEF_PRIVATE_H -#include "hb-ot-layout-private.h" - #include "hb-ot-layout-open-private.h" diff --git a/src/hb-ot-layout-gsub-private.h b/src/hb-ot-layout-gsub-private.h index 5a8895e..6dff78b 100644 --- a/src/hb-ot-layout-gsub-private.h +++ b/src/hb-ot-layout-gsub-private.h @@ -27,25 +27,7 @@ #ifndef HB_OT_LAYOUT_GSUB_PRIVATE_H #define HB_OT_LAYOUT_GSUB_PRIVATE_H -#include "hb-ot-layout-private.h" - -#include "hb-ot-layout-open-private.h" -#include "hb-ot-layout-gdef-private.h" - -#include "harfbuzz-buffer-private.h" /* XXX */ - -#define LOOKUP_ARGS_DEF \ - hb_ot_layout_t *layout, \ - hb_buffer_t *buffer, \ - unsigned int context_length HB_GNUC_UNUSED, \ - unsigned int nesting_level_left HB_GNUC_UNUSED, \ - unsigned int lookup_flag -#define LOOKUP_ARGS \ - layout, \ - buffer, \ - context_length, \ - nesting_level_left, \ - lookup_flag +#include "hb-ot-layout-gsubgpos-private.h" struct SingleSubstFormat1 { @@ -482,317 +464,15 @@ struct LigatureSubst { DEFINE_NULL (LigatureSubst, 2); -typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, char *data); -typedef bool (*apply_lookup_func_t) (LOOKUP_ARGS_DEF, unsigned int lookup_index); -struct ContextLookupContext { - inline bool match (hb_codepoint_t glyph_id, const USHORT &value) const { - return match_func (glyph_id, value, match_data); - } - inline bool apply (LOOKUP_ARGS_DEF, unsigned int lookup_index) const { - return apply_func (LOOKUP_ARGS, lookup_index); - } - - match_func_t match_func; - char *match_data; - apply_lookup_func_t apply_func; -}; - -struct LookupRecord { - - inline bool apply (LOOKUP_ARGS_DEF, ContextLookupContext &context) const { - return context.apply (LOOKUP_ARGS, lookupListIndex); - } - - USHORT sequenceIndex; /* Index into current glyph - * sequence--first glyph = 0 */ - USHORT lookupListIndex; /* Lookup to apply to that - * position--zero--based */ -}; -ASSERT_SIZE (LookupRecord, 4); - -static inline bool context_lookup (LOOKUP_ARGS_DEF, - USHORT glyphCount, /* Including the first glyph (not matched) */ - USHORT recordCount, - const USHORT value[], /* Array of match values--start with second glyph */ - const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ - ContextLookupContext &context) { - - unsigned int i, j; - unsigned int property; - unsigned int count = glyphCount; - - if (HB_UNLIKELY (buffer->in_pos + count > buffer->in_length || - context_length < count)) - return false; /* Not enough glyphs in input or context */ - - /* XXX context_length should also be checked when skipping glyphs, right? - * What does context_length really mean, anyway? */ - - for (i = 1, j = buffer->in_pos + 1; i < count; i++, j++) { - while (!_hb_ot_layout_check_glyph_property (layout, IN_ITEM (j), lookup_flag, &property)) { - if (HB_UNLIKELY (j + count - i == buffer->in_length)) - return false; - j++; - } - - if (HB_LIKELY (context.match (IN_GLYPH(j), value[i - 1]))) - return false; - } - - /* XXX right? or j - buffer_inpos? */ - context_length = count; - - unsigned int record_count = recordCount; - const LookupRecord *record = lookupRecord; - for (i = 0; i < count;) - { - if ( record_count && i == record->sequenceIndex ) - { - unsigned int old_pos = buffer->in_pos; - - /* Apply a lookup */ - bool done = record->apply (LOOKUP_ARGS, context); - - record++; - record_count--; - i += buffer->in_pos - old_pos; +static inline bool substitute_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index); - if (!done) - goto not_applied; - } - else - { - not_applied: - /* No lookup applied for this index */ - _hb_buffer_next_glyph (buffer); - i++; - } - } - - return true; -} -struct Rule { - - friend struct RuleSet; - - private: - DEFINE_ARRAY_TYPE (USHORT, value, (glyphCount ? glyphCount - 1 : 0)); - - bool apply (LOOKUP_ARGS_DEF, ContextLookupContext &context) const { - const LookupRecord *record = (const LookupRecord *) ((const char *) value + sizeof (value[0]) * (glyphCount - 1)); - return context_lookup (LOOKUP_ARGS, - glyphCount, - recordCount, - value, - record, - context); - } +struct ContextSubst : Context { - private: - USHORT glyphCount; /* Total number of glyphs in input - * glyph sequence--includes the first - * glyph */ - USHORT recordCount; /* Number of LookupRecords */ - USHORT value[]; /* Array of match values--start with - * second glyph */ - LookupRecord lookupRecord[]; /* Array of LookupRecords--in - * design order */ -}; -ASSERT_SIZE (Rule, 4); - -struct RuleSet { - - bool apply (LOOKUP_ARGS_DEF, ContextLookupContext &context) const { - - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) { - if ((this+rule[i]).apply (LOOKUP_ARGS, context)) - return true; - } - - return false; - } - - private: - OffsetArrayOf - rule; /* Array SubRule tables - * ordered by preference */ -}; - -static inline bool substitute_one_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index); - -static inline bool glyph_match (hb_codepoint_t glyph_id, const USHORT &value, char *data) { - return glyph_id == value; -} - -struct SubRuleSet : RuleSet { inline bool substitute (LOOKUP_ARGS_DEF) const { - struct ContextLookupContext context = { - glyph_match, NULL, - substitute_one_lookup - }; - return apply (LOOKUP_ARGS, context); + return this->apply (LOOKUP_ARGS, substitute_lookup); } }; -ASSERT_SIZE (SubRuleSet, 2); - -struct ContextSubstFormat1 { - - friend struct ContextSubst; - - private: - - inline bool substitute (LOOKUP_ARGS_DEF) const { - - unsigned int property; - if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property)) - return false; - - unsigned int index = (this+coverage) (IN_CURGLYPH ()); - const SubRuleSet &rule_set = this+subRuleSet[index]; - return rule_set.substitute (LOOKUP_ARGS); - } - - private: - USHORT substFormat; /* Format identifier--format = 1 */ - OffsetTo - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - OffsetArrayOf - subRuleSet; /* Array of SubRuleSet tables - * ordered by Coverage Index */ -}; -ASSERT_SIZE (ContextSubstFormat1, 6); - -static inline bool class_match (hb_codepoint_t glyph_id, const USHORT &value, char *data) { - const ClassDef &class_def = * (const ClassDef *) data; - return class_def.get_class (glyph_id) == value; -} - -struct SubClassSet : RuleSet { - inline bool substitute_class (LOOKUP_ARGS_DEF, const ClassDef &class_def) const { - /* LONGTERMTODO: Old code fetches glyph classes at most once and caches - * them across subrule lookups. Not sure it's worth it. - */ - struct ContextLookupContext context = { - class_match, (char *) &class_def, - substitute_one_lookup - }; - return apply (LOOKUP_ARGS, context); - } -}; -ASSERT_SIZE (SubClassSet, 2); - - -struct ContextSubstFormat2 { - - friend struct ContextSubst; - - private: - - inline bool substitute (LOOKUP_ARGS_DEF) const { - - unsigned int property; - if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property)) - return false; - - unsigned int index = (this+coverage) (IN_CURGLYPH ()); - const SubClassSet &class_set = this+subClassSet[index]; - return class_set.substitute_class (LOOKUP_ARGS, this+classDef); - } - - private: - USHORT substFormat; /* Format identifier--format = 2 */ - OffsetTo - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - OffsetTo - classDef; /* Offset to glyph ClassDef table--from - * beginning of Substitution table */ - OffsetArrayOf - subClassSet; /* Array of SubClassSet tables - * ordered by class */ -}; -ASSERT_SIZE (ContextSubstFormat2, 8); - -static inline bool coverage_match (hb_codepoint_t glyph_id, const USHORT &value, char *data) { - const OffsetTo &coverage = * (const OffsetTo *) &value; - return (data+coverage) (glyph_id) != NOT_COVERED; -} - -struct ContextSubstFormat3 { - - friend struct ContextSubst; - - private: - - /* Coverage tables, in glyph sequence order */ - DEFINE_OFFSET_ARRAY_TYPE (Coverage, coverage, glyphCount); - - inline bool substitute_coverage (LOOKUP_ARGS_DEF) const { - struct ContextLookupContext context = { - coverage_match, (char *) this, - substitute_one_lookup - }; - const LookupRecord *record = (const LookupRecord *) ((const char *) coverage + sizeof (coverage[0]) * glyphCount); - return context_lookup (LOOKUP_ARGS, - glyphCount, - recordCount, - (const USHORT *) (coverage + 1), - record, - context); - } - - inline bool substitute (LOOKUP_ARGS_DEF) const { - - unsigned int property; - if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property)) - return false; - - if ((*this)[0].get_coverage (IN_CURGLYPH () == NOT_COVERED)) - return false; - - return substitute_coverage (LOOKUP_ARGS); - } - - private: - USHORT substFormat; /* Format identifier--format = 3 */ - USHORT glyphCount; /* Number of glyphs in the input glyph - * sequence */ - USHORT recordCount; /* Number of LookupRecords */ - Offset coverage[]; /* Array of offsets to Coverage - * table--from beginning of - * Substitution table--in glyph - * sequence order */ - LookupRecord lookupRecord[]; /* Array of LookupRecords--in - * design order */ -}; -ASSERT_SIZE (ContextSubstFormat3, 6); - -struct ContextSubst { - - friend struct SubstLookupSubTable; - - private: - - inline bool substitute (LOOKUP_ARGS_DEF) const { - switch (u.substFormat) { - case 1: return u.format1.substitute (LOOKUP_ARGS); - case 2: return u.format2.substitute (LOOKUP_ARGS); - case 3: return u.format3.substitute (LOOKUP_ARGS); - default:return false; - } - } - - private: - union { - USHORT substFormat; /* Format identifier */ - ContextSubstFormat1 format1; - ContextSubstFormat2 format2; - ContextSubstFormat3 format3; - } u; -}; DEFINE_NULL (ContextSubst, 2); @@ -1237,7 +917,7 @@ inline bool ExtensionSubstFormat1::substitute (LOOKUP_ARGS_DEF) const { get_type ()); } -static inline bool substitute_one_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index) { +static inline bool substitute_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index) { const GSUB &gsub = *(layout->gsub); const SubstLookup &l = gsub.get_lookup (lookup_index); @@ -1245,5 +925,4 @@ static inline bool substitute_one_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_i } - #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */ diff --git a/src/hb-ot-layout-gsubgpos-private.h b/src/hb-ot-layout-gsubgpos-private.h new file mode 100644 index 0000000..e3060c0 --- /dev/null +++ b/src/hb-ot-layout-gsubgpos-private.h @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * + * This is part of HarfBuzz, an OpenType Layout engine library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_H +#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_H + +#include "hb-ot-layout-gdef-private.h" +#include "harfbuzz-buffer-private.h" /* XXX */ + +#define LOOKUP_ARGS_DEF \ + hb_ot_layout_t *layout, \ + hb_buffer_t *buffer, \ + unsigned int context_length HB_GNUC_UNUSED, \ + unsigned int nesting_level_left HB_GNUC_UNUSED, \ + unsigned int lookup_flag +#define LOOKUP_ARGS \ + layout, \ + buffer, \ + context_length, \ + nesting_level_left, \ + lookup_flag + + +/* Context lookups */ + +typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, char *data); +typedef bool (*apply_lookup_func_t) (LOOKUP_ARGS_DEF, unsigned int lookup_index); + +struct ContextLookupContext { + inline bool match (hb_codepoint_t glyph_id, const USHORT &value) const { + return match_func (glyph_id, value, match_data); + } + inline bool apply (LOOKUP_ARGS_DEF, unsigned int lookup_index) const { + return apply_func (LOOKUP_ARGS, lookup_index); + } + + match_func_t match_func; + char *match_data; + apply_lookup_func_t apply_func; +}; + +struct LookupRecord { + + inline bool apply (LOOKUP_ARGS_DEF, ContextLookupContext &context) const { + return context.apply (LOOKUP_ARGS, lookupListIndex); + } + + USHORT sequenceIndex; /* Index into current glyph + * sequence--first glyph = 0 */ + USHORT lookupListIndex; /* Lookup to apply to that + * position--zero--based */ +}; +ASSERT_SIZE (LookupRecord, 4); + +static inline bool context_lookup (LOOKUP_ARGS_DEF, + USHORT glyphCount, /* Including the first glyph (not matched) */ + USHORT recordCount, + const USHORT value[], /* Array of match values--start with second glyph */ + const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ + ContextLookupContext &context) { + + unsigned int i, j; + unsigned int property; + unsigned int count = glyphCount; + + if (HB_UNLIKELY (buffer->in_pos + count > buffer->in_length || + context_length < count)) + return false; /* Not enough glyphs in input or context */ + + /* XXX context_length should also be checked when skipping glyphs, right? + * What does context_length really mean, anyway? */ + + for (i = 1, j = buffer->in_pos + 1; i < count; i++, j++) { + while (!_hb_ot_layout_check_glyph_property (layout, IN_ITEM (j), lookup_flag, &property)) { + if (HB_UNLIKELY (j + count - i == buffer->in_length)) + return false; + j++; + } + + if (HB_LIKELY (context.match (IN_GLYPH(j), value[i - 1]))) + return false; + } + + /* XXX right? or j - buffer_inpos? */ + context_length = count; + + /* XXX We have to jump non-matching glyphs when applying too, right? */ + unsigned int record_count = recordCount; + const LookupRecord *record = lookupRecord; + for (i = 0; i < count;) + { + if ( record_count && i == record->sequenceIndex ) + { + unsigned int old_pos = buffer->in_pos; + + /* Apply a lookup */ + bool done = record->apply (LOOKUP_ARGS, context); + + record++; + record_count--; + i += buffer->in_pos - old_pos; + + if (!done) + goto not_applied; + } + else + { + not_applied: + /* No lookup applied for this index */ + _hb_buffer_next_glyph (buffer); + i++; + } + } + + return true; +} +struct Rule { + + friend struct RuleSet; + + private: + DEFINE_ARRAY_TYPE (USHORT, value, (glyphCount ? glyphCount - 1 : 0)); + + inline bool apply (LOOKUP_ARGS_DEF, ContextLookupContext &context) const { + const LookupRecord *record = (const LookupRecord *) ((const char *) value + sizeof (value[0]) * (glyphCount - 1)); + return context_lookup (LOOKUP_ARGS, + glyphCount, + recordCount, + value, + record, + context); + } + + private: + USHORT glyphCount; /* Total number of glyphs in input + * glyph sequence--includes the first + * glyph */ + USHORT recordCount; /* Number of LookupRecords */ + USHORT value[]; /* Array of match values--start with + * second glyph */ + LookupRecord lookupRecord[]; /* Array of LookupRecords--in + * design order */ +}; +ASSERT_SIZE (Rule, 4); + +struct RuleSet { + + inline bool apply (LOOKUP_ARGS_DEF, ContextLookupContext &context) const { + + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) { + if ((this+rule[i]).apply (LOOKUP_ARGS, context)) + return true; + } + + return false; + } + + private: + OffsetArrayOf + rule; /* Array SubRule tables + * ordered by preference */ +}; + + +static inline bool glyph_match (hb_codepoint_t glyph_id, const USHORT &value, char *data) { + return glyph_id == value; +} + +struct ContextFormat1 { + + friend struct Context; + + private: + + inline bool apply (LOOKUP_ARGS_DEF, apply_lookup_func_t apply_func) const { + + unsigned int property; + if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property)) + return false; + + unsigned int index = (this+coverage) (IN_CURGLYPH ()); + const RuleSet &rule_set = this+ruleSet[index]; + struct ContextLookupContext context = { + glyph_match, NULL, + apply_func + }; + return rule_set.apply (LOOKUP_ARGS, context); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + OffsetTo + coverage; /* Offset to Coverage table--from + * beginning of table */ + OffsetArrayOf + ruleSet; /* Array of RuleSet tables + * ordered by Coverage Index */ +}; +ASSERT_SIZE (ContextFormat1, 6); + + +static inline bool class_match (hb_codepoint_t glyph_id, const USHORT &value, char *data) { + const ClassDef &class_def = * (const ClassDef *) data; + return class_def.get_class (glyph_id) == value; +} + +struct ContextFormat2 { + + friend struct Context; + + private: + + inline bool apply (LOOKUP_ARGS_DEF, apply_lookup_func_t apply_func) const { + + unsigned int property; + if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property)) + return false; + + unsigned int index = (this+coverage) (IN_CURGLYPH ()); + const RuleSet &rule_set = this+ruleSet[index]; + /* LONGTERMTODO: Old code fetches glyph classes at most once and caches + * them across subrule lookups. Not sure it's worth it. + */ + struct ContextLookupContext context = { + class_match, (char *) &(this+classDef), + apply_func + }; + return rule_set.apply (LOOKUP_ARGS, context); + } + + private: + USHORT format; /* Format identifier--format = 2 */ + OffsetTo + coverage; /* Offset to Coverage table--from + * beginning of table */ + OffsetTo + classDef; /* Offset to glyph ClassDef table--from + * beginning of table */ + OffsetArrayOf + ruleSet; /* Array of RuleSet tables + * ordered by class */ +}; +ASSERT_SIZE (ContextFormat2, 8); + + +static inline bool coverage_match (hb_codepoint_t glyph_id, const USHORT &value, char *data) { + const OffsetTo &coverage = * (const OffsetTo *) &value; + return (data+coverage) (glyph_id) != NOT_COVERED; +} + +struct ContextFormat3 { + + friend struct Context; + + private: + + /* Coverage tables, in glyph sequence order */ + DEFINE_OFFSET_ARRAY_TYPE (Coverage, coverage, glyphCount); + + inline bool apply_coverage (LOOKUP_ARGS_DEF, apply_lookup_func_t apply_func) const { + const LookupRecord *record = (const LookupRecord *) ((const char *) coverage + sizeof (coverage[0]) * glyphCount); + struct ContextLookupContext context = { + coverage_match, (char *) this, + apply_func + }; + return context_lookup (LOOKUP_ARGS, + glyphCount, + recordCount, + (const USHORT *) (coverage + 1), + record, + context); + } + + inline bool apply (LOOKUP_ARGS_DEF, apply_lookup_func_t apply_func) const { + + unsigned int property; + if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property)) + return false; + + if ((*this)[0].get_coverage (IN_CURGLYPH () == NOT_COVERED)) + return false; + + return apply_coverage (LOOKUP_ARGS, apply_func); + } + + private: + USHORT format; /* Format identifier--format = 3 */ + USHORT glyphCount; /* Number of glyphs in the input glyph + * sequence */ + USHORT recordCount; /* Number of LookupRecords */ + Offset coverage[]; /* Array of offsets to Coverage + * table--from beginning of + * table--in glyph + * sequence order */ + LookupRecord lookupRecord[]; /* Array of LookupRecords--in + * design order */ +}; +ASSERT_SIZE (ContextFormat3, 6); + +struct Context { + + protected: + bool apply (LOOKUP_ARGS_DEF, apply_lookup_func_t apply_func) const { + switch (u.format) { + case 1: return u.format1.apply (LOOKUP_ARGS, apply_func); + case 2: return u.format2.apply (LOOKUP_ARGS, apply_func); + case 3: return u.format3.apply (LOOKUP_ARGS, apply_func); + default:return false; + } + } + + private: + union { + USHORT format; /* Format identifier */ + ContextFormat1 format1; + ContextFormat2 format2; + ContextFormat3 format3; + } u; +}; +DEFINE_NULL (Context, 2); + + +#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_H */ -- 2.7.4