Index: third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh |
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9ff5ca975b666d054edd1a1dc9d10a6989d4fc63 |
--- /dev/null |
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh |
@@ -0,0 +1,604 @@ |
+/* |
+ * Copyright (C) 2007,2008,2009 Red Hat, Inc. |
+ * Copyright (C) 2010 Google, Inc. |
+ * |
+ * This is part of HarfBuzz, a text shaping 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 |
+ * Google Author(s): Behdad Esfahbod |
+ */ |
+ |
+#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH |
+#define HB_OT_LAYOUT_COMMON_PRIVATE_HH |
+ |
+#include "hb-ot-layout-private.hh" |
+ |
+#include "hb-open-type-private.hh" |
+ |
+ |
+#define NO_CONTEXT ((unsigned int) 0x110000) |
+#define NOT_COVERED ((unsigned int) 0x110000) |
+#define MAX_NESTING_LEVEL 8 |
+ |
+HB_BEGIN_DECLS |
+HB_END_DECLS |
+ |
+ |
+/* |
+ * |
+ * OpenType Layout Common Table Formats |
+ * |
+ */ |
+ |
+ |
+/* |
+ * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList |
+ */ |
+ |
+template <typename Type> |
+struct Record |
+{ |
+ inline int cmp (hb_tag_t a) const { |
+ return tag.cmp (a); |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) { |
+ TRACE_SANITIZE (); |
+ return c->check_struct (this) |
+ && offset.sanitize (c, base); |
+ } |
+ |
+ Tag tag; /* 4-byte Tag identifier */ |
+ OffsetTo<Type> |
+ offset; /* Offset from beginning of object holding |
+ * the Record */ |
+ public: |
+ DEFINE_SIZE_STATIC (6); |
+}; |
+ |
+template <typename Type> |
+struct RecordArrayOf : SortedArrayOf<Record<Type> > { |
+ inline const Tag& get_tag (unsigned int i) const |
+ { |
+ /* We cheat slightly and don't define separate Null objects |
+ * for Record types. Instead, we return the correct Null(Tag) |
+ * here. */ |
+ if (unlikely (i >= this->len)) return Null(Tag); |
+ return (*this)[i].tag; |
+ } |
+ inline unsigned int get_tags (unsigned int start_offset, |
+ unsigned int *record_count /* IN/OUT */, |
+ hb_tag_t *record_tags /* OUT */) const |
+ { |
+ if (record_count) { |
+ const Record<Type> *array = this->sub_array (start_offset, record_count); |
+ unsigned int count = *record_count; |
+ for (unsigned int i = 0; i < count; i++) |
+ record_tags[i] = array[i].tag; |
+ } |
+ return this->len; |
+ } |
+ inline bool find_index (hb_tag_t tag, unsigned int *index) const |
+ { |
+ int i = this->search (tag); |
+ if (i != -1) { |
+ if (index) *index = i; |
+ return true; |
+ } else { |
+ if (index) *index = Index::NOT_FOUND_INDEX; |
+ return false; |
+ } |
+ } |
+}; |
+ |
+template <typename Type> |
+struct RecordListOf : RecordArrayOf<Type> |
+{ |
+ inline const Type& operator [] (unsigned int i) const |
+ { return this+RecordArrayOf<Type>::operator [](i).offset; } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return RecordArrayOf<Type>::sanitize (c, this); |
+ } |
+}; |
+ |
+ |
+struct RangeRecord |
+{ |
+ inline int cmp (hb_codepoint_t g) const { |
+ hb_codepoint_t a = start, b = end; |
+ return g < a ? -1 : g <= b ? 0 : +1 ; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return c->check_struct (this); |
+ } |
+ |
+ GlyphID start; /* First GlyphID in the range */ |
+ GlyphID end; /* Last GlyphID in the range */ |
+ USHORT value; /* Value */ |
+ public: |
+ DEFINE_SIZE_STATIC (6); |
+}; |
+DEFINE_NULL_DATA (RangeRecord, "\000\001"); |
+ |
+ |
+struct IndexArray : ArrayOf<Index> |
+{ |
+ inline unsigned int get_indexes (unsigned int start_offset, |
+ unsigned int *_count /* IN/OUT */, |
+ unsigned int *_indexes /* OUT */) const |
+ { |
+ if (_count) { |
+ const USHORT *array = this->sub_array (start_offset, _count); |
+ unsigned int count = *_count; |
+ for (unsigned int i = 0; i < count; i++) |
+ _indexes[i] = array[i]; |
+ } |
+ return this->len; |
+ } |
+}; |
+ |
+ |
+struct Script; |
+struct LangSys; |
+struct Feature; |
+ |
+ |
+struct LangSys |
+{ |
+ inline unsigned int get_feature_count (void) const |
+ { return featureIndex.len; } |
+ inline hb_tag_t get_feature_index (unsigned int i) const |
+ { return featureIndex[i]; } |
+ inline unsigned int get_feature_indexes (unsigned int start_offset, |
+ unsigned int *feature_count /* IN/OUT */, |
+ unsigned int *feature_indexes /* OUT */) const |
+ { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } |
+ |
+ inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; } |
+ inline unsigned int get_required_feature_index (void) const |
+ { |
+ if (reqFeatureIndex == 0xffff) |
+ return Index::NOT_FOUND_INDEX; |
+ return reqFeatureIndex;; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return c->check_struct (this) |
+ && featureIndex.sanitize (c); |
+ } |
+ |
+ Offset lookupOrder; /* = Null (reserved for an offset to a |
+ * reordering table) */ |
+ USHORT reqFeatureIndex;/* Index of a feature required for this |
+ * language system--if no required features |
+ * = 0xFFFF */ |
+ IndexArray featureIndex; /* Array of indices into the FeatureList */ |
+ public: |
+ DEFINE_SIZE_ARRAY (6, featureIndex); |
+}; |
+DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); |
+ |
+ |
+struct Script |
+{ |
+ inline unsigned int get_lang_sys_count (void) const |
+ { return langSys.len; } |
+ inline const Tag& get_lang_sys_tag (unsigned int i) const |
+ { return langSys.get_tag (i); } |
+ inline unsigned int get_lang_sys_tags (unsigned int start_offset, |
+ unsigned int *lang_sys_count /* IN/OUT */, |
+ hb_tag_t *lang_sys_tags /* OUT */) const |
+ { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } |
+ inline const LangSys& get_lang_sys (unsigned int i) const |
+ { |
+ if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); |
+ return this+langSys[i].offset; |
+ } |
+ inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const |
+ { return langSys.find_index (tag, index); } |
+ |
+ inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } |
+ inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return defaultLangSys.sanitize (c, this) |
+ && langSys.sanitize (c, this); |
+ } |
+ |
+ private: |
+ OffsetTo<LangSys> |
+ defaultLangSys; /* Offset to DefaultLangSys table--from |
+ * beginning of Script table--may be Null */ |
+ RecordArrayOf<LangSys> |
+ langSys; /* Array of LangSysRecords--listed |
+ * alphabetically by LangSysTag */ |
+ public: |
+ DEFINE_SIZE_ARRAY (4, langSys); |
+}; |
+ |
+typedef RecordListOf<Script> ScriptList; |
+ |
+ |
+struct Feature |
+{ |
+ inline unsigned int get_lookup_count (void) const |
+ { return lookupIndex.len; } |
+ inline hb_tag_t get_lookup_index (unsigned int i) const |
+ { return lookupIndex[i]; } |
+ inline unsigned int get_lookup_indexes (unsigned int start_index, |
+ unsigned int *lookup_count /* IN/OUT */, |
+ unsigned int *lookup_tags /* OUT */) const |
+ { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return c->check_struct (this) |
+ && lookupIndex.sanitize (c); |
+ } |
+ |
+ Offset featureParams; /* Offset to Feature Parameters table (if one |
+ * has been defined for the feature), relative |
+ * to the beginning of the Feature Table; = Null |
+ * if not required */ |
+ IndexArray lookupIndex; /* Array of LookupList indices */ |
+ public: |
+ DEFINE_SIZE_ARRAY (4, lookupIndex); |
+}; |
+ |
+typedef RecordListOf<Feature> FeatureList; |
+ |
+ |
+struct LookupFlag : USHORT |
+{ |
+ enum { |
+ RightToLeft = 0x0001u, |
+ IgnoreBaseGlyphs = 0x0002u, |
+ IgnoreLigatures = 0x0004u, |
+ IgnoreMarks = 0x0008u, |
+ IgnoreFlags = 0x000Eu, |
+ UseMarkFilteringSet = 0x0010u, |
+ Reserved = 0x00E0u, |
+ MarkAttachmentType = 0xFF00u |
+ }; |
+ public: |
+ DEFINE_SIZE_STATIC (2); |
+}; |
+ |
+struct Lookup |
+{ |
+ inline unsigned int get_subtable_count (void) const { return subTable.len; } |
+ |
+ inline unsigned int get_type (void) const { return lookupType; } |
+ |
+ /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and |
+ * higher 16-bit is mark-filtering-set if the lookup uses one. |
+ * Not to be confused with glyph_props which is very similar. */ |
+ inline uint32_t get_props (void) const |
+ { |
+ unsigned int flag = lookupFlag; |
+ if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) |
+ { |
+ const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
+ flag += (markFilteringSet << 16); |
+ } |
+ return flag; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ /* Real sanitize of the subtables is done by GSUB/GPOS/... */ |
+ if (!(c->check_struct (this) |
+ && subTable.sanitize (c))) return false; |
+ if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet)) |
+ { |
+ USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
+ if (!markFilteringSet.sanitize (c)) return false; |
+ } |
+ return true; |
+ } |
+ |
+ USHORT lookupType; /* Different enumerations for GSUB and GPOS */ |
+ USHORT lookupFlag; /* Lookup qualifiers */ |
+ ArrayOf<Offset> |
+ subTable; /* Array of SubTables */ |
+ USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets |
+ * structure. This field is only present if bit |
+ * UseMarkFilteringSet of lookup flags is set. */ |
+ public: |
+ DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX); |
+}; |
+ |
+typedef OffsetListOf<Lookup> LookupList; |
+ |
+ |
+/* |
+ * Coverage Table |
+ */ |
+ |
+struct CoverageFormat1 |
+{ |
+ friend struct Coverage; |
+ |
+ private: |
+ inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
+ { |
+ int i = glyphArray.search (glyph_id); |
+ if (i != -1) |
+ return i; |
+ return NOT_COVERED; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return glyphArray.sanitize (c); |
+ } |
+ |
+ private: |
+ USHORT coverageFormat; /* Format identifier--format = 1 */ |
+ SortedArrayOf<GlyphID> |
+ glyphArray; /* Array of GlyphIDs--in numerical order */ |
+ public: |
+ DEFINE_SIZE_ARRAY (4, glyphArray); |
+}; |
+ |
+struct CoverageFormat2 |
+{ |
+ friend struct Coverage; |
+ |
+ private: |
+ inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
+ { |
+ int i = rangeRecord.search (glyph_id); |
+ if (i != -1) { |
+ const RangeRecord &range = rangeRecord[i]; |
+ return (unsigned int) range.value + (glyph_id - range.start); |
+ } |
+ return NOT_COVERED; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return rangeRecord.sanitize (c); |
+ } |
+ |
+ private: |
+ USHORT coverageFormat; /* Format identifier--format = 2 */ |
+ SortedArrayOf<RangeRecord> |
+ rangeRecord; /* Array of glyph ranges--ordered by |
+ * Start GlyphID. rangeCount entries |
+ * long */ |
+ public: |
+ DEFINE_SIZE_ARRAY (4, rangeRecord); |
+}; |
+ |
+struct Coverage |
+{ |
+ inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); } |
+ |
+ inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
+ { |
+ switch (u.format) { |
+ case 1: return u.format1.get_coverage(glyph_id); |
+ case 2: return u.format2.get_coverage(glyph_id); |
+ default:return NOT_COVERED; |
+ } |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ if (!u.format.sanitize (c)) return false; |
+ switch (u.format) { |
+ case 1: return u.format1.sanitize (c); |
+ case 2: return u.format2.sanitize (c); |
+ default:return true; |
+ } |
+ } |
+ |
+ private: |
+ union { |
+ USHORT format; /* Format identifier */ |
+ CoverageFormat1 format1; |
+ CoverageFormat2 format2; |
+ } u; |
+ public: |
+ DEFINE_SIZE_UNION (2, format); |
+}; |
+ |
+ |
+/* |
+ * Class Definition Table |
+ */ |
+ |
+struct ClassDefFormat1 |
+{ |
+ friend struct ClassDef; |
+ |
+ private: |
+ inline unsigned int get_class (hb_codepoint_t glyph_id) const |
+ { |
+ if ((unsigned int) (glyph_id - startGlyph) < classValue.len) |
+ return classValue[glyph_id - startGlyph]; |
+ return 0; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return c->check_struct (this) |
+ && classValue.sanitize (c); |
+ } |
+ |
+ USHORT classFormat; /* Format identifier--format = 1 */ |
+ GlyphID startGlyph; /* First GlyphID of the classValueArray */ |
+ ArrayOf<USHORT> |
+ classValue; /* Array of Class Values--one per GlyphID */ |
+ public: |
+ DEFINE_SIZE_ARRAY (6, classValue); |
+}; |
+ |
+struct ClassDefFormat2 |
+{ |
+ friend struct ClassDef; |
+ |
+ private: |
+ inline unsigned int get_class (hb_codepoint_t glyph_id) const |
+ { |
+ int i = rangeRecord.search (glyph_id); |
+ if (i != -1) |
+ return rangeRecord[i].value; |
+ return 0; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return rangeRecord.sanitize (c); |
+ } |
+ |
+ USHORT classFormat; /* Format identifier--format = 2 */ |
+ SortedArrayOf<RangeRecord> |
+ rangeRecord; /* Array of glyph ranges--ordered by |
+ * Start GlyphID */ |
+ public: |
+ DEFINE_SIZE_ARRAY (4, rangeRecord); |
+}; |
+ |
+struct ClassDef |
+{ |
+ inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); } |
+ |
+ inline unsigned int get_class (hb_codepoint_t glyph_id) const |
+ { |
+ switch (u.format) { |
+ case 1: return u.format1.get_class(glyph_id); |
+ case 2: return u.format2.get_class(glyph_id); |
+ default:return 0; |
+ } |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ if (!u.format.sanitize (c)) return false; |
+ switch (u.format) { |
+ case 1: return u.format1.sanitize (c); |
+ case 2: return u.format2.sanitize (c); |
+ default:return true; |
+ } |
+ } |
+ |
+ private: |
+ union { |
+ USHORT format; /* Format identifier */ |
+ ClassDefFormat1 format1; |
+ ClassDefFormat2 format2; |
+ } u; |
+ public: |
+ DEFINE_SIZE_UNION (2, format); |
+}; |
+ |
+ |
+/* |
+ * Device Tables |
+ */ |
+ |
+struct Device |
+{ |
+ |
+ inline hb_position_t get_x_delta (hb_ot_layout_context_t *c) const |
+ { return get_delta (c->font->x_ppem, c->font->x_scale); } |
+ |
+ inline hb_position_t get_y_delta (hb_ot_layout_context_t *c) const |
+ { return get_delta (c->font->y_ppem, c->font->y_scale); } |
+ |
+ inline int get_delta (unsigned int ppem, unsigned int scale) const |
+ { |
+ if (!ppem) return 0; |
+ |
+ int pixels = get_delta_pixels (ppem); |
+ |
+ if (!pixels) return 0; |
+ |
+ /* pixels is at most in the -8..7 range. So 64-bit arithmetic is |
+ * not really necessary here. A simple cast to int may just work |
+ * as well. But since this code is not reached that often and |
+ * for the sake of correctness, we do a 64bit operation. */ |
+ return pixels * (int64_t) scale / ppem; |
+ } |
+ |
+ |
+ inline int get_delta_pixels (unsigned int ppem_size) const |
+ { |
+ unsigned int f = deltaFormat; |
+ if (unlikely (f < 1 || f > 3)) |
+ return 0; |
+ |
+ if (ppem_size < startSize || ppem_size > endSize) |
+ return 0; |
+ |
+ unsigned int s = ppem_size - startSize; |
+ |
+ unsigned int byte = deltaValue[s >> (4 - f)]; |
+ unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); |
+ unsigned int mask = (0xFFFF >> (16 - (1 << f))); |
+ |
+ int delta = bits & mask; |
+ |
+ if ((unsigned int) delta >= ((mask + 1) >> 1)) |
+ delta -= mask + 1; |
+ |
+ return delta; |
+ } |
+ |
+ inline unsigned int get_size (void) const |
+ { |
+ unsigned int f = deltaFormat; |
+ if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; |
+ return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (); |
+ return c->check_struct (this) |
+ && c->check_range (this, this->get_size ()); |
+ } |
+ |
+ private: |
+ USHORT startSize; /* Smallest size to correct--in ppem */ |
+ USHORT endSize; /* Largest size to correct--in ppem */ |
+ USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 |
+ * 1 Signed 2-bit value, 8 values per uint16 |
+ * 2 Signed 4-bit value, 4 values per uint16 |
+ * 3 Signed 8-bit value, 2 values per uint16 |
+ */ |
+ USHORT deltaValue[VAR]; /* Array of compressed data */ |
+ public: |
+ DEFINE_SIZE_ARRAY (6, deltaValue); |
+}; |
+ |
+ |
+HB_BEGIN_DECLS |
+HB_END_DECLS |
+ |
+#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ |