Index: third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh |
diff --git a/third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh b/third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d53141157d0d5992ba876dcd5a9af634d70947bf |
--- /dev/null |
+++ b/third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh |
@@ -0,0 +1,517 @@ |
+/* |
+ * Copyright © 2014 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. |
+ * |
+ * Google Author(s): Behdad Esfahbod |
+ */ |
+ |
+#ifndef HB_OT_CMAP_TABLE_HH |
+#define HB_OT_CMAP_TABLE_HH |
+ |
+#include "hb-open-type-private.hh" |
+ |
+ |
+namespace OT { |
+ |
+ |
+/* |
+ * cmap -- Character To Glyph Index Mapping Table |
+ */ |
+ |
+#define HB_OT_TAG_cmap HB_TAG('c','m','a','p') |
+ |
+ |
+struct CmapSubtableFormat0 |
+{ |
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const |
+ { |
+ hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; |
+ if (!gid) |
+ return false; |
+ *glyph = gid; |
+ return true; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this)); |
+ } |
+ |
+ protected: |
+ USHORT format; /* Format number is set to 0. */ |
+ USHORT lengthZ; /* Byte length of this subtable. */ |
+ USHORT languageZ; /* Ignore. */ |
+ BYTE glyphIdArray[256];/* An array that maps character |
+ * code to glyph index values. */ |
+ public: |
+ DEFINE_SIZE_STATIC (6 + 256); |
+}; |
+ |
+struct CmapSubtableFormat4 |
+{ |
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const |
+ { |
+ unsigned int segCount; |
+ const USHORT *endCount; |
+ const USHORT *startCount; |
+ const USHORT *idDelta; |
+ const USHORT *idRangeOffset; |
+ const USHORT *glyphIdArray; |
+ unsigned int glyphIdArrayLength; |
+ |
+ segCount = this->segCountX2 / 2; |
+ endCount = this->values; |
+ startCount = endCount + segCount + 1; |
+ idDelta = startCount + segCount; |
+ idRangeOffset = idDelta + segCount; |
+ glyphIdArray = idRangeOffset + segCount; |
+ glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2; |
+ |
+ /* Custom two-array bsearch. */ |
+ int min = 0, max = (int) segCount - 1; |
+ unsigned int i; |
+ while (min <= max) |
+ { |
+ int mid = (min + max) / 2; |
+ if (codepoint < startCount[mid]) |
+ max = mid - 1; |
+ else if (codepoint > endCount[mid]) |
+ min = mid + 1; |
+ else |
+ { |
+ i = mid; |
+ goto found; |
+ } |
+ } |
+ return false; |
+ |
+ found: |
+ hb_codepoint_t gid; |
+ unsigned int rangeOffset = idRangeOffset[i]; |
+ if (rangeOffset == 0) |
+ gid = codepoint + idDelta[i]; |
+ else |
+ { |
+ /* Somebody has been smoking... */ |
+ unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount; |
+ if (unlikely (index >= glyphIdArrayLength)) |
+ return false; |
+ gid = glyphIdArray[index]; |
+ if (unlikely (!gid)) |
+ return false; |
+ gid += idDelta[i]; |
+ } |
+ |
+ *glyph = gid & 0xFFFFu; |
+ return true; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) |
+ { |
+ TRACE_SANITIZE (this); |
+ if (unlikely (!c->check_struct (this))) |
+ return TRACE_RETURN (false); |
+ |
+ if (unlikely (!c->check_range (this, length))) |
+ { |
+ /* Some broken fonts have too long of a "length" value. |
+ * If that is the case, just change the value to truncate |
+ * the subtable at the end of the blob. */ |
+ uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, |
+ (uintptr_t) (c->end - |
+ (char *) this)); |
+ if (!c->try_set (&length, new_length)) |
+ return TRACE_RETURN (false); |
+ } |
+ |
+ return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length); |
+ } |
+ |
+ protected: |
+ USHORT format; /* Format number is set to 4. */ |
+ USHORT length; /* This is the length in bytes of the |
+ * subtable. */ |
+ USHORT languageZ; /* Ignore. */ |
+ USHORT segCountX2; /* 2 x segCount. */ |
+ USHORT searchRangeZ; /* 2 * (2**floor(log2(segCount))) */ |
+ USHORT entrySelectorZ; /* log2(searchRange/2) */ |
+ USHORT rangeShiftZ; /* 2 x segCount - searchRange */ |
+ |
+ USHORT values[VAR]; |
+#if 0 |
+ USHORT endCount[segCount]; /* End characterCode for each segment, |
+ * last=0xFFFFu. */ |
+ USHORT reservedPad; /* Set to 0. */ |
+ USHORT startCount[segCount]; /* Start character code for each segment. */ |
+ SHORT idDelta[segCount]; /* Delta for all character codes in segment. */ |
+ USHORT idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ |
+ USHORT glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */ |
+#endif |
+ |
+ public: |
+ DEFINE_SIZE_ARRAY (14, values); |
+}; |
+ |
+struct CmapSubtableLongGroup |
+{ |
+ friend struct CmapSubtableFormat12; |
+ friend struct CmapSubtableFormat13; |
+ |
+ int cmp (hb_codepoint_t codepoint) const |
+ { |
+ if (codepoint < startCharCode) return -1; |
+ if (codepoint > endCharCode) return +1; |
+ return 0; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this)); |
+ } |
+ |
+ private: |
+ ULONG startCharCode; /* First character code in this group. */ |
+ ULONG endCharCode; /* Last character code in this group. */ |
+ ULONG glyphID; /* Glyph index; interpretation depends on |
+ * subtable format. */ |
+ public: |
+ DEFINE_SIZE_STATIC (12); |
+}; |
+ |
+template <typename UINT> |
+struct CmapSubtableTrimmed |
+{ |
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const |
+ { |
+ /* Rely on our implicit array bound-checking. */ |
+ hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; |
+ if (!gid) |
+ return false; |
+ *glyph = gid; |
+ return true; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c)); |
+ } |
+ |
+ protected: |
+ UINT formatReserved; /* Subtable format and (maybe) padding. */ |
+ UINT lengthZ; /* Byte length of this subtable. */ |
+ UINT languageZ; /* Ignore. */ |
+ UINT startCharCode; /* First character code covered. */ |
+ ArrayOf<GlyphID, UINT> |
+ glyphIdArray; /* Array of glyph index values for character |
+ * codes in the range. */ |
+ public: |
+ DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray); |
+}; |
+ |
+struct CmapSubtableFormat6 : CmapSubtableTrimmed<USHORT> {}; |
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {}; |
+ |
+template <typename T> |
+struct CmapSubtableLongSegmented |
+{ |
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const |
+ { |
+ int i = groups.bsearch (codepoint); |
+ if (i == -1) |
+ return false; |
+ *glyph = T::group_get_glyph (groups[i], codepoint); |
+ return true; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c)); |
+ } |
+ |
+ protected: |
+ USHORT format; /* Subtable format; set to 12. */ |
+ USHORT reservedZ; /* Reserved; set to 0. */ |
+ ULONG lengthZ; /* Byte length of this subtable. */ |
+ ULONG languageZ; /* Ignore. */ |
+ SortedArrayOf<CmapSubtableLongGroup, ULONG> |
+ groups; /* Groupings. */ |
+ public: |
+ DEFINE_SIZE_ARRAY (16, groups); |
+}; |
+ |
+struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> |
+{ |
+ static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, |
+ hb_codepoint_t u) |
+ { return group.glyphID + (u - group.startCharCode); } |
+}; |
+ |
+struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> |
+{ |
+ static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, |
+ hb_codepoint_t u HB_UNUSED) |
+ { return group.glyphID; } |
+}; |
+ |
+typedef enum |
+{ |
+ GLYPH_VARIANT_NOT_FOUND = 0, |
+ GLYPH_VARIANT_FOUND = 1, |
+ GLYPH_VARIANT_USE_DEFAULT = 2 |
+} glyph_variant_t; |
+ |
+struct UnicodeValueRange |
+{ |
+ inline int cmp (const hb_codepoint_t &codepoint) const |
+ { |
+ if (codepoint < startUnicodeValue) return -1; |
+ if (codepoint > startUnicodeValue + additionalCount) return +1; |
+ return 0; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this)); |
+ } |
+ |
+ UINT24 startUnicodeValue; /* First value in this range. */ |
+ BYTE additionalCount; /* Number of additional values in this |
+ * range. */ |
+ public: |
+ DEFINE_SIZE_STATIC (4); |
+}; |
+ |
+typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS; |
+ |
+struct UVSMapping |
+{ |
+ inline int cmp (const hb_codepoint_t &codepoint) const |
+ { |
+ return unicodeValue.cmp (codepoint); |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this)); |
+ } |
+ |
+ UINT24 unicodeValue; /* Base Unicode value of the UVS */ |
+ GlyphID glyphID; /* Glyph ID of the UVS */ |
+ public: |
+ DEFINE_SIZE_STATIC (5); |
+}; |
+ |
+typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS; |
+ |
+struct VariationSelectorRecord |
+{ |
+ inline glyph_variant_t get_glyph (hb_codepoint_t codepoint, |
+ hb_codepoint_t *glyph, |
+ const void *base) const |
+ { |
+ int i; |
+ const DefaultUVS &defaults = base+defaultUVS; |
+ i = defaults.bsearch (codepoint); |
+ if (i != -1) |
+ return GLYPH_VARIANT_USE_DEFAULT; |
+ const NonDefaultUVS &nonDefaults = base+nonDefaultUVS; |
+ i = nonDefaults.bsearch (codepoint); |
+ if (i != -1) |
+ { |
+ *glyph = nonDefaults[i].glyphID; |
+ return GLYPH_VARIANT_FOUND; |
+ } |
+ return GLYPH_VARIANT_NOT_FOUND; |
+ } |
+ |
+ inline int cmp (const hb_codepoint_t &variation_selector) const |
+ { |
+ return varSelector.cmp (variation_selector); |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this) && |
+ defaultUVS.sanitize (c, base) && |
+ nonDefaultUVS.sanitize (c, base)); |
+ } |
+ |
+ UINT24 varSelector; /* Variation selector. */ |
+ OffsetTo<DefaultUVS, ULONG> |
+ defaultUVS; /* Offset to Default UVS Table. May be 0. */ |
+ OffsetTo<NonDefaultUVS, ULONG> |
+ nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ |
+ public: |
+ DEFINE_SIZE_STATIC (11); |
+}; |
+ |
+struct CmapSubtableFormat14 |
+{ |
+ inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, |
+ hb_codepoint_t variation_selector, |
+ hb_codepoint_t *glyph) const |
+ { |
+ return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this) && |
+ record.sanitize (c, this)); |
+ } |
+ |
+ protected: |
+ USHORT format; /* Format number is set to 0. */ |
+ ULONG lengthZ; /* Byte length of this subtable. */ |
+ SortedArrayOf<VariationSelectorRecord, ULONG> |
+ record; /* Variation selector records; sorted |
+ * in increasing order of `varSelector'. */ |
+ public: |
+ DEFINE_SIZE_ARRAY (10, record); |
+}; |
+ |
+struct CmapSubtable |
+{ |
+ /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ |
+ |
+ inline bool get_glyph (hb_codepoint_t codepoint, |
+ hb_codepoint_t *glyph) const |
+ { |
+ switch (u.format) { |
+ case 0: return u.format0 .get_glyph(codepoint, glyph); |
+ case 4: return u.format4 .get_glyph(codepoint, glyph); |
+ case 6: return u.format6 .get_glyph(codepoint, glyph); |
+ case 10: return u.format10.get_glyph(codepoint, glyph); |
+ case 12: return u.format12.get_glyph(codepoint, glyph); |
+ case 13: return u.format13.get_glyph(codepoint, glyph); |
+ case 14: |
+ default: return false; |
+ } |
+ } |
+ |
+ inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, |
+ hb_codepoint_t variation_selector, |
+ hb_codepoint_t *glyph) const |
+ { |
+ switch (u.format) { |
+ case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph); |
+ default: return GLYPH_VARIANT_NOT_FOUND; |
+ } |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ if (!u.format.sanitize (c)) return TRACE_RETURN (false); |
+ switch (u.format) { |
+ case 0: return TRACE_RETURN (u.format0 .sanitize (c)); |
+ case 4: return TRACE_RETURN (u.format4 .sanitize (c)); |
+ case 6: return TRACE_RETURN (u.format6 .sanitize (c)); |
+ case 10: return TRACE_RETURN (u.format10.sanitize (c)); |
+ case 12: return TRACE_RETURN (u.format12.sanitize (c)); |
+ case 13: return TRACE_RETURN (u.format13.sanitize (c)); |
+ case 14: return TRACE_RETURN (u.format14.sanitize (c)); |
+ default:return TRACE_RETURN (true); |
+ } |
+ } |
+ |
+ protected: |
+ union { |
+ USHORT format; /* Format identifier */ |
+ CmapSubtableFormat0 format0; |
+ CmapSubtableFormat4 format4; |
+ CmapSubtableFormat6 format6; |
+ CmapSubtableFormat10 format10; |
+ CmapSubtableFormat12 format12; |
+ CmapSubtableFormat13 format13; |
+ CmapSubtableFormat14 format14; |
+ } u; |
+ public: |
+ DEFINE_SIZE_UNION (2, format); |
+}; |
+ |
+ |
+struct EncodingRecord |
+{ |
+ inline int cmp (const EncodingRecord &other) const |
+ { |
+ int ret; |
+ ret = platformID.cmp (other.platformID); |
+ if (ret) return ret; |
+ ret = encodingID.cmp (other.encodingID); |
+ if (ret) return ret; |
+ return 0; |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this) && |
+ subtable.sanitize (c, base)); |
+ } |
+ |
+ USHORT platformID; /* Platform ID. */ |
+ USHORT encodingID; /* Platform-specific encoding ID. */ |
+ OffsetTo<CmapSubtable, ULONG> |
+ subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ |
+ public: |
+ DEFINE_SIZE_STATIC (8); |
+}; |
+ |
+struct cmap |
+{ |
+ static const hb_tag_t tableTag = HB_OT_TAG_cmap; |
+ |
+ inline const CmapSubtable *find_subtable (unsigned int platform_id, |
+ unsigned int encoding_id) const |
+ { |
+ EncodingRecord key; |
+ key.platformID.set (platform_id); |
+ key.encodingID.set (encoding_id); |
+ |
+ /* Note: We can use bsearch, but since it has no performance |
+ * implications, we use lsearch and as such accept fonts with |
+ * unsorted subtable list. */ |
+ int result = encodingRecord./*bsearch*/lsearch (key); |
+ if (result == -1 || !encodingRecord[result].subtable) |
+ return NULL; |
+ |
+ return &(this+encodingRecord[result].subtable); |
+ } |
+ |
+ inline bool sanitize (hb_sanitize_context_t *c) { |
+ TRACE_SANITIZE (this); |
+ return TRACE_RETURN (c->check_struct (this) && |
+ likely (version == 0) && |
+ encodingRecord.sanitize (c, this)); |
+ } |
+ |
+ USHORT version; /* Table version number (0). */ |
+ SortedArrayOf<EncodingRecord> |
+ encodingRecord; /* Encoding tables. */ |
+ public: |
+ DEFINE_SIZE_ARRAY (4, encodingRecord); |
+}; |
+ |
+ |
+} /* namespace OT */ |
+ |
+ |
+#endif /* HB_OT_CMAP_TABLE_HH */ |