[aat] Implement LigatureSubtable
We form the Zapfino ligature now. Yay! No further testing done.
This commit is contained in:
parent
f07ce661a2
commit
e6f283ed7d
|
@ -627,23 +627,26 @@ struct StateTableDriver
|
||||||
inline void drive (context_t *c)
|
inline void drive (context_t *c)
|
||||||
{
|
{
|
||||||
hb_glyph_info_t *info = buffer->info;
|
hb_glyph_info_t *info = buffer->info;
|
||||||
unsigned int count = buffer->len;
|
|
||||||
|
if (!c->in_place)
|
||||||
|
buffer->clear_output ();
|
||||||
|
|
||||||
unsigned int state = 0;
|
unsigned int state = 0;
|
||||||
bool last_was_dont_advance = false;
|
bool last_was_dont_advance = false;
|
||||||
for (buffer->idx = 0; buffer->idx <= count;)
|
for (buffer->idx = 0;;)
|
||||||
{
|
{
|
||||||
if (!state)
|
if (!state)
|
||||||
last_zero = buffer->idx;
|
last_zero = buffer->idx;
|
||||||
|
|
||||||
unsigned int klass = buffer->idx < count ?
|
unsigned int klass = buffer->idx < buffer->len ?
|
||||||
machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
|
machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
|
||||||
0 /* End of text */;
|
0 /* End of text */;
|
||||||
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
|
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
|
||||||
if (unlikely (!entry))
|
if (unlikely (!entry))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
c->transition (this, entry);
|
if (unlikely (!c->transition (this, entry)))
|
||||||
|
break;
|
||||||
|
|
||||||
if (entry->flags & context_t::DontAdvance)
|
if (entry->flags & context_t::DontAdvance)
|
||||||
{
|
{
|
||||||
|
@ -655,7 +658,7 @@ struct StateTableDriver
|
||||||
dont_advance_set = hb_set_create ();
|
dont_advance_set = hb_set_create ();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int key = info[buffer->idx].codepoint | (state << 16);
|
unsigned int key = info[buffer->idx].codepoint ^ (state << 16);
|
||||||
if (likely (!dont_advance_set->has (key)))
|
if (likely (!dont_advance_set->has (key)))
|
||||||
{
|
{
|
||||||
dont_advance_set->add (key);
|
dont_advance_set->add (key);
|
||||||
|
@ -667,16 +670,20 @@ struct StateTableDriver
|
||||||
else
|
else
|
||||||
last_was_dont_advance = false;
|
last_was_dont_advance = false;
|
||||||
|
|
||||||
|
state = entry->newState;
|
||||||
|
|
||||||
|
if (buffer->idx == buffer->len)
|
||||||
|
break;
|
||||||
|
|
||||||
if (!last_was_dont_advance)
|
if (!last_was_dont_advance)
|
||||||
buffer->next_glyph ();
|
buffer->next_glyph ();
|
||||||
|
|
||||||
state = entry->newState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c->in_place)
|
if (!c->in_place)
|
||||||
{
|
{
|
||||||
for (buffer->idx = 0; buffer->idx <= count;)
|
for (; buffer->idx < buffer->len;)
|
||||||
buffer->next_glyph ();
|
buffer->next_glyph ();
|
||||||
|
buffer->swap_buffers ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct RearrangementSubtable
|
||||||
start (0), end (0),
|
start (0), end (0),
|
||||||
last_zero_before_start (0) {}
|
last_zero_before_start (0) {}
|
||||||
|
|
||||||
inline void transition (StateTableDriver<void> *driver,
|
inline bool transition (StateTableDriver<void> *driver,
|
||||||
const Entry<void> *entry)
|
const Entry<void> *entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
@ -138,6 +138,8 @@ struct RearrangementSubtable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -200,7 +202,7 @@ struct ContextualSubtable
|
||||||
last_zero_before_mark (0),
|
last_zero_before_mark (0),
|
||||||
subs (table+table->substitutionTables) {}
|
subs (table+table->substitutionTables) {}
|
||||||
|
|
||||||
inline void transition (StateTableDriver<EntryData> *driver,
|
inline bool transition (StateTableDriver<EntryData> *driver,
|
||||||
const Entry<EntryData> *entry)
|
const Entry<EntryData> *entry)
|
||||||
{
|
{
|
||||||
hb_buffer_t *buffer = driver->buffer;
|
hb_buffer_t *buffer = driver->buffer;
|
||||||
|
@ -235,6 +237,8 @@ struct ContextualSubtable
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -309,28 +313,113 @@ struct LigatureSubtable
|
||||||
* group. */
|
* group. */
|
||||||
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
|
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
|
||||||
};
|
};
|
||||||
|
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. */
|
||||||
|
};
|
||||||
|
|
||||||
inline driver_context_t (const LigatureSubtable *table) :
|
inline driver_context_t (const LigatureSubtable *table,
|
||||||
ret (false) {}
|
hb_aat_apply_context_t *c_) :
|
||||||
|
ret (false),
|
||||||
|
c (c_),
|
||||||
|
ligAction (table+table->ligAction),
|
||||||
|
component (table+table->component),
|
||||||
|
ligature (table+table->ligature),
|
||||||
|
match_length (0) {}
|
||||||
|
|
||||||
inline void transition (StateTableDriver<EntryData> *driver,
|
inline bool transition (StateTableDriver<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;
|
||||||
|
|
||||||
/* TODO */
|
if (flags & SetComponent)
|
||||||
|
{
|
||||||
|
if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Never mark same index twice, in case DontAdvance was used... */
|
||||||
|
if (match_length && match_positions[match_length - 1] == buffer->out_len)
|
||||||
|
match_length--;
|
||||||
|
|
||||||
|
match_positions[match_length++] = buffer->out_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PerformAction)
|
||||||
|
{
|
||||||
|
unsigned int end = buffer->out_len;
|
||||||
|
unsigned int action_idx = entry->data.ligActionIndex;
|
||||||
|
unsigned int action;
|
||||||
|
unsigned int ligature_idx = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (unlikely (!match_length))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
buffer->move_to (match_positions[match_length - 1]);
|
||||||
|
|
||||||
|
const HBUINT32 &actionData = ligAction[action_idx];
|
||||||
|
if (unlikely (!actionData.sanitize (&c->sanitizer))) return false;
|
||||||
|
action = actionData;
|
||||||
|
|
||||||
|
uint32_t uoffset = action & LigActionOffset;
|
||||||
|
if (uoffset & 0x20000000)
|
||||||
|
uoffset += 0xC0000000;
|
||||||
|
int32_t offset = (int32_t) uoffset;
|
||||||
|
unsigned int component_idx = buffer->cur().codepoint + offset;
|
||||||
|
|
||||||
|
const HBUINT16 &componentData = component[component_idx];
|
||||||
|
if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
|
||||||
|
ligature_idx += componentData;
|
||||||
|
|
||||||
|
if (action & (LigActionStore | LigActionLast))
|
||||||
|
{
|
||||||
|
const GlyphID &ligatureData = ligature[ligature_idx];
|
||||||
|
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
|
||||||
|
hb_codepoint_t lig = ligatureData;
|
||||||
|
|
||||||
|
buffer->replace_glyph (lig);
|
||||||
|
|
||||||
|
//ligature_idx = 0; // XXX Yes or no?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer->skip_glyph ();
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
match_length--;
|
||||||
|
action_idx++;
|
||||||
|
}
|
||||||
|
while (!(action & LigActionLast));
|
||||||
|
buffer->move_to (end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool ret;
|
bool ret;
|
||||||
private:
|
private:
|
||||||
|
hb_aat_apply_context_t *c;
|
||||||
|
const UnsizedArrayOf<HBUINT32> &ligAction;
|
||||||
|
const UnsizedArrayOf<HBUINT16> &component;
|
||||||
|
const UnsizedArrayOf<GlyphID> &ligature;
|
||||||
|
unsigned int match_length;
|
||||||
|
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool apply (hb_aat_apply_context_t *c) const
|
inline bool apply (hb_aat_apply_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_APPLY (this);
|
TRACE_APPLY (this);
|
||||||
|
|
||||||
driver_context_t dc (this);
|
driver_context_t dc (this, c);
|
||||||
|
|
||||||
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
|
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
|
||||||
driver.drive (&dc);
|
driver.drive (&dc);
|
||||||
|
@ -341,8 +430,9 @@ struct LigatureSubtable
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
/* The main sanitization is done at run-time. */
|
/* The rest of array sanitizations are done at run-time. */
|
||||||
return machine.sanitize (c);
|
return c->check_struct (this) && machine.sanitize (c) &&
|
||||||
|
ligAction && component && ligature;
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue