Ligature.hh (5196B)
1 #ifndef OT_LAYOUT_GSUB_LIGATURE_HH 2 #define OT_LAYOUT_GSUB_LIGATURE_HH 3 4 #include "Common.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GSUB_impl { 9 10 template <typename Types> 11 struct Ligature 12 { 13 public: 14 typename Types::HBGlyphID 15 ligGlyph; /* GlyphID of ligature to substitute */ 16 HeadlessArray16Of<typename Types::HBGlyphID> 17 component; /* Array of component GlyphIDs--start 18 * with the second component--ordered 19 * in writing direction */ 20 public: 21 DEFINE_SIZE_ARRAY (Types::size + 2, component); 22 23 bool sanitize (hb_sanitize_context_t *c) const 24 { 25 TRACE_SANITIZE (this); 26 return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); 27 } 28 29 bool intersects (const hb_set_t *glyphs) const 30 { return hb_all (component, glyphs); } 31 32 bool intersects_lig_glyph (const hb_set_t *glyphs) const 33 { return glyphs->has(ligGlyph); } 34 35 void closure (hb_closure_context_t *c) const 36 { 37 if (!intersects (c->glyphs)) return; 38 c->output->add (ligGlyph); 39 } 40 41 void collect_glyphs (hb_collect_glyphs_context_t *c) const 42 { 43 c->input->add_array (component.arrayZ, component.get_length ()); 44 c->output->add (ligGlyph); 45 } 46 47 template <typename set_t> 48 void collect_second (set_t &s) const 49 { 50 if (unlikely (!component.get_length ())) 51 { 52 // A ligature without any components. Anything matches. 53 s = set_t::full (); 54 return; 55 } 56 s.add (component.arrayZ[0]); 57 } 58 59 bool would_apply (hb_would_apply_context_t *c) const 60 { 61 if (c->len != component.lenP1) 62 return false; 63 64 for (unsigned int i = 1; i < c->len; i++) 65 if (likely (c->glyphs[i] != component[i])) 66 return false; 67 68 return true; 69 } 70 71 bool apply (hb_ot_apply_context_t *c) const 72 { 73 TRACE_APPLY (this); 74 unsigned int count = component.lenP1; 75 76 if (unlikely (!count)) return_trace (false); 77 78 /* Special-case to make it in-place and not consider this 79 * as a "ligated" substitution. */ 80 if (unlikely (count == 1)) 81 { 82 83 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 84 { 85 c->buffer->sync_so_far (); 86 c->buffer->message (c->font, 87 "replacing glyph at %u (ligature substitution)", 88 c->buffer->idx); 89 } 90 91 c->replace_glyph (ligGlyph); 92 93 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 94 { 95 c->buffer->message (c->font, 96 "replaced glyph at %u (ligature substitution)", 97 c->buffer->idx - 1u); 98 } 99 100 return_trace (true); 101 } 102 103 unsigned int total_component_count = 0; 104 105 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false; 106 unsigned int match_end = 0; 107 108 if (likely (!match_input (c, count, 109 &component[1], 110 match_glyph, 111 nullptr, 112 &match_end, 113 &total_component_count))) 114 { 115 c->buffer->unsafe_to_concat (c->buffer->idx, match_end); 116 return_trace (false); 117 } 118 119 unsigned pos = 0; 120 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 121 { 122 unsigned delta = c->buffer->sync_so_far (); 123 124 pos = c->buffer->idx; 125 126 char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0}; 127 char *p = buf; 128 129 match_end += delta; 130 for (unsigned i = 0; i < count; i++) 131 { 132 c->match_positions[i] += delta; 133 if (i) 134 *p++ = ','; 135 snprintf (p, sizeof(buf) - (p - buf), "%u", c->match_positions[i]); 136 p += strlen(p); 137 } 138 139 c->buffer->message (c->font, 140 "ligating glyphs at %s", 141 buf); 142 } 143 144 ligate_input (c, 145 count, 146 match_end, 147 ligGlyph, 148 total_component_count); 149 150 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 151 { 152 c->buffer->sync_so_far (); 153 c->buffer->message (c->font, 154 "ligated glyph at %u", 155 pos); 156 } 157 158 return_trace (true); 159 } 160 161 template <typename Iterator, 162 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> 163 bool serialize (hb_serialize_context_t *c, 164 hb_codepoint_t ligature, 165 Iterator components /* Starting from second */) 166 { 167 TRACE_SERIALIZE (this); 168 if (unlikely (!c->extend_min (this))) return_trace (false); 169 ligGlyph = ligature; 170 if (unlikely (!component.serialize (c, components))) return_trace (false); 171 return_trace (true); 172 } 173 174 bool subset (hb_subset_context_t *c, unsigned coverage_idx) const 175 { 176 TRACE_SUBSET (this); 177 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 178 const hb_map_t &glyph_map = *c->plan->glyph_map; 179 180 if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); 181 // Ensure Coverage table is always packed after this. 182 c->serializer->add_virtual_link (coverage_idx); 183 184 auto it = 185 + hb_iter (component) 186 | hb_map (glyph_map) 187 ; 188 189 auto *out = c->serializer->start_embed (*this); 190 return_trace (out->serialize (c->serializer, 191 glyph_map[ligGlyph], 192 it)); } 193 }; 194 195 196 } 197 } 198 } 199 200 #endif /* OT_LAYOUT_GSUB_LIGATURE_HH */