summaryrefslogtreecommitdiff
path: root/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-kerx-table.hh
diff options
context:
space:
mode:
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.hh522
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 */