Merge branch 'master' into cff-more-arrayof-fixes
This commit is contained in:
commit
c685644386
|
@ -511,9 +511,10 @@ struct StateTable
|
||||||
const Entry<Extra> *get_entries () const
|
const Entry<Extra> *get_entries () const
|
||||||
{ return (this+entryTable).arrayZ; }
|
{ return (this+entryTable).arrayZ; }
|
||||||
|
|
||||||
const Entry<Extra> *get_entryZ (int state, unsigned int klass) const
|
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||||
{
|
{
|
||||||
if (unlikely (klass >= nClasses)) return nullptr;
|
if (unlikely (klass >= nClasses))
|
||||||
|
klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
|
||||||
|
|
||||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||||
|
@ -521,7 +522,7 @@ struct StateTable
|
||||||
unsigned int entry = states[state * nClasses + klass];
|
unsigned int entry = states[state * nClasses + klass];
|
||||||
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
|
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
|
||||||
|
|
||||||
return &entries[entry];
|
return entries[entry];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c,
|
bool sanitize (hb_sanitize_context_t *c,
|
||||||
|
@ -529,6 +530,7 @@ struct StateTable
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
if (unlikely (!(c->check_struct (this) &&
|
if (unlikely (!(c->check_struct (this) &&
|
||||||
|
nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
|
||||||
classTable.sanitize (c, this)))) return_trace (false);
|
classTable.sanitize (c, this)))) return_trace (false);
|
||||||
|
|
||||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||||
|
@ -571,7 +573,7 @@ struct StateTable
|
||||||
-min_state,
|
-min_state,
|
||||||
row_stride)))
|
row_stride)))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
if ((c->max_ops -= state_neg - min_state) < 0)
|
if ((c->max_ops -= state_neg - min_state) <= 0)
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
{ /* Sweep new states. */
|
{ /* Sweep new states. */
|
||||||
const HBUSHORT *stop = &states[min_state * num_classes];
|
const HBUSHORT *stop = &states[min_state * num_classes];
|
||||||
|
@ -590,7 +592,7 @@ struct StateTable
|
||||||
max_state + 1,
|
max_state + 1,
|
||||||
row_stride)))
|
row_stride)))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
if ((c->max_ops -= max_state - state_pos + 1) < 0)
|
if ((c->max_ops -= max_state - state_pos + 1) <= 0)
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
{ /* Sweep new states. */
|
{ /* Sweep new states. */
|
||||||
if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
|
if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
|
||||||
|
@ -606,7 +608,7 @@ struct StateTable
|
||||||
|
|
||||||
if (unlikely (!c->check_array (entries, num_entries)))
|
if (unlikely (!c->check_array (entries, num_entries)))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
if ((c->max_ops -= num_entries - entry) < 0)
|
if ((c->max_ops -= num_entries - entry) <= 0)
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
{ /* Sweep new entries. */
|
{ /* Sweep new entries. */
|
||||||
const Entry<Extra> *stop = &entries[num_entries];
|
const Entry<Extra> *stop = &entries[num_entries];
|
||||||
|
@ -745,16 +747,13 @@ struct StateTableDriver
|
||||||
buffer->clear_output ();
|
buffer->clear_output ();
|
||||||
|
|
||||||
int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
|
int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
|
||||||
bool last_was_dont_advance = false;
|
|
||||||
for (buffer->idx = 0; buffer->successful;)
|
for (buffer->idx = 0; buffer->successful;)
|
||||||
{
|
{
|
||||||
unsigned int klass = buffer->idx < buffer->len ?
|
unsigned int klass = buffer->idx < buffer->len ?
|
||||||
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
|
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
|
||||||
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
|
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
|
||||||
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
|
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
|
||||||
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
|
const Entry<EntryData> &entry = machine.get_entry (state, klass);
|
||||||
if (unlikely (!entry))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Unsafe-to-break before this if not in state 0, as things might
|
/* Unsafe-to-break before this if not in state 0, as things might
|
||||||
* go differently if we start from state 0 here.
|
* go differently if we start from state 0 here.
|
||||||
|
@ -765,31 +764,28 @@ struct StateTableDriver
|
||||||
/* If there's no action and we're just epsilon-transitioning to state 0,
|
/* If there's no action and we're just epsilon-transitioning to state 0,
|
||||||
* safe to break. */
|
* safe to break. */
|
||||||
if (c->is_actionable (this, entry) ||
|
if (c->is_actionable (this, entry) ||
|
||||||
!(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
|
!(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
|
||||||
entry->flags == context_t::DontAdvance))
|
entry.flags == context_t::DontAdvance))
|
||||||
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
|
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unsafe-to-break if end-of-text would kick in here. */
|
/* Unsafe-to-break if end-of-text would kick in here. */
|
||||||
if (buffer->idx + 2 <= buffer->len)
|
if (buffer->idx + 2 <= buffer->len)
|
||||||
{
|
{
|
||||||
const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
|
const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
|
||||||
if (c->is_actionable (this, end_entry))
|
if (c->is_actionable (this, end_entry))
|
||||||
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
|
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely (!c->transition (this, entry)))
|
c->transition (this, entry);
|
||||||
break;
|
|
||||||
|
|
||||||
last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
|
state = machine.new_state (entry.newState);
|
||||||
|
|
||||||
state = machine.new_state (entry->newState);
|
|
||||||
DEBUG_MSG (APPLY, nullptr, "s%d", state);
|
DEBUG_MSG (APPLY, nullptr, "s%d", state);
|
||||||
|
|
||||||
if (buffer->idx == buffer->len)
|
if (buffer->idx == buffer->len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!last_was_dont_advance)
|
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
|
||||||
buffer->next_glyph ();
|
buffer->next_glyph ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,11 +170,11 @@ struct Format1Entry<true>
|
||||||
DEFINE_SIZE_STATIC (2);
|
DEFINE_SIZE_STATIC (2);
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool performAction (const Entry<EntryData> *entry)
|
static bool performAction (const Entry<EntryData> &entry)
|
||||||
{ return entry->data.kernActionIndex != 0xFFFF; }
|
{ return entry.data.kernActionIndex != 0xFFFF; }
|
||||||
|
|
||||||
static unsigned int kernActionIndex (const Entry<EntryData> *entry)
|
static unsigned int kernActionIndex (const Entry<EntryData> &entry)
|
||||||
{ return entry->data.kernActionIndex; }
|
{ return entry.data.kernActionIndex; }
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct Format1Entry<false>
|
struct Format1Entry<false>
|
||||||
|
@ -192,11 +192,11 @@ struct Format1Entry<false>
|
||||||
|
|
||||||
typedef void EntryData;
|
typedef void EntryData;
|
||||||
|
|
||||||
static bool performAction (const Entry<EntryData> *entry)
|
static bool performAction (const Entry<EntryData> &entry)
|
||||||
{ return entry->flags & Offset; }
|
{ return entry.flags & Offset; }
|
||||||
|
|
||||||
static unsigned int kernActionIndex (const Entry<EntryData> *entry)
|
static unsigned int kernActionIndex (const Entry<EntryData> &entry)
|
||||||
{ return entry->flags & Offset; }
|
{ return entry.flags & Offset; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename KernSubTableHeader>
|
template <typename KernSubTableHeader>
|
||||||
|
@ -228,15 +228,15 @@ struct KerxSubTableFormat1
|
||||||
crossStream (table->header.coverage & table->header.CrossStream) {}
|
crossStream (table->header.coverage & table->header.CrossStream) {}
|
||||||
|
|
||||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
return Format1EntryT::performAction (entry);
|
return Format1EntryT::performAction (entry);
|
||||||
}
|
}
|
||||||
bool transition (StateTableDriver<Types, EntryData> *driver,
|
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
unsigned int flags = entry->flags;
|
unsigned int flags = entry.flags;
|
||||||
|
|
||||||
if (flags & Format1EntryT::Reset)
|
if (flags & Format1EntryT::Reset)
|
||||||
depth = 0;
|
depth = 0;
|
||||||
|
@ -259,7 +259,7 @@ struct KerxSubTableFormat1
|
||||||
if (!c->sanitizer.check_array (actions, depth, tuple_count))
|
if (!c->sanitizer.check_array (actions, depth, tuple_count))
|
||||||
{
|
{
|
||||||
depth = 0;
|
depth = 0;
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_mask_t kern_mask = c->plan->kern_mask;
|
hb_mask_t kern_mask = c->plan->kern_mask;
|
||||||
|
@ -334,8 +334,6 @@ struct KerxSubTableFormat1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -498,16 +496,16 @@ struct KerxSubTableFormat4
|
||||||
mark (0) {}
|
mark (0) {}
|
||||||
|
|
||||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
return entry->data.ankrActionIndex != 0xFFFF;
|
return entry.data.ankrActionIndex != 0xFFFF;
|
||||||
}
|
}
|
||||||
bool transition (StateTableDriver<Types, EntryData> *driver,
|
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
|
||||||
if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
|
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
|
||||||
{
|
{
|
||||||
hb_glyph_position_t &o = buffer->cur_pos();
|
hb_glyph_position_t &o = buffer->cur_pos();
|
||||||
switch (action_type)
|
switch (action_type)
|
||||||
|
@ -515,9 +513,8 @@ struct KerxSubTableFormat4
|
||||||
case 0: /* Control Point Actions.*/
|
case 0: /* Control Point Actions.*/
|
||||||
{
|
{
|
||||||
/* indexed into glyph outline. */
|
/* indexed into glyph outline. */
|
||||||
const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
|
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
|
||||||
if (!c->sanitizer.check_array (data, 2))
|
if (!c->sanitizer.check_array (data, 2)) return;
|
||||||
return false;
|
|
||||||
HB_UNUSED unsigned int markControlPoint = *data++;
|
HB_UNUSED unsigned int markControlPoint = *data++;
|
||||||
HB_UNUSED unsigned int currControlPoint = *data++;
|
HB_UNUSED unsigned int currControlPoint = *data++;
|
||||||
hb_position_t markX = 0;
|
hb_position_t markX = 0;
|
||||||
|
@ -532,7 +529,7 @@ struct KerxSubTableFormat4
|
||||||
currControlPoint,
|
currControlPoint,
|
||||||
HB_DIRECTION_LTR /*XXX*/,
|
HB_DIRECTION_LTR /*XXX*/,
|
||||||
&currX, &currY))
|
&currX, &currY))
|
||||||
return true; /* True, such that the machine continues. */
|
return;
|
||||||
|
|
||||||
o.x_offset = markX - currX;
|
o.x_offset = markX - currX;
|
||||||
o.y_offset = markY - currY;
|
o.y_offset = markY - currY;
|
||||||
|
@ -542,9 +539,8 @@ struct KerxSubTableFormat4
|
||||||
case 1: /* Anchor Point Actions. */
|
case 1: /* Anchor Point Actions. */
|
||||||
{
|
{
|
||||||
/* Indexed into 'ankr' table. */
|
/* Indexed into 'ankr' table. */
|
||||||
const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
|
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
|
||||||
if (!c->sanitizer.check_array (data, 2))
|
if (!c->sanitizer.check_array (data, 2)) return;
|
||||||
return false;
|
|
||||||
unsigned int markAnchorPoint = *data++;
|
unsigned int markAnchorPoint = *data++;
|
||||||
unsigned int currAnchorPoint = *data++;
|
unsigned int currAnchorPoint = *data++;
|
||||||
const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
|
const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
|
||||||
|
@ -561,9 +557,8 @@ struct KerxSubTableFormat4
|
||||||
|
|
||||||
case 2: /* Control Point Coordinate Actions. */
|
case 2: /* Control Point Coordinate Actions. */
|
||||||
{
|
{
|
||||||
const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex];
|
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
|
||||||
if (!c->sanitizer.check_array (data, 4))
|
if (!c->sanitizer.check_array (data, 4)) return;
|
||||||
return false;
|
|
||||||
int markX = *data++;
|
int markX = *data++;
|
||||||
int markY = *data++;
|
int markY = *data++;
|
||||||
int currX = *data++;
|
int currX = *data++;
|
||||||
|
@ -579,13 +574,11 @@ struct KerxSubTableFormat4
|
||||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->flags & Mark)
|
if (entry.flags & Mark)
|
||||||
{
|
{
|
||||||
mark_set = true;
|
mark_set = true;
|
||||||
mark = buffer->idx;
|
mark = buffer->idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -74,15 +74,15 @@ struct RearrangementSubtable
|
||||||
start (0), end (0) {}
|
start (0), end (0) {}
|
||||||
|
|
||||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
return (entry->flags & Verb) && start < end;
|
return (entry.flags & Verb) && start < end;
|
||||||
}
|
}
|
||||||
bool transition (StateTableDriver<Types, EntryData> *driver,
|
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
unsigned int flags = entry->flags;
|
unsigned int flags = entry.flags;
|
||||||
|
|
||||||
if (flags & MarkFirst)
|
if (flags & MarkFirst)
|
||||||
start = buffer->idx;
|
start = buffer->idx;
|
||||||
|
@ -152,8 +152,6 @@ struct RearrangementSubtable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -223,39 +221,39 @@ struct ContextualSubtable
|
||||||
subs (table+table->substitutionTables) {}
|
subs (table+table->substitutionTables) {}
|
||||||
|
|
||||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver,
|
bool is_actionable (StateTableDriver<Types, EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
|
||||||
if (buffer->idx == buffer->len && !mark_set)
|
if (buffer->idx == buffer->len && !mark_set)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
|
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
|
||||||
}
|
}
|
||||||
bool transition (StateTableDriver<Types, EntryData> *driver,
|
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
|
||||||
/* Looks like CoreText applies neither mark nor current substitution for
|
/* Looks like CoreText applies neither mark nor current substitution for
|
||||||
* end-of-text if mark was not explicitly set. */
|
* end-of-text if mark was not explicitly set. */
|
||||||
if (buffer->idx == buffer->len && !mark_set)
|
if (buffer->idx == buffer->len && !mark_set)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
const GlyphID *replacement;
|
const GlyphID *replacement;
|
||||||
|
|
||||||
replacement = nullptr;
|
replacement = nullptr;
|
||||||
if (Types::extended)
|
if (Types::extended)
|
||||||
{
|
{
|
||||||
if (entry->data.markIndex != 0xFFFF)
|
if (entry.data.markIndex != 0xFFFF)
|
||||||
{
|
{
|
||||||
const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
|
const Lookup<GlyphID> &lookup = subs[entry.data.markIndex];
|
||||||
replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
|
replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned int offset = entry->data.markIndex + buffer->info[mark].codepoint;
|
unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
|
||||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||||
|
@ -272,15 +270,15 @@ struct ContextualSubtable
|
||||||
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
||||||
if (Types::extended)
|
if (Types::extended)
|
||||||
{
|
{
|
||||||
if (entry->data.currentIndex != 0xFFFF)
|
if (entry.data.currentIndex != 0xFFFF)
|
||||||
{
|
{
|
||||||
const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
|
const Lookup<GlyphID> &lookup = subs[entry.data.currentIndex];
|
||||||
replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
|
replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned int offset = entry->data.currentIndex + buffer->info[idx].codepoint;
|
unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
|
||||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||||
|
@ -292,13 +290,11 @@ struct ContextualSubtable
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->flags & SetMark)
|
if (entry.flags & SetMark)
|
||||||
{
|
{
|
||||||
mark_set = true;
|
mark_set = true;
|
||||||
mark = buffer->idx;
|
mark = buffer->idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -385,11 +381,11 @@ struct LigatureEntry<true>
|
||||||
DEFINE_SIZE_STATIC (2);
|
DEFINE_SIZE_STATIC (2);
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool performAction (const Entry<EntryData> *entry)
|
static bool performAction (const Entry<EntryData> &entry)
|
||||||
{ return entry->flags & PerformAction; }
|
{ return entry.flags & PerformAction; }
|
||||||
|
|
||||||
static unsigned int ligActionIndex (const Entry<EntryData> *entry)
|
static unsigned int ligActionIndex (const Entry<EntryData> &entry)
|
||||||
{ return entry->data.ligActionIndex; }
|
{ return entry.data.ligActionIndex; }
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct LigatureEntry<false>
|
struct LigatureEntry<false>
|
||||||
|
@ -407,11 +403,11 @@ struct LigatureEntry<false>
|
||||||
|
|
||||||
typedef void EntryData;
|
typedef void EntryData;
|
||||||
|
|
||||||
static bool performAction (const Entry<EntryData> *entry)
|
static bool performAction (const Entry<EntryData> &entry)
|
||||||
{ return entry->flags & Offset; }
|
{ return entry.flags & Offset; }
|
||||||
|
|
||||||
static unsigned int ligActionIndex (const Entry<EntryData> *entry)
|
static unsigned int ligActionIndex (const Entry<EntryData> &entry)
|
||||||
{ return entry->flags & Offset; }
|
{ return entry.flags & Offset; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -453,26 +449,23 @@ struct LigatureSubtable
|
||||||
match_length (0) {}
|
match_length (0) {}
|
||||||
|
|
||||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
return LigatureEntryT::performAction (entry);
|
return LigatureEntryT::performAction (entry);
|
||||||
}
|
}
|
||||||
bool transition (StateTableDriver<Types, EntryData> *driver,
|
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
|
||||||
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
|
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
|
||||||
if (entry->flags & LigatureEntryT::SetComponent)
|
if (entry.flags & LigatureEntryT::SetComponent)
|
||||||
{
|
{
|
||||||
if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Never mark same index twice, in case DontAdvance was used... */
|
/* Never mark same index twice, in case DontAdvance was used... */
|
||||||
if (match_length && match_positions[match_length - 1] == buffer->out_len)
|
if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
|
||||||
match_length--;
|
match_length--;
|
||||||
|
|
||||||
match_positions[match_length++] = buffer->out_len;
|
match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
|
||||||
DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
|
DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,10 +475,10 @@ struct LigatureSubtable
|
||||||
unsigned int end = buffer->out_len;
|
unsigned int end = buffer->out_len;
|
||||||
|
|
||||||
if (unlikely (!match_length))
|
if (unlikely (!match_length))
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
if (buffer->idx >= buffer->len)
|
if (buffer->idx >= buffer->len)
|
||||||
return false; // TODO Work on previous instead?
|
return; /* TODO Work on previous instead? */
|
||||||
|
|
||||||
unsigned int cursor = match_length;
|
unsigned int cursor = match_length;
|
||||||
|
|
||||||
|
@ -506,9 +499,9 @@ struct LigatureSubtable
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
|
DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
|
||||||
buffer->move_to (match_positions[--cursor]);
|
buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
|
||||||
|
|
||||||
if (unlikely (!actionData->sanitize (&c->sanitizer))) return false;
|
if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
|
||||||
action = *actionData;
|
action = *actionData;
|
||||||
|
|
||||||
uint32_t uoffset = action & LigActionOffset;
|
uint32_t uoffset = action & LigActionOffset;
|
||||||
|
@ -518,7 +511,7 @@ struct LigatureSubtable
|
||||||
unsigned int component_idx = buffer->cur().codepoint + offset;
|
unsigned int component_idx = buffer->cur().codepoint + offset;
|
||||||
component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
|
component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
|
||||||
const HBUINT16 &componentData = component[component_idx];
|
const HBUINT16 &componentData = component[component_idx];
|
||||||
if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
|
if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
|
||||||
ligature_idx += componentData;
|
ligature_idx += componentData;
|
||||||
|
|
||||||
DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
|
DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
|
||||||
|
@ -528,23 +521,23 @@ struct LigatureSubtable
|
||||||
{
|
{
|
||||||
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
|
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
|
||||||
const GlyphID &ligatureData = ligature[ligature_idx];
|
const GlyphID &ligatureData = ligature[ligature_idx];
|
||||||
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
|
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
|
||||||
hb_codepoint_t lig = ligatureData;
|
hb_codepoint_t lig = ligatureData;
|
||||||
|
|
||||||
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
|
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
|
||||||
buffer->replace_glyph (lig);
|
buffer->replace_glyph (lig);
|
||||||
|
|
||||||
unsigned int lig_end = match_positions[match_length - 1] + 1;
|
unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
|
||||||
/* Now go and delete all subsequent components. */
|
/* Now go and delete all subsequent components. */
|
||||||
while (match_length - 1 > cursor)
|
while (match_length - 1u > cursor)
|
||||||
{
|
{
|
||||||
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
|
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
|
||||||
buffer->move_to (match_positions[--match_length]);
|
buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
|
||||||
buffer->replace_glyph (DELETED_GLYPH);
|
buffer->replace_glyph (DELETED_GLYPH);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->move_to (lig_end);
|
buffer->move_to (lig_end);
|
||||||
buffer->merge_out_clusters (match_positions[cursor], buffer->out_len);
|
buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
actionData++;
|
actionData++;
|
||||||
|
@ -552,8 +545,6 @@ struct LigatureSubtable
|
||||||
while (!(action & LigActionLast));
|
while (!(action & LigActionLast));
|
||||||
buffer->move_to (end);
|
buffer->move_to (end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -718,25 +709,25 @@ struct InsertionSubtable
|
||||||
insertionAction (table+table->insertionAction) {}
|
insertionAction (table+table->insertionAction) {}
|
||||||
|
|
||||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
|
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
|
||||||
(entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
|
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
|
||||||
}
|
}
|
||||||
bool transition (StateTableDriver<Types, EntryData> *driver,
|
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> &entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
unsigned int flags = entry->flags;
|
unsigned int flags = entry.flags;
|
||||||
|
|
||||||
unsigned mark_loc = buffer->out_len;
|
unsigned mark_loc = buffer->out_len;
|
||||||
|
|
||||||
if (entry->data.markedInsertIndex != 0xFFFF)
|
if (entry.data.markedInsertIndex != 0xFFFF)
|
||||||
{
|
{
|
||||||
unsigned int count = (flags & MarkedInsertCount);
|
unsigned int count = (flags & MarkedInsertCount);
|
||||||
unsigned int start = entry->data.markedInsertIndex;
|
unsigned int start = entry.data.markedInsertIndex;
|
||||||
const GlyphID *glyphs = &insertionAction[start];
|
const GlyphID *glyphs = &insertionAction[start];
|
||||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
|
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
|
||||||
|
|
||||||
bool before = flags & MarkedInsertBefore;
|
bool before = flags & MarkedInsertBefore;
|
||||||
|
|
||||||
|
@ -759,12 +750,12 @@ struct InsertionSubtable
|
||||||
if (flags & SetMark)
|
if (flags & SetMark)
|
||||||
mark = mark_loc;
|
mark = mark_loc;
|
||||||
|
|
||||||
if (entry->data.currentInsertIndex != 0xFFFF)
|
if (entry.data.currentInsertIndex != 0xFFFF)
|
||||||
{
|
{
|
||||||
unsigned int count = (flags & CurrentInsertCount) >> 5;
|
unsigned int count = (flags & CurrentInsertCount) >> 5;
|
||||||
unsigned int start = entry->data.currentInsertIndex;
|
unsigned int start = entry.data.currentInsertIndex;
|
||||||
const GlyphID *glyphs = &insertionAction[start];
|
const GlyphID *glyphs = &insertionAction[start];
|
||||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
|
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
|
||||||
|
|
||||||
bool before = flags & CurrentInsertBefore;
|
bool before = flags & CurrentInsertBefore;
|
||||||
|
|
||||||
|
@ -795,8 +786,6 @@ struct InsertionSubtable
|
||||||
*/
|
*/
|
||||||
buffer->move_to ((flags & DontAdvance) ? end : end + count);
|
buffer->move_to ((flags & DontAdvance) ? end : end + count);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in New Issue