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-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"
44 HB_SHAPER_DATA_ENSURE_DECLARE(ot
, face
)
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
))
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
);
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
));
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
);
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
;
126 hb_ot_layout_has_glyph_classes (hb_face_t
*face
)
128 return _get_gdef (face
).has_glyph_classes ();
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
);
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
);
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
);
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
);
178 static const OT::GSUBGPOS
&
179 get_gsubgpos_table (hb_face_t
*face
,
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
);
191 hb_ot_layout_table_get_script_tags (hb_face_t
*face
,
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')
205 hb_ot_layout_table_find_script (hb_face_t
*face
,
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
))
216 /* try finding 'DFLT' */
217 if (g
.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT
, script_index
))
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
))
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
))
230 if (script_index
) *script_index
= HB_OT_LAYOUT_NO_SCRIPT_INDEX
;
235 hb_ot_layout_table_choose_script (hb_face_t
*face
,
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
);
246 if (g
.find_script_index (*script_tags
, script_index
)) {
248 *chosen_script
= *script_tags
;
254 /* try finding 'DFLT' */
255 if (g
.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT
, script_index
)) {
257 *chosen_script
= HB_OT_TAG_DEFAULT_SCRIPT
;
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
)) {
264 *chosen_script
= HB_OT_TAG_DEFAULT_LANGUAGE
;
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
)) {
272 *chosen_script
= HB_OT_TAG_LATIN_SCRIPT
;
276 if (script_index
) *script_index
= HB_OT_LAYOUT_NO_SCRIPT_INDEX
;
278 *chosen_script
= HB_OT_LAYOUT_NO_SCRIPT_INDEX
;
283 hb_ot_layout_table_get_feature_tags (hb_face_t
*face
,
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
);
295 hb_ot_layout_table_find_feature (hb_face_t
*face
,
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
;
312 if (feature_index
) *feature_index
= HB_OT_LAYOUT_NO_FEATURE_INDEX
;
318 hb_ot_layout_script_get_language_tags (hb_face_t
*face
,
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
);
331 hb_ot_layout_script_find_language (hb_face_t
*face
,
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
))
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
))
347 if (language_index
) *language_index
= HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
;
352 hb_ot_layout_language_get_required_feature_index (hb_face_t
*face
,
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
,
370 hb_ot_layout_language_get_required_feature (hb_face_t
*face
,
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 ();
388 hb_ot_layout_language_get_feature_indexes (hb_face_t
*face
,
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
);
403 hb_ot_layout_language_get_feature_tags (hb_face_t
*face
,
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
);
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
]);
428 hb_ot_layout_language_find_feature (hb_face_t
*face
,
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
;
449 if (feature_index
) *feature_index
= HB_OT_LAYOUT_NO_FEATURE_INDEX
;
457 hb_ot_layout_feature_get_lookups (hb_face_t
*face
,
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
);
474 hb_ot_layout_table_get_lookup_count (hb_face_t
*face
,
481 return hb_ot_layout_from_face (face
)->gsub_lookup_count
;
485 return hb_ot_layout_from_face (face
)->gpos_lookup_count
;
492 _hb_ot_layout_collect_lookups_lookups (hb_face_t
*face
,
494 unsigned int feature_index
,
495 hb_set_t
*lookup_indexes
/* OUT */)
497 unsigned int lookup_indices
[32];
498 unsigned int offset
, len
;
502 len
= ARRAY_LENGTH (lookup_indices
);
503 hb_ot_layout_feature_get_lookups (face
,
509 for (unsigned int i
= 0; i
< len
; i
++)
510 lookup_indexes
->add (lookup_indices
[i
]);
513 } while (len
== ARRAY_LENGTH (lookup_indices
));
517 _hb_ot_layout_collect_lookups_features (hb_face_t
*face
,
519 unsigned int script_index
,
520 unsigned int language_index
,
521 const hb_tag_t
*features
,
522 hb_set_t
*lookup_indexes
/* OUT */)
526 unsigned int required_feature_index
;
527 if (hb_ot_layout_language_get_required_feature (face
,
531 &required_feature_index
,
533 _hb_ot_layout_collect_lookups_lookups (face
,
535 required_feature_index
,
539 unsigned int feature_indices
[32];
540 unsigned int offset
, len
;
544 len
= ARRAY_LENGTH (feature_indices
);
545 hb_ot_layout_language_get_feature_indexes (face
,
552 for (unsigned int i
= 0; i
< len
; i
++)
553 _hb_ot_layout_collect_lookups_lookups (face
,
559 } while (len
== ARRAY_LENGTH (feature_indices
));
563 for (; *features
; features
++)
565 unsigned int feature_index
;
566 if (hb_ot_layout_language_find_feature (face
,
572 _hb_ot_layout_collect_lookups_lookups (face
,
581 _hb_ot_layout_collect_lookups_languages (hb_face_t
*face
,
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
,
591 HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
,
598 unsigned int count
= hb_ot_layout_script_get_language_tags (face
,
602 for (unsigned int language_index
= 0; language_index
< count
; language_index
++)
603 _hb_ot_layout_collect_lookups_features (face
,
612 for (; *languages
; languages
++)
614 unsigned int language_index
;
615 if (hb_ot_layout_script_find_language (face
,
620 _hb_ot_layout_collect_lookups_features (face
,
634 hb_ot_layout_collect_lookups (hb_face_t
*face
,
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 */)
644 unsigned int count
= hb_ot_layout_table_get_script_tags (face
,
647 for (unsigned int script_index
= 0; script_index
< count
; script_index
++)
648 _hb_ot_layout_collect_lookups_languages (face
,
657 for (; *scripts
; scripts
++)
659 unsigned int script_index
;
660 if (hb_ot_layout_table_find_script (face
,
664 _hb_ot_layout_collect_lookups_languages (face
,
678 hb_ot_layout_lookup_collect_glyphs (hb_face_t
*face
,
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
,
698 const OT::SubstLookup
& l
= hb_ot_layout_from_face (face
)->gsub
->get_lookup (lookup_index
);
699 l
.collect_glyphs (&c
);
704 const OT::PosLookup
& l
= hb_ot_layout_from_face (face
)->gpos
->get_lookup (lookup_index
);
705 l
.collect_glyphs (&c
);
717 hb_ot_layout_has_substitution (hb_face_t
*face
)
719 return &_get_gsub (face
) != &OT::Null(OT::GSUB
);
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
);
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
]);
752 hb_ot_layout_substitute_start (hb_font_t
*font
, hb_buffer_t
*buffer
)
754 OT::GSUB::substitute_start (font
, buffer
);
758 hb_ot_layout_substitute_finish (hb_font_t
*font
, hb_buffer_t
*buffer
)
760 OT::GSUB::substitute_finish (font
, buffer
);
767 hb_ot_layout_lookup_substitute_closure (hb_face_t
*face
,
768 unsigned int lookup_index
,
771 OT::hb_closure_context_t
c (face
, glyphs
);
773 const OT::SubstLookup
& l
= _get_gsub (face
).get_lookup (lookup_index
);
783 hb_ot_layout_has_positioning (hb_face_t
*face
)
785 return &_get_gpos (face
) != &OT::Null(OT::GPOS
);
789 hb_ot_layout_position_start (hb_font_t
*font
, hb_buffer_t
*buffer
)
791 OT::GPOS::position_start (font
, buffer
);
795 hb_ot_layout_position_finish (hb_font_t
*font
, hb_buffer_t
*buffer
)
797 OT::GPOS::position_finish (font
, buffer
);
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
¶ms
= 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
);
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
);
850 * Parts of different types are implemented here such that they have direct
851 * access to GSUB/GPOS lookups.
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
;
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
>
886 apply_forward (OT::hb_apply_context_t
*c
,
888 const hb_ot_layout_lookup_accelerator_t
&accel
)
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
) &&
900 buffer
->next_glyph ();
905 template <typename Obj
>
907 apply_backward (OT::hb_apply_context_t
*c
,
909 const hb_ot_layout_lookup_accelerator_t
&accel
)
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
) &&
920 /* The reverse lookup doesn't "advance" cursor (for good reason). */
924 while ((int) buffer
->idx
>= 0);
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_
) :
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
>
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
))
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 ();
972 if (lookup
.get_subtable_count () == 1)
974 hb_apply_forward_context_t
c_forward (c
, accel
);
975 ret
= lookup
.dispatch (&c_forward
);
978 ret
= apply_forward (c
, lookup
, accel
);
982 buffer
->swap_buffers ();
984 assert (!buffer
->has_separate_output ());
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
,
1002 hb_buffer_t
*buffer
) const
1004 const unsigned int table_index
= proxy
.table_index
;
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
++)
1015 hb_buffer_serialize_glyphs (buffer
, 0, buffer
->len
,
1016 buf
, sizeof (buf
), NULL
,
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
);
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
);
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
);