Add git cl format presubmit warning for extension and apps.
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-ot-layout.cc
blob183726e63cf47e44a4626d9f5d5cdc7e447c347c
1 /*
2 * Copyright © 1998-2004 David Turner and Werner Lemberg
3 * Copyright © 2006 Behdad Esfahbod
4 * Copyright © 2007,2008,2009 Red Hat, Inc.
5 * Copyright © 2012,2013 Google, Inc.
7 * This is part of HarfBuzz, a text shaping library.
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and its documentation for any purpose, provided that the
12 * above copyright notice and the following two paragraphs appear in
13 * all copies of this software.
15 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
16 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
17 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
18 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * DAMAGE.
21 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
22 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
23 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
24 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
25 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27 * Red Hat Author(s): Behdad Esfahbod
28 * Google Author(s): Behdad Esfahbod
31 #include "hb-ot-layout-private.hh"
33 #include "hb-ot-layout-gdef-table.hh"
34 #include "hb-ot-layout-gsub-table.hh"
35 #include "hb-ot-layout-gpos-table.hh"
36 #include "hb-ot-layout-jstf-table.hh"
38 #include "hb-ot-map-private.hh"
40 #include <stdlib.h>
41 #include <string.h>
44 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
46 hb_ot_layout_t *
47 _hb_ot_layout_create (hb_face_t *face)
49 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
50 if (unlikely (!layout))
51 return NULL;
53 layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
54 layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
56 layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
57 layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
59 layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
60 layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
62 layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
63 layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
65 layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
66 layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
68 if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
69 (layout->gpos_lookup_count && !layout->gpos_accels)))
71 _hb_ot_layout_destroy (layout);
72 return NULL;
75 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
76 layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
77 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
78 layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
80 return layout;
83 void
84 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
86 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
87 layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
88 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
89 layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));
91 free (layout->gsub_accels);
92 free (layout->gpos_accels);
94 hb_blob_destroy (layout->gdef_blob);
95 hb_blob_destroy (layout->gsub_blob);
96 hb_blob_destroy (layout->gpos_blob);
98 free (layout);
101 static inline const OT::GDEF&
102 _get_gdef (hb_face_t *face)
104 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
105 return *hb_ot_layout_from_face (face)->gdef;
107 static inline const OT::GSUB&
108 _get_gsub (hb_face_t *face)
110 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
111 return *hb_ot_layout_from_face (face)->gsub;
113 static inline const OT::GPOS&
114 _get_gpos (hb_face_t *face)
116 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
117 return *hb_ot_layout_from_face (face)->gpos;
122 * GDEF
125 hb_bool_t
126 hb_ot_layout_has_glyph_classes (hb_face_t *face)
128 return _get_gdef (face).has_glyph_classes ();
131 hb_ot_layout_glyph_class_t
132 hb_ot_layout_get_glyph_class (hb_face_t *face,
133 hb_codepoint_t glyph)
135 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
138 void
139 hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
140 hb_ot_layout_glyph_class_t klass,
141 hb_set_t *glyphs /* OUT */)
143 return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
146 unsigned int
147 hb_ot_layout_get_attach_points (hb_face_t *face,
148 hb_codepoint_t glyph,
149 unsigned int start_offset,
150 unsigned int *point_count /* IN/OUT */,
151 unsigned int *point_array /* OUT */)
153 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
156 unsigned int
157 hb_ot_layout_get_ligature_carets (hb_font_t *font,
158 hb_direction_t direction,
159 hb_codepoint_t glyph,
160 unsigned int start_offset,
161 unsigned int *caret_count /* IN/OUT */,
162 int *caret_array /* OUT */)
164 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
169 * GSUB/GPOS
172 static const OT::GSUBGPOS&
173 get_gsubgpos_table (hb_face_t *face,
174 hb_tag_t table_tag)
176 switch (table_tag) {
177 case HB_OT_TAG_GSUB: return _get_gsub (face);
178 case HB_OT_TAG_GPOS: return _get_gpos (face);
179 default: return OT::Null(OT::GSUBGPOS);
184 unsigned int
185 hb_ot_layout_table_get_script_tags (hb_face_t *face,
186 hb_tag_t table_tag,
187 unsigned int start_offset,
188 unsigned int *script_count /* IN/OUT */,
189 hb_tag_t *script_tags /* OUT */)
191 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
193 return g.get_script_tags (start_offset, script_count, script_tags);
196 #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
198 hb_bool_t
199 hb_ot_layout_table_find_script (hb_face_t *face,
200 hb_tag_t table_tag,
201 hb_tag_t script_tag,
202 unsigned int *script_index)
204 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
205 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
207 if (g.find_script_index (script_tag, script_index))
208 return true;
210 /* try finding 'DFLT' */
211 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
212 return false;
214 /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
215 * including many versions of DejaVu Sans Mono! */
216 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
217 return false;
219 /* try with 'latn'; some old fonts put their features there even though
220 they're really trying to support Thai, for example :( */
221 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
222 return false;
224 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
225 return false;
228 hb_bool_t
229 hb_ot_layout_table_choose_script (hb_face_t *face,
230 hb_tag_t table_tag,
231 const hb_tag_t *script_tags,
232 unsigned int *script_index,
233 hb_tag_t *chosen_script)
235 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
236 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
238 while (*script_tags)
240 if (g.find_script_index (*script_tags, script_index)) {
241 if (chosen_script)
242 *chosen_script = *script_tags;
243 return true;
245 script_tags++;
248 /* try finding 'DFLT' */
249 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
250 if (chosen_script)
251 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
252 return false;
255 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
256 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
257 if (chosen_script)
258 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
259 return false;
262 /* try with 'latn'; some old fonts put their features there even though
263 they're really trying to support Thai, for example :( */
264 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
265 if (chosen_script)
266 *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
267 return false;
270 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
271 if (chosen_script)
272 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
273 return false;
276 unsigned int
277 hb_ot_layout_table_get_feature_tags (hb_face_t *face,
278 hb_tag_t table_tag,
279 unsigned int start_offset,
280 unsigned int *feature_count /* IN/OUT */,
281 hb_tag_t *feature_tags /* OUT */)
283 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
285 return g.get_feature_tags (start_offset, feature_count, feature_tags);
289 unsigned int
290 hb_ot_layout_script_get_language_tags (hb_face_t *face,
291 hb_tag_t table_tag,
292 unsigned int script_index,
293 unsigned int start_offset,
294 unsigned int *language_count /* IN/OUT */,
295 hb_tag_t *language_tags /* OUT */)
297 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
299 return s.get_lang_sys_tags (start_offset, language_count, language_tags);
302 hb_bool_t
303 hb_ot_layout_script_find_language (hb_face_t *face,
304 hb_tag_t table_tag,
305 unsigned int script_index,
306 hb_tag_t language_tag,
307 unsigned int *language_index)
309 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
310 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
312 if (s.find_lang_sys_index (language_tag, language_index))
313 return true;
315 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
316 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
317 return false;
319 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
320 return false;
323 hb_bool_t
324 hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
325 hb_tag_t table_tag,
326 unsigned int script_index,
327 unsigned int language_index,
328 unsigned int *feature_index)
330 const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
332 if (feature_index) *feature_index = l.get_required_feature_index ();
334 return l.has_required_feature ();
337 unsigned int
338 hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
339 hb_tag_t table_tag,
340 unsigned int script_index,
341 unsigned int language_index,
342 unsigned int start_offset,
343 unsigned int *feature_count /* IN/OUT */,
344 unsigned int *feature_indexes /* OUT */)
346 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
347 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
349 return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
352 unsigned int
353 hb_ot_layout_language_get_feature_tags (hb_face_t *face,
354 hb_tag_t table_tag,
355 unsigned int script_index,
356 unsigned int language_index,
357 unsigned int start_offset,
358 unsigned int *feature_count /* IN/OUT */,
359 hb_tag_t *feature_tags /* OUT */)
361 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
362 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
364 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
365 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
367 if (feature_tags) {
368 unsigned int count = *feature_count;
369 for (unsigned int i = 0; i < count; i++)
370 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
373 return ret;
377 hb_bool_t
378 hb_ot_layout_language_find_feature (hb_face_t *face,
379 hb_tag_t table_tag,
380 unsigned int script_index,
381 unsigned int language_index,
382 hb_tag_t feature_tag,
383 unsigned int *feature_index)
385 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
386 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
387 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
389 unsigned int num_features = l.get_feature_count ();
390 for (unsigned int i = 0; i < num_features; i++) {
391 unsigned int f_index = l.get_feature_index (i);
393 if (feature_tag == g.get_feature_tag (f_index)) {
394 if (feature_index) *feature_index = f_index;
395 return true;
399 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
400 return false;
403 unsigned int
404 hb_ot_layout_feature_get_lookups (hb_face_t *face,
405 hb_tag_t table_tag,
406 unsigned int feature_index,
407 unsigned int start_offset,
408 unsigned int *lookup_count /* IN/OUT */,
409 unsigned int *lookup_indexes /* OUT */)
411 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
412 const OT::Feature &f = g.get_feature (feature_index);
414 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
417 unsigned int
418 hb_ot_layout_table_get_lookup_count (hb_face_t *face,
419 hb_tag_t table_tag)
421 switch (table_tag)
423 case HB_OT_TAG_GSUB:
425 return hb_ot_layout_from_face (face)->gsub_lookup_count;
427 case HB_OT_TAG_GPOS:
429 return hb_ot_layout_from_face (face)->gpos_lookup_count;
432 return 0;
435 static void
436 _hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
437 hb_tag_t table_tag,
438 unsigned int feature_index,
439 hb_set_t *lookup_indexes /* OUT */)
441 unsigned int lookup_indices[32];
442 unsigned int offset, len;
444 offset = 0;
445 do {
446 len = ARRAY_LENGTH (lookup_indices);
447 hb_ot_layout_feature_get_lookups (face,
448 table_tag,
449 feature_index,
450 offset, &len,
451 lookup_indices);
453 for (unsigned int i = 0; i < len; i++)
454 lookup_indexes->add (lookup_indices[i]);
456 offset += len;
457 } while (len == ARRAY_LENGTH (lookup_indices));
460 static void
461 _hb_ot_layout_collect_lookups_features (hb_face_t *face,
462 hb_tag_t table_tag,
463 unsigned int script_index,
464 unsigned int language_index,
465 const hb_tag_t *features,
466 hb_set_t *lookup_indexes /* OUT */)
468 if (!features)
470 unsigned int required_feature_index;
471 if (hb_ot_layout_language_get_required_feature_index (face,
472 table_tag,
473 script_index,
474 language_index,
475 &required_feature_index))
476 _hb_ot_layout_collect_lookups_lookups (face,
477 table_tag,
478 required_feature_index,
479 lookup_indexes);
481 /* All features */
482 unsigned int feature_indices[32];
483 unsigned int offset, len;
485 offset = 0;
486 do {
487 len = ARRAY_LENGTH (feature_indices);
488 hb_ot_layout_language_get_feature_indexes (face,
489 table_tag,
490 script_index,
491 language_index,
492 offset, &len,
493 feature_indices);
495 for (unsigned int i = 0; i < len; i++)
496 _hb_ot_layout_collect_lookups_lookups (face,
497 table_tag,
498 feature_indices[i],
499 lookup_indexes);
501 offset += len;
502 } while (len == ARRAY_LENGTH (feature_indices));
504 else
506 for (; *features; features++)
508 unsigned int feature_index;
509 if (hb_ot_layout_language_find_feature (face,
510 table_tag,
511 script_index,
512 language_index,
513 *features,
514 &feature_index))
515 _hb_ot_layout_collect_lookups_lookups (face,
516 table_tag,
517 feature_index,
518 lookup_indexes);
523 static void
524 _hb_ot_layout_collect_lookups_languages (hb_face_t *face,
525 hb_tag_t table_tag,
526 unsigned int script_index,
527 const hb_tag_t *languages,
528 const hb_tag_t *features,
529 hb_set_t *lookup_indexes /* OUT */)
531 _hb_ot_layout_collect_lookups_features (face,
532 table_tag,
533 script_index,
534 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
535 features,
536 lookup_indexes);
538 if (!languages)
540 /* All languages */
541 unsigned int count = hb_ot_layout_script_get_language_tags (face,
542 table_tag,
543 script_index,
544 0, NULL, NULL);
545 for (unsigned int language_index = 0; language_index < count; language_index++)
546 _hb_ot_layout_collect_lookups_features (face,
547 table_tag,
548 script_index,
549 language_index,
550 features,
551 lookup_indexes);
553 else
555 for (; *languages; languages++)
557 unsigned int language_index;
558 if (hb_ot_layout_script_find_language (face,
559 table_tag,
560 script_index,
561 *languages,
562 &language_index))
563 _hb_ot_layout_collect_lookups_features (face,
564 table_tag,
565 script_index,
566 language_index,
567 features,
568 lookup_indexes);
573 void
574 hb_ot_layout_collect_lookups (hb_face_t *face,
575 hb_tag_t table_tag,
576 const hb_tag_t *scripts,
577 const hb_tag_t *languages,
578 const hb_tag_t *features,
579 hb_set_t *lookup_indexes /* OUT */)
581 if (!scripts)
583 /* All scripts */
584 unsigned int count = hb_ot_layout_table_get_script_tags (face,
585 table_tag,
586 0, NULL, NULL);
587 for (unsigned int script_index = 0; script_index < count; script_index++)
588 _hb_ot_layout_collect_lookups_languages (face,
589 table_tag,
590 script_index,
591 languages,
592 features,
593 lookup_indexes);
595 else
597 for (; *scripts; scripts++)
599 unsigned int script_index;
600 if (hb_ot_layout_table_find_script (face,
601 table_tag,
602 *scripts,
603 &script_index))
604 _hb_ot_layout_collect_lookups_languages (face,
605 table_tag,
606 script_index,
607 languages,
608 features,
609 lookup_indexes);
614 void
615 hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
616 hb_tag_t table_tag,
617 unsigned int lookup_index,
618 hb_set_t *glyphs_before, /* OUT. May be NULL */
619 hb_set_t *glyphs_input, /* OUT. May be NULL */
620 hb_set_t *glyphs_after, /* OUT. May be NULL */
621 hb_set_t *glyphs_output /* OUT. May be NULL */)
623 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
625 OT::hb_collect_glyphs_context_t c (face,
626 glyphs_before,
627 glyphs_input,
628 glyphs_after,
629 glyphs_output);
631 switch (table_tag)
633 case HB_OT_TAG_GSUB:
635 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
636 l.collect_glyphs (&c);
637 return;
639 case HB_OT_TAG_GPOS:
641 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
642 l.collect_glyphs (&c);
643 return;
650 * OT::GSUB
653 hb_bool_t
654 hb_ot_layout_has_substitution (hb_face_t *face)
656 return &_get_gsub (face) != &OT::Null(OT::GSUB);
659 hb_bool_t
660 hb_ot_layout_lookup_would_substitute (hb_face_t *face,
661 unsigned int lookup_index,
662 const hb_codepoint_t *glyphs,
663 unsigned int glyphs_length,
664 hb_bool_t zero_context)
666 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
667 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
670 hb_bool_t
671 hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
672 unsigned int lookup_index,
673 const hb_codepoint_t *glyphs,
674 unsigned int glyphs_length,
675 hb_bool_t zero_context)
677 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
678 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
680 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
682 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
685 void
686 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
688 OT::GSUB::substitute_start (font, buffer);
691 void
692 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
694 OT::GSUB::substitute_finish (font, buffer);
697 void
698 hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
699 unsigned int lookup_index,
700 hb_set_t *glyphs)
702 OT::hb_closure_context_t c (face, glyphs);
704 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
706 l.closure (&c);
710 * OT::GPOS
713 hb_bool_t
714 hb_ot_layout_has_positioning (hb_face_t *face)
716 return &_get_gpos (face) != &OT::Null(OT::GPOS);
719 void
720 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
722 OT::GPOS::position_start (font, buffer);
725 void
726 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
728 OT::GPOS::position_finish (font, buffer);
731 hb_bool_t
732 hb_ot_layout_get_size_params (hb_face_t *face,
733 unsigned int *design_size, /* OUT. May be NULL */
734 unsigned int *subfamily_id, /* OUT. May be NULL */
735 unsigned int *subfamily_name_id, /* OUT. May be NULL */
736 unsigned int *range_start, /* OUT. May be NULL */
737 unsigned int *range_end /* OUT. May be NULL */)
739 const OT::GPOS &gpos = _get_gpos (face);
740 const hb_tag_t tag = HB_TAG ('s','i','z','e');
742 unsigned int num_features = gpos.get_feature_count ();
743 for (unsigned int i = 0; i < num_features; i++)
745 if (tag == gpos.get_feature_tag (i))
747 const OT::Feature &f = gpos.get_feature (i);
748 const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
750 if (params.designSize)
752 #define PARAM(a, A) if (a) *a = params.A
753 PARAM (design_size, designSize);
754 PARAM (subfamily_id, subfamilyID);
755 PARAM (subfamily_name_id, subfamilyNameID);
756 PARAM (range_start, rangeStart);
757 PARAM (range_end, rangeEnd);
758 #undef PARAM
760 return true;
765 #define PARAM(a, A) if (a) *a = 0
766 PARAM (design_size, designSize);
767 PARAM (subfamily_id, subfamilyID);
768 PARAM (subfamily_name_id, subfamilyNameID);
769 PARAM (range_start, rangeStart);
770 PARAM (range_end, rangeEnd);
771 #undef PARAM
773 return false;
778 * Parts of different types are implemented here such that they have direct
779 * access to GSUB/GPOS lookups.
783 struct GSUBProxy
785 static const unsigned int table_index = 0;
786 static const bool inplace = false;
787 typedef OT::SubstLookup Lookup;
789 GSUBProxy (hb_face_t *face) :
790 table (*hb_ot_layout_from_face (face)->gsub),
791 accels (hb_ot_layout_from_face (face)->gsub_accels) {}
793 const OT::GSUB &table;
794 const hb_ot_layout_lookup_accelerator_t *accels;
797 struct GPOSProxy
799 static const unsigned int table_index = 1;
800 static const bool inplace = true;
801 typedef OT::PosLookup Lookup;
803 GPOSProxy (hb_face_t *face) :
804 table (*hb_ot_layout_from_face (face)->gpos),
805 accels (hb_ot_layout_from_face (face)->gpos_accels) {}
807 const OT::GPOS &table;
808 const hb_ot_layout_lookup_accelerator_t *accels;
812 template <typename Lookup>
813 static inline bool apply_once (OT::hb_apply_context_t *c,
814 const Lookup &lookup)
816 if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
817 return false;
818 return lookup.dispatch (c);
821 template <typename Proxy>
822 static inline bool
823 apply_string (OT::hb_apply_context_t *c,
824 const typename Proxy::Lookup &lookup,
825 const hb_ot_layout_lookup_accelerator_t &accel)
827 bool ret = false;
828 hb_buffer_t *buffer = c->buffer;
830 if (unlikely (!buffer->len || !c->lookup_mask))
831 return false;
833 c->set_lookup (lookup);
835 if (likely (!lookup.is_reverse ()))
837 /* in/out forward substitution/positioning */
838 if (Proxy::table_index == 0)
839 buffer->clear_output ();
840 buffer->idx = 0;
842 while (buffer->idx < buffer->len)
844 if (accel.digest.may_have (buffer->cur().codepoint) &&
845 (buffer->cur().mask & c->lookup_mask) &&
846 apply_once (c, lookup))
847 ret = true;
848 else
849 buffer->next_glyph ();
851 if (ret)
853 if (!Proxy::inplace)
854 buffer->swap_buffers ();
855 else
856 assert (!buffer->has_separate_output ());
859 else
861 /* in-place backward substitution/positioning */
862 if (Proxy::table_index == 0)
863 buffer->remove_output ();
864 buffer->idx = buffer->len - 1;
867 if (accel.digest.may_have (buffer->cur().codepoint) &&
868 (buffer->cur().mask & c->lookup_mask) &&
869 apply_once (c, lookup))
870 ret = true;
871 /* The reverse lookup doesn't "advance" cursor (for good reason). */
872 buffer->idx--;
875 while ((int) buffer->idx >= 0);
878 return ret;
881 template <typename Proxy>
882 inline void hb_ot_map_t::apply (const Proxy &proxy,
883 const hb_ot_shape_plan_t *plan,
884 hb_font_t *font,
885 hb_buffer_t *buffer) const
887 const unsigned int table_index = proxy.table_index;
888 unsigned int i = 0;
889 OT::hb_apply_context_t c (table_index, font, buffer);
890 c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
892 for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
893 const stage_map_t *stage = &stages[table_index][stage_index];
894 for (; i < stage->last_lookup; i++)
896 unsigned int lookup_index = lookups[table_index][i].index;
897 c.set_lookup_mask (lookups[table_index][i].mask);
898 c.set_auto_zwj (lookups[table_index][i].auto_zwj);
899 apply_string<Proxy> (&c,
900 proxy.table.get_lookup (lookup_index),
901 proxy.accels[lookup_index]);
904 if (stage->pause_func)
906 buffer->clear_output ();
907 stage->pause_func (plan, font, buffer);
912 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
914 GSUBProxy proxy (font->face);
915 apply (proxy, plan, font, buffer);
918 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
920 GPOSProxy proxy (font->face);
921 apply (proxy, plan, font, buffer);
924 HB_INTERNAL void
925 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
926 const OT::SubstLookup &lookup,
927 const hb_ot_layout_lookup_accelerator_t &accel)
929 apply_string<GSUBProxy> (c, lookup, accel);