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 sanitizeOT::Layout::GSUB_impl::Ligature23 bool sanitize (hb_sanitize_context_t *c) const 24 { 25 TRACE_SANITIZE (this); 26 return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); 27 } 28 intersectsOT::Layout::GSUB_impl::Ligature29 bool intersects (const hb_set_t *glyphs) const 30 { return hb_all (component, glyphs); } 31 intersects_lig_glyphOT::Layout::GSUB_impl::Ligature32 bool intersects_lig_glyph (const hb_set_t *glyphs) const 33 { return glyphs->has(ligGlyph); } 34 closureOT::Layout::GSUB_impl::Ligature35 void closure (hb_closure_context_t *c) const 36 { 37 if (!intersects (c->glyphs)) return; 38 c->output->add (ligGlyph); 39 } 40 collect_glyphsOT::Layout::GSUB_impl::Ligature41 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 would_applyOT::Layout::GSUB_impl::Ligature47 bool would_apply (hb_would_apply_context_t *c) const 48 { 49 if (c->len != component.lenP1) 50 return false; 51 52 for (unsigned int i = 1; i < c->len; i++) 53 if (likely (c->glyphs[i] != component[i])) 54 return false; 55 56 return true; 57 } 58 applyOT::Layout::GSUB_impl::Ligature59 bool apply (hb_ot_apply_context_t *c) const 60 { 61 TRACE_APPLY (this); 62 unsigned int count = component.lenP1; 63 64 if (unlikely (!count)) return_trace (false); 65 66 /* Special-case to make it in-place and not consider this 67 * as a "ligated" substitution. */ 68 if (unlikely (count == 1)) 69 { 70 71 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 72 { 73 c->buffer->sync_so_far (); 74 c->buffer->message (c->font, 75 "replacing glyph at %u (ligature substitution)", 76 c->buffer->idx); 77 } 78 79 c->replace_glyph (ligGlyph); 80 81 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 82 { 83 c->buffer->message (c->font, 84 "replaced glyph at %u (ligature substitution)", 85 c->buffer->idx - 1u); 86 } 87 88 return_trace (true); 89 } 90 91 unsigned int total_component_count = 0; 92 93 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false; 94 unsigned match_positions_stack[4]; 95 unsigned *match_positions = match_positions_stack; 96 if (unlikely (count > ARRAY_LENGTH (match_positions_stack))) 97 { 98 match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned)); 99 if (unlikely (!match_positions)) 100 return_trace (false); 101 } 102 103 unsigned int match_end = 0; 104 105 if (likely (!match_input (c, count, 106 &component[1], 107 match_glyph, 108 nullptr, 109 &match_end, 110 match_positions, 111 &total_component_count))) 112 { 113 c->buffer->unsafe_to_concat (c->buffer->idx, match_end); 114 if (match_positions != match_positions_stack) 115 hb_free (match_positions); 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 match_positions[i] += delta; 133 if (i) 134 *p++ = ','; 135 snprintf (p, sizeof(buf) - (p - buf), "%u", 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_positions, 147 match_end, 148 ligGlyph, 149 total_component_count); 150 151 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 152 { 153 c->buffer->sync_so_far (); 154 c->buffer->message (c->font, 155 "ligated glyph at %u", 156 pos); 157 } 158 159 if (match_positions != match_positions_stack) 160 hb_free (match_positions); 161 return_trace (true); 162 } 163 164 template <typename Iterator, 165 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> serializeOT::Layout::GSUB_impl::Ligature166 bool serialize (hb_serialize_context_t *c, 167 hb_codepoint_t ligature, 168 Iterator components /* Starting from second */) 169 { 170 TRACE_SERIALIZE (this); 171 if (unlikely (!c->extend_min (this))) return_trace (false); 172 ligGlyph = ligature; 173 if (unlikely (!component.serialize (c, components))) return_trace (false); 174 return_trace (true); 175 } 176 subsetOT::Layout::GSUB_impl::Ligature177 bool subset (hb_subset_context_t *c, unsigned coverage_idx) const 178 { 179 TRACE_SUBSET (this); 180 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 181 const hb_map_t &glyph_map = *c->plan->glyph_map; 182 183 if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); 184 // Ensure Coverage table is always packed after this. 185 c->serializer->add_virtual_link (coverage_idx); 186 187 auto it = 188 + hb_iter (component) 189 | hb_map (glyph_map) 190 ; 191 192 auto *out = c->serializer->start_embed (*this); 193 return_trace (out->serialize (c->serializer, 194 glyph_map[ligGlyph], 195 it)); } 196 }; 197 198 199 } 200 } 201 } 202 203 #endif /* OT_LAYOUT_GSUB_LIGATURE_HH */ 204