diff options
author | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2018-11-19 04:05:47 +0000 |
---|---|---|
committer | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2018-11-19 04:05:47 +0000 |
commit | a0f9dd8213083d3021d12beceb451325ee8fce30 (patch) | |
tree | c3de2c62a20cf8b71dbe6d968f463e8c5b76fc26 /Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh | |
parent | a34ffc9669bd1c626c01adc0292ee625b3ad16de (diff) |
harfbuzz-2.1.3
git-svn-id: svn://tug.org/texlive/trunk@49193 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh')
-rw-r--r-- | Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh | 522 |
1 files changed, 377 insertions, 145 deletions
diff --git a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh index d2242c5496e..f075a270a6b 100644 --- a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh +++ b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh @@ -28,10 +28,8 @@ #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH #define HB_AAT_LAYOUT_KERX_TABLE_HH -#include "hb-open-type.hh" -#include "hb-aat-layout-common.hh" -#include "hb-ot-layout-gpos-table.hh" -#include "hb-ot-kern-table.hh" +#include "hb-kern.hh" +#include "hb-aat-layout-ankr-table.hh" /* * kerx -- Extended Kerning @@ -55,29 +53,54 @@ kerxTupleKern (int value, unsigned int offset = value; const FWORD *pv = &StructAtOffset<FWORD> (base, offset); - if (unlikely (!pv->sanitize (&c->sanitizer))) return 0; + if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0; return *pv; } -struct KerxSubTableHeader +struct hb_glyph_pair_t { + hb_codepoint_t left; + hb_codepoint_t right; +}; + +struct KernPair +{ + inline int get_kerning (void) const + { return value; } + + inline int cmp (const hb_glyph_pair_t &o) const + { + int ret = left.cmp (o.left); + if (ret) return ret; + return right.cmp (o.right); + } + inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } + protected: + GlyphID left; + GlyphID right; + FWORD value; public: - HBUINT32 length; - HBUINT32 coverage; - HBUINT32 tupleCount; - public: - DEFINE_SIZE_STATIC (12); + DEFINE_SIZE_STATIC (6); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat0 { + 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 int get_kerning (hb_codepoint_t left, hb_codepoint_t right, hb_aat_apply_context_t *c) const { @@ -85,7 +108,7 @@ struct KerxSubTableFormat0 int i = pairs.bsearch (pair); if (i == -1) return 0; int v = pairs[i].get_kerning (); - return kerxTupleKern (v, header.tupleCount, this, c); + return kerxTupleKern (v, header.tuple_count (), this, c); } inline bool apply (hb_aat_apply_context_t *c) const @@ -95,8 +118,11 @@ struct KerxSubTableFormat0 if (!c->plan->requested_kerning) return false; + if (header.coverage & header.Backwards) + return false; + accelerator_t accel (*this, c); - hb_kern_machine_t<accelerator_t> machine (accel); + hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); machine.kern (c->font, c->buffer, c->plan->kern_mask); return_trace (true); @@ -119,20 +145,33 @@ struct KerxSubTableFormat0 inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - pairs.sanitize (c))); + return_trace (likely (pairs.sanitize (c))); } protected: - KerxSubTableHeader header; - BinSearchArrayOf<KernPair, HBUINT32> + KernSubTableHeader header; + BinSearchArrayOf<KernPair, typename KernSubTableHeader::Types::HBUINT> pairs; /* Sorted kern records. */ public: - DEFINE_SIZE_ARRAY (28, pairs); + DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 16, pairs); }; -struct KerxSubTableFormat1 + +template <bool extended> +struct Format1Entry; + +template <> +struct Format1Entry<true> { + enum Flags + { + Push = 0x8000, /* If set, push this glyph on the kerning stack. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph + * before going to the new state. */ + Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */ + Reserved = 0x1FFF, /* Not used; set to 0. */ + }; + struct EntryData { HBUINT16 kernActionIndex;/* Index into the kerning value array. If @@ -142,44 +181,78 @@ struct KerxSubTableFormat1 DEFINE_SIZE_STATIC (2); }; + static inline bool performAction (const Entry<EntryData> *entry) + { return entry->data.kernActionIndex != 0xFFFF; } + + static inline unsigned int kernActionIndex (const Entry<EntryData> *entry) + { return entry->data.kernActionIndex; } +}; +template <> +struct Format1Entry<false> +{ + enum Flags + { + Push = 0x8000, /* If set, push this glyph on the kerning stack. */ + DontAdvance = 0x4000, /* If set, don't advance to the next glyph + * before going to the new state. */ + Offset = 0x3FFF, /* Byte offset from beginning of subtable to the + * value table for the glyphs on the kerning stack. */ + + Reset = 0x0000, /* Not supported? */ + }; + + typedef void EntryData; + + static inline bool performAction (const Entry<EntryData> *entry) + { return entry->flags & Offset; } + + static inline unsigned int kernActionIndex (const Entry<EntryData> *entry) + { return entry->flags & Offset; } +}; + +template <typename KernSubTableHeader> +struct KerxSubTableFormat1 +{ + typedef typename KernSubTableHeader::Types Types; + typedef typename Types::HBUINT HBUINT; + + typedef Format1Entry<Types::extended> Format1EntryT; + typedef typename Format1EntryT::EntryData EntryData; + struct driver_context_t { static const bool in_place = true; - enum Flags + enum { - Push = 0x8000, /* If set, push this glyph on the kerning stack. */ - DontAdvance = 0x4000, /* If set, don't advance to the next glyph - * before going to the new state. */ - Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */ - Reserved = 0x1FFF, /* Not used; set to 0. */ + DontAdvance = Format1EntryT::DontAdvance, }; - inline driver_context_t (const KerxSubTableFormat1 *table, + inline driver_context_t (const KerxSubTableFormat1 *table_, hb_aat_apply_context_t *c_) : c (c_), + table (table_), /* Apparently the offset kernAction is from the beginning of the state-machine, * similar to offsets in morx table, NOT from beginning of this table, like * other subtables in kerx. Discovered via testing. */ kernAction (&table->machine + table->kernAction), - depth (0) {} + depth (0), + crossStream (table->header.coverage & table->header.CrossStream) {} - inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED, + inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, const Entry<EntryData> *entry) { - return entry->data.kernActionIndex != 0xFFFF; + return Format1EntryT::performAction (entry); } - inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver, + inline bool transition (StateTableDriver<Types, EntryData> *driver, const Entry<EntryData> *entry) { hb_buffer_t *buffer = driver->buffer; unsigned int flags = entry->flags; - if (flags & Reset) - { + if (flags & Format1EntryT::Reset) depth = 0; - } - if (flags & Push) + if (flags & Format1EntryT::Push) { if (likely (depth < ARRAY_LENGTH (stack))) stack[depth++] = buffer->idx; @@ -187,41 +260,90 @@ struct KerxSubTableFormat1 depth = 0; /* Probably not what CoreText does, but better? */ } - if (entry->data.kernActionIndex != 0xFFFF) + if (Format1EntryT::performAction (entry) && depth) { - const FWORD *actions = &kernAction[entry->data.kernActionIndex]; - if (!c->sanitizer.check_array (actions, depth)) + unsigned int tuple_count = MAX (1u, table->header.tuple_count ()); + + unsigned int kern_idx = Format1EntryT::kernActionIndex (entry); + kern_idx = Types::offsetToIndex (kern_idx, &table->machine, kernAction.arrayZ); + const FWORD *actions = &kernAction[kern_idx]; + if (!c->sanitizer.check_array (actions, depth, tuple_count)) { depth = 0; return false; } hb_mask_t kern_mask = c->plan->kern_mask; - for (unsigned int i = 0; i < depth; i++) + + /* From Apple 'kern' spec: + * "Each pops one glyph from the kerning stack and applies the kerning value to it. + * The end of the list is marked by an odd value... */ + bool last = false; + while (!last && depth) { - /* Apparently, when spec says "Each pops one glyph from the kerning stack - * and applies the kerning value to it.", it doesn't mean it in that order. - * The deepest item in the stack corresponds to the first item in the action - * list. Discovered by testing. */ - unsigned int idx = stack[i]; - int v = *actions++; - if (idx < buffer->len && buffer->info[idx].mask & kern_mask) + unsigned int idx = stack[--depth]; + int v = *actions; + actions += tuple_count; + if (idx >= buffer->len) continue; + + /* "The end of the list is marked by an odd value..." */ + last = v & 1; + v &= ~1; + + hb_glyph_position_t &o = buffer->pos[idx]; + + /* Testing shows that CoreText only applies kern (cross-stream or not) + * if none has been applied by previous subtables. That is, it does + * NOT seem to accumulate as otherwise implied by specs. */ + + /* The following flag is undocumented in the spec, but described + * in the 'kern' table example. */ + if (v == -0x8000) + { + o.attach_type() = ATTACH_TYPE_NONE; + o.attach_chain() = 0; + o.x_offset = o.y_offset = 0; + } + else if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) { - if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + if (crossStream) { - buffer->pos[idx].x_advance += c->font->em_scale_x (v); - if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + if (buffer->pos[idx].attach_type() && !buffer->pos[idx].y_offset) + { + o.y_offset = c->font->em_scale_y (v); + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } + } + else if (buffer->info[idx].mask & kern_mask) + { + if (!buffer->pos[idx].x_offset) + { + buffer->pos[idx].x_advance += c->font->em_scale_x (v); buffer->pos[idx].x_offset += c->font->em_scale_x (v); + } + } + } + else + { + if (crossStream) + { + /* CoreText doesn't do crossStream kerning in vertical. We do. */ + if (buffer->pos[idx].attach_type() && !buffer->pos[idx].x_offset) + { + o.x_offset = c->font->em_scale_x (v); + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + } } - else + else if (buffer->info[idx].mask & kern_mask) { - buffer->pos[idx].y_advance += c->font->em_scale_y (v); - if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + if (!buffer->pos[idx].y_offset) + { + buffer->pos[idx].y_advance += c->font->em_scale_y (v); buffer->pos[idx].y_offset += c->font->em_scale_y (v); + } } } } - depth = 0; } return true; @@ -229,24 +351,24 @@ struct KerxSubTableFormat1 private: hb_aat_apply_context_t *c; + const KerxSubTableFormat1 *table; const UnsizedArrayOf<FWORD> &kernAction; unsigned int stack[8]; unsigned int depth; + bool crossStream; }; inline bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); - if (!c->plan->requested_kerning) + if (!c->plan->requested_kerning && + !(header.coverage & header.CrossStream)) return false; - if (header.tupleCount) - return_trace (false); /* TODO kerxTupleKern */ - driver_context_t dc (this, c); - StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face); + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); driver.drive (&dc); return_trace (true); @@ -261,25 +383,29 @@ struct KerxSubTableFormat1 } protected: - KerxSubTableHeader header; - StateTable<MorxTypes, EntryData> machine; - LOffsetTo<UnsizedArrayOf<FWORD>, false> kernAction; + KernSubTableHeader header; + StateTable<Types, EntryData> machine; + OffsetTo<UnsizedArrayOf<FWORD>, HBUINT, false>kernAction; public: - DEFINE_SIZE_STATIC (32); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT)); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat2 { + typedef typename KernSubTableHeader::Types Types; + typedef typename Types::HBUINT HBUINT; + inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, hb_aat_apply_context_t *c) const { unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); - unsigned int l = (this+leftClassTable).get_value_or_null (left, num_glyphs); - unsigned int r = (this+rightClassTable).get_value_or_null (right, num_glyphs); + unsigned int l = (this+leftClassTable).get_class (left, num_glyphs, 0); + unsigned int r = (this+rightClassTable).get_class (right, num_glyphs, 0); unsigned int offset = l + r; const FWORD *v = &StructAtOffset<FWORD> (&(this+array), offset); if (unlikely (!v->sanitize (&c->sanitizer))) return 0; - return kerxTupleKern (*v, header.tupleCount, this, c); + return kerxTupleKern (*v, header.tuple_count (), this, c); } inline bool apply (hb_aat_apply_context_t *c) const @@ -289,8 +415,11 @@ struct KerxSubTableFormat2 if (!c->plan->requested_kerning) return false; + if (header.coverage & header.Backwards) + return false; + accelerator_t accel (*this, c); - hb_kern_machine_t<accelerator_t> machine (accel); + hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); machine.kern (c->font, c->buffer, c->plan->kern_mask); return_trace (true); @@ -318,24 +447,33 @@ struct KerxSubTableFormat2 c->check_range (this, array))); } + /* Note: + * OT kern table specifies ClassTable as having 16-bit entries, whereas + * AAT kern table specifies them as having 8bit entries. + * I've not seen any fonts with this format in kern table. + * We follow AAT. */ + protected: - KerxSubTableHeader header; - HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ - LOffsetTo<Lookup<HBUINT16>, false> + KernSubTableHeader header; + HBUINT rowWidth; /* The width, in bytes, of a row in the table. */ + OffsetTo<typename Types::ClassType, HBUINT, false> leftClassTable; /* Offset from beginning of this subtable to * left-hand class table. */ - LOffsetTo<Lookup<HBUINT16>, false> + OffsetTo<typename Types::ClassType, HBUINT, false> rightClassTable;/* Offset from beginning of this subtable to * right-hand class table. */ - LOffsetTo<UnsizedArrayOf<FWORD>, false> + OffsetTo<UnsizedArrayOf<FWORD>, HBUINT, false> array; /* Offset from beginning of this subtable to * the start of the kerning array. */ public: - DEFINE_SIZE_STATIC (28); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 4 * sizeof (HBUINT)); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat4 { + typedef ExtendedTypes Types; + struct EntryData { HBUINT16 ankrActionIndex;/* Either 0xFFFF (for no action) or the index of @@ -372,16 +510,15 @@ struct KerxSubTableFormat4 mark_set (false), mark (0) {} - inline bool is_actionable (StateTableDriver<MorxTypes, EntryData> *driver HB_UNUSED, + inline bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, const Entry<EntryData> *entry) { return entry->data.ankrActionIndex != 0xFFFF; } - inline bool transition (StateTableDriver<MorxTypes, EntryData> *driver, + inline bool transition (StateTableDriver<Types, EntryData> *driver, const Entry<EntryData> *entry) { hb_buffer_t *buffer = driver->buffer; - unsigned int flags = entry->flags; if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) { @@ -457,7 +594,7 @@ struct KerxSubTableFormat4 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; } - if (flags & Mark) + if (entry->flags & Mark) { mark_set = true; mark = buffer->idx; @@ -480,7 +617,7 @@ struct KerxSubTableFormat4 driver_context_t dc (this, c); - StateTableDriver<MorxTypes, EntryData> driver (machine, c->buffer, c->font->face); + StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face); driver.drive (&dc); return_trace (true); @@ -495,14 +632,14 @@ struct KerxSubTableFormat4 } protected: - KerxSubTableHeader header; - StateTable<MorxTypes, EntryData> - machine; - HBUINT32 flags; + KernSubTableHeader header; + StateTable<Types, EntryData> machine; + HBUINT32 flags; public: - DEFINE_SIZE_STATIC (32); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 20); }; +template <typename KernSubTableHeader> struct KerxSubTableFormat6 { enum Flags @@ -518,7 +655,7 @@ struct KerxSubTableFormat6 unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); if (is_long ()) { - const U::Long &t = u.l; + const typename U::Long &t = u.l; unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); unsigned int offset = l + r; @@ -526,17 +663,17 @@ struct KerxSubTableFormat6 if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0; const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32)); if (unlikely (!v->sanitize (&c->sanitizer))) return 0; - return kerxTupleKern (*v, header.tupleCount, &(this+vector), c); + return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); } else { - const U::Short &t = u.s; + const typename U::Short &t = u.s; unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); unsigned int offset = l + r; const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD)); if (unlikely (!v->sanitize (&c->sanitizer))) return 0; - return kerxTupleKern (*v, header.tupleCount, &(this+vector), c); + return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); } } @@ -547,8 +684,11 @@ struct KerxSubTableFormat6 if (!c->plan->requested_kerning) return false; + if (header.coverage & header.Backwards) + return false; + accelerator_t accel (*this, c); - hb_kern_machine_t<accelerator_t> machine (accel); + hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); machine.kern (c->font, c->buffer, c->plan->kern_mask); return_trace (true); @@ -568,7 +708,7 @@ struct KerxSubTableFormat6 u.s.columnIndexTable.sanitize (c, this) && c->check_range (this, u.s.array) )) && - (header.tupleCount == 0 || + (header.tuple_count () == 0 || c->check_range (this, vector)))); } @@ -586,7 +726,7 @@ struct KerxSubTableFormat6 }; protected: - KerxSubTableHeader header; + KernSubTableHeader header; HBUINT32 flags; HBUINT16 rowCount; HBUINT16 columnCount; @@ -607,42 +747,64 @@ struct KerxSubTableFormat6 } u; LOffsetTo<UnsizedArrayOf<FWORD>, false> vector; public: - DEFINE_SIZE_STATIC (36); + DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24); }; -struct KerxTable + +struct KerxSubTableHeader { - friend struct kerx; + typedef ExtendedTypes Types; - inline unsigned int get_size (void) const { return u.header.length; } - inline unsigned int get_type (void) const { return u.header.coverage & SubtableType; } + inline unsigned int tuple_count (void) const { return tupleCount; } + inline bool is_horizontal (void) const { return !(coverage & Vertical); } enum Coverage { - Vertical = 0x80000000, /* Set if table has vertical kerning values. */ - CrossStream = 0x40000000, /* Set if table has cross-stream kerning values. */ - Variation = 0x20000000, /* Set if table has variation kerning values. */ - Backwards = 0x10000000, /* If clear, process the glyphs forwards, that - * is, from first to last in the glyph stream. - * If we, process them from last to first. - * This flag only applies to state-table based - * 'kerx' subtables (types 1 and 4). */ - Reserved = 0x0FFFFF00, /* Reserved, set to zero. */ - SubtableType = 0x000000FF, /* Subtable type. */ + Vertical = 0x80000000u, /* Set if table has vertical kerning values. */ + CrossStream = 0x40000000u, /* Set if table has cross-stream kerning values. */ + Variation = 0x20000000u, /* Set if table has variation kerning values. */ + Backwards = 0x10000000u, /* If clear, process the glyphs forwards, that + * is, from first to last in the glyph stream. + * If we, process them from last to first. + * This flag only applies to state-table based + * 'kerx' subtables (types 1 and 4). */ + Reserved = 0x0FFFFF00u, /* Reserved, set to zero. */ + SubtableType= 0x000000FFu, /* Subtable type. */ }; + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this))); + } + + public: + HBUINT32 length; + HBUINT32 coverage; + HBUINT32 tupleCount; + public: + DEFINE_SIZE_STATIC (12); +}; + +struct KerxSubTable +{ + friend struct kerx; + + inline unsigned int get_size (void) const { return u.header.length; } + inline unsigned int get_type (void) const { return u.header.coverage & u.header.SubtableType; } + template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); switch (subtable_type) { - case 0 : return_trace (c->dispatch (u.format0)); - case 1 : return_trace (c->dispatch (u.format1)); - case 2 : return_trace (c->dispatch (u.format2)); - case 4 : return_trace (c->dispatch (u.format4)); - case 6 : return_trace (c->dispatch (u.format6)); - default: return_trace (c->default_return_value ()); + case 0: return_trace (c->dispatch (u.format0)); + case 1: return_trace (c->dispatch (u.format1)); + case 2: return_trace (c->dispatch (u.format2)); + case 4: return_trace (c->dispatch (u.format4)); + case 6: return_trace (c->dispatch (u.format6)); + default: return_trace (c->default_return_value ()); } } @@ -656,16 +818,16 @@ struct KerxTable return_trace (dispatch (c)); } -protected: + public: union { - KerxSubTableHeader header; - KerxSubTableFormat0 format0; - KerxSubTableFormat1 format1; - KerxSubTableFormat2 format2; - KerxSubTableFormat4 format4; - KerxSubTableFormat6 format6; + KerxSubTableHeader header; + KerxSubTableFormat0<KerxSubTableHeader> format0; + KerxSubTableFormat1<KerxSubTableHeader> format1; + KerxSubTableFormat2<KerxSubTableHeader> format2; + KerxSubTableFormat4<KerxSubTableHeader> format4; + KerxSubTableFormat6<KerxSubTableHeader> format6; } u; -public: + public: DEFINE_SIZE_MIN (12); }; @@ -674,73 +836,142 @@ public: * The 'kerx' Table */ -struct kerx +template <typename T> +struct KerxTable { - static const hb_tag_t tableTag = HB_AAT_TAG_kerx; + /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ + inline const T* thiz (void) const { return static_cast<const T *> (this); } - inline bool has_data (void) const { return version != 0; } + inline bool has_cross_stream (void) const + { + typedef typename T::SubTable SubTable; + + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) + { + if (st->u.header.coverage & st->u.header.CrossStream) + return true; + st = &StructAfter<SubTable> (*st); + } + return false; + } + + inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const + { + typedef typename T::SubTable SubTable; + + int v = 0; + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; + for (unsigned int i = 0; i < count; i++) + { + if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) || + !st->u.header.is_horizontal ()) + continue; + v += st->get_kerning (left, right); + st = &StructAfter<SubTable> (*st); + } + return v; + } - inline void apply (hb_aat_apply_context_t *c) const + inline bool apply (AAT::hb_aat_apply_context_t *c) const { + typedef typename T::SubTable SubTable; + + bool ret = false; + bool seenCrossStream = false; c->set_lookup_index (0); - const KerxTable *table = &firstTable; - unsigned int count = tableCount; + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; for (unsigned int i = 0; i < count; i++) { bool reverse; - if (table->u.header.coverage & (KerxTable::CrossStream)) - goto skip; /* We do NOT handle cross-stream. */ + if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation)) + goto skip; - if (HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != - bool (table->u.header.coverage & KerxTable::Vertical)) + if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ()) goto skip; - reverse = bool (table->u.header.coverage & KerxTable::Backwards) != + reverse = bool (st->u.header.coverage & st->u.header.Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start kerx subtable %d", c->lookup_index)) + if (!c->buffer->message (c->font, "start %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index)) goto skip; + if (!seenCrossStream && + (st->u.header.coverage & st->u.header.CrossStream)) + { + /* Attach all glyphs into a chain. */ + seenCrossStream = true; + hb_glyph_position_t *pos = c->buffer->pos; + unsigned int count = c->buffer->len; + for (unsigned int i = 0; i < count; i++) + { + pos[i].attach_type() = ATTACH_TYPE_CURSIVE; + pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1; + /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT, + * since there needs to be a non-zero attachment for post-positioning to + * be needed. */ + } + } + if (reverse) c->buffer->reverse (); - c->sanitizer.set_object (*table); + c->sanitizer.set_object (*st); - /* XXX Reverse-kern is not working yet... - * hb_kern_machine_t would need to know that it's reverse-kerning. - * Or better yet, make it work in reverse as well, so we don't have - * to reverse and reverse back? */ - table->dispatch (c); + ret |= st->dispatch (c); if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end kerx subtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index); skip: - table = &StructAfter<KerxTable> (*table); + st = &StructAfter<SubTable> (*st); + c->set_lookup_index (c->lookup_index + 1); } + + return ret; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!version.sanitize (c) || version < 2 || - !tableCount.sanitize (c)) + if (unlikely (!thiz()->version.sanitize (c) || + thiz()->version < T::minVersion || + !thiz()->tableCount.sanitize (c))) return_trace (false); - const KerxTable *table = &firstTable; - unsigned int count = tableCount; + typedef typename T::SubTable SubTable; + + const SubTable *st = &thiz()->firstSubTable; + unsigned int count = thiz()->tableCount; for (unsigned int i = 0; i < count; i++) { - if (!table->sanitize (c)) + if (unlikely (!st->sanitize (c))) return_trace (false); - table = &StructAfter<KerxTable> (*table); + st = &StructAfter<SubTable> (*st); } return_trace (true); } +}; + +struct kerx : KerxTable<kerx> +{ + friend struct KerxTable<kerx>; + + static const hb_tag_t tableTag = HB_AAT_TAG_kerx; + static const uint16_t minVersion = 2; + + typedef KerxSubTableHeader SubTableHeader; + typedef SubTableHeader::Types Types; + typedef KerxSubTable SubTable; + + inline bool has_data (void) const { return version; } protected: HBUINT16 version; /* The version number of the extended kerning table @@ -748,13 +979,14 @@ struct kerx HBUINT16 unused; /* Set to 0. */ HBUINT32 tableCount; /* The number of subtables included in the extended kerning * table. */ - KerxTable firstTable; /* Subtables. */ + SubTable firstSubTable; /* Subtables. */ /*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ public: DEFINE_SIZE_MIN (8); }; + } /* namespace AAT */ |