From 403feb3804cb61a73c32ff2c87659fd49900fe4f Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Wed, 23 Mar 2022 15:19:04 -0700 Subject: [PATCH] [reorg] Move LigatureSubst to new layout. --- src/Makefile.sources | 4 + src/OT/Layout/GSUB/Ligature.hh | 135 +++++++ src/OT/Layout/GSUB/LigatureSet.hh | 118 ++++++ src/OT/Layout/GSUB/LigatureSubst.hh | 59 +++ src/OT/Layout/GSUB/LigatureSubstFormat1.hh | 165 ++++++++ src/hb-ot-layout-gsub-table.hh | 420 +-------------------- src/meson.build | 4 + 7 files changed, 487 insertions(+), 418 deletions(-) create mode 100644 src/OT/Layout/GSUB/Ligature.hh create mode 100644 src/OT/Layout/GSUB/LigatureSet.hh create mode 100644 src/OT/Layout/GSUB/LigatureSubst.hh create mode 100644 src/OT/Layout/GSUB/LigatureSubstFormat1.hh diff --git a/src/Makefile.sources b/src/Makefile.sources index d15cf63b6..e41d7d338 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -98,6 +98,10 @@ HB_BASE_sources = \ OT/Layout/GSUB/AlternateSubstFormat1.hh \ OT/Layout/GSUB/AlternateSubst.hh \ OT/Layout/GSUB/AlternateSet.hh \ + OT/Layout/GSUB/LigatureSubstFormat1.hh \ + OT/Layout/GSUB/LigatureSubst.hh \ + OT/Layout/GSUB/LigatureSet.hh \ + OT/Layout/GSUB/Ligature.hh \ hb-ot-layout-gsubgpos.hh \ hb-ot-layout-jstf-table.hh \ hb-ot-layout.cc \ diff --git a/src/OT/Layout/GSUB/Ligature.hh b/src/OT/Layout/GSUB/Ligature.hh new file mode 100644 index 000000000..0448d925d --- /dev/null +++ b/src/OT/Layout/GSUB/Ligature.hh @@ -0,0 +1,135 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURE_HH +#define OT_LAYOUT_GSUB_LIGATURE_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct Ligature +{ + protected: + HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */ + HeadlessArrayOf + component; /* Array of component GlyphIDs--start + * with the second component--ordered + * in writing direction */ + public: + DEFINE_SIZE_ARRAY (4, component); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { return hb_all (component, glyphs); } + + void closure (hb_closure_context_t *c) const + { + if (!intersects (c->glyphs)) return; + c->output->add (ligGlyph); + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + c->input->add_array (component.arrayZ, component.get_length ()); + c->output->add (ligGlyph); + } + + bool would_apply (hb_would_apply_context_t *c) const + { + if (c->len != component.lenP1) + return false; + + for (unsigned int i = 1; i < c->len; i++) + if (likely (c->glyphs[i] != component[i])) + return false; + + return true; + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int count = component.lenP1; + + if (unlikely (!count)) return_trace (false); + + /* Special-case to make it in-place and not consider this + * as a "ligated" substitution. */ + if (unlikely (count == 1)) + { + c->replace_glyph (ligGlyph); + return_trace (true); + } + + unsigned int total_component_count = 0; + + unsigned int match_end = 0; + unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; + + if (likely (!match_input (c, count, + &component[1], + match_glyph, + nullptr, + &match_end, + match_positions, + &total_component_count))) + { + c->buffer->unsafe_to_concat (c->buffer->idx, match_end); + return_trace (false); + } + + ligate_input (c, + count, + match_positions, + match_end, + ligGlyph, + total_component_count); + + return_trace (true); + } + + template + bool serialize (hb_serialize_context_t *c, + hb_codepoint_t ligature, + Iterator components /* Starting from second */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + ligGlyph = ligature; + if (unlikely (!component.serialize (c, components))) return_trace (false); + return_trace (true); + } + + bool subset (hb_subset_context_t *c, unsigned coverage_idx) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); + // Ensure Coverage table is always packed after this. + c->serializer->add_virtual_link (coverage_idx); + + auto it = + + hb_iter (component) + | hb_map (glyph_map) + ; + + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, + glyph_map[ligGlyph], + it)); } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURE_HH */ diff --git a/src/OT/Layout/GSUB/LigatureSet.hh b/src/OT/Layout/GSUB/LigatureSet.hh new file mode 100644 index 000000000..185b324b3 --- /dev/null +++ b/src/OT/Layout/GSUB/LigatureSet.hh @@ -0,0 +1,118 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURESET_HH +#define OT_LAYOUT_GSUB_LIGATURESET_HH + +#include "Common.hh" +#include "Ligature.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct LigatureSet +{ + protected: + Array16OfOffset16To + ligature; /* Array LigatureSet tables + * ordered by preference */ + public: + DEFINE_SIZE_ARRAY (2, ligature); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (ligature.sanitize (c, this)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); }) + | hb_any + ; + } + + void closure (hb_closure_context_t *c) const + { + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Ligature &_) { _.closure (c); }) + ; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); }) + ; + } + + bool would_apply (hb_would_apply_context_t *c) const + { + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([c] (const Ligature &_) { return _.would_apply (c); }) + | hb_any + ; + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + { + const Ligature &lig = this+ligature[i]; + if (lig.apply (c)) return_trace (true); + } + + return_trace (false); + } + + bool serialize (hb_serialize_context_t *c, + hb_array_t ligatures, + hb_array_t component_count_list, + hb_array_t &component_list /* Starting from second for each ligature */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); + for (unsigned int i = 0; i < ligatures.length; i++) + { + unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0); + if (unlikely (!ligature[i].serialize_serialize (c, + ligatures[i], + component_list.sub_array (0, component_count)))) + return_trace (false); + component_list += component_count; + } + return_trace (true); + } + + bool subset (hb_subset_context_t *c, unsigned coverage_idx) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + hb_iter (ligature) + | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx)) + | hb_drain + ; + + if (bool (out->ligature)) + // Ensure Coverage table is always packed after this. + c->serializer->add_virtual_link (coverage_idx); + + return_trace (bool (out->ligature)); + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURESET_HH */ diff --git a/src/OT/Layout/GSUB/LigatureSubst.hh b/src/OT/Layout/GSUB/LigatureSubst.hh new file mode 100644 index 000000000..a029bf5e9 --- /dev/null +++ b/src/OT/Layout/GSUB/LigatureSubst.hh @@ -0,0 +1,59 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURESUBST_HH +#define OT_LAYOUT_GSUB_LIGATURESUBST_HH + +#include "Common.hh" +#include "LigatureSubstFormat1.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct LigatureSubst +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + LigatureSubstFormat1 format1; + } u; + + public: + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t first_glyphs, + hb_array_t ligature_per_first_glyph_count_list, + hb_array_t ligatures_list, + hb_array_t component_count_list, + hb_array_t component_list /* Starting from second for each ligature */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (u.format))) return_trace (false); + unsigned int format = 1; + u.format = format; + switch (u.format) { + case 1: return_trace (u.format1.serialize (c, + first_glyphs, + ligature_per_first_glyph_count_list, + ligatures_list, + component_count_list, + component_list)); + default:return_trace (false); + } + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURESUBST_HH */ diff --git a/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh new file mode 100644 index 000000000..19dfe9846 --- /dev/null +++ b/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -0,0 +1,165 @@ +#ifndef OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH +#define OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH + +#include "Common.hh" +#include "LigatureSet.hh" + +namespace OT { +namespace Layout { +namespace GSUB { + +struct LigatureSubstFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To + coverage; /* Offset to Coverage table--from + * beginning of Substitution table */ + Array16OfOffset16To + ligatureSet; /* Array LigatureSet tables + * ordered by Coverage Index */ + public: + DEFINE_SIZE_ARRAY (6, ligatureSet); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return + + hb_zip (this+coverage, ligatureSet) + | hb_filter (*glyphs, hb_first) + | hb_map (hb_second) + | hb_map ([this, glyphs] (const Offset16To &_) + { return (this+_).intersects (glyphs); }) + | hb_any + ; + } + + bool may_have_non_1to1 () const + { return true; } + + void closure (hb_closure_context_t *c) const + { + + hb_zip (this+coverage, ligatureSet) + | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) + ; + + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + + hb_zip (this+coverage, ligatureSet) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); }) + ; + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool would_apply (hb_would_apply_context_t *c) const + { + unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); + if (likely (index == NOT_COVERED)) return false; + + const LigatureSet &lig_set = this+ligatureSet[index]; + return lig_set.would_apply (c); + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + + unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + const LigatureSet &lig_set = this+ligatureSet[index]; + return_trace (lig_set.apply (c)); + } + + bool serialize (hb_serialize_context_t *c, + hb_sorted_array_t first_glyphs, + hb_array_t ligature_per_first_glyph_count_list, + hb_array_t ligatures_list, + hb_array_t component_count_list, + hb_array_t component_list /* Starting from second for each ligature */) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false); + for (unsigned int i = 0; i < first_glyphs.length; i++) + { + unsigned int ligature_count = ligature_per_first_glyph_count_list[i]; + if (unlikely (!ligatureSet[i] + .serialize_serialize (c, + ligatures_list.sub_array (0, ligature_count), + component_count_list.sub_array (0, ligature_count), + component_list))) return_trace (false); + ligatures_list += ligature_count; + component_count_list += ligature_count; + } + return_trace (coverage.serialize_serialize (c, first_glyphs)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + // Due to a bug in some older versions of windows 7 the Coverage table must be + // packed after the LigatureSet and Ligature tables, so serialize Coverage first + // which places it last in the packed order. + hb_set_t new_coverage; + + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) + | hb_filter (glyphset, hb_first) + | hb_filter ([&] (const LigatureSet& _) { + return _.intersects (&glyphset); + }, hb_second) + | hb_map (hb_first) + | hb_sink (new_coverage); + + if (!c->serializer->push () + ->serialize (c->serializer, + + new_coverage.iter () | hb_map_retains_sorting (glyph_map))) + { + c->serializer->pop_discard (); + return_trace (false); + } + + unsigned coverage_idx = c->serializer->pop_pack (); + c->serializer->add_link (out->coverage, coverage_idx); + + + hb_zip (this+coverage, ligatureSet) + | hb_filter (new_coverage, hb_first) + | hb_map (hb_second) + // to ensure that the repacker always orders the coverage table after the LigatureSet + // and LigatureSubtable's they will be linked to the Coverage table via a virtual link + // the coverage table object idx is passed down to facilitate this. + | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx)) + ; + + return_trace (bool (new_coverage)); + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */ diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh index 1787cbc88..e02ffdf27 100644 --- a/src/hb-ot-layout-gsub-table.hh +++ b/src/hb-ot-layout-gsub-table.hh @@ -34,6 +34,7 @@ #include "OT/Layout/GSUB/SingleSubst.hh" #include "OT/Layout/GSUB/MultipleSubst.hh" #include "OT/Layout/GSUB/AlternateSubst.hh" +#include "OT/Layout/GSUB/LigatureSubst.hh" namespace OT { @@ -41,424 +42,7 @@ using Layout::GSUB::hb_codepoint_pair_t; using Layout::GSUB::SingleSubst; using Layout::GSUB::MultipleSubst; using Layout::GSUB::AlternateSubst; - -struct Ligature -{ - bool intersects (const hb_set_t *glyphs) const - { return hb_all (component, glyphs); } - - void closure (hb_closure_context_t *c) const - { - if (!intersects (c->glyphs)) return; - c->output->add (ligGlyph); - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - c->input->add_array (component.arrayZ, component.get_length ()); - c->output->add (ligGlyph); - } - - bool would_apply (hb_would_apply_context_t *c) const - { - if (c->len != component.lenP1) - return false; - - for (unsigned int i = 1; i < c->len; i++) - if (likely (c->glyphs[i] != component[i])) - return false; - - return true; - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - unsigned int count = component.lenP1; - - if (unlikely (!count)) return_trace (false); - - /* Special-case to make it in-place and not consider this - * as a "ligated" substitution. */ - if (unlikely (count == 1)) - { - c->replace_glyph (ligGlyph); - return_trace (true); - } - - unsigned int total_component_count = 0; - - unsigned int match_end = 0; - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; - - if (likely (!match_input (c, count, - &component[1], - match_glyph, - nullptr, - &match_end, - match_positions, - &total_component_count))) - { - c->buffer->unsafe_to_concat (c->buffer->idx, match_end); - return_trace (false); - } - - ligate_input (c, - count, - match_positions, - match_end, - ligGlyph, - total_component_count); - - return_trace (true); - } - - template - bool serialize (hb_serialize_context_t *c, - hb_codepoint_t ligature, - Iterator components /* Starting from second */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - ligGlyph = ligature; - if (unlikely (!component.serialize (c, components))) return_trace (false); - return_trace (true); - } - - bool subset (hb_subset_context_t *c, unsigned coverage_idx) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); - // Ensure Coverage table is always packed after this. - c->serializer->add_virtual_link (coverage_idx); - - auto it = - + hb_iter (component) - | hb_map (glyph_map) - ; - - auto *out = c->serializer->start_embed (*this); - return_trace (out->serialize (c->serializer, - glyph_map[ligGlyph], - it)); - } - - public: - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); - } - - protected: - HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */ - HeadlessArrayOf - component; /* Array of component GlyphIDs--start - * with the second component--ordered - * in writing direction */ - public: - DEFINE_SIZE_ARRAY (4, component); -}; - -struct LigatureSet -{ - bool intersects (const hb_set_t *glyphs) const - { - return - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); }) - | hb_any - ; - } - - void closure (hb_closure_context_t *c) const - { - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_apply ([c] (const Ligature &_) { _.closure (c); }) - ; - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); }) - ; - } - - bool would_apply (hb_would_apply_context_t *c) const - { - return - + hb_iter (ligature) - | hb_map (hb_add (this)) - | hb_map ([c] (const Ligature &_) { return _.would_apply (c); }) - | hb_any - ; - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - unsigned int num_ligs = ligature.len; - for (unsigned int i = 0; i < num_ligs; i++) - { - const Ligature &lig = this+ligature[i]; - if (lig.apply (c)) return_trace (true); - } - - return_trace (false); - } - - bool serialize (hb_serialize_context_t *c, - hb_array_t ligatures, - hb_array_t component_count_list, - hb_array_t &component_list /* Starting from second for each ligature */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); - for (unsigned int i = 0; i < ligatures.length; i++) - { - unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0); - if (unlikely (!ligature[i].serialize_serialize (c, - ligatures[i], - component_list.sub_array (0, component_count)))) - return_trace (false); - component_list += component_count; - } - return_trace (true); - } - - bool subset (hb_subset_context_t *c, unsigned coverage_idx) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - + hb_iter (ligature) - | hb_filter (subset_offset_array (c, out->ligature, this, coverage_idx)) - | hb_drain - ; - - if (bool (out->ligature)) - // Ensure Coverage table is always packed after this. - c->serializer->add_virtual_link (coverage_idx); - - return_trace (bool (out->ligature)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (ligature.sanitize (c, this)); - } - - protected: - Array16OfOffset16To - ligature; /* Array LigatureSet tables - * ordered by preference */ - public: - DEFINE_SIZE_ARRAY (2, ligature); -}; - -struct LigatureSubstFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { - return - + hb_zip (this+coverage, ligatureSet) - | hb_filter (*glyphs, hb_first) - | hb_map (hb_second) - | hb_map ([this, glyphs] (const Offset16To &_) - { return (this+_).intersects (glyphs); }) - | hb_any - ; - } - - bool may_have_non_1to1 () const - { return true; } - - void closure (hb_closure_context_t *c) const - { - + hb_zip (this+coverage, ligatureSet) - | hb_filter (c->parent_active_glyphs (), hb_first) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) - ; - - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - - + hb_zip (this+coverage, ligatureSet) - | hb_map (hb_second) - | hb_map (hb_add (this)) - | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); }) - ; - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool would_apply (hb_would_apply_context_t *c) const - { - unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); - if (likely (index == NOT_COVERED)) return false; - - const LigatureSet &lig_set = this+ligatureSet[index]; - return lig_set.would_apply (c); - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - - unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - const LigatureSet &lig_set = this+ligatureSet[index]; - return_trace (lig_set.apply (c)); - } - - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t first_glyphs, - hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, - hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false); - for (unsigned int i = 0; i < first_glyphs.length; i++) - { - unsigned int ligature_count = ligature_per_first_glyph_count_list[i]; - if (unlikely (!ligatureSet[i] - .serialize_serialize (c, - ligatures_list.sub_array (0, ligature_count), - component_count_list.sub_array (0, ligature_count), - component_list))) return_trace (false); - ligatures_list += ligature_count; - component_count_list += ligature_count; - } - return_trace (coverage.serialize_serialize (c, first_glyphs)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->format = format; - - // Due to a bug in some older versions of windows 7 the Coverage table must be - // packed after the LigatureSet and Ligature tables, so serialize Coverage first - // which places it last in the packed order. - hb_set_t new_coverage; - + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) - | hb_filter (glyphset, hb_first) - | hb_filter ([&] (const LigatureSet& _) { - return _.intersects (&glyphset); - }, hb_second) - | hb_map (hb_first) - | hb_sink (new_coverage); - - if (!c->serializer->push () - ->serialize (c->serializer, - + new_coverage.iter () | hb_map_retains_sorting (glyph_map))) - { - c->serializer->pop_discard (); - return_trace (false); - } - - unsigned coverage_idx = c->serializer->pop_pack (); - c->serializer->add_link (out->coverage, coverage_idx); - - + hb_zip (this+coverage, ligatureSet) - | hb_filter (new_coverage, hb_first) - | hb_map (hb_second) - // to ensure that the repacker always orders the coverage table after the LigatureSet - // and LigatureSubtable's they will be linked to the Coverage table via a virtual link - // the coverage table object idx is passed down to facilitate this. - | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx)) - ; - - return_trace (bool (new_coverage)); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To - coverage; /* Offset to Coverage table--from - * beginning of Substitution table */ - Array16OfOffset16To - ligatureSet; /* Array LigatureSet tables - * ordered by Coverage Index */ - public: - DEFINE_SIZE_ARRAY (6, ligatureSet); -}; - -struct LigatureSubst -{ - bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t first_glyphs, - hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, - hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return_trace (false); - unsigned int format = 1; - u.format = format; - switch (u.format) { - case 1: return_trace (u.format1.serialize (c, - first_glyphs, - ligature_per_first_glyph_count_list, - ligatures_list, - component_count_list, - component_list)); - default:return_trace (false); - } - } - - template - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - LigatureSubstFormat1 format1; - } u; -}; - +using Layout::GSUB::LigatureSubst; struct ContextSubst : Context {}; diff --git a/src/meson.build b/src/meson.build index fcdfb708f..30f35cbaa 100644 --- a/src/meson.build +++ b/src/meson.build @@ -102,6 +102,10 @@ hb_base_sources = files( 'OT/Layout/GSUB/AlternateSubstFormat1.hh', 'OT/Layout/GSUB/AlternateSubst.hh', 'OT/Layout/GSUB/AlternateSet.hh', + 'OT/Layout/GSUB/LigatureSubstFormat1.hh', + 'OT/Layout/GSUB/LigatureSubst.hh', + 'OT/Layout/GSUB/LigatureSet.hh', + 'OT/Layout/GSUB/Ligature.hh', 'hb-ot-layout-gsubgpos.hh', 'hb-ot-layout-jstf-table.hh', 'hb-ot-layout.cc',