Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / src / OT / Layout / GSUB / Sequence.hh
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
19   bool sanitize (hb_sanitize_context_t *c) const
20   {
21     TRACE_SANITIZE (this);
22     return_trace (substitute.sanitize (c));
23   }
24
25   bool intersects (const hb_set_t *glyphs) const
26   { return hb_all (substitute, glyphs); }
27
28   void closure (hb_closure_context_t *c) const
29   { c->output->add_array (substitute.arrayZ, substitute.len); }
30
31   void collect_glyphs (hb_collect_glyphs_context_t *c) const
32   { c->output->add_array (substitute.arrayZ, substitute.len); }
33
34   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))>
134   bool serialize (hb_serialize_context_t *c,
135                   Iterator subst)
136   {
137     TRACE_SERIALIZE (this);
138     return_trace (substitute.serialize (c, subst));
139   }
140
141   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 */