1 /*
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012,2013 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) & 0xFFFFu);
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) & 0xFFFFu);
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 (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 (false);
79
80 /* According to the Adobe Annotated OpenType Suite, result is always
81 * limited to 16bit. */
82 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
83 c->replace_glyph (glyph_id);
84
85 return_trace (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 (false);
95 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
96 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
97 return_trace (true);
98 }
99
sanitizeOT::SingleSubstFormat1100 inline bool sanitize (hb_sanitize_context_t *c) const
101 {
102 TRACE_SANITIZE (this);
103 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
104 }
105
106 protected:
107 USHORT format; /* Format identifier--format = 1 */
108 OffsetTo<Coverage>
109 coverage; /* Offset to Coverage table--from
110 * beginning of Substitution table */
111 SHORT deltaGlyphID; /* Add to original GlyphID to get
112 * substitute GlyphID */
113 public:
114 DEFINE_SIZE_STATIC (6);
115 };
116
117 struct SingleSubstFormat2
118 {
closureOT::SingleSubstFormat2119 inline void closure (hb_closure_context_t *c) const
120 {
121 TRACE_CLOSURE (this);
122 Coverage::Iter iter;
123 for (iter.init (this+coverage); iter.more (); iter.next ()) {
124 if (c->glyphs->has (iter.get_glyph ()))
125 c->glyphs->add (substitute[iter.get_coverage ()]);
126 }
127 }
128
collect_glyphsOT::SingleSubstFormat2129 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
130 {
131 TRACE_COLLECT_GLYPHS (this);
132 Coverage::Iter iter;
133 for (iter.init (this+coverage); iter.more (); iter.next ()) {
134 c->input->add (iter.get_glyph ());
135 c->output->add (substitute[iter.get_coverage ()]);
136 }
137 }
138
get_coverageOT::SingleSubstFormat2139 inline const Coverage &get_coverage (void) const
140 {
141 return this+coverage;
142 }
143
would_applyOT::SingleSubstFormat2144 inline bool would_apply (hb_would_apply_context_t *c) const
145 {
146 TRACE_WOULD_APPLY (this);
147 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
148 }
149
applyOT::SingleSubstFormat2150 inline bool apply (hb_apply_context_t *c) const
151 {
152 TRACE_APPLY (this);
153 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
154 unsigned int index = (this+coverage).get_coverage (glyph_id);
155 if (likely (index == NOT_COVERED)) return_trace (false);
156
157 if (unlikely (index >= substitute.len)) return_trace (false);
158
159 glyph_id = substitute[index];
160 c->replace_glyph (glyph_id);
161
162 return_trace (true);
163 }
164
serializeOT::SingleSubstFormat2165 inline bool serialize (hb_serialize_context_t *c,
166 Supplier<GlyphID> &glyphs,
167 Supplier<GlyphID> &substitutes,
168 unsigned int num_glyphs)
169 {
170 TRACE_SERIALIZE (this);
171 if (unlikely (!c->extend_min (*this))) return_trace (false);
172 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
173 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
174 return_trace (true);
175 }
176
sanitizeOT::SingleSubstFormat2177 inline bool sanitize (hb_sanitize_context_t *c) const
178 {
179 TRACE_SANITIZE (this);
180 return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
181 }
182
183 protected:
184 USHORT format; /* Format identifier--format = 2 */
185 OffsetTo<Coverage>
186 coverage; /* Offset to Coverage table--from
187 * beginning of Substitution table */
188 ArrayOf<GlyphID>
189 substitute; /* Array of substitute
190 * GlyphIDs--ordered by Coverage Index */
191 public:
192 DEFINE_SIZE_ARRAY (6, substitute);
193 };
194
195 struct SingleSubst
196 {
serializeOT::SingleSubst197 inline bool serialize (hb_serialize_context_t *c,
198 Supplier<GlyphID> &glyphs,
199 Supplier<GlyphID> &substitutes,
200 unsigned int num_glyphs)
201 {
202 TRACE_SERIALIZE (this);
203 if (unlikely (!c->extend_min (u.format))) return_trace (false);
204 unsigned int format = 2;
205 int delta = 0;
206 if (num_glyphs) {
207 format = 1;
208 /* TODO(serialize) check for wrap-around */
209 delta = substitutes[0] - glyphs[0];
210 for (unsigned int i = 1; i < num_glyphs; i++)
211 if (delta != substitutes[i] - glyphs[i]) {
212 format = 2;
213 break;
214 }
215 }
216 u.format.set (format);
217 switch (u.format) {
218 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
219 case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
220 default:return_trace (false);
221 }
222 }
223
224 template <typename context_t>
dispatchOT::SingleSubst225 inline typename context_t::return_t dispatch (context_t *c) const
226 {
227 TRACE_DISPATCH (this, u.format);
228 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
229 switch (u.format) {
230 case 1: return_trace (c->dispatch (u.format1));
231 case 2: return_trace (c->dispatch (u.format2));
232 default:return_trace (c->default_return_value ());
233 }
234 }
235
236 protected:
237 union {
238 USHORT format; /* Format identifier */
239 SingleSubstFormat1 format1;
240 SingleSubstFormat2 format2;
241 } u;
242 };
243
244
245 struct Sequence
246 {
closureOT::Sequence247 inline void closure (hb_closure_context_t *c) const
248 {
249 TRACE_CLOSURE (this);
250 unsigned int count = substitute.len;
251 for (unsigned int i = 0; i < count; i++)
252 c->glyphs->add (substitute[i]);
253 }
254
collect_glyphsOT::Sequence255 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
256 {
257 TRACE_COLLECT_GLYPHS (this);
258 unsigned int count = substitute.len;
259 for (unsigned int i = 0; i < count; i++)
260 c->output->add (substitute[i]);
261 }
262
applyOT::Sequence263 inline bool apply (hb_apply_context_t *c) const
264 {
265 TRACE_APPLY (this);
266 unsigned int count = substitute.len;
267
268 /* TODO:
269 * Testing shows that Uniscribe actually allows zero-len susbstitute,
270 * which essentially deletes a glyph. We don't allow for now. It
271 * can be confusing to the client since the cluster from the deleted
272 * glyph won't be merged with any output cluster... Also, currently
273 * buffer->move_to() makes assumptions about this too. Perhaps fix
274 * in the future after figuring out what to do with the clusters.
275 */
276 if (unlikely (!count)) return_trace (false);
277
278 /* Special-case to make it in-place and not consider this
279 * as a "multiplied" substitution. */
280 if (unlikely (count == 1))
281 {
282 c->replace_glyph (substitute.array[0]);
283 return_trace (true);
284 }
285
286 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
287 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
288
289 for (unsigned int i = 0; i < count; i++) {
290 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
291 c->output_glyph_for_component (substitute.array[i], klass);
292 }
293 c->buffer->skip_glyph ();
294
295 return_trace (true);
296 }
297
serializeOT::Sequence298 inline bool serialize (hb_serialize_context_t *c,
299 Supplier<GlyphID> &glyphs,
300 unsigned int num_glyphs)
301 {
302 TRACE_SERIALIZE (this);
303 if (unlikely (!c->extend_min (*this))) return_trace (false);
304 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
305 return_trace (true);
306 }
307
sanitizeOT::Sequence308 inline bool sanitize (hb_sanitize_context_t *c) const
309 {
310 TRACE_SANITIZE (this);
311 return_trace (substitute.sanitize (c));
312 }
313
314 protected:
315 ArrayOf<GlyphID>
316 substitute; /* String of GlyphIDs to substitute */
317 public:
318 DEFINE_SIZE_ARRAY (2, substitute);
319 };
320
321 struct MultipleSubstFormat1
322 {
closureOT::MultipleSubstFormat1323 inline void closure (hb_closure_context_t *c) const
324 {
325 TRACE_CLOSURE (this);
326 Coverage::Iter iter;
327 for (iter.init (this+coverage); iter.more (); iter.next ()) {
328 if (c->glyphs->has (iter.get_glyph ()))
329 (this+sequence[iter.get_coverage ()]).closure (c);
330 }
331 }
332
collect_glyphsOT::MultipleSubstFormat1333 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
334 {
335 TRACE_COLLECT_GLYPHS (this);
336 (this+coverage).add_coverage (c->input);
337 unsigned int count = sequence.len;
338 for (unsigned int i = 0; i < count; i++)
339 (this+sequence[i]).collect_glyphs (c);
340 }
341
get_coverageOT::MultipleSubstFormat1342 inline const Coverage &get_coverage (void) const
343 {
344 return this+coverage;
345 }
346
would_applyOT::MultipleSubstFormat1347 inline bool would_apply (hb_would_apply_context_t *c) const
348 {
349 TRACE_WOULD_APPLY (this);
350 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
351 }
352
applyOT::MultipleSubstFormat1353 inline bool apply (hb_apply_context_t *c) const
354 {
355 TRACE_APPLY (this);
356
357 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
358 if (likely (index == NOT_COVERED)) return_trace (false);
359
360 return_trace ((this+sequence[index]).apply (c));
361 }
362
serializeOT::MultipleSubstFormat1363 inline bool serialize (hb_serialize_context_t *c,
364 Supplier<GlyphID> &glyphs,
365 Supplier<unsigned int> &substitute_len_list,
366 unsigned int num_glyphs,
367 Supplier<GlyphID> &substitute_glyphs_list)
368 {
369 TRACE_SERIALIZE (this);
370 if (unlikely (!c->extend_min (*this))) return_trace (false);
371 if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
372 for (unsigned int i = 0; i < num_glyphs; i++)
373 if (unlikely (!sequence[i].serialize (c, this).serialize (c,
374 substitute_glyphs_list,
375 substitute_len_list[i]))) return_trace (false);
376 substitute_len_list.advance (num_glyphs);
377 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
378 return_trace (true);
379 }
380
sanitizeOT::MultipleSubstFormat1381 inline bool sanitize (hb_sanitize_context_t *c) const
382 {
383 TRACE_SANITIZE (this);
384 return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
385 }
386
387 protected:
388 USHORT format; /* Format identifier--format = 1 */
389 OffsetTo<Coverage>
390 coverage; /* Offset to Coverage table--from
391 * beginning of Substitution table */
392 OffsetArrayOf<Sequence>
393 sequence; /* Array of Sequence tables
394 * ordered by Coverage Index */
395 public:
396 DEFINE_SIZE_ARRAY (6, sequence);
397 };
398
399 struct MultipleSubst
400 {
serializeOT::MultipleSubst401 inline bool serialize (hb_serialize_context_t *c,
402 Supplier<GlyphID> &glyphs,
403 Supplier<unsigned int> &substitute_len_list,
404 unsigned int num_glyphs,
405 Supplier<GlyphID> &substitute_glyphs_list)
406 {
407 TRACE_SERIALIZE (this);
408 if (unlikely (!c->extend_min (u.format))) return_trace (false);
409 unsigned int format = 1;
410 u.format.set (format);
411 switch (u.format) {
412 case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
413 default:return_trace (false);
414 }
415 }
416
417 template <typename context_t>
dispatchOT::MultipleSubst418 inline typename context_t::return_t dispatch (context_t *c) const
419 {
420 TRACE_DISPATCH (this, u.format);
421 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
422 switch (u.format) {
423 case 1: return_trace (c->dispatch (u.format1));
424 default:return_trace (c->default_return_value ());
425 }
426 }
427
428 protected:
429 union {
430 USHORT format; /* Format identifier */
431 MultipleSubstFormat1 format1;
432 } u;
433 };
434
435
436 typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
437 * arbitrary order */
438
439 struct AlternateSubstFormat1
440 {
closureOT::AlternateSubstFormat1441 inline void closure (hb_closure_context_t *c) const
442 {
443 TRACE_CLOSURE (this);
444 Coverage::Iter iter;
445 for (iter.init (this+coverage); iter.more (); iter.next ()) {
446 if (c->glyphs->has (iter.get_glyph ())) {
447 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
448 unsigned int count = alt_set.len;
449 for (unsigned int i = 0; i < count; i++)
450 c->glyphs->add (alt_set[i]);
451 }
452 }
453 }
454
collect_glyphsOT::AlternateSubstFormat1455 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
456 {
457 TRACE_COLLECT_GLYPHS (this);
458 Coverage::Iter iter;
459 for (iter.init (this+coverage); iter.more (); iter.next ()) {
460 c->input->add (iter.get_glyph ());
461 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
462 unsigned int count = alt_set.len;
463 for (unsigned int i = 0; i < count; i++)
464 c->output->add (alt_set[i]);
465 }
466 }
467
get_coverageOT::AlternateSubstFormat1468 inline const Coverage &get_coverage (void) const
469 {
470 return this+coverage;
471 }
472
would_applyOT::AlternateSubstFormat1473 inline bool would_apply (hb_would_apply_context_t *c) const
474 {
475 TRACE_WOULD_APPLY (this);
476 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
477 }
478
applyOT::AlternateSubstFormat1479 inline bool apply (hb_apply_context_t *c) const
480 {
481 TRACE_APPLY (this);
482 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
483
484 unsigned int index = (this+coverage).get_coverage (glyph_id);
485 if (likely (index == NOT_COVERED)) return_trace (false);
486
487 const AlternateSet &alt_set = this+alternateSet[index];
488
489 if (unlikely (!alt_set.len)) return_trace (false);
490
491 hb_mask_t glyph_mask = c->buffer->cur().mask;
492 hb_mask_t lookup_mask = c->lookup_mask;
493
494 /* Note: This breaks badly if two features enabled this lookup together. */
495 unsigned int shift = _hb_ctz (lookup_mask);
496 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
497
498 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
499
500 glyph_id = alt_set[alt_index - 1];
501
502 c->replace_glyph (glyph_id);
503
504 return_trace (true);
505 }
506
serializeOT::AlternateSubstFormat1507 inline bool serialize (hb_serialize_context_t *c,
508 Supplier<GlyphID> &glyphs,
509 Supplier<unsigned int> &alternate_len_list,
510 unsigned int num_glyphs,
511 Supplier<GlyphID> &alternate_glyphs_list)
512 {
513 TRACE_SERIALIZE (this);
514 if (unlikely (!c->extend_min (*this))) return_trace (false);
515 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
516 for (unsigned int i = 0; i < num_glyphs; i++)
517 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
518 alternate_glyphs_list,
519 alternate_len_list[i]))) return_trace (false);
520 alternate_len_list.advance (num_glyphs);
521 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
522 return_trace (true);
523 }
524
sanitizeOT::AlternateSubstFormat1525 inline bool sanitize (hb_sanitize_context_t *c) const
526 {
527 TRACE_SANITIZE (this);
528 return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
529 }
530
531 protected:
532 USHORT format; /* Format identifier--format = 1 */
533 OffsetTo<Coverage>
534 coverage; /* Offset to Coverage table--from
535 * beginning of Substitution table */
536 OffsetArrayOf<AlternateSet>
537 alternateSet; /* Array of AlternateSet tables
538 * ordered by Coverage Index */
539 public:
540 DEFINE_SIZE_ARRAY (6, alternateSet);
541 };
542
543 struct AlternateSubst
544 {
serializeOT::AlternateSubst545 inline bool serialize (hb_serialize_context_t *c,
546 Supplier<GlyphID> &glyphs,
547 Supplier<unsigned int> &alternate_len_list,
548 unsigned int num_glyphs,
549 Supplier<GlyphID> &alternate_glyphs_list)
550 {
551 TRACE_SERIALIZE (this);
552 if (unlikely (!c->extend_min (u.format))) return_trace (false);
553 unsigned int format = 1;
554 u.format.set (format);
555 switch (u.format) {
556 case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
557 default:return_trace (false);
558 }
559 }
560
561 template <typename context_t>
dispatchOT::AlternateSubst562 inline typename context_t::return_t dispatch (context_t *c) const
563 {
564 TRACE_DISPATCH (this, u.format);
565 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
566 switch (u.format) {
567 case 1: return_trace (c->dispatch (u.format1));
568 default:return_trace (c->default_return_value ());
569 }
570 }
571
572 protected:
573 union {
574 USHORT format; /* Format identifier */
575 AlternateSubstFormat1 format1;
576 } u;
577 };
578
579
580 struct Ligature
581 {
closureOT::Ligature582 inline void closure (hb_closure_context_t *c) const
583 {
584 TRACE_CLOSURE (this);
585 unsigned int count = component.len;
586 for (unsigned int i = 1; i < count; i++)
587 if (!c->glyphs->has (component[i]))
588 return;
589 c->glyphs->add (ligGlyph);
590 }
591
collect_glyphsOT::Ligature592 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
593 {
594 TRACE_COLLECT_GLYPHS (this);
595 unsigned int count = component.len;
596 for (unsigned int i = 1; i < count; i++)
597 c->input->add (component[i]);
598 c->output->add (ligGlyph);
599 }
600
would_applyOT::Ligature601 inline bool would_apply (hb_would_apply_context_t *c) const
602 {
603 TRACE_WOULD_APPLY (this);
604 if (c->len != component.len)
605 return_trace (false);
606
607 for (unsigned int i = 1; i < c->len; i++)
608 if (likely (c->glyphs[i] != component[i]))
609 return_trace (false);
610
611 return_trace (true);
612 }
613
applyOT::Ligature614 inline bool apply (hb_apply_context_t *c) const
615 {
616 TRACE_APPLY (this);
617 unsigned int count = component.len;
618
619 if (unlikely (!count)) return_trace (false);
620
621 /* Special-case to make it in-place and not consider this
622 * as a "ligated" substitution. */
623 if (unlikely (count == 1))
624 {
625 c->replace_glyph (ligGlyph);
626 return_trace (true);
627 }
628
629 bool is_mark_ligature = false;
630 unsigned int total_component_count = 0;
631
632 unsigned int match_length = 0;
633 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
634
635 if (likely (!match_input (c, count,
636 &component[1],
637 match_glyph,
638 NULL,
639 &match_length,
640 match_positions,
641 &is_mark_ligature,
642 &total_component_count)))
643 return_trace (false);
644
645 ligate_input (c,
646 count,
647 match_positions,
648 match_length,
649 ligGlyph,
650 is_mark_ligature,
651 total_component_count);
652
653 return_trace (true);
654 }
655
serializeOT::Ligature656 inline bool serialize (hb_serialize_context_t *c,
657 GlyphID ligature,
658 Supplier<GlyphID> &components, /* Starting from second */
659 unsigned int num_components /* Including first component */)
660 {
661 TRACE_SERIALIZE (this);
662 if (unlikely (!c->extend_min (*this))) return_trace (false);
663 ligGlyph = ligature;
664 if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
665 return_trace (true);
666 }
667
668 public:
sanitizeOT::Ligature669 inline bool sanitize (hb_sanitize_context_t *c) const
670 {
671 TRACE_SANITIZE (this);
672 return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
673 }
674
675 protected:
676 GlyphID ligGlyph; /* GlyphID of ligature to substitute */
677 HeadlessArrayOf<GlyphID>
678 component; /* Array of component GlyphIDs--start
679 * with the second component--ordered
680 * in writing direction */
681 public:
682 DEFINE_SIZE_ARRAY (4, component);
683 };
684
685 struct LigatureSet
686 {
closureOT::LigatureSet687 inline void closure (hb_closure_context_t *c) const
688 {
689 TRACE_CLOSURE (this);
690 unsigned int num_ligs = ligature.len;
691 for (unsigned int i = 0; i < num_ligs; i++)
692 (this+ligature[i]).closure (c);
693 }
694
collect_glyphsOT::LigatureSet695 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
696 {
697 TRACE_COLLECT_GLYPHS (this);
698 unsigned int num_ligs = ligature.len;
699 for (unsigned int i = 0; i < num_ligs; i++)
700 (this+ligature[i]).collect_glyphs (c);
701 }
702
would_applyOT::LigatureSet703 inline bool would_apply (hb_would_apply_context_t *c) const
704 {
705 TRACE_WOULD_APPLY (this);
706 unsigned int num_ligs = ligature.len;
707 for (unsigned int i = 0; i < num_ligs; i++)
708 {
709 const Ligature &lig = this+ligature[i];
710 if (lig.would_apply (c))
711 return_trace (true);
712 }
713 return_trace (false);
714 }
715
applyOT::LigatureSet716 inline bool apply (hb_apply_context_t *c) const
717 {
718 TRACE_APPLY (this);
719 unsigned int num_ligs = ligature.len;
720 for (unsigned int i = 0; i < num_ligs; i++)
721 {
722 const Ligature &lig = this+ligature[i];
723 if (lig.apply (c)) return_trace (true);
724 }
725
726 return_trace (false);
727 }
728
serializeOT::LigatureSet729 inline bool serialize (hb_serialize_context_t *c,
730 Supplier<GlyphID> &ligatures,
731 Supplier<unsigned int> &component_count_list,
732 unsigned int num_ligatures,
733 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
734 {
735 TRACE_SERIALIZE (this);
736 if (unlikely (!c->extend_min (*this))) return_trace (false);
737 if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
738 for (unsigned int i = 0; i < num_ligatures; i++)
739 if (unlikely (!ligature[i].serialize (c, this).serialize (c,
740 ligatures[i],
741 component_list,
742 component_count_list[i]))) return_trace (false);
743 ligatures.advance (num_ligatures);
744 component_count_list.advance (num_ligatures);
745 return_trace (true);
746 }
747
sanitizeOT::LigatureSet748 inline bool sanitize (hb_sanitize_context_t *c) const
749 {
750 TRACE_SANITIZE (this);
751 return_trace (ligature.sanitize (c, this));
752 }
753
754 protected:
755 OffsetArrayOf<Ligature>
756 ligature; /* Array LigatureSet tables
757 * ordered by preference */
758 public:
759 DEFINE_SIZE_ARRAY (2, ligature);
760 };
761
762 struct LigatureSubstFormat1
763 {
closureOT::LigatureSubstFormat1764 inline void closure (hb_closure_context_t *c) const
765 {
766 TRACE_CLOSURE (this);
767 Coverage::Iter iter;
768 for (iter.init (this+coverage); iter.more (); iter.next ()) {
769 if (c->glyphs->has (iter.get_glyph ()))
770 (this+ligatureSet[iter.get_coverage ()]).closure (c);
771 }
772 }
773
collect_glyphsOT::LigatureSubstFormat1774 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
775 {
776 TRACE_COLLECT_GLYPHS (this);
777 Coverage::Iter iter;
778 for (iter.init (this+coverage); iter.more (); iter.next ()) {
779 c->input->add (iter.get_glyph ());
780 (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
781 }
782 }
783
get_coverageOT::LigatureSubstFormat1784 inline const Coverage &get_coverage (void) const
785 {
786 return this+coverage;
787 }
788
would_applyOT::LigatureSubstFormat1789 inline bool would_apply (hb_would_apply_context_t *c) const
790 {
791 TRACE_WOULD_APPLY (this);
792 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
793 if (likely (index == NOT_COVERED)) return_trace (false);
794
795 const LigatureSet &lig_set = this+ligatureSet[index];
796 return_trace (lig_set.would_apply (c));
797 }
798
applyOT::LigatureSubstFormat1799 inline bool apply (hb_apply_context_t *c) const
800 {
801 TRACE_APPLY (this);
802 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
803
804 unsigned int index = (this+coverage).get_coverage (glyph_id);
805 if (likely (index == NOT_COVERED)) return_trace (false);
806
807 const LigatureSet &lig_set = this+ligatureSet[index];
808 return_trace (lig_set.apply (c));
809 }
810
serializeOT::LigatureSubstFormat1811 inline bool serialize (hb_serialize_context_t *c,
812 Supplier<GlyphID> &first_glyphs,
813 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
814 unsigned int num_first_glyphs,
815 Supplier<GlyphID> &ligatures_list,
816 Supplier<unsigned int> &component_count_list,
817 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
818 {
819 TRACE_SERIALIZE (this);
820 if (unlikely (!c->extend_min (*this))) return_trace (false);
821 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
822 for (unsigned int i = 0; i < num_first_glyphs; i++)
823 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
824 ligatures_list,
825 component_count_list,
826 ligature_per_first_glyph_count_list[i],
827 component_list))) return_trace (false);
828 ligature_per_first_glyph_count_list.advance (num_first_glyphs);
829 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
830 return_trace (true);
831 }
832
sanitizeOT::LigatureSubstFormat1833 inline bool sanitize (hb_sanitize_context_t *c) const
834 {
835 TRACE_SANITIZE (this);
836 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
837 }
838
839 protected:
840 USHORT format; /* Format identifier--format = 1 */
841 OffsetTo<Coverage>
842 coverage; /* Offset to Coverage table--from
843 * beginning of Substitution table */
844 OffsetArrayOf<LigatureSet>
845 ligatureSet; /* Array LigatureSet tables
846 * ordered by Coverage Index */
847 public:
848 DEFINE_SIZE_ARRAY (6, ligatureSet);
849 };
850
851 struct LigatureSubst
852 {
serializeOT::LigatureSubst853 inline bool serialize (hb_serialize_context_t *c,
854 Supplier<GlyphID> &first_glyphs,
855 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
856 unsigned int num_first_glyphs,
857 Supplier<GlyphID> &ligatures_list,
858 Supplier<unsigned int> &component_count_list,
859 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
860 {
861 TRACE_SERIALIZE (this);
862 if (unlikely (!c->extend_min (u.format))) return_trace (false);
863 unsigned int format = 1;
864 u.format.set (format);
865 switch (u.format) {
866 case 1: return_trace (u.format1.serialize (c,
867 first_glyphs,
868 ligature_per_first_glyph_count_list,
869 num_first_glyphs,
870 ligatures_list,
871 component_count_list,
872 component_list));
873 default:return_trace (false);
874 }
875 }
876
877 template <typename context_t>
dispatchOT::LigatureSubst878 inline typename context_t::return_t dispatch (context_t *c) const
879 {
880 TRACE_DISPATCH (this, u.format);
881 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
882 switch (u.format) {
883 case 1: return_trace (c->dispatch (u.format1));
884 default:return_trace (c->default_return_value ());
885 }
886 }
887
888 protected:
889 union {
890 USHORT format; /* Format identifier */
891 LigatureSubstFormat1 format1;
892 } u;
893 };
894
895
896 struct ContextSubst : Context {};
897
898 struct ChainContextSubst : ChainContext {};
899
900 struct ExtensionSubst : Extension<ExtensionSubst>
901 {
902 typedef struct SubstLookupSubTable LookupSubTable;
903
904 inline bool is_reverse (void) const;
905 };
906
907
908 struct ReverseChainSingleSubstFormat1
909 {
closureOT::ReverseChainSingleSubstFormat1910 inline void closure (hb_closure_context_t *c) const
911 {
912 TRACE_CLOSURE (this);
913 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
914
915 unsigned int count;
916
917 count = backtrack.len;
918 for (unsigned int i = 0; i < count; i++)
919 if (!(this+backtrack[i]).intersects (c->glyphs))
920 return;
921
922 count = lookahead.len;
923 for (unsigned int i = 0; i < count; i++)
924 if (!(this+lookahead[i]).intersects (c->glyphs))
925 return;
926
927 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
928 Coverage::Iter iter;
929 for (iter.init (this+coverage); iter.more (); iter.next ()) {
930 if (c->glyphs->has (iter.get_glyph ()))
931 c->glyphs->add (substitute[iter.get_coverage ()]);
932 }
933 }
934
collect_glyphsOT::ReverseChainSingleSubstFormat1935 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
936 {
937 TRACE_COLLECT_GLYPHS (this);
938
939 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
940
941 unsigned int count;
942
943 (this+coverage).add_coverage (c->input);
944
945 count = backtrack.len;
946 for (unsigned int i = 0; i < count; i++)
947 (this+backtrack[i]).add_coverage (c->before);
948
949 count = lookahead.len;
950 for (unsigned int i = 0; i < count; i++)
951 (this+lookahead[i]).add_coverage (c->after);
952
953 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
954 count = substitute.len;
955 for (unsigned int i = 0; i < count; i++)
956 c->output->add (substitute[i]);
957 }
958
get_coverageOT::ReverseChainSingleSubstFormat1959 inline const Coverage &get_coverage (void) const
960 {
961 return this+coverage;
962 }
963
would_applyOT::ReverseChainSingleSubstFormat1964 inline bool would_apply (hb_would_apply_context_t *c) const
965 {
966 TRACE_WOULD_APPLY (this);
967 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
968 }
969
applyOT::ReverseChainSingleSubstFormat1970 inline bool apply (hb_apply_context_t *c) const
971 {
972 TRACE_APPLY (this);
973 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
974 return_trace (false); /* No chaining to this type */
975
976 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
977 if (likely (index == NOT_COVERED)) return_trace (false);
978
979 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
980 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
981
982 if (match_backtrack (c,
983 backtrack.len, (USHORT *) backtrack.array,
984 match_coverage, this) &&
985 match_lookahead (c,
986 lookahead.len, (USHORT *) lookahead.array,
987 match_coverage, this,
988 1))
989 {
990 c->replace_glyph_inplace (substitute[index]);
991 /* Note: We DON'T decrease buffer->idx. The main loop does it
992 * for us. This is useful for preventing surprises if someone
993 * calls us through a Context lookup. */
994 return_trace (true);
995 }
996
997 return_trace (false);
998 }
999
sanitizeOT::ReverseChainSingleSubstFormat11000 inline bool sanitize (hb_sanitize_context_t *c) const
1001 {
1002 TRACE_SANITIZE (this);
1003 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
1004 return_trace (false);
1005 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1006 if (!lookahead.sanitize (c, this))
1007 return_trace (false);
1008 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1009 return_trace (substitute.sanitize (c));
1010 }
1011
1012 protected:
1013 USHORT format; /* Format identifier--format = 1 */
1014 OffsetTo<Coverage>
1015 coverage; /* Offset to Coverage table--from
1016 * beginning of table */
1017 OffsetArrayOf<Coverage>
1018 backtrack; /* Array of coverage tables
1019 * in backtracking sequence, in glyph
1020 * sequence order */
1021 OffsetArrayOf<Coverage>
1022 lookaheadX; /* Array of coverage tables
1023 * in lookahead sequence, in glyph
1024 * sequence order */
1025 ArrayOf<GlyphID>
1026 substituteX; /* Array of substitute
1027 * GlyphIDs--ordered by Coverage Index */
1028 public:
1029 DEFINE_SIZE_MIN (10);
1030 };
1031
1032 struct ReverseChainSingleSubst
1033 {
1034 template <typename context_t>
dispatchOT::ReverseChainSingleSubst1035 inline typename context_t::return_t dispatch (context_t *c) const
1036 {
1037 TRACE_DISPATCH (this, u.format);
1038 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1039 switch (u.format) {
1040 case 1: return_trace (c->dispatch (u.format1));
1041 default:return_trace (c->default_return_value ());
1042 }
1043 }
1044
1045 protected:
1046 union {
1047 USHORT format; /* Format identifier */
1048 ReverseChainSingleSubstFormat1 format1;
1049 } u;
1050 };
1051
1052
1053
1054 /*
1055 * SubstLookup
1056 */
1057
1058 struct SubstLookupSubTable
1059 {
1060 friend struct SubstLookup;
1061
1062 enum Type {
1063 Single = 1,
1064 Multiple = 2,
1065 Alternate = 3,
1066 Ligature = 4,
1067 Context = 5,
1068 ChainContext = 6,
1069 Extension = 7,
1070 ReverseChainSingle = 8
1071 };
1072
1073 template <typename context_t>
dispatchOT::SubstLookupSubTable1074 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1075 {
1076 TRACE_DISPATCH (this, lookup_type);
1077 if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1078 switch (lookup_type) {
1079 case Single: return_trace (u.single.dispatch (c));
1080 case Multiple: return_trace (u.multiple.dispatch (c));
1081 case Alternate: return_trace (u.alternate.dispatch (c));
1082 case Ligature: return_trace (u.ligature.dispatch (c));
1083 case Context: return_trace (u.context.dispatch (c));
1084 case ChainContext: return_trace (u.chainContext.dispatch (c));
1085 case Extension: return_trace (u.extension.dispatch (c));
1086 case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c));
1087 default: return_trace (c->default_return_value ());
1088 }
1089 }
1090
1091 protected:
1092 union {
1093 USHORT sub_format;
1094 SingleSubst single;
1095 MultipleSubst multiple;
1096 AlternateSubst alternate;
1097 LigatureSubst ligature;
1098 ContextSubst context;
1099 ChainContextSubst chainContext;
1100 ExtensionSubst extension;
1101 ReverseChainSingleSubst reverseChainContextSingle;
1102 } u;
1103 public:
1104 DEFINE_SIZE_UNION (2, sub_format);
1105 };
1106
1107
1108 struct SubstLookup : Lookup
1109 {
get_subtableOT::SubstLookup1110 inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1111 { return Lookup::get_subtable<SubstLookupSubTable> (i); }
1112
lookup_type_is_reverseOT::SubstLookup1113 inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1114 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1115
is_reverseOT::SubstLookup1116 inline bool is_reverse (void) const
1117 {
1118 unsigned int type = get_type ();
1119 if (unlikely (type == SubstLookupSubTable::Extension))
1120 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1121 return lookup_type_is_reverse (type);
1122 }
1123
applyOT::SubstLookup1124 inline bool apply (hb_apply_context_t *c) const
1125 {
1126 TRACE_APPLY (this);
1127 return_trace (dispatch (c));
1128 }
1129
closureOT::SubstLookup1130 inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
1131 {
1132 TRACE_CLOSURE (this);
1133 c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
1134 return_trace (dispatch (c));
1135 }
1136
collect_glyphsOT::SubstLookup1137 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1138 {
1139 TRACE_COLLECT_GLYPHS (this);
1140 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
1141 return_trace (dispatch (c));
1142 }
1143
1144 template <typename set_t>
add_coverageOT::SubstLookup1145 inline void add_coverage (set_t *glyphs) const
1146 {
1147 hb_add_coverage_context_t<set_t> c (glyphs);
1148 dispatch (&c);
1149 }
1150
would_applyOT::SubstLookup1151 inline bool would_apply (hb_would_apply_context_t *c,
1152 const hb_ot_layout_lookup_accelerator_t *accel) const
1153 {
1154 TRACE_WOULD_APPLY (this);
1155 if (unlikely (!c->len)) return_trace (false);
1156 if (!accel->may_have (c->glyphs[0])) return_trace (false);
1157 return_trace (dispatch (c));
1158 }
1159
1160 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1161
serialize_subtableOT::SubstLookup1162 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1163 unsigned int i)
1164 { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1165
serialize_singleOT::SubstLookup1166 inline bool serialize_single (hb_serialize_context_t *c,
1167 uint32_t lookup_props,
1168 Supplier<GlyphID> &glyphs,
1169 Supplier<GlyphID> &substitutes,
1170 unsigned int num_glyphs)
1171 {
1172 TRACE_SERIALIZE (this);
1173 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
1174 return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1175 }
1176
serialize_multipleOT::SubstLookup1177 inline bool serialize_multiple (hb_serialize_context_t *c,
1178 uint32_t lookup_props,
1179 Supplier<GlyphID> &glyphs,
1180 Supplier<unsigned int> &substitute_len_list,
1181 unsigned int num_glyphs,
1182 Supplier<GlyphID> &substitute_glyphs_list)
1183 {
1184 TRACE_SERIALIZE (this);
1185 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
1186 return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
1187 glyphs,
1188 substitute_len_list,
1189 num_glyphs,
1190 substitute_glyphs_list));
1191 }
1192
serialize_alternateOT::SubstLookup1193 inline bool serialize_alternate (hb_serialize_context_t *c,
1194 uint32_t lookup_props,
1195 Supplier<GlyphID> &glyphs,
1196 Supplier<unsigned int> &alternate_len_list,
1197 unsigned int num_glyphs,
1198 Supplier<GlyphID> &alternate_glyphs_list)
1199 {
1200 TRACE_SERIALIZE (this);
1201 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
1202 return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
1203 glyphs,
1204 alternate_len_list,
1205 num_glyphs,
1206 alternate_glyphs_list));
1207 }
1208
serialize_ligatureOT::SubstLookup1209 inline bool serialize_ligature (hb_serialize_context_t *c,
1210 uint32_t lookup_props,
1211 Supplier<GlyphID> &first_glyphs,
1212 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1213 unsigned int num_first_glyphs,
1214 Supplier<GlyphID> &ligatures_list,
1215 Supplier<unsigned int> &component_count_list,
1216 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1217 {
1218 TRACE_SERIALIZE (this);
1219 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
1220 return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
1221 first_glyphs,
1222 ligature_per_first_glyph_count_list,
1223 num_first_glyphs,
1224 ligatures_list,
1225 component_count_list,
1226 component_list));
1227 }
1228
1229 template <typename context_t>
1230 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1231
1232 template <typename context_t>
dispatchOT::SubstLookup1233 inline typename context_t::return_t dispatch (context_t *c) const
1234 { return Lookup::dispatch<SubstLookupSubTable> (c); }
1235
sanitizeOT::SubstLookup1236 inline bool sanitize (hb_sanitize_context_t *c) const
1237 {
1238 TRACE_SANITIZE (this);
1239 if (unlikely (!Lookup::sanitize (c))) return_trace (false);
1240 if (unlikely (!dispatch (c))) return_trace (false);
1241
1242 if (unlikely (get_type () == SubstLookupSubTable::Extension))
1243 {
1244 /* The spec says all subtables of an Extension lookup should
1245 * have the same type. This is specially important if one has
1246 * a reverse type! */
1247 unsigned int type = get_subtable (0).u.extension.get_type ();
1248 unsigned int count = get_subtable_count ();
1249 for (unsigned int i = 1; i < count; i++)
1250 if (get_subtable (i).u.extension.get_type () != type)
1251 return_trace (false);
1252 }
1253 return_trace (true);
1254 }
1255 };
1256
1257 typedef OffsetListOf<SubstLookup> SubstLookupList;
1258
1259 /*
1260 * GSUB -- The Glyph Substitution Table
1261 */
1262
1263 struct GSUB : GSUBGPOS
1264 {
1265 static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
1266
get_lookupOT::GSUB1267 inline const SubstLookup& get_lookup (unsigned int i) const
1268 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1269
1270 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1271
sanitizeOT::GSUB1272 inline bool sanitize (hb_sanitize_context_t *c) const
1273 {
1274 TRACE_SANITIZE (this);
1275 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
1276 const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1277 return_trace (list.sanitize (c, this));
1278 }
1279 public:
1280 DEFINE_SIZE_STATIC (10);
1281 };
1282
1283
1284 void
substitute_start(hb_font_t * font,hb_buffer_t * buffer)1285 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1286 {
1287 _hb_buffer_assert_gsubgpos_vars (buffer);
1288
1289 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1290 unsigned int count = buffer->len;
1291 hb_glyph_info_t *info = buffer->info;
1292 for (unsigned int i = 0; i < count; i++)
1293 {
1294 unsigned int props = gdef.get_glyph_props (info[i].codepoint);
1295 if (!props)
1296 {
1297 /* Never mark default-ignorables as marks.
1298 * They won't get in the way of lookups anyway,
1299 * but having them as mark will cause them to be skipped
1300 * over if the lookup-flag says so, but at least for the
1301 * Mongolian variation selectors, looks like Uniscribe
1302 * marks them as non-mark. Some Mongolian fonts without
1303 * GDEF rely on this. Another notable character that
1304 * this applies to is COMBINING GRAPHEME JOINER. */
1305 props = (_hb_glyph_info_get_general_category (&info[i]) !=
1306 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
1307 _hb_glyph_info_is_default_ignorable (&info[i])) ?
1308 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
1309 HB_OT_LAYOUT_GLYPH_PROPS_MARK;
1310 }
1311 _hb_glyph_info_set_glyph_props (&info[i], props);
1312 _hb_glyph_info_clear_lig_props (&info[i]);
1313 buffer->info[i].syllable() = 0;
1314 }
1315 }
1316
1317
1318 /* Out-of-class implementation for methods recursing */
1319
is_reverse(void) const1320 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
1321 {
1322 unsigned int type = get_type ();
1323 if (unlikely (type == SubstLookupSubTable::Extension))
1324 return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
1325 return SubstLookup::lookup_type_is_reverse (type);
1326 }
1327
1328 template <typename context_t>
dispatch_recurse_func(context_t * c,unsigned int lookup_index)1329 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1330 {
1331 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1332 const SubstLookup &l = gsub.get_lookup (lookup_index);
1333 return l.dispatch (c);
1334 }
1335
apply_recurse_func(hb_apply_context_t * c,unsigned int lookup_index)1336 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1337 {
1338 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1339 const SubstLookup &l = gsub.get_lookup (lookup_index);
1340 unsigned int saved_lookup_props = c->lookup_props;
1341 unsigned int saved_lookup_index = c->lookup_index;
1342 c->set_lookup_index (lookup_index);
1343 c->set_lookup_props (l.get_props ());
1344 bool ret = l.dispatch (c);
1345 c->set_lookup_index (saved_lookup_index);
1346 c->set_lookup_props (saved_lookup_props);
1347 return ret;
1348 }
1349
1350
1351 } /* namespace OT */
1352
1353
1354 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
1355