• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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