• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3  * Copyright © 2010,2012  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Red Hat Author(s): Behdad Esfahbod
26  * Google Author(s): Behdad Esfahbod
27  */
28 
29 #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
30 #define HB_OT_LAYOUT_GSUB_TABLE_HH
31 
32 #include "hb-ot-layout-gsubgpos-private.hh"
33 
34 
35 namespace OT {
36 
37 
38 struct SingleSubstFormat1
39 {
closureOT::SingleSubstFormat140   inline void closure (hb_closure_context_t *c) const
41   {
42     TRACE_CLOSURE (this);
43     Coverage::Iter iter;
44     for (iter.init (this+coverage); iter.more (); iter.next ()) {
45       hb_codepoint_t glyph_id = iter.get_glyph ();
46       if (c->glyphs->has (glyph_id))
47 	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
48     }
49   }
50 
collect_glyphsOT::SingleSubstFormat151   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
52   {
53     TRACE_COLLECT_GLYPHS (this);
54     Coverage::Iter iter;
55     for (iter.init (this+coverage); iter.more (); iter.next ()) {
56       hb_codepoint_t glyph_id = iter.get_glyph ();
57       c->input->add (glyph_id);
58       c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF);
59     }
60   }
61 
get_coverageOT::SingleSubstFormat162   inline const Coverage &get_coverage (void) const
63   {
64     return this+coverage;
65   }
66 
would_applyOT::SingleSubstFormat167   inline bool would_apply (hb_would_apply_context_t *c) const
68   {
69     TRACE_WOULD_APPLY (this);
70     return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
71   }
72 
applyOT::SingleSubstFormat173   inline bool apply (hb_apply_context_t *c) const
74   {
75     TRACE_APPLY (this);
76     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
77     unsigned int index = (this+coverage).get_coverage (glyph_id);
78     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
79 
80     /* According to the Adobe Annotated OpenType Suite, result is always
81      * limited to 16bit. */
82     glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
83     c->replace_glyph (glyph_id);
84 
85     return TRACE_RETURN (true);
86   }
87 
serializeOT::SingleSubstFormat188   inline bool serialize (hb_serialize_context_t *c,
89 			 Supplier<GlyphID> &glyphs,
90 			 unsigned int num_glyphs,
91 			 int delta)
92   {
93     TRACE_SERIALIZE (this);
94     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
95     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
96     deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
97     return TRACE_RETURN (true);
98   }
99 
sanitizeOT::SingleSubstFormat1100   inline bool sanitize (hb_sanitize_context_t *c) {
101     TRACE_SANITIZE (this);
102     return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
103   }
104 
105   protected:
106   USHORT	format;			/* Format identifier--format = 1 */
107   OffsetTo<Coverage>
108 		coverage;		/* Offset to Coverage table--from
109 					 * beginning of Substitution table */
110   SHORT		deltaGlyphID;		/* Add to original GlyphID to get
111 					 * substitute GlyphID */
112   public:
113   DEFINE_SIZE_STATIC (6);
114 };
115 
116 struct SingleSubstFormat2
117 {
closureOT::SingleSubstFormat2118   inline void closure (hb_closure_context_t *c) const
119   {
120     TRACE_CLOSURE (this);
121     Coverage::Iter iter;
122     for (iter.init (this+coverage); iter.more (); iter.next ()) {
123       if (c->glyphs->has (iter.get_glyph ()))
124 	c->glyphs->add (substitute[iter.get_coverage ()]);
125     }
126   }
127 
collect_glyphsOT::SingleSubstFormat2128   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
129   {
130     TRACE_COLLECT_GLYPHS (this);
131     Coverage::Iter iter;
132     for (iter.init (this+coverage); iter.more (); iter.next ()) {
133       c->input->add (iter.get_glyph ());
134       c->output->add (substitute[iter.get_coverage ()]);
135     }
136   }
137 
get_coverageOT::SingleSubstFormat2138   inline const Coverage &get_coverage (void) const
139   {
140     return this+coverage;
141   }
142 
would_applyOT::SingleSubstFormat2143   inline bool would_apply (hb_would_apply_context_t *c) const
144   {
145     TRACE_WOULD_APPLY (this);
146     return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
147   }
148 
applyOT::SingleSubstFormat2149   inline bool apply (hb_apply_context_t *c) const
150   {
151     TRACE_APPLY (this);
152     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
153     unsigned int index = (this+coverage).get_coverage (glyph_id);
154     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
155 
156     if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
157 
158     glyph_id = substitute[index];
159     c->replace_glyph (glyph_id);
160 
161     return TRACE_RETURN (true);
162   }
163 
serializeOT::SingleSubstFormat2164   inline bool serialize (hb_serialize_context_t *c,
165 			 Supplier<GlyphID> &glyphs,
166 			 Supplier<GlyphID> &substitutes,
167 			 unsigned int num_glyphs)
168   {
169     TRACE_SERIALIZE (this);
170     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
171     if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
172     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
173     return TRACE_RETURN (true);
174   }
175 
sanitizeOT::SingleSubstFormat2176   inline bool sanitize (hb_sanitize_context_t *c) {
177     TRACE_SANITIZE (this);
178     return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
179   }
180 
181   protected:
182   USHORT	format;			/* Format identifier--format = 2 */
183   OffsetTo<Coverage>
184 		coverage;		/* Offset to Coverage table--from
185 					 * beginning of Substitution table */
186   ArrayOf<GlyphID>
187 		substitute;		/* Array of substitute
188 					 * GlyphIDs--ordered by Coverage Index */
189   public:
190   DEFINE_SIZE_ARRAY (6, substitute);
191 };
192 
193 struct SingleSubst
194 {
serializeOT::SingleSubst195   inline bool serialize (hb_serialize_context_t *c,
196 			 Supplier<GlyphID> &glyphs,
197 			 Supplier<GlyphID> &substitutes,
198 			 unsigned int num_glyphs)
199   {
200     TRACE_SERIALIZE (this);
201     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
202     unsigned int format = 2;
203     int delta;
204     if (num_glyphs) {
205       format = 1;
206       /* TODO(serialize) check for wrap-around */
207       delta = substitutes[0] - glyphs[0];
208       for (unsigned int i = 1; i < num_glyphs; i++)
209 	if (delta != substitutes[i] - glyphs[i]) {
210 	  format = 2;
211 	  break;
212 	}
213     }
214     u.format.set (format);
215     switch (u.format) {
216     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
217     case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
218     default:return TRACE_RETURN (false);
219     }
220   }
221 
222   template <typename context_t>
dispatchOT::SingleSubst223   inline typename context_t::return_t dispatch (context_t *c) const
224   {
225     TRACE_DISPATCH (this);
226     switch (u.format) {
227     case 1: return TRACE_RETURN (c->dispatch (u.format1));
228     case 2: return TRACE_RETURN (c->dispatch (u.format2));
229     default:return TRACE_RETURN (c->default_return_value ());
230     }
231   }
232 
sanitizeOT::SingleSubst233   inline bool sanitize (hb_sanitize_context_t *c) {
234     TRACE_SANITIZE (this);
235     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
236     switch (u.format) {
237     case 1: return TRACE_RETURN (u.format1.sanitize (c));
238     case 2: return TRACE_RETURN (u.format2.sanitize (c));
239     default:return TRACE_RETURN (true);
240     }
241   }
242 
243   protected:
244   union {
245   USHORT		format;		/* Format identifier */
246   SingleSubstFormat1	format1;
247   SingleSubstFormat2	format2;
248   } u;
249 };
250 
251 
252 struct Sequence
253 {
closureOT::Sequence254   inline void closure (hb_closure_context_t *c) const
255   {
256     TRACE_CLOSURE (this);
257     unsigned int count = substitute.len;
258     for (unsigned int i = 0; i < count; i++)
259       c->glyphs->add (substitute[i]);
260   }
261 
collect_glyphsOT::Sequence262   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
263   {
264     TRACE_COLLECT_GLYPHS (this);
265     unsigned int count = substitute.len;
266     for (unsigned int i = 0; i < count; i++)
267       c->output->add (substitute[i]);
268   }
269 
applyOT::Sequence270   inline bool apply (hb_apply_context_t *c) const
271   {
272     TRACE_APPLY (this);
273     if (unlikely (!substitute.len)) return TRACE_RETURN (false);
274 
275     unsigned int klass = c->buffer->cur().glyph_props() &
276 			 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
277     unsigned int count = substitute.len;
278     for (unsigned int i = 0; i < count; i++) {
279       set_lig_props_for_component (c->buffer->cur(), i);
280       c->output_glyph (substitute.array[i], klass);
281     }
282     c->buffer->skip_glyph ();
283 
284     return TRACE_RETURN (true);
285   }
286 
serializeOT::Sequence287   inline bool serialize (hb_serialize_context_t *c,
288 			 Supplier<GlyphID> &glyphs,
289 			 unsigned int num_glyphs)
290   {
291     TRACE_SERIALIZE (this);
292     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
293     if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
294     return TRACE_RETURN (true);
295   }
296 
sanitizeOT::Sequence297   inline bool sanitize (hb_sanitize_context_t *c) {
298     TRACE_SANITIZE (this);
299     return TRACE_RETURN (substitute.sanitize (c));
300   }
301 
302   protected:
303   ArrayOf<GlyphID>
304 		substitute;		/* String of GlyphIDs to substitute */
305   public:
306   DEFINE_SIZE_ARRAY (2, substitute);
307 };
308 
309 struct MultipleSubstFormat1
310 {
closureOT::MultipleSubstFormat1311   inline void closure (hb_closure_context_t *c) const
312   {
313     TRACE_CLOSURE (this);
314     Coverage::Iter iter;
315     for (iter.init (this+coverage); iter.more (); iter.next ()) {
316       if (c->glyphs->has (iter.get_glyph ()))
317 	(this+sequence[iter.get_coverage ()]).closure (c);
318     }
319   }
320 
collect_glyphsOT::MultipleSubstFormat1321   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
322   {
323     TRACE_COLLECT_GLYPHS (this);
324     (this+coverage).add_coverage (c->input);
325     unsigned int count = sequence.len;
326     for (unsigned int i = 0; i < count; i++)
327 	(this+sequence[i]).collect_glyphs (c);
328   }
329 
get_coverageOT::MultipleSubstFormat1330   inline const Coverage &get_coverage (void) const
331   {
332     return this+coverage;
333   }
334 
would_applyOT::MultipleSubstFormat1335   inline bool would_apply (hb_would_apply_context_t *c) const
336   {
337     TRACE_WOULD_APPLY (this);
338     return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
339   }
340 
applyOT::MultipleSubstFormat1341   inline bool apply (hb_apply_context_t *c) const
342   {
343     TRACE_APPLY (this);
344 
345     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
346     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
347 
348     return TRACE_RETURN ((this+sequence[index]).apply (c));
349   }
350 
serializeOT::MultipleSubstFormat1351   inline bool serialize (hb_serialize_context_t *c,
352 			 Supplier<GlyphID> &glyphs,
353 			 Supplier<unsigned int> &substitute_len_list,
354 			 unsigned int num_glyphs,
355 			 Supplier<GlyphID> &substitute_glyphs_list)
356   {
357     TRACE_SERIALIZE (this);
358     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
359     if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
360     for (unsigned int i = 0; i < num_glyphs; i++)
361       if (unlikely (!sequence[i].serialize (c, this).serialize (c,
362 								substitute_glyphs_list,
363 								substitute_len_list[i]))) return TRACE_RETURN (false);
364     substitute_len_list.advance (num_glyphs);
365     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
366     return TRACE_RETURN (true);
367   }
368 
sanitizeOT::MultipleSubstFormat1369   inline bool sanitize (hb_sanitize_context_t *c) {
370     TRACE_SANITIZE (this);
371     return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
372   }
373 
374   protected:
375   USHORT	format;			/* Format identifier--format = 1 */
376   OffsetTo<Coverage>
377 		coverage;		/* Offset to Coverage table--from
378 					 * beginning of Substitution table */
379   OffsetArrayOf<Sequence>
380 		sequence;		/* Array of Sequence tables
381 					 * ordered by Coverage Index */
382   public:
383   DEFINE_SIZE_ARRAY (6, sequence);
384 };
385 
386 struct MultipleSubst
387 {
serializeOT::MultipleSubst388   inline bool serialize (hb_serialize_context_t *c,
389 			 Supplier<GlyphID> &glyphs,
390 			 Supplier<unsigned int> &substitute_len_list,
391 			 unsigned int num_glyphs,
392 			 Supplier<GlyphID> &substitute_glyphs_list)
393   {
394     TRACE_SERIALIZE (this);
395     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
396     unsigned int format = 1;
397     u.format.set (format);
398     switch (u.format) {
399     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
400     default:return TRACE_RETURN (false);
401     }
402   }
403 
404   template <typename context_t>
dispatchOT::MultipleSubst405   inline typename context_t::return_t dispatch (context_t *c) const
406   {
407     TRACE_DISPATCH (this);
408     switch (u.format) {
409     case 1: return TRACE_RETURN (c->dispatch (u.format1));
410     default:return TRACE_RETURN (c->default_return_value ());
411     }
412   }
413 
sanitizeOT::MultipleSubst414   inline bool sanitize (hb_sanitize_context_t *c) {
415     TRACE_SANITIZE (this);
416     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
417     switch (u.format) {
418     case 1: return TRACE_RETURN (u.format1.sanitize (c));
419     default:return TRACE_RETURN (true);
420     }
421   }
422 
423   protected:
424   union {
425   USHORT		format;		/* Format identifier */
426   MultipleSubstFormat1	format1;
427   } u;
428 };
429 
430 
431 typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
432 					 * arbitrary order */
433 
434 struct AlternateSubstFormat1
435 {
closureOT::AlternateSubstFormat1436   inline void closure (hb_closure_context_t *c) const
437   {
438     TRACE_CLOSURE (this);
439     Coverage::Iter iter;
440     for (iter.init (this+coverage); iter.more (); iter.next ()) {
441       if (c->glyphs->has (iter.get_glyph ())) {
442 	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
443 	unsigned int count = alt_set.len;
444 	for (unsigned int i = 0; i < count; i++)
445 	  c->glyphs->add (alt_set[i]);
446       }
447     }
448   }
449 
collect_glyphsOT::AlternateSubstFormat1450   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
451   {
452     TRACE_COLLECT_GLYPHS (this);
453     Coverage::Iter iter;
454     for (iter.init (this+coverage); iter.more (); iter.next ()) {
455       c->input->add (iter.get_glyph ());
456       const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
457       unsigned int count = alt_set.len;
458       for (unsigned int i = 0; i < count; i++)
459 	c->output->add (alt_set[i]);
460     }
461   }
462 
get_coverageOT::AlternateSubstFormat1463   inline const Coverage &get_coverage (void) const
464   {
465     return this+coverage;
466   }
467 
would_applyOT::AlternateSubstFormat1468   inline bool would_apply (hb_would_apply_context_t *c) const
469   {
470     TRACE_WOULD_APPLY (this);
471     return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
472   }
473 
applyOT::AlternateSubstFormat1474   inline bool apply (hb_apply_context_t *c) const
475   {
476     TRACE_APPLY (this);
477     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
478 
479     unsigned int index = (this+coverage).get_coverage (glyph_id);
480     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
481 
482     const AlternateSet &alt_set = this+alternateSet[index];
483 
484     if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
485 
486     hb_mask_t glyph_mask = c->buffer->cur().mask;
487     hb_mask_t lookup_mask = c->lookup_mask;
488 
489     /* Note: This breaks badly if two features enabled this lookup together. */
490     unsigned int shift = _hb_ctz (lookup_mask);
491     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
492 
493     if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
494 
495     glyph_id = alt_set[alt_index - 1];
496 
497     c->replace_glyph (glyph_id);
498 
499     return TRACE_RETURN (true);
500   }
501 
serializeOT::AlternateSubstFormat1502   inline bool serialize (hb_serialize_context_t *c,
503 			 Supplier<GlyphID> &glyphs,
504 			 Supplier<unsigned int> &alternate_len_list,
505 			 unsigned int num_glyphs,
506 			 Supplier<GlyphID> &alternate_glyphs_list)
507   {
508     TRACE_SERIALIZE (this);
509     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
510     if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
511     for (unsigned int i = 0; i < num_glyphs; i++)
512       if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
513 								    alternate_glyphs_list,
514 								    alternate_len_list[i]))) return TRACE_RETURN (false);
515     alternate_len_list.advance (num_glyphs);
516     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
517     return TRACE_RETURN (true);
518   }
519 
sanitizeOT::AlternateSubstFormat1520   inline bool sanitize (hb_sanitize_context_t *c) {
521     TRACE_SANITIZE (this);
522     return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
523   }
524 
525   protected:
526   USHORT	format;			/* Format identifier--format = 1 */
527   OffsetTo<Coverage>
528 		coverage;		/* Offset to Coverage table--from
529 					 * beginning of Substitution table */
530   OffsetArrayOf<AlternateSet>
531 		alternateSet;		/* Array of AlternateSet tables
532 					 * ordered by Coverage Index */
533   public:
534   DEFINE_SIZE_ARRAY (6, alternateSet);
535 };
536 
537 struct AlternateSubst
538 {
serializeOT::AlternateSubst539   inline bool serialize (hb_serialize_context_t *c,
540 			 Supplier<GlyphID> &glyphs,
541 			 Supplier<unsigned int> &alternate_len_list,
542 			 unsigned int num_glyphs,
543 			 Supplier<GlyphID> &alternate_glyphs_list)
544   {
545     TRACE_SERIALIZE (this);
546     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
547     unsigned int format = 1;
548     u.format.set (format);
549     switch (u.format) {
550     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
551     default:return TRACE_RETURN (false);
552     }
553   }
554 
555   template <typename context_t>
dispatchOT::AlternateSubst556   inline typename context_t::return_t dispatch (context_t *c) const
557   {
558     TRACE_DISPATCH (this);
559     switch (u.format) {
560     case 1: return TRACE_RETURN (c->dispatch (u.format1));
561     default:return TRACE_RETURN (c->default_return_value ());
562     }
563   }
564 
sanitizeOT::AlternateSubst565   inline bool sanitize (hb_sanitize_context_t *c) {
566     TRACE_SANITIZE (this);
567     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
568     switch (u.format) {
569     case 1: return TRACE_RETURN (u.format1.sanitize (c));
570     default:return TRACE_RETURN (true);
571     }
572   }
573 
574   protected:
575   union {
576   USHORT		format;		/* Format identifier */
577   AlternateSubstFormat1	format1;
578   } u;
579 };
580 
581 
582 struct Ligature
583 {
closureOT::Ligature584   inline void closure (hb_closure_context_t *c) const
585   {
586     TRACE_CLOSURE (this);
587     unsigned int count = component.len;
588     for (unsigned int i = 1; i < count; i++)
589       if (!c->glyphs->has (component[i]))
590         return;
591     c->glyphs->add (ligGlyph);
592   }
593 
collect_glyphsOT::Ligature594   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
595   {
596     TRACE_COLLECT_GLYPHS (this);
597     unsigned int count = component.len;
598     for (unsigned int i = 1; i < count; i++)
599       c->input->add (component[i]);
600     c->output->add (ligGlyph);
601   }
602 
would_applyOT::Ligature603   inline bool would_apply (hb_would_apply_context_t *c) const
604   {
605     TRACE_WOULD_APPLY (this);
606     if (c->len != component.len)
607       return TRACE_RETURN (false);
608 
609     for (unsigned int i = 1; i < c->len; i++)
610       if (likely (c->glyphs[i] != component[i]))
611 	return TRACE_RETURN (false);
612 
613     return TRACE_RETURN (true);
614   }
615 
applyOT::Ligature616   inline bool apply (hb_apply_context_t *c) const
617   {
618     TRACE_APPLY (this);
619     unsigned int count = component.len;
620     if (unlikely (count < 1)) return TRACE_RETURN (false);
621 
622     unsigned int end_offset = 0;
623     bool is_mark_ligature = false;
624     unsigned int total_component_count = 0;
625 
626     if (likely (!match_input (c, count,
627 			      &component[1],
628 			      match_glyph,
629 			      NULL,
630 			      &end_offset,
631 			      &is_mark_ligature,
632 			      &total_component_count)))
633       return TRACE_RETURN (false);
634 
635     /* Deal, we are forming the ligature. */
636     c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
637 
638     ligate_input (c,
639 		  count,
640 		  &component[1],
641 		  match_glyph,
642 		  NULL,
643 		  ligGlyph,
644 		  is_mark_ligature,
645 		  total_component_count);
646 
647     return TRACE_RETURN (true);
648   }
649 
serializeOT::Ligature650   inline bool serialize (hb_serialize_context_t *c,
651 			 GlyphID ligature,
652 			 Supplier<GlyphID> &components, /* Starting from second */
653 			 unsigned int num_components /* Including first component */)
654   {
655     TRACE_SERIALIZE (this);
656     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
657     ligGlyph = ligature;
658     if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
659     return TRACE_RETURN (true);
660   }
661 
662   public:
sanitizeOT::Ligature663   inline bool sanitize (hb_sanitize_context_t *c) {
664     TRACE_SANITIZE (this);
665     return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
666   }
667 
668   protected:
669   GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
670   HeadlessArrayOf<GlyphID>
671 		component;		/* Array of component GlyphIDs--start
672 					 * with the second  component--ordered
673 					 * in writing direction */
674   public:
675   DEFINE_SIZE_ARRAY (4, component);
676 };
677 
678 struct LigatureSet
679 {
closureOT::LigatureSet680   inline void closure (hb_closure_context_t *c) const
681   {
682     TRACE_CLOSURE (this);
683     unsigned int num_ligs = ligature.len;
684     for (unsigned int i = 0; i < num_ligs; i++)
685       (this+ligature[i]).closure (c);
686   }
687 
collect_glyphsOT::LigatureSet688   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
689   {
690     TRACE_COLLECT_GLYPHS (this);
691     unsigned int num_ligs = ligature.len;
692     for (unsigned int i = 0; i < num_ligs; i++)
693       (this+ligature[i]).collect_glyphs (c);
694   }
695 
would_applyOT::LigatureSet696   inline bool would_apply (hb_would_apply_context_t *c) const
697   {
698     TRACE_WOULD_APPLY (this);
699     unsigned int num_ligs = ligature.len;
700     for (unsigned int i = 0; i < num_ligs; i++)
701     {
702       const Ligature &lig = this+ligature[i];
703       if (lig.would_apply (c))
704         return TRACE_RETURN (true);
705     }
706     return TRACE_RETURN (false);
707   }
708 
applyOT::LigatureSet709   inline bool apply (hb_apply_context_t *c) const
710   {
711     TRACE_APPLY (this);
712     unsigned int num_ligs = ligature.len;
713     for (unsigned int i = 0; i < num_ligs; i++)
714     {
715       const Ligature &lig = this+ligature[i];
716       if (lig.apply (c)) return TRACE_RETURN (true);
717     }
718 
719     return TRACE_RETURN (false);
720   }
721 
serializeOT::LigatureSet722   inline bool serialize (hb_serialize_context_t *c,
723 			 Supplier<GlyphID> &ligatures,
724 			 Supplier<unsigned int> &component_count_list,
725 			 unsigned int num_ligatures,
726 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
727   {
728     TRACE_SERIALIZE (this);
729     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
730     if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
731     for (unsigned int i = 0; i < num_ligatures; i++)
732       if (unlikely (!ligature[i].serialize (c, this).serialize (c,
733 								ligatures[i],
734 								component_list,
735 								component_count_list[i]))) return TRACE_RETURN (false);
736     ligatures.advance (num_ligatures);
737     component_count_list.advance (num_ligatures);
738     return TRACE_RETURN (true);
739   }
740 
sanitizeOT::LigatureSet741   inline bool sanitize (hb_sanitize_context_t *c) {
742     TRACE_SANITIZE (this);
743     return TRACE_RETURN (ligature.sanitize (c, this));
744   }
745 
746   protected:
747   OffsetArrayOf<Ligature>
748 		ligature;		/* Array LigatureSet tables
749 					 * ordered by preference */
750   public:
751   DEFINE_SIZE_ARRAY (2, ligature);
752 };
753 
754 struct LigatureSubstFormat1
755 {
closureOT::LigatureSubstFormat1756   inline void closure (hb_closure_context_t *c) const
757   {
758     TRACE_CLOSURE (this);
759     Coverage::Iter iter;
760     for (iter.init (this+coverage); iter.more (); iter.next ()) {
761       if (c->glyphs->has (iter.get_glyph ()))
762 	(this+ligatureSet[iter.get_coverage ()]).closure (c);
763     }
764   }
765 
collect_glyphsOT::LigatureSubstFormat1766   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
767   {
768     TRACE_COLLECT_GLYPHS (this);
769     Coverage::Iter iter;
770     for (iter.init (this+coverage); iter.more (); iter.next ()) {
771       c->input->add (iter.get_glyph ());
772       (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
773     }
774   }
775 
get_coverageOT::LigatureSubstFormat1776   inline const Coverage &get_coverage (void) const
777   {
778     return this+coverage;
779   }
780 
would_applyOT::LigatureSubstFormat1781   inline bool would_apply (hb_would_apply_context_t *c) const
782   {
783     TRACE_WOULD_APPLY (this);
784     unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
785     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
786 
787     const LigatureSet &lig_set = this+ligatureSet[index];
788     return TRACE_RETURN (lig_set.would_apply (c));
789   }
790 
applyOT::LigatureSubstFormat1791   inline bool apply (hb_apply_context_t *c) const
792   {
793     TRACE_APPLY (this);
794     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
795 
796     unsigned int index = (this+coverage).get_coverage (glyph_id);
797     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
798 
799     const LigatureSet &lig_set = this+ligatureSet[index];
800     return TRACE_RETURN (lig_set.apply (c));
801   }
802 
serializeOT::LigatureSubstFormat1803   inline bool serialize (hb_serialize_context_t *c,
804 			 Supplier<GlyphID> &first_glyphs,
805 			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
806 			 unsigned int num_first_glyphs,
807 			 Supplier<GlyphID> &ligatures_list,
808 			 Supplier<unsigned int> &component_count_list,
809 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
810   {
811     TRACE_SERIALIZE (this);
812     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
813     if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
814     for (unsigned int i = 0; i < num_first_glyphs; i++)
815       if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
816 								   ligatures_list,
817 								   component_count_list,
818 								   ligature_per_first_glyph_count_list[i],
819 								   component_list))) return TRACE_RETURN (false);
820     ligature_per_first_glyph_count_list.advance (num_first_glyphs);
821     if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
822     return TRACE_RETURN (true);
823   }
824 
sanitizeOT::LigatureSubstFormat1825   inline bool sanitize (hb_sanitize_context_t *c) {
826     TRACE_SANITIZE (this);
827     return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
828   }
829 
830   protected:
831   USHORT	format;			/* Format identifier--format = 1 */
832   OffsetTo<Coverage>
833 		coverage;		/* Offset to Coverage table--from
834 					 * beginning of Substitution table */
835   OffsetArrayOf<LigatureSet>
836 		ligatureSet;		/* Array LigatureSet tables
837 					 * ordered by Coverage Index */
838   public:
839   DEFINE_SIZE_ARRAY (6, ligatureSet);
840 };
841 
842 struct LigatureSubst
843 {
serializeOT::LigatureSubst844   inline bool serialize (hb_serialize_context_t *c,
845 			 Supplier<GlyphID> &first_glyphs,
846 			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
847 			 unsigned int num_first_glyphs,
848 			 Supplier<GlyphID> &ligatures_list,
849 			 Supplier<unsigned int> &component_count_list,
850 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
851   {
852     TRACE_SERIALIZE (this);
853     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
854     unsigned int format = 1;
855     u.format.set (format);
856     switch (u.format) {
857     case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
858 						      ligatures_list, component_count_list, component_list));
859     default:return TRACE_RETURN (false);
860     }
861   }
862 
863   template <typename context_t>
dispatchOT::LigatureSubst864   inline typename context_t::return_t dispatch (context_t *c) const
865   {
866     TRACE_DISPATCH (this);
867     switch (u.format) {
868     case 1: return TRACE_RETURN (c->dispatch (u.format1));
869     default:return TRACE_RETURN (c->default_return_value ());
870     }
871   }
872 
sanitizeOT::LigatureSubst873   inline bool sanitize (hb_sanitize_context_t *c) {
874     TRACE_SANITIZE (this);
875     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
876     switch (u.format) {
877     case 1: return TRACE_RETURN (u.format1.sanitize (c));
878     default:return TRACE_RETURN (true);
879     }
880   }
881 
882   protected:
883   union {
884   USHORT		format;		/* Format identifier */
885   LigatureSubstFormat1	format1;
886   } u;
887 };
888 
889 
890 struct ContextSubst : Context {};
891 
892 struct ChainContextSubst : ChainContext {};
893 
894 struct ExtensionSubst : Extension<ExtensionSubst>
895 {
896   typedef struct SubstLookupSubTable LookupSubTable;
897 
898   inline bool is_reverse (void) const;
899 };
900 
901 
902 struct ReverseChainSingleSubstFormat1
903 {
closureOT::ReverseChainSingleSubstFormat1904   inline void closure (hb_closure_context_t *c) const
905   {
906     TRACE_CLOSURE (this);
907     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
908 
909     unsigned int count;
910 
911     count = backtrack.len;
912     for (unsigned int i = 0; i < count; i++)
913       if (!(this+backtrack[i]).intersects (c->glyphs))
914         return;
915 
916     count = lookahead.len;
917     for (unsigned int i = 0; i < count; i++)
918       if (!(this+lookahead[i]).intersects (c->glyphs))
919         return;
920 
921     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
922     Coverage::Iter iter;
923     for (iter.init (this+coverage); iter.more (); iter.next ()) {
924       if (c->glyphs->has (iter.get_glyph ()))
925 	c->glyphs->add (substitute[iter.get_coverage ()]);
926     }
927   }
928 
collect_glyphsOT::ReverseChainSingleSubstFormat1929   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
930   {
931     TRACE_COLLECT_GLYPHS (this);
932 
933     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
934 
935     unsigned int count;
936 
937     (this+coverage).add_coverage (c->input);
938 
939     count = backtrack.len;
940     for (unsigned int i = 0; i < count; i++)
941       (this+backtrack[i]).add_coverage (c->before);
942 
943     count = lookahead.len;
944     for (unsigned int i = 0; i < count; i++)
945       (this+lookahead[i]).add_coverage (c->after);
946 
947     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
948     count = substitute.len;
949     for (unsigned int i = 0; i < count; i++)
950       c->output->add (substitute[i]);
951   }
952 
get_coverageOT::ReverseChainSingleSubstFormat1953   inline const Coverage &get_coverage (void) const
954   {
955     return this+coverage;
956   }
957 
would_applyOT::ReverseChainSingleSubstFormat1958   inline bool would_apply (hb_would_apply_context_t *c) const
959   {
960     TRACE_WOULD_APPLY (this);
961     return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
962   }
963 
applyOT::ReverseChainSingleSubstFormat1964   inline bool apply (hb_apply_context_t *c) const
965   {
966     TRACE_APPLY (this);
967     if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
968       return TRACE_RETURN (false); /* No chaining to this type */
969 
970     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
971     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
972 
973     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
974     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
975 
976     if (match_backtrack (c,
977 			 backtrack.len, (USHORT *) backtrack.array,
978 			 match_coverage, this) &&
979         match_lookahead (c,
980 			 lookahead.len, (USHORT *) lookahead.array,
981 			 match_coverage, this,
982 			 1))
983     {
984       c->replace_glyph_inplace (substitute[index]);
985       c->buffer->idx--; /* Reverse! */
986       return TRACE_RETURN (true);
987     }
988 
989     return TRACE_RETURN (false);
990   }
991 
sanitizeOT::ReverseChainSingleSubstFormat1992   inline bool sanitize (hb_sanitize_context_t *c) {
993     TRACE_SANITIZE (this);
994     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
995       return TRACE_RETURN (false);
996     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
997     if (!lookahead.sanitize (c, this))
998       return TRACE_RETURN (false);
999     ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1000     return TRACE_RETURN (substitute.sanitize (c));
1001   }
1002 
1003   protected:
1004   USHORT	format;			/* Format identifier--format = 1 */
1005   OffsetTo<Coverage>
1006 		coverage;		/* Offset to Coverage table--from
1007 					 * beginning of table */
1008   OffsetArrayOf<Coverage>
1009 		backtrack;		/* Array of coverage tables
1010 					 * in backtracking sequence, in  glyph
1011 					 * sequence order */
1012   OffsetArrayOf<Coverage>
1013 		lookaheadX;		/* Array of coverage tables
1014 					 * in lookahead sequence, in glyph
1015 					 * sequence order */
1016   ArrayOf<GlyphID>
1017 		substituteX;		/* Array of substitute
1018 					 * GlyphIDs--ordered by Coverage Index */
1019   public:
1020   DEFINE_SIZE_MIN (10);
1021 };
1022 
1023 struct ReverseChainSingleSubst
1024 {
1025   template <typename context_t>
dispatchOT::ReverseChainSingleSubst1026   inline typename context_t::return_t dispatch (context_t *c) const
1027   {
1028     TRACE_DISPATCH (this);
1029     switch (u.format) {
1030     case 1: return TRACE_RETURN (c->dispatch (u.format1));
1031     default:return TRACE_RETURN (c->default_return_value ());
1032     }
1033   }
1034 
sanitizeOT::ReverseChainSingleSubst1035   inline bool sanitize (hb_sanitize_context_t *c) {
1036     TRACE_SANITIZE (this);
1037     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1038     switch (u.format) {
1039     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1040     default:return TRACE_RETURN (true);
1041     }
1042   }
1043 
1044   protected:
1045   union {
1046   USHORT				format;		/* Format identifier */
1047   ReverseChainSingleSubstFormat1	format1;
1048   } u;
1049 };
1050 
1051 
1052 
1053 /*
1054  * SubstLookup
1055  */
1056 
1057 struct SubstLookupSubTable
1058 {
1059   friend struct SubstLookup;
1060 
1061   enum Type {
1062     Single		= 1,
1063     Multiple		= 2,
1064     Alternate		= 3,
1065     Ligature		= 4,
1066     Context		= 5,
1067     ChainContext	= 6,
1068     Extension		= 7,
1069     ReverseChainSingle	= 8
1070   };
1071 
1072   template <typename context_t>
dispatchOT::SubstLookupSubTable1073   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1074   {
1075     TRACE_DISPATCH (this);
1076     switch (lookup_type) {
1077     case Single:		return TRACE_RETURN (u.single.dispatch (c));
1078     case Multiple:		return TRACE_RETURN (u.multiple.dispatch (c));
1079     case Alternate:		return TRACE_RETURN (u.alternate.dispatch (c));
1080     case Ligature:		return TRACE_RETURN (u.ligature.dispatch (c));
1081     case Context:		return TRACE_RETURN (u.context.dispatch (c));
1082     case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
1083     case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
1084     case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
1085     default:			return TRACE_RETURN (c->default_return_value ());
1086     }
1087   }
1088 
sanitizeOT::SubstLookupSubTable1089   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1090     TRACE_SANITIZE (this);
1091     if (!u.header.sub_format.sanitize (c))
1092       return TRACE_RETURN (false);
1093     switch (lookup_type) {
1094     case Single:		return TRACE_RETURN (u.single.sanitize (c));
1095     case Multiple:		return TRACE_RETURN (u.multiple.sanitize (c));
1096     case Alternate:		return TRACE_RETURN (u.alternate.sanitize (c));
1097     case Ligature:		return TRACE_RETURN (u.ligature.sanitize (c));
1098     case Context:		return TRACE_RETURN (u.context.sanitize (c));
1099     case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
1100     case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
1101     case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
1102     default:			return TRACE_RETURN (true);
1103     }
1104   }
1105 
1106   protected:
1107   union {
1108   struct {
1109     USHORT			sub_format;
1110   } header;
1111   SingleSubst			single;
1112   MultipleSubst			multiple;
1113   AlternateSubst		alternate;
1114   LigatureSubst			ligature;
1115   ContextSubst			context;
1116   ChainContextSubst		chainContext;
1117   ExtensionSubst		extension;
1118   ReverseChainSingleSubst	reverseChainContextSingle;
1119   } u;
1120   public:
1121   DEFINE_SIZE_UNION (2, header.sub_format);
1122 };
1123 
1124 
1125 struct SubstLookup : Lookup
1126 {
get_subtableOT::SubstLookup1127   inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1128   { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
1129 
lookup_type_is_reverseOT::SubstLookup1130   inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1131   { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1132 
is_reverseOT::SubstLookup1133   inline bool is_reverse (void) const
1134   {
1135     unsigned int type = get_type ();
1136     if (unlikely (type == SubstLookupSubTable::Extension))
1137       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1138     return lookup_type_is_reverse (type);
1139   }
1140 
closureOT::SubstLookup1141   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
1142   {
1143     TRACE_CLOSURE (this);
1144     c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
1145     return TRACE_RETURN (dispatch (c));
1146   }
1147 
collect_glyphs_lookupOT::SubstLookup1148   inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
1149   {
1150     TRACE_COLLECT_GLYPHS (this);
1151     c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
1152     return TRACE_RETURN (dispatch (c));
1153   }
1154 
1155   template <typename set_t>
add_coverageOT::SubstLookup1156   inline void add_coverage (set_t *glyphs) const
1157   {
1158     hb_get_coverage_context_t c;
1159     const Coverage *last = NULL;
1160     unsigned int count = get_subtable_count ();
1161     for (unsigned int i = 0; i < count; i++) {
1162       const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1163       if (coverage != last) {
1164         coverage->add_coverage (glyphs);
1165         last = coverage;
1166       }
1167     }
1168   }
1169 
would_applyOT::SubstLookup1170   inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
1171   {
1172     TRACE_WOULD_APPLY (this);
1173     if (unlikely (!c->len))  return TRACE_RETURN (false);
1174     if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
1175       return TRACE_RETURN (dispatch (c));
1176   }
1177 
apply_onceOT::SubstLookup1178   inline bool apply_once (hb_apply_context_t *c) const
1179   {
1180     TRACE_APPLY (this);
1181     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
1182       return TRACE_RETURN (false);
1183     return TRACE_RETURN (dispatch (c));
1184   }
1185 
1186   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
apply_stringOT::SubstLookup1187   inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
1188   {
1189     bool ret = false;
1190 
1191     if (unlikely (!c->buffer->len || !c->lookup_mask))
1192       return false;
1193 
1194     c->set_recurse_func (apply_recurse_func);
1195     c->set_lookup (*this);
1196 
1197     if (likely (!is_reverse ()))
1198     {
1199 	/* in/out forward substitution */
1200 	c->buffer->clear_output ();
1201 	c->buffer->idx = 0;
1202 
1203 	while (c->buffer->idx < c->buffer->len)
1204 	{
1205 	  if ((c->buffer->cur().mask & c->lookup_mask) &&
1206 	      digest->may_have (c->buffer->cur().codepoint) &&
1207 	      apply_once (c))
1208 	    ret = true;
1209 	  else
1210 	    c->buffer->next_glyph ();
1211 	}
1212 	if (ret)
1213 	  c->buffer->swap_buffers ();
1214     }
1215     else
1216     {
1217 	/* in-place backward substitution */
1218 	c->buffer->remove_output ();
1219 	c->buffer->idx = c->buffer->len - 1;
1220 	do
1221 	{
1222 	  if ((c->buffer->cur().mask & c->lookup_mask) &&
1223 	      digest->may_have (c->buffer->cur().codepoint) &&
1224 	      apply_once (c))
1225 	    ret = true;
1226 	  else
1227 	    c->buffer->idx--;
1228 
1229 	}
1230 	while ((int) c->buffer->idx >= 0);
1231     }
1232 
1233     return ret;
1234   }
1235 
serialize_subtableOT::SubstLookup1236   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1237 						  unsigned int i)
1238   { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
1239 
serialize_singleOT::SubstLookup1240   inline bool serialize_single (hb_serialize_context_t *c,
1241 				uint32_t lookup_props,
1242 			        Supplier<GlyphID> &glyphs,
1243 			        Supplier<GlyphID> &substitutes,
1244 			        unsigned int num_glyphs)
1245   {
1246     TRACE_SERIALIZE (this);
1247     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
1248     return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1249   }
1250 
serialize_multipleOT::SubstLookup1251   inline bool serialize_multiple (hb_serialize_context_t *c,
1252 				  uint32_t lookup_props,
1253 				  Supplier<GlyphID> &glyphs,
1254 				  Supplier<unsigned int> &substitute_len_list,
1255 				  unsigned int num_glyphs,
1256 				  Supplier<GlyphID> &substitute_glyphs_list)
1257   {
1258     TRACE_SERIALIZE (this);
1259     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
1260     return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
1261 									 substitute_glyphs_list));
1262   }
1263 
serialize_alternateOT::SubstLookup1264   inline bool serialize_alternate (hb_serialize_context_t *c,
1265 				   uint32_t lookup_props,
1266 				   Supplier<GlyphID> &glyphs,
1267 				   Supplier<unsigned int> &alternate_len_list,
1268 				   unsigned int num_glyphs,
1269 				   Supplier<GlyphID> &alternate_glyphs_list)
1270   {
1271     TRACE_SERIALIZE (this);
1272     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
1273     return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
1274 									  alternate_glyphs_list));
1275   }
1276 
serialize_ligatureOT::SubstLookup1277   inline bool serialize_ligature (hb_serialize_context_t *c,
1278 				  uint32_t lookup_props,
1279 				  Supplier<GlyphID> &first_glyphs,
1280 				  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1281 				  unsigned int num_first_glyphs,
1282 				  Supplier<GlyphID> &ligatures_list,
1283 				  Supplier<unsigned int> &component_count_list,
1284 				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1285   {
1286     TRACE_SERIALIZE (this);
1287     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
1288     return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
1289 									 ligatures_list, component_count_list, component_list));
1290   }
1291 
1292   template <typename context_t>
1293   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1294 
1295   template <typename context_t>
dispatchOT::SubstLookup1296   inline typename context_t::return_t dispatch (context_t *c) const
1297   {
1298     TRACE_DISPATCH (this);
1299     unsigned int lookup_type = get_type ();
1300     unsigned int count = get_subtable_count ();
1301     for (unsigned int i = 0; i < count; i++) {
1302       typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
1303       if (c->stop_sublookup_iteration (r))
1304         return TRACE_RETURN (r);
1305     }
1306     return TRACE_RETURN (c->default_return_value ());
1307   }
1308 
sanitizeOT::SubstLookup1309   inline bool sanitize (hb_sanitize_context_t *c)
1310   {
1311     TRACE_SANITIZE (this);
1312     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1313     OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
1314     if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
1315 
1316     if (unlikely (get_type () == SubstLookupSubTable::Extension))
1317     {
1318       /* The spec says all subtables of an Extension lookup should
1319        * have the same type.  This is specially important if one has
1320        * a reverse type! */
1321       unsigned int type = get_subtable (0).u.extension.get_type ();
1322       unsigned int count = get_subtable_count ();
1323       for (unsigned int i = 1; i < count; i++)
1324         if (get_subtable (i).u.extension.get_type () != type)
1325 	  return TRACE_RETURN (false);
1326     }
1327     return TRACE_RETURN (true);
1328   }
1329 };
1330 
1331 typedef OffsetListOf<SubstLookup> SubstLookupList;
1332 
1333 /*
1334  * GSUB -- The Glyph Substitution Table
1335  */
1336 
1337 struct GSUB : GSUBGPOS
1338 {
1339   static const hb_tag_t Tag	= HB_OT_TAG_GSUB;
1340 
get_lookupOT::GSUB1341   inline const SubstLookup& get_lookup (unsigned int i) const
1342   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1343 
1344   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1345   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
1346 
sanitizeOT::GSUB1347   inline bool sanitize (hb_sanitize_context_t *c) {
1348     TRACE_SANITIZE (this);
1349     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1350     OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1351     return TRACE_RETURN (list.sanitize (c, this));
1352   }
1353   public:
1354   DEFINE_SIZE_STATIC (10);
1355 };
1356 
1357 
1358 void
substitute_start(hb_font_t * font,hb_buffer_t * buffer)1359 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1360 {
1361   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
1362   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
1363   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
1364 
1365   const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1366   unsigned int count = buffer->len;
1367   for (unsigned int i = 0; i < count; i++) {
1368     buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
1369     buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
1370   }
1371 }
1372 
1373 void
substitute_finish(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer HB_UNUSED)1374 GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
1375 {
1376 }
1377 
1378 
1379 /* Out-of-class implementation for methods recursing */
1380 
is_reverse(void) const1381 inline bool ExtensionSubst::is_reverse (void) const
1382 {
1383   unsigned int type = get_type ();
1384   if (unlikely (type == SubstLookupSubTable::Extension))
1385     return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
1386   return SubstLookup::lookup_type_is_reverse (type);
1387 }
1388 
1389 template <typename context_t>
dispatch_recurse_func(context_t * c,unsigned int lookup_index)1390 inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1391 {
1392   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1393   const SubstLookup &l = gsub.get_lookup (lookup_index);
1394   return l.dispatch (c);
1395 }
1396 
apply_recurse_func(hb_apply_context_t * c,unsigned int lookup_index)1397 inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1398 {
1399   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1400   const SubstLookup &l = gsub.get_lookup (lookup_index);
1401   unsigned int saved_lookup_props = c->lookup_props;
1402   c->set_lookup (l);
1403   bool ret = l.apply_once (c);
1404   c->lookup_props = saved_lookup_props;
1405   return ret;
1406 }
1407 
1408 
1409 } /* namespace OT */
1410 
1411 
1412 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
1413