Merge branch 'upstream' into tizen
[platform/upstream/harfbuzz.git] / src / OT / Layout / GSUB / Ligature.hh
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
23   bool sanitize (hb_sanitize_context_t *c) const
24   {
25     TRACE_SANITIZE (this);
26     return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
27   }
28
29   bool intersects (const hb_set_t *glyphs) const
30   { return hb_all (component, glyphs); }
31
32   bool intersects_lig_glyph (const hb_set_t *glyphs) const
33   { return glyphs->has(ligGlyph); }
34
35   void closure (hb_closure_context_t *c) const
36   {
37     if (!intersects (c->glyphs)) return;
38     c->output->add (ligGlyph);
39   }
40
41   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
47   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
59   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))>
153   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
164   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 */