summaryrefslogtreecommitdiff
path: root/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh')
-rw-r--r--Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh391
1 files changed, 335 insertions, 56 deletions
diff --git a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
index ef452e22b29..651af2188fd 100644
--- a/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
+++ b/Build/source/libs/harfbuzz/harfbuzz-src/src/hb-aat-layout-morx-table.hh
@@ -50,7 +50,8 @@ struct RearrangementSubtable
struct driver_context_t
{
static const bool in_place = true;
- enum Flags {
+ enum Flags
+ {
MarkFirst = 0x8000, /* If set, make the current glyph the first
* glyph to be rearranged. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
@@ -163,7 +164,7 @@ struct RearrangementSubtable
driver_context_t dc (this);
- StateTableDriver<void> driver (machine, c->buffer, c->face);
+ StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
@@ -196,7 +197,8 @@ struct ContextualSubtable
struct driver_context_t
{
static const bool in_place = true;
- enum Flags {
+ enum Flags
+ {
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
@@ -268,7 +270,7 @@ struct ContextualSubtable
private:
bool mark_set;
unsigned int mark;
- const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> &subs;
+ const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false> &subs;
};
inline bool apply (hb_aat_apply_context_t *c) const
@@ -309,7 +311,7 @@ struct ContextualSubtable
protected:
StateTable<EntryData>
machine;
- LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> >
+ LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false>, false>
substitutionTables;
public:
DEFINE_SIZE_STATIC (20);
@@ -329,7 +331,8 @@ struct LigatureSubtable
struct driver_context_t
{
static const bool in_place = false;
- enum Flags {
+ enum Flags
+ {
SetComponent = 0x8000, /* Push this glyph onto the component stack for
* eventual processing. */
DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the
@@ -338,7 +341,8 @@ struct LigatureSubtable
* group. */
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
};
- enum LigActionFlags {
+ enum LigActionFlags
+ {
LigActionLast = 0x80000000, /* This is the last action in the list. This also
* implies storage. */
LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index
@@ -361,7 +365,7 @@ struct LigatureSubtable
inline bool is_actionable (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
{
- return !!(entry->flags & PerformAction);
+ return entry->flags & PerformAction;
}
inline bool transition (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
@@ -387,12 +391,20 @@ struct LigatureSubtable
unsigned int action_idx = entry->data.ligActionIndex;
unsigned int action;
unsigned int ligature_idx = 0;
+
+ if (unlikely (!match_length))
+ return true;
+
+ /* TODO Only when ligation happens? */
+ buffer->merge_out_clusters (match_positions[0], buffer->out_len);
+
+ unsigned int cursor = match_length;
do
{
- if (unlikely (!match_length))
- return false;
+ if (unlikely (!cursor))
+ break;
- buffer->move_to (match_positions[--match_length]);
+ buffer->move_to (match_positions[--cursor]);
const HBUINT32 &actionData = ligAction[action_idx];
if (unlikely (!actionData.sanitize (&c->sanitizer))) return false;
@@ -400,8 +412,10 @@ struct LigatureSubtable
uint32_t uoffset = action & LigActionOffset;
if (uoffset & 0x20000000)
- uoffset += 0xC0000000;
+ uoffset |= 0xC0000000; /* Sign-extend. */
int32_t offset = (int32_t) uoffset;
+ if (buffer->idx >= buffer->len)
+ return false; // TODO Work on previous instead?
unsigned int component_idx = buffer->cur().codepoint + offset;
const HBUINT16 &componentData = component[component_idx];
@@ -414,21 +428,21 @@ struct LigatureSubtable
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
hb_codepoint_t lig = ligatureData;
- match_positions[match_length++] = buffer->out_len;
buffer->replace_glyph (lig);
- //ligature_idx = 0; // XXX Yes or no?
- }
- else
- {
- buffer->skip_glyph ();
- end--;
+ /* Now go and delete all subsequent components. */
+ while (match_length - 1 > cursor)
+ {
+ buffer->move_to (match_positions[--match_length]);
+ buffer->skip_glyph ();
+ end--;
+ }
}
- /* TODO merge_clusters / unsafe_to_break */
action_idx++;
}
while (!(action & LigActionLast));
+ match_length = 0;
buffer->move_to (end);
}
@@ -469,11 +483,11 @@ struct LigatureSubtable
protected:
StateTable<EntryData>
machine;
- LOffsetTo<UnsizedArrayOf<HBUINT32> >
+ LOffsetTo<UnsizedArrayOf<HBUINT32>, false>
ligAction; /* Offset to the ligature action table. */
- LOffsetTo<UnsizedArrayOf<HBUINT16> >
+ LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
component; /* Offset to the component table. */
- LOffsetTo<UnsizedArrayOf<GlyphID> >
+ LOffsetTo<UnsizedArrayOf<GlyphID>, false>
ligature; /* Offset to the actual ligature lists. */
public:
DEFINE_SIZE_STATIC (28);
@@ -517,19 +531,201 @@ struct NoncontextualSubtable
struct InsertionSubtable
{
+ struct EntryData
+ {
+ HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table.
+ * The number of glyphs to be inserted is contained
+ * in the currentInsertCount field in the flags.
+ * A value of 0xFFFF indicates no insertion is to
+ * be done. */
+ HBUINT16 markedInsertIndex; /* Zero-based index into the insertion glyph table.
+ * The number of glyphs to be inserted is contained
+ * in the markedInsertCount field in the flags.
+ * A value of 0xFFFF indicates no insertion is to
+ * be done. */
+ public:
+ DEFINE_SIZE_STATIC (4);
+ };
+
+ struct driver_context_t
+ {
+ static const bool in_place = false;
+ enum Flags
+ {
+ SetMark = 0x8000, /* If set, mark the current glyph. */
+ DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
+ * going to the new state. This does not mean
+ * that the glyph pointed to is the same one as
+ * before. If you've made insertions immediately
+ * downstream of the current glyph, the next glyph
+ * processed would in fact be the first one
+ * inserted. */
+ CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero,
+ * then the specified glyph list will be inserted
+ * as a kashida-like insertion, either before or
+ * after the current glyph (depending on the state
+ * of the currentInsertBefore flag). If clear, and
+ * the currentInsertList is nonzero, then the
+ * specified glyph list will be inserted as a
+ * split-vowel-like insertion, either before or
+ * after the current glyph (depending on the state
+ * of the currentInsertBefore flag). */
+ MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero,
+ * then the specified glyph list will be inserted
+ * as a kashida-like insertion, either before or
+ * after the marked glyph (depending on the state
+ * of the markedInsertBefore flag). If clear, and
+ * the markedInsertList is nonzero, then the
+ * specified glyph list will be inserted as a
+ * split-vowel-like insertion, either before or
+ * after the marked glyph (depending on the state
+ * of the markedInsertBefore flag). */
+ CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made
+ * to the left of the current glyph. If clear,
+ * they're made to the right of the current glyph. */
+ MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be
+ * made to the left of the marked glyph. If clear,
+ * they're made to the right of the marked glyph. */
+ CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the
+ * number of glyphs to insert at the current
+ * position. Since zero means no insertions, the
+ * largest number of insertions at any given
+ * current location is 31 glyphs. */
+ MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the
+ * number of glyphs to insert at the marked
+ * position. Since zero means no insertions, the
+ * largest number of insertions at any given
+ * marked location is 31 glyphs. */
+ };
+
+ inline driver_context_t (const InsertionSubtable *table,
+ hb_aat_apply_context_t *c_) :
+ ret (false),
+ c (c_),
+ mark_set (false),
+ mark (0),
+ insertionAction (table+table->insertionAction) {}
+
+ inline bool is_actionable (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
+ (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
+ }
+ inline bool transition (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ hb_buffer_t *buffer = driver->buffer;
+ unsigned int flags = entry->flags;
+
+ if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
+ {
+ unsigned int count = (flags & MarkedInsertCount);
+ unsigned int start = entry->data.markedInsertIndex;
+ const GlyphID *glyphs = &insertionAction[start];
+ if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+
+ bool before = flags & MarkedInsertBefore;
+
+ unsigned int end = buffer->out_len;
+ buffer->move_to (mark);
+
+ if (buffer->idx < buffer->len && !before)
+ buffer->copy_glyph ();
+ /* TODO We ignore KashidaLike setting. */
+ for (unsigned int i = 0; i < count; i++)
+ buffer->output_glyph (glyphs[i]);
+ if (buffer->idx < buffer->len && !before)
+ buffer->skip_glyph ();
+
+ buffer->move_to (end + count);
+
+ buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
+ }
+
+ if (entry->data.currentInsertIndex != 0xFFFF)
+ {
+ unsigned int count = (flags & CurrentInsertCount) >> 5;
+ unsigned int start = entry->data.currentInsertIndex;
+ const GlyphID *glyphs = &insertionAction[start];
+ if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+
+ bool before = flags & CurrentInsertBefore;
+
+ unsigned int end = buffer->out_len;
+
+ if (buffer->idx < buffer->len && !before)
+ buffer->copy_glyph ();
+ /* TODO We ignore KashidaLike setting. */
+ for (unsigned int i = 0; i < count; i++)
+ buffer->output_glyph (glyphs[i]);
+ if (buffer->idx < buffer->len && !before)
+ buffer->skip_glyph ();
+
+ /* Humm. Not sure where to move to. There's this wording under
+ * DontAdvance flag:
+ *
+ * "If set, don't update the glyph index before going to the new state.
+ * This does not mean that the glyph pointed to is the same one as
+ * before. If you've made insertions immediately downstream of the
+ * current glyph, the next glyph processed would in fact be the first
+ * one inserted."
+ *
+ * This suggests that if DontAdvance is NOT set, we should move to
+ * end+count. If it *was*, then move to end, such that newly inserted
+ * glyphs are now visible.
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
+ */
+ buffer->move_to ((flags & DontAdvance) ? end : end + count);
+ }
+
+ if (flags & SetMark)
+ {
+ mark_set = true;
+ mark = buffer->out_len;
+ }
+
+ return true;
+ }
+
+ public:
+ bool ret;
+ private:
+ hb_aat_apply_context_t *c;
+ bool mark_set;
+ unsigned int mark;
+ const UnsizedArrayOf<GlyphID> &insertionAction;
+ };
+
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
- /* TODO */
- return_trace (false);
+
+ driver_context_t dc (this, c);
+
+ StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+ driver.drive (&dc);
+
+ return_trace (dc.ret);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- /* TODO */
- return_trace (true);
+ /* The rest of array sanitizations are done at run-time. */
+ return_trace (c->check_struct (this) && machine.sanitize (c) &&
+ insertionAction);
}
+
+ protected:
+ StateTable<EntryData>
+ machine;
+ LOffsetTo<UnsizedArrayOf<GlyphID>, false>
+ insertionAction; /* Byte offset from stateHeader to the start of
+ * the insertion glyph table. */
+ public:
+ DEFINE_SIZE_STATIC (20);
};
@@ -559,9 +755,27 @@ struct ChainSubtable
friend struct Chain;
inline unsigned int get_size (void) const { return length; }
- inline unsigned int get_type (void) const { return coverage & 0xFF; }
+ inline unsigned int get_type (void) const { return coverage & SubtableType; }
- enum Type {
+ enum Coverage
+ {
+ Vertical = 0x80000000, /* If set, this subtable will only be applied
+ * to vertical text. If clear, this subtable
+ * will only be applied to horizontal text. */
+ Backwards = 0x40000000, /* If set, this subtable will process glyphs
+ * in descending order. If clear, it will
+ * process the glyphs in ascending order. */
+ AllDirections = 0x20000000, /* If set, this subtable will be applied to
+ * both horizontal and vertical text (i.e.
+ * the state of bit 0x80000000 is ignored). */
+ Logical = 0x10000000, /* If set, this subtable will process glyphs
+ * in logical order (or reverse logical order,
+ * depending on the value of bit 0x80000000). */
+ Reserved = 0x0FFFFF00, /* Reserved, set to zero. */
+ SubtableType = 0x000000FF, /* Subtable type; see following table. */
+ };
+ enum Type
+ {
Rearrangement = 0,
Contextual = 1,
Ligature = 2,
@@ -569,11 +783,6 @@ struct ChainSubtable
Insertion = 5
};
- inline void apply (hb_aat_apply_context_t *c) const
- {
- dispatch (c);
- }
-
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
{
@@ -619,28 +828,94 @@ struct Chain
{
inline void apply (hb_aat_apply_context_t *c) const
{
- const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
+ uint32_t flags = defaultFlags;
+ {
+ /* Compute applicable flags. TODO Should move this to planning
+ * stage and take user-requested features into account. */
+ unsigned int count = featureCount;
+ for (unsigned i = 0; i < count; i++)
+ {
+ const Feature &feature = featureZ[i];
+ if (false) /* XXX Check if feature enabled... */
+ {
+ flags &= feature.disableFlags;
+ flags |= feature.enableFlags;
+ }
+ }
+ }
+
+ const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
+ bool reverse;
+
+ if (!(subtable->subFeatureFlags & flags))
+ goto skip;
+
+ if (!(subtable->coverage & ChainSubtable::AllDirections) &&
+ HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
+ bool (subtable->coverage & ChainSubtable::Vertical))
+ goto skip;
+
+ /* Buffer contents is always in logical direction. Determine if
+ * we need to reverse before applying this subtable. We reverse
+ * back after if we did reverse indeed.
+ *
+ * Quoting the spac:
+ * """
+ * Bits 28 and 30 of the coverage field control the order in which
+ * glyphs are processed when the subtable is run by the layout engine.
+ * Bit 28 is used to indicate if the glyph processing direction is
+ * the same as logical order or layout order. Bit 30 is used to
+ * indicate whether glyphs are processed forwards or backwards within
+ * that order.
+
+ Bit 30 Bit 28 Interpretation for Horizontal Text
+ 0 0 The subtable is processed in layout order
+ (the same order as the glyphs, which is
+ always left-to-right).
+ 1 0 The subtable is processed in reverse layout order
+ (the order opposite that of the glyphs, which is
+ always right-to-left).
+ 0 1 The subtable is processed in logical order
+ (the same order as the characters, which may be
+ left-to-right or right-to-left).
+ 1 1 The subtable is processed in reverse logical order
+ (the order opposite that of the characters, which
+ may be right-to-left or left-to-right).
+ */
+ reverse = subtable->coverage & ChainSubtable::Logical ?
+ bool (subtable->coverage & ChainSubtable::Backwards) :
+ bool (subtable->coverage & ChainSubtable::Backwards) !=
+ HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
+
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
- {
- c->set_lookup_index (c->lookup_index + 1);
- continue;
- }
+ goto skip;
- subtable->apply (c);
- subtable = &StructAfter<ChainSubtable> (*subtable);
+ if (reverse)
+ c->buffer->reverse ();
+
+ c->sanitizer.set_object (*subtable);
+
+ subtable->dispatch (c);
+
+ if (reverse)
+ c->buffer->reverse ();
(void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
+ if (unlikely (!c->buffer->successful)) return;
+
+ skip:
+ subtable = &StructAfter<ChainSubtable> (*subtable);
c->set_lookup_index (c->lookup_index + 1);
}
}
inline unsigned int get_size (void) const { return length; }
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int major) const
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
{
TRACE_SANITIZE (this);
if (!length.sanitize (c) ||
@@ -648,10 +923,10 @@ struct Chain
!c->check_range (this, length))
return_trace (false);
- if (!c->check_array (featureZ, featureZ[0].static_size, featureCount))
+ if (!c->check_array (featureZ.arrayZ, featureCount))
return_trace (false);
- const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
+ const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
@@ -669,9 +944,9 @@ struct Chain
HBUINT32 featureCount; /* Number of feature subtable entries. */
HBUINT32 subtableCount; /* The number of subtables in the chain. */
- Feature featureZ[VAR]; /* Features. */
-/*ChainSubtable subtableX[VAR];*//* Subtables. */
-/*subtableGlyphCoverageArray*/ /* Only if major == 3. */
+ UnsizedArrayOf<Feature> featureZ; /* Features. */
+/*ChainSubtable firstSubtable;*//* Subtables. */
+/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
public:
DEFINE_SIZE_MIN (16);
@@ -679,21 +954,25 @@ struct Chain
/*
- * The 'mort'/'morx' Tables
+ * The 'morx' Table
*/
struct morx
{
static const hb_tag_t tableTag = HB_AAT_TAG_morx;
+ inline bool has_data (void) const { return version != 0; }
+
inline void apply (hb_aat_apply_context_t *c) const
{
+ if (unlikely (!c->buffer->successful)) return;
c->set_lookup_index (0);
- const Chain *chain = chainsZ;
+ const Chain *chain = &firstChain;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
chain->apply (c);
+ if (unlikely (!c->buffer->successful)) return;
chain = &StructAfter<Chain> (*chain);
}
}
@@ -701,16 +980,15 @@ struct morx
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!version.sanitize (c) ||
- (version.major >> (sizeof (HBUINT32) == 4 ? 1 : 0)) != 1 ||
+ if (!version.sanitize (c) || version < 2 ||
!chainCount.sanitize (c))
return_trace (false);
- const Chain *chain = chainsZ;
+ const Chain *chain = &firstChain;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
- if (!chain->sanitize (c, version.major))
+ if (!chain->sanitize (c, version))
return_trace (false);
chain = &StructAfter<Chain> (*chain);
}
@@ -719,11 +997,12 @@ struct morx
}
protected:
- FixedVersion<>version; /* Version number of the glyph metamorphosis table.
- * 1 for mort, 2 or 3 for morx. */
+ HBUINT16 version; /* Version number of the glyph metamorphosis table.
+ * 2 or 3. */
+ HBUINT16 unused; /* Set to 0. */
HBUINT32 chainCount; /* Number of metamorphosis chains contained in this
* table. */
- Chain chainsZ[VAR]; /* Chains. */
+ Chain firstChain; /* Chains. */
public:
DEFINE_SIZE_MIN (8);