struct driver_context_t
{ static constexpr bool in_place = true; 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 * before going to the new state. This means * that the glyph index doesn't change, even
* if the glyph at that index has changed. */
MarkLast = 0x2000, /* If set, make the current glyph the last
* glyph to be rearranged. */
Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */
Verb = 0x000F, /* The type of rearrangement specified. */
};
driver_context_t (const RearrangementSubtable *table HB_UNUSED) :
ret (false),
start (0), end (0) {}
struct EntryData
{
HBUINT16 markIndex; /* Index of the substitution table for the
* marked glyph (use 0xFFFF for none). */
HBUINT16 currentIndex; /* Index of the substitution table for the
* current glyph (use 0xFFFF for none). */ public:
DEFINE_SIZE_STATIC (4);
};
struct driver_context_t
{ static constexpr bool in_place = true; 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. */
Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */
};
driver_context_t (const ContextualSubtable *table_,
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
gdef (*c->gdef_table),
mark_set (false),
has_glyph_classes (gdef.has_glyph_classes ()),
mark (0),
table (table_),
subs (table+table->substitutionTables) {}
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
} void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver, const Entry<EntryData> &entry)
{ /* Looks like CoreText applies neither mark nor current substitution for
* end-of-text if mark was not explicitly set. */ if (buffer->idx == buffer->len && !mark_set) return;
template <> struct LigatureEntry<true>
{ 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
next iteration. */
PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature
* group. */
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
};
struct EntryData
{
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry * for processing this group, if indicated
* by the flags. */ public:
DEFINE_SIZE_STATIC (2);
};
staticunsignedint ligActionIndex (const Entry<EntryData> &entry)
{ return entry.data.ligActionIndex; }
}; template <> struct LigatureEntry<false>
{ 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
next iteration. */
Offset = 0x3FFF, /* Byte offset from beginning of subtable to the * ligature action list. This value must be a
* multiple of 4. */
};
struct driver_context_t
{ static constexpr bool in_place = false; enum
{
DontAdvance = LigatureEntryT::DontAdvance,
}; 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 * in the ligature table in place of the marked
* (i.e. currently-popped) glyph. */
LigActionOffset = 0x3FFFFFFF, /* A 30-bit value which is sign-extended to 32-bits * and added to the glyph ID, resulting in an index
* into the component table. */
};
bool ret = false; unsignedint num_glyphs = c->face->get_num_glyphs ();
hb_glyph_info_t *info = c->buffer->info; unsignedint count = c->buffer->len; // If there's only one range, we already checked the flag. auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr; for (unsignedint i = 0; i < count; i++)
{ /* This block copied from StateTableDriver::drive. Keep in sync. */ if (last_range)
{ auto *range = last_range;
{ unsigned cluster = info[i].cluster; while (cluster < range->cluster_first)
range--; while (cluster > range->cluster_last)
range++;
last_range = range;
} if (!(range->flags & c->subtable_flags)) continue;
}
const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); if (replacement)
{
info[i].codepoint = *replacement;
c->buffer_digest.add (*replacement); if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&info[i],
gdef.get_glyph_props (*replacement));
ret = true;
}
}
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 constexpr 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. */
};
driver_context_t (const InsertionSubtable *table,
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
mark (0),
insertionAction (table+table->insertionAction) {}
unsignedint end = buffer->out_len; if (unlikely (!buffer->move_to (mark))) return;
if (buffer->idx < buffer->len && !before) if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; for (unsignedint i = 0; i < count; i++)
c->buffer_digest.add (glyphs[i]);
ret = true; if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
if (unlikely (!buffer->move_to (end + count))) return;
if (buffer->idx < buffer->len && !before) if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; 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
*/ if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
}
}
public:
HBUINT16 featureType; /* The type of feature. */
HBUINT16 featureSetting; /* The feature's setting (aka selector). */
HBUINT32 enableFlags; /* Flags for the settings that this feature
* and setting enables. */
HBUINT32 disableFlags; /* Complement of flags for the settings that this
* feature and setting disable. */
/* The following is a calloc because when we are collecting subtables, * some of them might be invalid and hence not collect; as a result, * we might not fill in all the count entries of the subtables array. * Zeroing it allows the set digest to gatekeep it without having to
* initialize it further. */ auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size); if (unlikely (!thiz)) return nullptr;
enum Coverage
{
Vertical = 0x80, /* If set, this subtable will only be applied * to vertical text. If clear, this subtable
* will only be applied to horizontal text. */
Backwards = 0x40, /* If set, this subtable will process glyphs * in descending order. If clear, it will
* process the glyphs in ascending order. */
AllDirections = 0x20, /* If set, this subtable will be applied to * both horizontal and vertical text (i.e.
* the state of bit 0x80000000 is ignored). */
Logical = 0x10, /* If set, this subtable will process glyphs * in logical order (or reverse logical order,
* depending on the value of bit 0x80000000). */
}; enum Type
{
Rearrangement = 0,
Contextual = 1,
Ligature = 2,
Noncontextual = 4,
Insertion = 5
};
/* 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->get_coverage () & ChainSubtable<Types>::Logical ? bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) : bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) goto skip;
if (!c->check_array (featureZ.arrayZ, featureCount))
return_trace (false);
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); unsignedint count = subtableCount; for (unsignedint i = 0; i < count; i++)
{ if (!subtable->sanitize (c))
return_trace (false);
hb_barrier ();
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
}
if (version >= 3)
{ const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable; if (!coverage->sanitize (c, count))
return_trace (false);
}
return_trace (true);
}
protected:
HBUINT32 defaultFlags; /* The default specification for subtables. */
HBUINT32 length; /* Total byte count, including this header. */
HBUINT featureCount; /* Number of feature subtable entries. */
HBUINT subtableCount; /* The number of subtables in the chain. */
UnsizedArrayOf<Feature> featureZ; /* Features. */ /*ChainSubtable firstSubtable;*//* Subtables. */ /*SubtableGlyphCoverage coverages*//* Only if version >= 3. */
const Chain<Types> *chain = &firstChain; unsignedint count = chainCount; for (unsignedint i = 0; i < count; i++)
{ if (!chain->sanitize (c, version))
return_trace (false);
hb_barrier ();
chain = &StructAfter<Chain<Types>> (*chain);
}
return_trace (true);
}
protected:
HBUINT16 version; /* Version number of the glyph metamorphosis table.
* 1, 2, or 3. */
HBUINT16 unused; /* Set to 0. */
HBUINT32 chainCount; /* Number of metamorphosis chains contained in this
* table. */
Chain<Types> firstChain; /* Chains. */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.