1 #ifndef OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH 2 #define OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH 3 4 #include "Common.hh" 5 #include "LigatureSet.hh" 6 7 namespace OT { 8 namespace Layout { 9 namespace GSUB_impl { 10 11 template <typename Types> 12 struct LigatureSubstFormat1_2 13 { 14 protected: 15 HBUINT16 format; /* Format identifier--format = 1 */ 16 typename Types::template OffsetTo<Coverage> 17 coverage; /* Offset to Coverage table--from 18 * beginning of Substitution table */ 19 Array16Of<typename Types::template OffsetTo<LigatureSet<Types>>> 20 ligatureSet; /* Array LigatureSet tables 21 * ordered by Coverage Index */ 22 public: 23 DEFINE_SIZE_ARRAY (4 + Types::size, ligatureSet); 24 sanitizeOT::Layout::GSUB_impl::LigatureSubstFormat1_225 bool sanitize (hb_sanitize_context_t *c) const 26 { 27 TRACE_SANITIZE (this); 28 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); 29 } 30 intersectsOT::Layout::GSUB_impl::LigatureSubstFormat1_231 bool intersects (const hb_set_t *glyphs) const 32 { 33 return 34 + hb_zip (this+coverage, ligatureSet) 35 | hb_filter (*glyphs, hb_first) 36 | hb_map (hb_second) 37 | hb_map ([this, glyphs] (const typename Types::template OffsetTo<LigatureSet<Types>> &_) 38 { return (this+_).intersects (glyphs); }) 39 | hb_any 40 ; 41 } 42 may_have_non_1to1OT::Layout::GSUB_impl::LigatureSubstFormat1_243 bool may_have_non_1to1 () const 44 { return true; } 45 closureOT::Layout::GSUB_impl::LigatureSubstFormat1_246 void closure (hb_closure_context_t *c) const 47 { 48 + hb_zip (this+coverage, ligatureSet) 49 | hb_filter (c->parent_active_glyphs (), hb_first) 50 | hb_map (hb_second) 51 | hb_map (hb_add (this)) 52 | hb_apply ([c] (const LigatureSet<Types> &_) { _.closure (c); }) 53 ; 54 55 } 56 closure_lookupsOT::Layout::GSUB_impl::LigatureSubstFormat1_257 void closure_lookups (hb_closure_lookups_context_t *c) const {} 58 collect_glyphsOT::Layout::GSUB_impl::LigatureSubstFormat1_259 void collect_glyphs (hb_collect_glyphs_context_t *c) const 60 { 61 if (unlikely (!(this+coverage).collect_coverage (c->input))) return; 62 63 + hb_zip (this+coverage, ligatureSet) 64 | hb_map (hb_second) 65 | hb_map (hb_add (this)) 66 | hb_apply ([c] (const LigatureSet<Types> &_) { _.collect_glyphs (c); }) 67 ; 68 } 69 get_coverageOT::Layout::GSUB_impl::LigatureSubstFormat1_270 const Coverage &get_coverage () const { return this+coverage; } 71 would_applyOT::Layout::GSUB_impl::LigatureSubstFormat1_272 bool would_apply (hb_would_apply_context_t *c) const 73 { 74 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); 75 if (likely (index == NOT_COVERED)) return false; 76 77 const auto &lig_set = this+ligatureSet[index]; 78 return lig_set.would_apply (c); 79 } 80 applyOT::Layout::GSUB_impl::LigatureSubstFormat1_281 bool apply (hb_ot_apply_context_t *c) const 82 { 83 TRACE_APPLY (this); 84 85 unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); 86 if (likely (index == NOT_COVERED)) return_trace (false); 87 88 const auto &lig_set = this+ligatureSet[index]; 89 return_trace (lig_set.apply (c)); 90 } 91 serializeOT::Layout::GSUB_impl::LigatureSubstFormat1_292 bool serialize (hb_serialize_context_t *c, 93 hb_sorted_array_t<const HBGlyphID16> first_glyphs, 94 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, 95 hb_array_t<const HBGlyphID16> ligatures_list, 96 hb_array_t<const unsigned int> component_count_list, 97 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) 98 { 99 TRACE_SERIALIZE (this); 100 if (unlikely (!c->extend_min (this))) return_trace (false); 101 if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false); 102 for (unsigned int i = 0; i < first_glyphs.length; i++) 103 { 104 unsigned int ligature_count = ligature_per_first_glyph_count_list[i]; 105 if (unlikely (!ligatureSet[i] 106 .serialize_serialize (c, 107 ligatures_list.sub_array (0, ligature_count), 108 component_count_list.sub_array (0, ligature_count), 109 component_list))) return_trace (false); 110 ligatures_list += ligature_count; 111 component_count_list += ligature_count; 112 } 113 return_trace (coverage.serialize_serialize (c, first_glyphs)); 114 } 115 subsetOT::Layout::GSUB_impl::LigatureSubstFormat1_2116 bool subset (hb_subset_context_t *c) const 117 { 118 TRACE_SUBSET (this); 119 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 120 const hb_map_t &glyph_map = *c->plan->glyph_map; 121 122 auto *out = c->serializer->start_embed (*this); 123 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 124 out->format = format; 125 126 // Due to a bug in some older versions of windows 7 the Coverage table must be 127 // packed after the LigatureSet and Ligature tables, so serialize Coverage first 128 // which places it last in the packed order. 129 hb_set_t new_coverage; 130 + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) 131 | hb_filter (glyphset, hb_first) 132 | hb_filter ([&] (const LigatureSet<Types>& _) { 133 return _.intersects_lig_glyph (&glyphset); 134 }, hb_second) 135 | hb_map (hb_first) 136 | hb_sink (new_coverage); 137 138 if (!c->serializer->push<Coverage> () 139 ->serialize (c->serializer, 140 + new_coverage.iter () | hb_map_retains_sorting (glyph_map))) 141 { 142 c->serializer->pop_discard (); 143 return_trace (false); 144 } 145 146 unsigned coverage_idx = c->serializer->pop_pack (); 147 c->serializer->add_link (out->coverage, coverage_idx); 148 149 + hb_zip (this+coverage, ligatureSet) 150 | hb_filter (new_coverage, hb_first) 151 | hb_map (hb_second) 152 // to ensure that the repacker always orders the coverage table after the LigatureSet 153 // and LigatureSubtable's they will be linked to the Coverage table via a virtual link 154 // the coverage table object idx is passed down to facilitate this. 155 | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx)) 156 ; 157 158 return_trace (bool (new_coverage)); 159 } 160 }; 161 162 } 163 } 164 } 165 166 #endif /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */ 167