1 #ifndef OT_LAYOUT_GSUB_SEQUENCE_HH 2 #define OT_LAYOUT_GSUB_SEQUENCE_HH 3 4 #include "Common.hh" 5 6 namespace OT { 7 namespace Layout { 8 namespace GSUB_impl { 9 10 template <typename Types> 11 struct Sequence 12 { 13 protected: 14 Array16Of<typename Types::HBGlyphID> 15 substitute; /* String of GlyphIDs to substitute */ 16 public: 17 DEFINE_SIZE_ARRAY (2, substitute); 18 sanitizeOT::Layout::GSUB_impl::Sequence19 bool sanitize (hb_sanitize_context_t *c) const 20 { 21 TRACE_SANITIZE (this); 22 return_trace (substitute.sanitize (c)); 23 } 24 intersectsOT::Layout::GSUB_impl::Sequence25 bool intersects (const hb_set_t *glyphs) const 26 { return hb_all (substitute, glyphs); } 27 closureOT::Layout::GSUB_impl::Sequence28 void closure (hb_closure_context_t *c) const 29 { c->output->add_array (substitute.arrayZ, substitute.len); } 30 collect_glyphsOT::Layout::GSUB_impl::Sequence31 void collect_glyphs (hb_collect_glyphs_context_t *c) const 32 { c->output->add_array (substitute.arrayZ, substitute.len); } 33 applyOT::Layout::GSUB_impl::Sequence34 bool apply (hb_ot_apply_context_t *c) const 35 { 36 TRACE_APPLY (this); 37 unsigned int count = substitute.len; 38 39 /* Special-case to make it in-place and not consider this 40 * as a "multiplied" substitution. */ 41 if (unlikely (count == 1)) 42 { 43 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 44 { 45 c->buffer->sync_so_far (); 46 c->buffer->message (c->font, 47 "replacing glyph at %u (multiple substitution)", 48 c->buffer->idx); 49 } 50 51 c->replace_glyph (substitute.arrayZ[0]); 52 53 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 54 { 55 c->buffer->message (c->font, 56 "replaced glyph at %u (multiple substitution)", 57 c->buffer->idx - 1u); 58 } 59 60 return_trace (true); 61 } 62 /* Spec disallows this, but Uniscribe allows it. 63 * https://github.com/harfbuzz/harfbuzz/issues/253 */ 64 else if (unlikely (count == 0)) 65 { 66 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 67 { 68 c->buffer->sync_so_far (); 69 c->buffer->message (c->font, 70 "deleting glyph at %u (multiple substitution)", 71 c->buffer->idx); 72 } 73 74 c->buffer->delete_glyph (); 75 76 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 77 { 78 c->buffer->sync_so_far (); 79 c->buffer->message (c->font, 80 "deleted glyph at %u (multiple substitution)", 81 c->buffer->idx); 82 } 83 84 return_trace (true); 85 } 86 87 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 88 { 89 c->buffer->sync_so_far (); 90 c->buffer->message (c->font, 91 "multiplying glyph at %u", 92 c->buffer->idx); 93 } 94 95 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? 96 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; 97 unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur()); 98 99 for (unsigned int i = 0; i < count; i++) 100 { 101 /* If is attached to a ligature, don't disturb that. 102 * https://github.com/harfbuzz/harfbuzz/issues/3069 */ 103 if (!lig_id) 104 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i); 105 c->output_glyph_for_component (substitute.arrayZ[i], klass); 106 } 107 c->buffer->skip_glyph (); 108 109 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) 110 { 111 c->buffer->sync_so_far (); 112 113 char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0}; 114 char *p = buf; 115 116 for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++) 117 { 118 if (buf < p) 119 *p++ = ','; 120 snprintf (p, sizeof(buf) - (p - buf), "%u", i); 121 p += strlen(p); 122 } 123 124 c->buffer->message (c->font, 125 "multiplied glyphs at %s", 126 buf); 127 } 128 129 return_trace (true); 130 } 131 132 template <typename Iterator, 133 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))> serializeOT::Layout::GSUB_impl::Sequence134 bool serialize (hb_serialize_context_t *c, 135 Iterator subst) 136 { 137 TRACE_SERIALIZE (this); 138 return_trace (substitute.serialize (c, subst)); 139 } 140 subsetOT::Layout::GSUB_impl::Sequence141 bool subset (hb_subset_context_t *c) const 142 { 143 TRACE_SUBSET (this); 144 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 145 const hb_map_t &glyph_map = *c->plan->glyph_map; 146 147 if (!intersects (&glyphset)) return_trace (false); 148 149 auto it = 150 + hb_iter (substitute) 151 | hb_map (glyph_map) 152 ; 153 154 auto *out = c->serializer->start_embed (*this); 155 return_trace (out->serialize (c->serializer, it)); 156 } 157 }; 158 159 160 } 161 } 162 } 163 164 165 #endif /* OT_LAYOUT_GSUB_SEQUENCE_HH */ 166