| /* |
| * Copyright © 2018 Ebrahim Byagowi |
| * Copyright © 2018 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_AAT_LAYOUT_KERX_TABLE_HH |
| #define HB_AAT_LAYOUT_KERX_TABLE_HH |
| |
| #include "hb-open-type-private.hh" |
| #include "hb-aat-layout-common-private.hh" |
| |
| /* |
| * kerx -- Extended Kerning |
| * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html |
| */ |
| #define HB_AAT_TAG_kerx HB_TAG('k','e','r','x') |
| |
| |
| namespace AAT { |
| |
| using namespace OT; |
| |
| |
| struct KerxFormat0Records |
| { |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this)); |
| } |
| |
| protected: |
| GlyphID left; |
| GlyphID right; |
| FWORD value; |
| public: |
| DEFINE_SIZE_STATIC (6); |
| }; |
| |
| struct KerxSubTableFormat0 |
| { |
| // TODO(ebraminio) Enable when we got suitable BinSearchArrayOf |
| // inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const |
| // { |
| // hb_glyph_pair_t pair = {left, right}; |
| // int i = pairs.bsearch (pair); |
| // if (i == -1) |
| // return 0; |
| // return pairs[i].get_kerning (); |
| // } |
| |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this) && |
| recordsZ.sanitize (c, nPairs)); |
| } |
| |
| protected: |
| // TODO(ebraminio): A custom version of "BinSearchArrayOf<KerxPair> pairs;" is |
| // needed here to use HBUINT32 instead |
| HBUINT32 nPairs; /* The number of kerning pairs in this subtable */ |
| HBUINT32 searchRange; /* The largest power of two less than or equal to the value of nPairs, |
| * multiplied by the size in bytes of an entry in the subtable. */ |
| HBUINT32 entrySelector; /* This is calculated as log2 of the largest power of two less |
| * than or equal to the value of nPairs. */ |
| HBUINT32 rangeShift; /* The value of nPairs minus the largest power of two less than or equal to nPairs. */ |
| UnsizedArrayOf<KerxFormat0Records> |
| recordsZ; /* VAR=nPairs */ |
| public: |
| DEFINE_SIZE_ARRAY (16, recordsZ); |
| }; |
| |
| struct KerxSubTableFormat1 |
| { |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this) && |
| stateHeader.sanitize (c)); |
| } |
| |
| protected: |
| StateTable<HBUINT16> stateHeader; |
| LOffsetTo<ArrayOf<HBUINT16> > valueTable; |
| public: |
| DEFINE_SIZE_STATIC (20); |
| }; |
| |
| // TODO(ebraminio): Maybe this can be replaced with Lookup<HBUINT16>? |
| struct KerxClassTable |
| { |
| inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; } |
| |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (firstGlyph.sanitize (c) && classes.sanitize (c)); |
| } |
| |
| protected: |
| HBUINT16 firstGlyph; /* First glyph in class range. */ |
| ArrayOf<HBUINT16> classes; /* Glyph classes. */ |
| public: |
| DEFINE_SIZE_ARRAY (4, classes); |
| }; |
| |
| struct KerxSubTableFormat2 |
| { |
| inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const |
| { |
| unsigned int l = (this+leftClassTable).get_class (left); |
| unsigned int r = (this+leftClassTable).get_class (left); |
| unsigned int offset = l * rowWidth + r * sizeof (FWORD); |
| const FWORD *arr = &(this+array); |
| if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end)) |
| return 0; |
| const FWORD *v = &StructAtOffset<FWORD> (arr, offset); |
| if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end)) |
| return 0; |
| return *v; |
| } |
| |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this) && |
| rowWidth.sanitize (c) && |
| leftClassTable.sanitize (c, this) && |
| rightClassTable.sanitize (c, this) && |
| array.sanitize (c, this)); |
| } |
| |
| protected: |
| HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ |
| LOffsetTo<KerxClassTable> |
| leftClassTable; /* Offset from beginning of this subtable to |
| * left-hand class table. */ |
| LOffsetTo<KerxClassTable> |
| rightClassTable;/* Offset from beginning of this subtable to |
| * right-hand class table. */ |
| LOffsetTo<FWORD> |
| array; /* Offset from beginning of this subtable to |
| * the start of the kerning array. */ |
| public: |
| DEFINE_SIZE_STATIC (16); |
| }; |
| |
| struct KerxSubTableFormat4 |
| { |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this) && |
| rowWidth.sanitize (c) && |
| leftClassTable.sanitize (c, this) && |
| rightClassTable.sanitize (c, this) && |
| array.sanitize (c, this)); |
| } |
| |
| protected: |
| HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ |
| LOffsetTo<KerxClassTable> |
| leftClassTable; /* Offset from beginning of this subtable to |
| * left-hand class table. */ |
| LOffsetTo<KerxClassTable> |
| rightClassTable;/* Offset from beginning of this subtable to |
| * right-hand class table. */ |
| LOffsetTo<FWORD> |
| array; /* Offset from beginning of this subtable to |
| * the start of the kerning array. */ |
| public: |
| DEFINE_SIZE_STATIC (16); |
| }; |
| |
| struct KerxSubTableFormat6 |
| { |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this) && |
| rowIndexTable.sanitize (c, this) && |
| columnIndexTable.sanitize (c, this) && |
| kerningArray.sanitize (c, this) && |
| kerningVector.sanitize (c, this)); |
| } |
| |
| protected: |
| HBUINT32 flags; |
| HBUINT16 rowCount; |
| HBUINT16 columnCount; |
| LOffsetTo<Lookup<HBUINT16> > rowIndexTable; |
| LOffsetTo<Lookup<HBUINT16> > columnIndexTable; |
| LOffsetTo<Lookup<HBUINT16> > kerningArray; |
| LOffsetTo<Lookup<HBUINT16> > kerningVector; |
| public: |
| DEFINE_SIZE_STATIC (24); |
| }; |
| |
| enum coverage_flags_t |
| { |
| COVERAGE_VERTICAL_FLAG = 0x80u, |
| COVERAGE_CROSSSTREAM_FLAG = 0x40u, |
| COVERAGE_VARIATION_FLAG = 0x20u, |
| COVERAGE_PROCESS_DIRECTION = 0x10u, |
| }; |
| |
| struct KerxTable |
| { |
| inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const |
| { |
| TRACE_APPLY (this); |
| /* TODO */ |
| return_trace (false); |
| } |
| |
| inline unsigned int get_size (void) const { return length; } |
| |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| if (!c->check_struct (this)) |
| return_trace (false); |
| |
| switch (format) { |
| case 0: return u.format0.sanitize (c); |
| case 1: return u.format1.sanitize (c); |
| case 2: return u.format2.sanitize (c); |
| case 4: return u.format4.sanitize (c); |
| case 6: return u.format6.sanitize (c); |
| default:return_trace (false); |
| } |
| } |
| |
| protected: |
| HBUINT32 length; |
| HBUINT8 coverage; |
| HBUINT16 unused; |
| HBUINT8 format; |
| HBUINT32 tupleIndex; |
| union { |
| KerxSubTableFormat0 format0; |
| KerxSubTableFormat1 format1; |
| KerxSubTableFormat2 format2; |
| KerxSubTableFormat4 format4; |
| KerxSubTableFormat6 format6; |
| } u; |
| public: |
| DEFINE_SIZE_MIN (12); |
| }; |
| |
| struct SubtableGlyphCoverageArray |
| { |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| return_trace (c->check_struct (this)); |
| } |
| |
| protected: |
| HBUINT32 length; |
| HBUINT32 coverage; |
| HBUINT32 tupleCount; |
| public: |
| DEFINE_SIZE_STATIC (12); |
| }; |
| |
| struct kerx |
| { |
| static const hb_tag_t tableTag = HB_AAT_TAG_kerx; |
| |
| inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const |
| { |
| TRACE_APPLY (this); |
| const KerxTable &table = StructAfter<KerxTable> (*this); |
| return_trace (table.apply (c, ankr)); |
| } |
| |
| inline bool sanitize (hb_sanitize_context_t *c) const |
| { |
| TRACE_SANITIZE (this); |
| if (!(c->check_struct (this))) |
| return_trace (false); |
| |
| /* TODO: Something like `morx`s ChainSubtable should be done here instead */ |
| const KerxTable *table = &StructAfter<KerxTable> (*this); |
| if (!(table->sanitize (c))) |
| return_trace (false); |
| |
| for (unsigned int i = 0; i < nTables - 1; ++i) |
| { |
| table = &StructAfter<KerxTable> (*table); |
| if (!(table->sanitize (c))) |
| return_trace (false); |
| } |
| |
| // If version is less than 3, we are done here; otherwise better to check footer also |
| if (version < 3) |
| return_trace (true); |
| |
| // TODO: Investigate why this just work on some fonts no matter of version |
| // const SubtableGlyphCoverageArray &footer = |
| // StructAfter<SubtableGlyphCoverageArray> (*table); |
| // return_trace (footer.sanitize (c)); |
| |
| return_trace (true); |
| } |
| |
| protected: |
| HBUINT16 version; |
| HBUINT16 padding; |
| HBUINT32 nTables; |
| /*KerxTable tables[VAR];*/ |
| /*SubtableGlyphCoverageArray coverage_array;*/ |
| public: |
| DEFINE_SIZE_STATIC (8); |
| }; |
| |
| } /* namespace AAT */ |
| |
| |
| #endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */ |