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 unsigned int match_end = 0; 94 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; 95 96 if (likely (!match_input (c, count, 97 &component[1], 98 match_glyph, 99 nullptr, 100 &match_end, 101 match_positions, 102 &total_component_count))) 103 { 104 c->buffer->unsafe_to_concat (c->buffer->idx, match_end); 105 return_trace (false); 106 } 107 108 unsigned pos = 0; 109 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 110 { 111 unsigned delta = c->buffer->sync_so_far (); 112 113 pos = c->buffer->idx; 114 115 char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0}; 116 char *p = buf; 117 118 match_end += delta; 119 for (unsigned i = 0; i < count; i++) 120 { 121 match_positions[i] += delta; 122 if (i) 123 *p++ = ','; 124 snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]); 125 p += strlen(p); 126 } 127 128 c->buffer->message (c->font, 129 "ligating glyphs at %s", 130 buf); 131 } 132 133 ligate_input (c, 134 count, 135 match_positions, 136 match_end, 137 ligGlyph, 138 total_component_count); 139 140 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 141 { 142 c->buffer->sync_so_far (); 143 c->buffer->message (c->font, 144 "ligated glyph at %u", 145 pos); 146 } 147 148 return_trace (true); 149 } 150 151 template <typename Iterator, 152 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> serializeOT::Layout::GSUB_impl::Ligature153 bool serialize (hb_serialize_context_t *c, 154 hb_codepoint_t ligature, 155 Iterator components /* Starting from second */) 156 { 157 TRACE_SERIALIZE (this); 158 if (unlikely (!c->extend_min (this))) return_trace (false); 159 ligGlyph = ligature; 160 if (unlikely (!component.serialize (c, components))) return_trace (false); 161 return_trace (true); 162 } 163 subsetOT::Layout::GSUB_impl::Ligature164 bool subset (hb_subset_context_t *c, unsigned coverage_idx) const 165 { 166 TRACE_SUBSET (this); 167 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 168 const hb_map_t &glyph_map = *c->plan->glyph_map; 169 170 if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); 171 // Ensure Coverage table is always packed after this. 172 c->serializer->add_virtual_link (coverage_idx); 173 174 auto it = 175 + hb_iter (component) 176 | hb_map (glyph_map) 177 ; 178 179 auto *out = c->serializer->start_embed (*this); 180 return_trace (out->serialize (c->serializer, 181 glyph_map[ligGlyph], 182 it)); } 183 }; 184 185 186 } 187 } 188 } 189 190 #endif /* OT_LAYOUT_GSUB_LIGATURE_HH */ 191