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
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-open-type-private.hh"
32 #include "hb-ot-layout-private.hh"
34 #include "hb-ot-layout-gdef-table.hh"
35 #include "hb-ot-layout-gsub-table.hh"
36 #include "hb-ot-layout-gpos-table.hh"
37 #include "hb-ot-layout-jstf-table.hh"
39 #include "hb-ot-map-private.hh"
45 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
48 _hb_ot_layout_create (hb_face_t *face)
50 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
51 if (unlikely (!layout))
54 layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
55 layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
57 layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
58 layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
60 layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
61 layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
65 * The ugly business of blacklisting individual fonts' tables happen here!
66 * See this thread for why we finally had to bend in and do this:
67 * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
69 unsigned int gdef_len = hb_blob_get_length (layout->gdef_blob);
70 unsigned int gsub_len = hb_blob_get_length (layout->gsub_blob);
71 unsigned int gpos_len = hb_blob_get_length (layout->gpos_blob);
73 /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
74 || (442 == gdef_len && 42038 == gpos_len && 2874 == gsub_len)
75 /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
76 || (430 == gdef_len && 40662 == gpos_len && 2874 == gsub_len)
77 /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
78 || (442 == gdef_len && 39116 == gpos_len && 2874 == gsub_len)
79 /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
80 || (430 == gdef_len && 39374 == gpos_len && 2874 == gsub_len)
81 /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
82 || (490 == gdef_len && 41638 == gpos_len && 3046 == gsub_len)
83 /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
84 || (478 == gdef_len && 41902 == gpos_len && 3046 == gsub_len)
87 /* In certain versions of Times New Roman Italic and Bold Italic,
88 * ASCII double quotation mark U+0022, mapped to glyph 5, has wrong
89 * glyph class 3 (mark) in GDEF. Nuke the GDEF to avoid zero-width
91 * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
93 if (3 == layout->gdef->get_glyph_class (5))
94 layout->gdef = &OT::Null(OT::GDEF);
98 layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
99 layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
101 layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
102 layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
104 if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
105 (layout->gpos_lookup_count && !layout->gpos_accels)))
107 _hb_ot_layout_destroy (layout);
111 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
112 layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
113 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
114 layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
120 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
122 for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
123 layout->gsub_accels[i].fini ();
124 for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
125 layout->gpos_accels[i].fini ();
127 free (layout->gsub_accels);
128 free (layout->gpos_accels);
130 hb_blob_destroy (layout->gdef_blob);
131 hb_blob_destroy (layout->gsub_blob);
132 hb_blob_destroy (layout->gpos_blob);
137 static inline const OT::GDEF&
138 _get_gdef (hb_face_t *face)
140 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
141 return *hb_ot_layout_from_face (face)->gdef;
143 static inline const OT::GSUB&
144 _get_gsub (hb_face_t *face)
146 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
147 return *hb_ot_layout_from_face (face)->gsub;
149 static inline const OT::GPOS&
150 _get_gpos (hb_face_t *face)
152 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
153 return *hb_ot_layout_from_face (face)->gpos;
162 hb_ot_layout_has_glyph_classes (hb_face_t *face)
164 return _get_gdef (face).has_glyph_classes ();
168 * hb_ot_layout_get_glyph_class:
172 hb_ot_layout_glyph_class_t
173 hb_ot_layout_get_glyph_class (hb_face_t *face,
174 hb_codepoint_t glyph)
176 return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
180 * hb_ot_layout_get_glyphs_in_class:
185 hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
186 hb_ot_layout_glyph_class_t klass,
187 hb_set_t *glyphs /* OUT */)
189 return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
193 hb_ot_layout_get_attach_points (hb_face_t *face,
194 hb_codepoint_t glyph,
195 unsigned int start_offset,
196 unsigned int *point_count /* IN/OUT */,
197 unsigned int *point_array /* OUT */)
199 return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
203 hb_ot_layout_get_ligature_carets (hb_font_t *font,
204 hb_direction_t direction,
205 hb_codepoint_t glyph,
206 unsigned int start_offset,
207 unsigned int *caret_count /* IN/OUT */,
208 int *caret_array /* OUT */)
210 return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
218 static const OT::GSUBGPOS&
219 get_gsubgpos_table (hb_face_t *face,
223 case HB_OT_TAG_GSUB: return _get_gsub (face);
224 case HB_OT_TAG_GPOS: return _get_gpos (face);
225 default: return OT::Null(OT::GSUBGPOS);
231 hb_ot_layout_table_get_script_tags (hb_face_t *face,
233 unsigned int start_offset,
234 unsigned int *script_count /* IN/OUT */,
235 hb_tag_t *script_tags /* OUT */)
237 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
239 return g.get_script_tags (start_offset, script_count, script_tags);
242 #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
245 hb_ot_layout_table_find_script (hb_face_t *face,
248 unsigned int *script_index)
250 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
251 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
253 if (g.find_script_index (script_tag, script_index))
256 /* try finding 'DFLT' */
257 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
260 /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
261 * including many versions of DejaVu Sans Mono! */
262 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
265 /* try with 'latn'; some old fonts put their features there even though
266 they're really trying to support Thai, for example :( */
267 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
270 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
275 hb_ot_layout_table_choose_script (hb_face_t *face,
277 const hb_tag_t *script_tags,
278 unsigned int *script_index,
279 hb_tag_t *chosen_script)
281 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
282 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
286 if (g.find_script_index (*script_tags, script_index)) {
288 *chosen_script = *script_tags;
294 /* try finding 'DFLT' */
295 if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
297 *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
301 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
302 if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
304 *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
308 /* try with 'latn'; some old fonts put their features there even though
309 they're really trying to support Thai, for example :( */
310 if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
312 *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
316 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
318 *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
323 hb_ot_layout_table_get_feature_tags (hb_face_t *face,
325 unsigned int start_offset,
326 unsigned int *feature_count /* IN/OUT */,
327 hb_tag_t *feature_tags /* OUT */)
329 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
331 return g.get_feature_tags (start_offset, feature_count, feature_tags);
335 hb_ot_layout_table_find_feature (hb_face_t *face,
337 hb_tag_t feature_tag,
338 unsigned int *feature_index)
340 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
341 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
343 unsigned int num_features = g.get_feature_count ();
344 for (unsigned int i = 0; i < num_features; i++)
346 if (feature_tag == g.get_feature_tag (i)) {
347 if (feature_index) *feature_index = i;
352 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
358 hb_ot_layout_script_get_language_tags (hb_face_t *face,
360 unsigned int script_index,
361 unsigned int start_offset,
362 unsigned int *language_count /* IN/OUT */,
363 hb_tag_t *language_tags /* OUT */)
365 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
367 return s.get_lang_sys_tags (start_offset, language_count, language_tags);
371 hb_ot_layout_script_find_language (hb_face_t *face,
373 unsigned int script_index,
374 hb_tag_t language_tag,
375 unsigned int *language_index)
377 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
378 const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
380 if (s.find_lang_sys_index (language_tag, language_index))
383 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
384 if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
387 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
392 hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
394 unsigned int script_index,
395 unsigned int language_index,
396 unsigned int *feature_index)
398 return hb_ot_layout_language_get_required_feature (face,
407 * hb_ot_layout_language_get_required_feature:
412 hb_ot_layout_language_get_required_feature (hb_face_t *face,
414 unsigned int script_index,
415 unsigned int language_index,
416 unsigned int *feature_index,
417 hb_tag_t *feature_tag)
419 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
420 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
422 unsigned int index = l.get_required_feature_index ();
423 if (feature_index) *feature_index = index;
424 if (feature_tag) *feature_tag = g.get_feature_tag (index);
426 return l.has_required_feature ();
430 hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
432 unsigned int script_index,
433 unsigned int language_index,
434 unsigned int start_offset,
435 unsigned int *feature_count /* IN/OUT */,
436 unsigned int *feature_indexes /* OUT */)
438 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
439 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
441 return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
445 hb_ot_layout_language_get_feature_tags (hb_face_t *face,
447 unsigned int script_index,
448 unsigned int language_index,
449 unsigned int start_offset,
450 unsigned int *feature_count /* IN/OUT */,
451 hb_tag_t *feature_tags /* OUT */)
453 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
454 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
456 ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
457 unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
460 unsigned int count = *feature_count;
461 for (unsigned int i = 0; i < count; i++)
462 feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
470 hb_ot_layout_language_find_feature (hb_face_t *face,
472 unsigned int script_index,
473 unsigned int language_index,
474 hb_tag_t feature_tag,
475 unsigned int *feature_index)
477 ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
478 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
479 const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
481 unsigned int num_features = l.get_feature_count ();
482 for (unsigned int i = 0; i < num_features; i++) {
483 unsigned int f_index = l.get_feature_index (i);
485 if (feature_tag == g.get_feature_tag (f_index)) {
486 if (feature_index) *feature_index = f_index;
491 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
496 * hb_ot_layout_feature_get_lookups:
501 hb_ot_layout_feature_get_lookups (hb_face_t *face,
503 unsigned int feature_index,
504 unsigned int start_offset,
505 unsigned int *lookup_count /* IN/OUT */,
506 unsigned int *lookup_indexes /* OUT */)
508 const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
509 const OT::Feature &f = g.get_feature (feature_index);
511 return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
515 * hb_ot_layout_table_get_lookup_count:
520 hb_ot_layout_table_get_lookup_count (hb_face_t *face,
527 return hb_ot_layout_from_face (face)->gsub_lookup_count;
531 return hb_ot_layout_from_face (face)->gpos_lookup_count;
538 _hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
540 unsigned int feature_index,
541 hb_set_t *lookup_indexes /* OUT */)
543 unsigned int lookup_indices[32];
544 unsigned int offset, len;
548 len = ARRAY_LENGTH (lookup_indices);
549 hb_ot_layout_feature_get_lookups (face,
555 for (unsigned int i = 0; i < len; i++)
556 lookup_indexes->add (lookup_indices[i]);
559 } while (len == ARRAY_LENGTH (lookup_indices));
563 _hb_ot_layout_collect_lookups_features (hb_face_t *face,
565 unsigned int script_index,
566 unsigned int language_index,
567 const hb_tag_t *features,
568 hb_set_t *lookup_indexes /* OUT */)
572 unsigned int required_feature_index;
573 if (hb_ot_layout_language_get_required_feature (face,
577 &required_feature_index,
579 _hb_ot_layout_collect_lookups_lookups (face,
581 required_feature_index,
585 unsigned int feature_indices[32];
586 unsigned int offset, len;
590 len = ARRAY_LENGTH (feature_indices);
591 hb_ot_layout_language_get_feature_indexes (face,
598 for (unsigned int i = 0; i < len; i++)
599 _hb_ot_layout_collect_lookups_lookups (face,
605 } while (len == ARRAY_LENGTH (feature_indices));
609 for (; *features; features++)
611 unsigned int feature_index;
612 if (hb_ot_layout_language_find_feature (face,
618 _hb_ot_layout_collect_lookups_lookups (face,
627 _hb_ot_layout_collect_lookups_languages (hb_face_t *face,
629 unsigned int script_index,
630 const hb_tag_t *languages,
631 const hb_tag_t *features,
632 hb_set_t *lookup_indexes /* OUT */)
634 _hb_ot_layout_collect_lookups_features (face,
637 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
644 unsigned int count = hb_ot_layout_script_get_language_tags (face,
648 for (unsigned int language_index = 0; language_index < count; language_index++)
649 _hb_ot_layout_collect_lookups_features (face,
658 for (; *languages; languages++)
660 unsigned int language_index;
661 if (hb_ot_layout_script_find_language (face,
666 _hb_ot_layout_collect_lookups_features (face,
677 * hb_ot_layout_collect_lookups:
682 hb_ot_layout_collect_lookups (hb_face_t *face,
684 const hb_tag_t *scripts,
685 const hb_tag_t *languages,
686 const hb_tag_t *features,
687 hb_set_t *lookup_indexes /* OUT */)
692 unsigned int count = hb_ot_layout_table_get_script_tags (face,
695 for (unsigned int script_index = 0; script_index < count; script_index++)
696 _hb_ot_layout_collect_lookups_languages (face,
705 for (; *scripts; scripts++)
707 unsigned int script_index;
708 if (hb_ot_layout_table_find_script (face,
712 _hb_ot_layout_collect_lookups_languages (face,
723 * hb_ot_layout_lookup_collect_glyphs:
728 hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
730 unsigned int lookup_index,
731 hb_set_t *glyphs_before, /* OUT. May be NULL */
732 hb_set_t *glyphs_input, /* OUT. May be NULL */
733 hb_set_t *glyphs_after, /* OUT. May be NULL */
734 hb_set_t *glyphs_output /* OUT. May be NULL */)
736 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
738 OT::hb_collect_glyphs_context_t c (face,
748 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
749 l.collect_glyphs (&c);
754 const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
755 l.collect_glyphs (&c);
767 hb_ot_layout_has_substitution (hb_face_t *face)
769 return &_get_gsub (face) != &OT::Null(OT::GSUB);
773 * hb_ot_layout_lookup_would_substitute:
778 hb_ot_layout_lookup_would_substitute (hb_face_t *face,
779 unsigned int lookup_index,
780 const hb_codepoint_t *glyphs,
781 unsigned int glyphs_length,
782 hb_bool_t zero_context)
784 if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
785 return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
789 hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
790 unsigned int lookup_index,
791 const hb_codepoint_t *glyphs,
792 unsigned int glyphs_length,
793 hb_bool_t zero_context)
795 if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
796 OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
798 const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
800 return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
804 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
806 OT::GSUB::substitute_start (font, buffer);
810 * hb_ot_layout_lookup_substitute_closure:
815 hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
816 unsigned int lookup_index,
819 OT::hb_closure_context_t c (face, glyphs);
821 const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
831 hb_ot_layout_has_positioning (hb_face_t *face)
833 return &_get_gpos (face) != &OT::Null(OT::GPOS);
837 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
839 OT::GPOS::position_start (font, buffer);
843 hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
845 OT::GPOS::position_finish_advances (font, buffer);
849 hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
851 OT::GPOS::position_finish_offsets (font, buffer);
855 * hb_ot_layout_get_size_params:
860 hb_ot_layout_get_size_params (hb_face_t *face,
861 unsigned int *design_size, /* OUT. May be NULL */
862 unsigned int *subfamily_id, /* OUT. May be NULL */
863 unsigned int *subfamily_name_id, /* OUT. May be NULL */
864 unsigned int *range_start, /* OUT. May be NULL */
865 unsigned int *range_end /* OUT. May be NULL */)
867 const OT::GPOS &gpos = _get_gpos (face);
868 const hb_tag_t tag = HB_TAG ('s','i','z','e');
870 unsigned int num_features = gpos.get_feature_count ();
871 for (unsigned int i = 0; i < num_features; i++)
873 if (tag == gpos.get_feature_tag (i))
875 const OT::Feature &f = gpos.get_feature (i);
876 const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag);
878 if (params.designSize)
880 #define PARAM(a, A) if (a) *a = params.A
881 PARAM (design_size, designSize);
882 PARAM (subfamily_id, subfamilyID);
883 PARAM (subfamily_name_id, subfamilyNameID);
884 PARAM (range_start, rangeStart);
885 PARAM (range_end, rangeEnd);
893 #define PARAM(a, A) if (a) *a = 0
894 PARAM (design_size, designSize);
895 PARAM (subfamily_id, subfamilyID);
896 PARAM (subfamily_name_id, subfamilyNameID);
897 PARAM (range_start, rangeStart);
898 PARAM (range_end, rangeEnd);
906 * Parts of different types are implemented here such that they have direct
907 * access to GSUB/GPOS lookups.
913 static const unsigned int table_index = 0;
914 static const bool inplace = false;
915 typedef OT::SubstLookup Lookup;
917 GSUBProxy (hb_face_t *face) :
918 table (*hb_ot_layout_from_face (face)->gsub),
919 accels (hb_ot_layout_from_face (face)->gsub_accels) {}
921 const OT::GSUB &table;
922 const hb_ot_layout_lookup_accelerator_t *accels;
927 static const unsigned int table_index = 1;
928 static const bool inplace = true;
929 typedef OT::PosLookup Lookup;
931 GPOSProxy (hb_face_t *face) :
932 table (*hb_ot_layout_from_face (face)->gpos),
933 accels (hb_ot_layout_from_face (face)->gpos_accels) {}
935 const OT::GPOS &table;
936 const hb_ot_layout_lookup_accelerator_t *accels;
940 struct hb_get_subtables_context_t :
941 OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
943 template <typename Type>
944 static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c)
946 const Type *typed_obj = (const Type *) obj;
947 return typed_obj->apply (c);
950 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c);
952 struct hb_applicable_t
954 inline void init (const void *obj_, hb_apply_func_t apply_func_)
957 apply_func = apply_func_;
960 inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); }
964 hb_apply_func_t apply_func;
967 typedef hb_auto_array_t<hb_applicable_t> array_t;
969 /* Dispatch interface. */
970 inline const char *get_name (void) { return "GET_SUBTABLES"; }
971 template <typename T>
972 inline return_t dispatch (const T &obj)
974 hb_applicable_t *entry = array.push();
976 entry->init (&obj, apply_to<T>);
979 static return_t default_return_value (void) { return HB_VOID; }
980 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
982 hb_get_subtables_context_t (array_t &array_) :
987 unsigned int debug_depth;
991 apply_forward (OT::hb_apply_context_t *c,
992 const hb_ot_layout_lookup_accelerator_t &accel,
993 const hb_get_subtables_context_t::array_t &subtables)
996 hb_buffer_t *buffer = c->buffer;
997 while (buffer->idx < buffer->len && !buffer->in_error)
999 bool applied = false;
1000 if (accel.may_have (buffer->cur().codepoint) &&
1001 (buffer->cur().mask & c->lookup_mask) &&
1002 c->check_glyph_property (&buffer->cur(), c->lookup_props))
1004 for (unsigned int i = 0; i < subtables.len; i++)
1005 if (subtables[i].apply (c))
1015 buffer->next_glyph ();
1021 apply_backward (OT::hb_apply_context_t *c,
1022 const hb_ot_layout_lookup_accelerator_t &accel,
1023 const hb_get_subtables_context_t::array_t &subtables)
1026 hb_buffer_t *buffer = c->buffer;
1029 if (accel.may_have (buffer->cur().codepoint) &&
1030 (buffer->cur().mask & c->lookup_mask) &&
1031 c->check_glyph_property (&buffer->cur(), c->lookup_props))
1033 for (unsigned int i = 0; i < subtables.len; i++)
1034 if (subtables[i].apply (c))
1040 /* The reverse lookup doesn't "advance" cursor (for good reason). */
1044 while ((int) buffer->idx >= 0);
1048 template <typename Proxy>
1050 apply_string (OT::hb_apply_context_t *c,
1051 const typename Proxy::Lookup &lookup,
1052 const hb_ot_layout_lookup_accelerator_t &accel)
1054 hb_buffer_t *buffer = c->buffer;
1056 if (unlikely (!buffer->len || !c->lookup_mask))
1059 c->set_lookup_props (lookup.get_props ());
1061 hb_get_subtables_context_t::array_t subtables;
1062 hb_get_subtables_context_t c_get_subtables (subtables);
1063 lookup.dispatch (&c_get_subtables);
1065 if (likely (!lookup.is_reverse ()))
1067 /* in/out forward substitution/positioning */
1068 if (Proxy::table_index == 0)
1069 buffer->clear_output ();
1073 ret = apply_forward (c, accel, subtables);
1076 if (!Proxy::inplace)
1077 buffer->swap_buffers ();
1079 assert (!buffer->has_separate_output ());
1084 /* in-place backward substitution/positioning */
1085 if (Proxy::table_index == 0)
1086 buffer->remove_output ();
1087 buffer->idx = buffer->len - 1;
1089 apply_backward (c, accel, subtables);
1093 template <typename Proxy>
1094 inline void hb_ot_map_t::apply (const Proxy &proxy,
1095 const hb_ot_shape_plan_t *plan,
1097 hb_buffer_t *buffer) const
1099 const unsigned int table_index = proxy.table_index;
1101 OT::hb_apply_context_t c (table_index, font, buffer);
1102 c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
1104 for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
1105 const stage_map_t *stage = &stages[table_index][stage_index];
1106 for (; i < stage->last_lookup; i++)
1108 unsigned int lookup_index = lookups[table_index][i].index;
1109 if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
1110 c.set_lookup_index (lookup_index);
1111 c.set_lookup_mask (lookups[table_index][i].mask);
1112 c.set_auto_zwj (lookups[table_index][i].auto_zwj);
1113 apply_string<Proxy> (&c,
1114 proxy.table.get_lookup (lookup_index),
1115 proxy.accels[lookup_index]);
1116 (void) buffer->message (font, "end lookup %d", lookup_index);
1119 if (stage->pause_func)
1121 buffer->clear_output ();
1122 stage->pause_func (plan, font, buffer);
1127 void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1129 GSUBProxy proxy (font->face);
1130 apply (proxy, plan, font, buffer);
1133 void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
1135 GPOSProxy proxy (font->face);
1136 apply (proxy, plan, font, buffer);
1140 hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
1141 const OT::SubstLookup &lookup,
1142 const hb_ot_layout_lookup_accelerator_t &accel)
1144 apply_string<GSUBProxy> (c, lookup, accel);