Restore variadic macros in DevToolsEmbedderMessageDispatcher
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-ot-layout.cc
blob39d007d676415a2facc8ea2378f8388be9a059f3
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 ();
88 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
89 layout->gpos_accels[i].fini ();
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 ();
132 * Since: 0.9.7
134 hb_ot_layout_glyph_class_t
135 hb_ot_layout_get_glyph_class (hb_face_t *face,
136 hb_codepoint_t glyph)
138 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
142 * Since: 0.9.7
144 void
145 hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
146 hb_ot_layout_glyph_class_t klass,
147 hb_set_t *glyphs /* OUT */)
149 return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
152 unsigned int
153 hb_ot_layout_get_attach_points (hb_face_t *face,
154 hb_codepoint_t glyph,
155 unsigned int start_offset,
156 unsigned int *point_count /* IN/OUT */,
157 unsigned int *point_array /* OUT */)
159 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
162 unsigned int
163 hb_ot_layout_get_ligature_carets (hb_font_t *font,
164 hb_direction_t direction,
165 hb_codepoint_t glyph,
166 unsigned int start_offset,
167 unsigned int *caret_count /* IN/OUT */,
168 int *caret_array /* OUT */)
170 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
175 * GSUB/GPOS
178 static const OT::GSUBGPOS&
179 get_gsubgpos_table (hb_face_t *face,
180 hb_tag_t table_tag)
182 switch (table_tag) {
183 case HB_OT_TAG_GSUB: return _get_gsub (face);
184 case HB_OT_TAG_GPOS: return _get_gpos (face);
185 default: return OT::Null(OT::GSUBGPOS);
190 unsigned int
191 hb_ot_layout_table_get_script_tags (hb_face_t *face,
192 hb_tag_t table_tag,
193 unsigned int start_offset,
194 unsigned int *script_count /* IN/OUT */,
195 hb_tag_t *script_tags /* OUT */)
197 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
199 return g.get_script_tags (start_offset, script_count, script_tags);
202 #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
204 hb_bool_t
205 hb_ot_layout_table_find_script (hb_face_t *face,
206 hb_tag_t table_tag,
207 hb_tag_t script_tag,
208 unsigned int *script_index)
210 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
211 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
213 if (g.find_script_index (script_tag, script_index))
214 return true;
216 /* try finding 'DFLT' */
217 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
218 return false;
220 /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
221 * including many versions of DejaVu Sans Mono! */
222 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
223 return false;
225 /* try with 'latn'; some old fonts put their features there even though
226 they're really trying to support Thai, for example :( */
227 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
228 return false;
230 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
231 return false;
234 hb_bool_t
235 hb_ot_layout_table_choose_script (hb_face_t *face,
236 hb_tag_t table_tag,
237 const hb_tag_t *script_tags,
238 unsigned int *script_index,
239 hb_tag_t *chosen_script)
241 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
242 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
244 while (*script_tags)
246 if (g.find_script_index (*script_tags, script_index)) {
247 if (chosen_script)
248 *chosen_script = *script_tags;
249 return true;
251 script_tags++;
254 /* try finding 'DFLT' */
255 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
256 if (chosen_script)
257 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
258 return false;
261 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
262 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
263 if (chosen_script)
264 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
265 return false;
268 /* try with 'latn'; some old fonts put their features there even though
269 they're really trying to support Thai, for example :( */
270 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
271 if (chosen_script)
272 *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
273 return false;
276 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
277 if (chosen_script)
278 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
279 return false;
282 unsigned int
283 hb_ot_layout_table_get_feature_tags (hb_face_t *face,
284 hb_tag_t table_tag,
285 unsigned int start_offset,
286 unsigned int *feature_count /* IN/OUT */,
287 hb_tag_t *feature_tags /* OUT */)
289 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
291 return g.get_feature_tags (start_offset, feature_count, feature_tags);
294 hb_bool_t
295 hb_ot_layout_table_find_feature (hb_face_t *face,
296 hb_tag_t table_tag,
297 hb_tag_t feature_tag,
298 unsigned int *feature_index)
300 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
301 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
303 unsigned int num_features = g.get_feature_count ();
304 for (unsigned int i = 0; i < num_features; i++)
306 if (feature_tag == g.get_feature_tag (i)) {
307 if (feature_index) *feature_index = i;
308 return true;
312 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
313 return false;
317 unsigned int
318 hb_ot_layout_script_get_language_tags (hb_face_t *face,
319 hb_tag_t table_tag,
320 unsigned int script_index,
321 unsigned int start_offset,
322 unsigned int *language_count /* IN/OUT */,
323 hb_tag_t *language_tags /* OUT */)
325 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
327 return s.get_lang_sys_tags (start_offset, language_count, language_tags);
330 hb_bool_t
331 hb_ot_layout_script_find_language (hb_face_t *face,
332 hb_tag_t table_tag,
333 unsigned int script_index,
334 hb_tag_t language_tag,
335 unsigned int *language_index)
337 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
338 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
340 if (s.find_lang_sys_index (language_tag, language_index))
341 return true;
343 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
344 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
345 return false;
347 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
348 return false;
351 hb_bool_t
352 hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
353 hb_tag_t table_tag,
354 unsigned int script_index,
355 unsigned int language_index,
356 unsigned int *feature_index)
358 return hb_ot_layout_language_get_required_feature (face,
359 table_tag,
360 script_index,
361 language_index,
362 feature_index,
363 NULL);
367 * Since: 0.9.30
369 hb_bool_t
370 hb_ot_layout_language_get_required_feature (hb_face_t *face,
371 hb_tag_t table_tag,
372 unsigned int script_index,
373 unsigned int language_index,
374 unsigned int *feature_index,
375 hb_tag_t *feature_tag)
377 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
378 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
380 unsigned int index = l.get_required_feature_index ();
381 if (feature_index) *feature_index = index;
382 if (feature_tag) *feature_tag = g.get_feature_tag (index);
384 return l.has_required_feature ();
387 unsigned int
388 hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
389 hb_tag_t table_tag,
390 unsigned int script_index,
391 unsigned int language_index,
392 unsigned int start_offset,
393 unsigned int *feature_count /* IN/OUT */,
394 unsigned int *feature_indexes /* OUT */)
396 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
397 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
399 return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
402 unsigned int
403 hb_ot_layout_language_get_feature_tags (hb_face_t *face,
404 hb_tag_t table_tag,
405 unsigned int script_index,
406 unsigned int language_index,
407 unsigned int start_offset,
408 unsigned int *feature_count /* IN/OUT */,
409 hb_tag_t *feature_tags /* OUT */)
411 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
412 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
414 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
415 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
417 if (feature_tags) {
418 unsigned int count = *feature_count;
419 for (unsigned int i = 0; i < count; i++)
420 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
423 return ret;
427 hb_bool_t
428 hb_ot_layout_language_find_feature (hb_face_t *face,
429 hb_tag_t table_tag,
430 unsigned int script_index,
431 unsigned int language_index,
432 hb_tag_t feature_tag,
433 unsigned int *feature_index)
435 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
436 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
437 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
439 unsigned int num_features = l.get_feature_count ();
440 for (unsigned int i = 0; i < num_features; i++) {
441 unsigned int f_index = l.get_feature_index (i);
443 if (feature_tag == g.get_feature_tag (f_index)) {
444 if (feature_index) *feature_index = f_index;
445 return true;
449 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
450 return false;
454 * Since: 0.9.7
456 unsigned int
457 hb_ot_layout_feature_get_lookups (hb_face_t *face,
458 hb_tag_t table_tag,
459 unsigned int feature_index,
460 unsigned int start_offset,
461 unsigned int *lookup_count /* IN/OUT */,
462 unsigned int *lookup_indexes /* OUT */)
464 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
465 const OT::Feature &f = g.get_feature (feature_index);
467 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
471 * Since: 0.9.22
473 unsigned int
474 hb_ot_layout_table_get_lookup_count (hb_face_t *face,
475 hb_tag_t table_tag)
477 switch (table_tag)
479 case HB_OT_TAG_GSUB:
481 return hb_ot_layout_from_face (face)->gsub_lookup_count;
483 case HB_OT_TAG_GPOS:
485 return hb_ot_layout_from_face (face)->gpos_lookup_count;
488 return 0;
491 static void
492 _hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
493 hb_tag_t table_tag,
494 unsigned int feature_index,
495 hb_set_t *lookup_indexes /* OUT */)
497 unsigned int lookup_indices[32];
498 unsigned int offset, len;
500 offset = 0;
501 do {
502 len = ARRAY_LENGTH (lookup_indices);
503 hb_ot_layout_feature_get_lookups (face,
504 table_tag,
505 feature_index,
506 offset, &len,
507 lookup_indices);
509 for (unsigned int i = 0; i < len; i++)
510 lookup_indexes->add (lookup_indices[i]);
512 offset += len;
513 } while (len == ARRAY_LENGTH (lookup_indices));
516 static void
517 _hb_ot_layout_collect_lookups_features (hb_face_t *face,
518 hb_tag_t table_tag,
519 unsigned int script_index,
520 unsigned int language_index,
521 const hb_tag_t *features,
522 hb_set_t *lookup_indexes /* OUT */)
524 if (!features)
526 unsigned int required_feature_index;
527 if (hb_ot_layout_language_get_required_feature (face,
528 table_tag,
529 script_index,
530 language_index,
531 &required_feature_index,
532 NULL))
533 _hb_ot_layout_collect_lookups_lookups (face,
534 table_tag,
535 required_feature_index,
536 lookup_indexes);
538 /* All features */
539 unsigned int feature_indices[32];
540 unsigned int offset, len;
542 offset = 0;
543 do {
544 len = ARRAY_LENGTH (feature_indices);
545 hb_ot_layout_language_get_feature_indexes (face,
546 table_tag,
547 script_index,
548 language_index,
549 offset, &len,
550 feature_indices);
552 for (unsigned int i = 0; i < len; i++)
553 _hb_ot_layout_collect_lookups_lookups (face,
554 table_tag,
555 feature_indices[i],
556 lookup_indexes);
558 offset += len;
559 } while (len == ARRAY_LENGTH (feature_indices));
561 else
563 for (; *features; features++)
565 unsigned int feature_index;
566 if (hb_ot_layout_language_find_feature (face,
567 table_tag,
568 script_index,
569 language_index,
570 *features,
571 &feature_index))
572 _hb_ot_layout_collect_lookups_lookups (face,
573 table_tag,
574 feature_index,
575 lookup_indexes);
580 static void
581 _hb_ot_layout_collect_lookups_languages (hb_face_t *face,
582 hb_tag_t table_tag,
583 unsigned int script_index,
584 const hb_tag_t *languages,
585 const hb_tag_t *features,
586 hb_set_t *lookup_indexes /* OUT */)
588 _hb_ot_layout_collect_lookups_features (face,
589 table_tag,
590 script_index,
591 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
592 features,
593 lookup_indexes);
595 if (!languages)
597 /* All languages */
598 unsigned int count = hb_ot_layout_script_get_language_tags (face,
599 table_tag,
600 script_index,
601 0, NULL, NULL);
602 for (unsigned int language_index = 0; language_index < count; language_index++)
603 _hb_ot_layout_collect_lookups_features (face,
604 table_tag,
605 script_index,
606 language_index,
607 features,
608 lookup_indexes);
610 else
612 for (; *languages; languages++)
614 unsigned int language_index;
615 if (hb_ot_layout_script_find_language (face,
616 table_tag,
617 script_index,
618 *languages,
619 &language_index))
620 _hb_ot_layout_collect_lookups_features (face,
621 table_tag,
622 script_index,
623 language_index,
624 features,
625 lookup_indexes);
631 * Since: 0.9.8
633 void
634 hb_ot_layout_collect_lookups (hb_face_t *face,
635 hb_tag_t table_tag,
636 const hb_tag_t *scripts,
637 const hb_tag_t *languages,
638 const hb_tag_t *features,
639 hb_set_t *lookup_indexes /* OUT */)
641 if (!scripts)
643 /* All scripts */
644 unsigned int count = hb_ot_layout_table_get_script_tags (face,
645 table_tag,
646 0, NULL, NULL);
647 for (unsigned int script_index = 0; script_index < count; script_index++)
648 _hb_ot_layout_collect_lookups_languages (face,
649 table_tag,
650 script_index,
651 languages,
652 features,
653 lookup_indexes);
655 else
657 for (; *scripts; scripts++)
659 unsigned int script_index;
660 if (hb_ot_layout_table_find_script (face,
661 table_tag,
662 *scripts,
663 &script_index))
664 _hb_ot_layout_collect_lookups_languages (face,
665 table_tag,
666 script_index,
667 languages,
668 features,
669 lookup_indexes);
675 * Since: 0.9.7
677 void
678 hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
679 hb_tag_t table_tag,
680 unsigned int lookup_index,
681 hb_set_t *glyphs_before, /* OUT. May be NULL */
682 hb_set_t *glyphs_input, /* OUT. May be NULL */
683 hb_set_t *glyphs_after, /* OUT. May be NULL */
684 hb_set_t *glyphs_output /* OUT. May be NULL */)
686 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
688 OT::hb_collect_glyphs_context_t c (face,
689 glyphs_before,
690 glyphs_input,
691 glyphs_after,
692 glyphs_output);
694 switch (table_tag)
696 case HB_OT_TAG_GSUB:
698 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
699 l.collect_glyphs (&c);
700 return;
702 case HB_OT_TAG_GPOS:
704 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
705 l.collect_glyphs (&c);
706 return;
713 * OT::GSUB
716 hb_bool_t
717 hb_ot_layout_has_substitution (hb_face_t *face)
719 return &_get_gsub (face) != &OT::Null(OT::GSUB);
723 * Since: 0.9.7
725 hb_bool_t
726 hb_ot_layout_lookup_would_substitute (hb_face_t *face,
727 unsigned int lookup_index,
728 const hb_codepoint_t *glyphs,
729 unsigned int glyphs_length,
730 hb_bool_t zero_context)
732 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
733 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
736 hb_bool_t
737 hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
738 unsigned int lookup_index,
739 const hb_codepoint_t *glyphs,
740 unsigned int glyphs_length,
741 hb_bool_t zero_context)
743 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
744 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
746 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
748 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
751 void
752 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
754 OT::GSUB::substitute_start (font, buffer);
757 void
758 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
760 OT::GSUB::substitute_finish (font, buffer);
764 * Since: 0.9.7
766 void
767 hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
768 unsigned int lookup_index,
769 hb_set_t *glyphs)
771 OT::hb_closure_context_t c (face, glyphs);
773 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
775 l.closure (&c);
779 * OT::GPOS
782 hb_bool_t
783 hb_ot_layout_has_positioning (hb_face_t *face)
785 return &_get_gpos (face) != &OT::Null(OT::GPOS);
788 void
789 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
791 OT::GPOS::position_start (font, buffer);
794 void
795 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
797 OT::GPOS::position_finish (font, buffer);
801 * Since: 0.9.8
803 hb_bool_t
804 hb_ot_layout_get_size_params (hb_face_t *face,
805 unsigned int *design_size, /* OUT. May be NULL */
806 unsigned int *subfamily_id, /* OUT. May be NULL */
807 unsigned int *subfamily_name_id, /* OUT. May be NULL */
808 unsigned int *range_start, /* OUT. May be NULL */
809 unsigned int *range_end /* OUT. May be NULL */)
811 const OT::GPOS &gpos = _get_gpos (face);
812 const hb_tag_t tag = HB_TAG ('s','i','z','e');
814 unsigned int num_features = gpos.get_feature_count ();
815 for (unsigned int i = 0; i < num_features; i++)
817 if (tag == gpos.get_feature_tag (i))
819 const OT::Feature &f = gpos.get_feature (i);
820 const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
822 if (params.designSize)
824 #define PARAM(a, A) if (a) *a = params.A
825 PARAM (design_size, designSize);
826 PARAM (subfamily_id, subfamilyID);
827 PARAM (subfamily_name_id, subfamilyNameID);
828 PARAM (range_start, rangeStart);
829 PARAM (range_end, rangeEnd);
830 #undef PARAM
832 return true;
837 #define PARAM(a, A) if (a) *a = 0
838 PARAM (design_size, designSize);
839 PARAM (subfamily_id, subfamilyID);
840 PARAM (subfamily_name_id, subfamilyNameID);
841 PARAM (range_start, rangeStart);
842 PARAM (range_end, rangeEnd);
843 #undef PARAM
845 return false;
850 * Parts of different types are implemented here such that they have direct
851 * access to GSUB/GPOS lookups.
855 struct GSUBProxy
857 static const unsigned int table_index = 0;
858 static const bool inplace = false;
859 typedef OT::SubstLookup Lookup;
861 GSUBProxy (hb_face_t *face) :
862 table (*hb_ot_layout_from_face (face)->gsub),
863 accels (hb_ot_layout_from_face (face)->gsub_accels) {}
865 const OT::GSUB &table;
866 const hb_ot_layout_lookup_accelerator_t *accels;
869 struct GPOSProxy
871 static const unsigned int table_index = 1;
872 static const bool inplace = true;
873 typedef OT::PosLookup Lookup;
875 GPOSProxy (hb_face_t *face) :
876 table (*hb_ot_layout_from_face (face)->gpos),
877 accels (hb_ot_layout_from_face (face)->gpos_accels) {}
879 const OT::GPOS &table;
880 const hb_ot_layout_lookup_accelerator_t *accels;
884 template <typename Obj>
885 static inline bool
886 apply_forward (OT::hb_apply_context_t *c,
887 const Obj &obj,
888 const hb_ot_layout_lookup_accelerator_t &accel)
890 bool ret = false;
891 hb_buffer_t *buffer = c->buffer;
892 while (buffer->idx < buffer->len)
894 if (accel.may_have (buffer->cur().codepoint) &&
895 (buffer->cur().mask & c->lookup_mask) &&
896 c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
897 obj.apply (c))
898 ret = true;
899 else
900 buffer->next_glyph ();
902 return ret;
905 template <typename Obj>
906 static inline bool
907 apply_backward (OT::hb_apply_context_t *c,
908 const Obj &obj,
909 const hb_ot_layout_lookup_accelerator_t &accel)
911 bool ret = false;
912 hb_buffer_t *buffer = c->buffer;
915 if (accel.may_have (buffer->cur().codepoint) &&
916 (buffer->cur().mask & c->lookup_mask) &&
917 c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
918 obj.apply (c))
919 ret = true;
920 /* The reverse lookup doesn't "advance" cursor (for good reason). */
921 buffer->idx--;
924 while ((int) buffer->idx >= 0);
925 return ret;
928 struct hb_apply_forward_context_t
930 inline const char *get_name (void) { return "APPLY_FWD"; }
931 static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
932 typedef bool return_t;
933 template <typename T, typename F>
934 inline bool may_dispatch (const T *obj, const F *format) { return true; }
935 template <typename T>
936 inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
937 static return_t default_return_value (void) { return false; }
938 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
940 hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
941 const hb_ot_layout_lookup_accelerator_t &accel_) :
942 c (c_),
943 accel (accel_),
944 debug_depth (0) {}
946 OT::hb_apply_context_t *c;
947 const hb_ot_layout_lookup_accelerator_t &accel;
948 unsigned int debug_depth;
951 template <typename Proxy>
952 static inline void
953 apply_string (OT::hb_apply_context_t *c,
954 const typename Proxy::Lookup &lookup,
955 const hb_ot_layout_lookup_accelerator_t &accel)
957 hb_buffer_t *buffer = c->buffer;
959 if (unlikely (!buffer->len || !c->lookup_mask))
960 return;
962 c->set_lookup_props (lookup.get_props ());
964 if (likely (!lookup.is_reverse ()))
966 /* in/out forward substitution/positioning */
967 if (Proxy::table_index == 0)
968 buffer->clear_output ();
969 buffer->idx = 0;
971 bool ret;
972 if (lookup.get_subtable_count () == 1)
974 hb_apply_forward_context_t c_forward (c, accel);
975 ret = lookup.dispatch (&c_forward);
977 else
978 ret = apply_forward (c, lookup, accel);
979 if (ret)
981 if (!Proxy::inplace)
982 buffer->swap_buffers ();
983 else
984 assert (!buffer->has_separate_output ());
987 else
989 /* in-place backward substitution/positioning */
990 if (Proxy::table_index == 0)
991 buffer->remove_output ();
992 buffer->idx = buffer->len - 1;
994 apply_backward (c, lookup, accel);
998 template <typename Proxy>
999 inline void hb_ot_map_t::apply (const Proxy &proxy,
1000 const hb_ot_shape_plan_t *plan,
1001 hb_font_t *font,
1002 hb_buffer_t *buffer) const
1004 const unsigned int table_index = proxy.table_index;
1005 unsigned int i = 0;
1006 OT::hb_apply_context_t c (table_index, font, buffer);
1007 c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
1009 for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
1010 const stage_map_t *stage = &stages[table_index][stage_index];
1011 for (; i < stage->last_lookup; i++)
1013 #if 0
1014 char buf[4096];
1015 hb_buffer_serialize_glyphs (buffer, 0, buffer->len,
1016 buf, sizeof (buf), NULL,
1017 font,
1018 HB_BUFFER_SERIALIZE_FORMAT_TEXT,
1019 Proxy::table_index == 0 ?
1020 HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS :
1021 HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
1022 printf ("buf: [%s]\n", buf);
1023 #endif
1025 unsigned int lookup_index = lookups[table_index][i].index;
1026 c.set_lookup_index (lookup_index);
1027 c.set_lookup_mask (lookups[table_index][i].mask);
1028 c.set_auto_zwj (lookups[table_index][i].auto_zwj);
1029 apply_string<Proxy> (&c,
1030 proxy.table.get_lookup (lookup_index),
1031 proxy.accels[lookup_index]);
1034 if (stage->pause_func)
1036 buffer->clear_output ();
1037 stage->pause_func (plan, font, buffer);
1042 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1044 GSUBProxy proxy (font->face);
1045 apply (proxy, plan, font, buffer);
1048 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1050 GPOSProxy proxy (font->face);
1051 apply (proxy, plan, font, buffer);
1054 HB_INTERNAL void
1055 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
1056 const OT::SubstLookup &lookup,
1057 const hb_ot_layout_lookup_accelerator_t &accel)
1059 apply_string<GSUBProxy> (c, lookup, accel);