xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Layout/GSUB/Sequence.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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