From e6f283ed7db6f8e2f8016dcbf07e589c40976aa6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 19 Jan 2018 18:08:56 -0800 Subject: [PATCH] [aat] Implement LigatureSubtable We form the Zapfino ligature now. Yay! No further testing done. --- src/hb-aat-layout-common-private.hh | 25 ++++--- src/hb-aat-layout-morx-table.hh | 108 +++++++++++++++++++++++++--- 2 files changed, 115 insertions(+), 18 deletions(-) diff --git a/src/hb-aat-layout-common-private.hh b/src/hb-aat-layout-common-private.hh index 538615f76..d62bafc5d 100644 --- a/src/hb-aat-layout-common-private.hh +++ b/src/hb-aat-layout-common-private.hh @@ -627,23 +627,26 @@ struct StateTableDriver inline void drive (context_t *c) { hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; + + if (!c->in_place) + buffer->clear_output (); + unsigned int state = 0; bool last_was_dont_advance = false; - for (buffer->idx = 0; buffer->idx <= count;) + for (buffer->idx = 0;;) { if (!state) 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) : 0 /* End of text */; const Entry *entry = machine.get_entryZ (state, klass); if (unlikely (!entry)) break; - c->transition (this, entry); - + if (unlikely (!c->transition (this, entry))) + break; if (entry->flags & context_t::DontAdvance) { @@ -655,7 +658,7 @@ struct StateTableDriver 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))) { dont_advance_set->add (key); @@ -667,16 +670,20 @@ struct StateTableDriver else last_was_dont_advance = false; + state = entry->newState; + + if (buffer->idx == buffer->len) + break; + if (!last_was_dont_advance) buffer->next_glyph (); - - state = entry->newState; } if (!c->in_place) { - for (buffer->idx = 0; buffer->idx <= count;) + for (; buffer->idx < buffer->len;) buffer->next_glyph (); + buffer->swap_buffers (); } } diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index 5b3402be5..4a997eeca 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -61,7 +61,7 @@ struct RearrangementSubtable start (0), end (0), last_zero_before_start (0) {} - inline void transition (StateTableDriver *driver, + inline bool transition (StateTableDriver *driver, const Entry *entry) { hb_buffer_t *buffer = driver->buffer; @@ -138,6 +138,8 @@ struct RearrangementSubtable } } } + + return true; } public: @@ -200,7 +202,7 @@ struct ContextualSubtable last_zero_before_mark (0), subs (table+table->substitutionTables) {} - inline void transition (StateTableDriver *driver, + inline bool transition (StateTableDriver *driver, const Entry *entry) { hb_buffer_t *buffer = driver->buffer; @@ -235,6 +237,8 @@ struct ContextualSubtable ret = true; } } + + return true; } public: @@ -309,28 +313,113 @@ struct LigatureSubtable * group. */ 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) : - ret (false) {} + inline driver_context_t (const LigatureSubtable *table, + 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 *driver, + inline bool transition (StateTableDriver *driver, const Entry *entry) { hb_buffer_t *buffer = driver->buffer; + unsigned int flags = entry->flags; + + 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]); - /* TODO */ + 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: bool ret; private: + hb_aat_apply_context_t *c; + const UnsizedArrayOf &ligAction; + const UnsizedArrayOf &component; + const UnsizedArrayOf &ligature; + unsigned int match_length; + unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; }; inline bool apply (hb_aat_apply_context_t *c) const { TRACE_APPLY (this); - driver_context_t dc (this); + driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->face); driver.drive (&dc); @@ -341,8 +430,9 @@ struct LigatureSubtable inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - /* The main sanitization is done at run-time. */ - return machine.sanitize (c); + /* The rest of array sanitizations are done at run-time. */ + return c->check_struct (this) && machine.sanitize (c) && + ligAction && component && ligature; return_trace (true); }