LigatureSubstFormat1.hh (6725B)
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 25 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 31 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 43 bool may_have_non_1to1 () const 44 { return true; } 45 46 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 57 void closure_lookups (hb_closure_lookups_context_t *c) const {} 58 59 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 70 const Coverage &get_coverage () const { return this+coverage; } 71 72 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 81 struct external_cache_t 82 { 83 hb_ot_layout_mapping_cache_t coverage; 84 hb_set_digest_t seconds; 85 }; 86 void *external_cache_create () const 87 { 88 external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t)); 89 if (likely (cache)) 90 { 91 cache->coverage.clear (); 92 93 cache->seconds.init (); 94 + hb_iter (ligatureSet) 95 | hb_map (hb_add (this)) 96 | hb_apply ([cache] (const LigatureSet<Types> &_) { _.collect_seconds (cache->seconds); }) 97 ; 98 } 99 return cache; 100 } 101 102 bool apply (hb_ot_apply_context_t *c, void *external_cache) const 103 { 104 TRACE_APPLY (this); 105 hb_buffer_t *buffer = c->buffer; 106 107 #ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE 108 external_cache_t *cache = (external_cache_t *) external_cache; 109 const hb_set_digest_t *seconds = cache ? &cache->seconds : nullptr; 110 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr); 111 #else 112 const hb_set_digest_t *seconds = nullptr; 113 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); 114 #endif 115 if (index == NOT_COVERED) return_trace (false); 116 117 const auto &lig_set = this+ligatureSet[index]; 118 return_trace (lig_set.apply (c, seconds)); 119 } 120 121 bool serialize (hb_serialize_context_t *c, 122 hb_sorted_array_t<const HBGlyphID16> first_glyphs, 123 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list, 124 hb_array_t<const HBGlyphID16> ligatures_list, 125 hb_array_t<const unsigned int> component_count_list, 126 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */) 127 { 128 TRACE_SERIALIZE (this); 129 if (unlikely (!c->extend_min (this))) return_trace (false); 130 if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false); 131 for (unsigned int i = 0; i < first_glyphs.length; i++) 132 { 133 unsigned int ligature_count = ligature_per_first_glyph_count_list[i]; 134 if (unlikely (!ligatureSet[i] 135 .serialize_serialize (c, 136 ligatures_list.sub_array (0, ligature_count), 137 component_count_list.sub_array (0, ligature_count), 138 component_list))) return_trace (false); 139 ligatures_list += ligature_count; 140 component_count_list += ligature_count; 141 } 142 return_trace (coverage.serialize_serialize (c, first_glyphs)); 143 } 144 145 bool subset (hb_subset_context_t *c) const 146 { 147 TRACE_SUBSET (this); 148 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 149 const hb_map_t &glyph_map = *c->plan->glyph_map; 150 151 auto *out = c->serializer->start_embed (*this); 152 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 153 out->format = format; 154 155 // Due to a bug in some older versions of windows 7 the Coverage table must be 156 // packed after the LigatureSet and Ligature tables, so serialize Coverage first 157 // which places it last in the packed order. 158 hb_set_t new_coverage; 159 + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) 160 | hb_filter (glyphset, hb_first) 161 | hb_filter ([&] (const LigatureSet<Types>& _) { 162 return _.intersects_lig_glyph (&glyphset); 163 }, hb_second) 164 | hb_map (hb_first) 165 | hb_sink (new_coverage); 166 167 if (!c->serializer->push<Coverage> () 168 ->serialize (c->serializer, 169 + new_coverage.iter () | hb_map_retains_sorting (glyph_map))) 170 { 171 c->serializer->pop_discard (); 172 return_trace (false); 173 } 174 175 unsigned coverage_idx = c->serializer->pop_pack (); 176 c->serializer->add_link (out->coverage, coverage_idx); 177 178 + hb_zip (this+coverage, ligatureSet) 179 | hb_filter (new_coverage, hb_first) 180 | hb_map (hb_second) 181 // to ensure that the repacker always orders the coverage table after the LigatureSet 182 // and LigatureSubtable's they will be linked to the Coverage table via a virtual link 183 // the coverage table object idx is passed down to facilitate this. 184 | hb_apply (subset_offset_array (c, out->ligatureSet, this, coverage_idx)) 185 ; 186 187 return_trace (bool (new_coverage)); 188 } 189 }; 190 191 } 192 } 193 } 194 195 #endif /* OT_LAYOUT_GSUB_LIGATURESUBSTFORMAT1_HH */