2 * Copyright (C) 1998-2004 David Turner and Werner Lemberg
3 * Copyright (C) 2006 Behdad Esfahbod
4 * Copyright (C) 2007,2008,2009 Red Hat, Inc.
6 * This is part of HarfBuzz, an OpenType Layout engine library.
8 * Permission is hereby granted, without written agreement and without
9 * license or royalty fees, to use, copy, modify, and distribute this
10 * software and its documentation for any purpose, provided that the
11 * above copyright notice and the following two paragraphs appear in
12 * all copies of this software.
14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26 * Red Hat Author(s): Behdad Esfahbod
29 #define HB_OT_LAYOUT_CC
32 #include "hb-buffer-private.h"
34 #include "hb-ot-layout.h"
35 #include "hb-ot-layout-private.h"
37 #include "hb-ot-layout-open-private.h"
38 #include "hb-ot-layout-gdef-private.h"
39 #include "hb-ot-layout-gsub-private.h"
40 #include "hb-ot-layout-gpos-private.h"
48 hb_ot_layout_create (void)
50 hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
52 layout->gdef = &Null(GDEF);
53 layout->gsub = &Null(GSUB);
54 layout->gpos = &Null(GPOS);
60 hb_ot_layout_has_substitution (hb_ot_layout_t *layout)
62 return layout->gsub != &Null(GSUB);
66 hb_ot_layout_has_positioning (hb_ot_layout_t *layout)
68 return layout->gpos != &Null(GPOS);
72 hb_ot_layout_create_for_data (const char *font_data,
75 hb_ot_layout_t *layout;
77 if (HB_UNLIKELY (font_data == NULL))
78 return hb_ot_layout_create ();
80 layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
82 const OpenTypeFontFile &font = OpenTypeFontFile::get_for_data (font_data);
83 const OpenTypeFontFace &face = font.get_face (face_index);
85 layout->gdef = &GDEF::get_for_data (font.get_table_data (face.get_table_by_tag (GDEF::Tag)));
86 layout->gsub = &GSUB::get_for_data (font.get_table_data (face.get_table_by_tag (GSUB::Tag)));
87 layout->gpos = &GPOS::get_for_data (font.get_table_data (face.get_table_by_tag (GPOS::Tag)));
93 hb_ot_layout_create_for_tables (const char *gdef_data,
94 const char *gsub_data,
95 const char *gpos_data)
97 hb_ot_layout_t *layout;
99 if (HB_UNLIKELY (gdef_data == NULL && gsub_data == NULL && gpos_data == NULL))
100 return hb_ot_layout_create ();
102 layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
104 layout->gdef = &GDEF::get_for_data (gdef_data);
105 layout->gsub = &GSUB::get_for_data (gsub_data);
106 layout->gpos = &GPOS::get_for_data (gpos_data);
112 hb_ot_layout_destroy (hb_ot_layout_t *layout)
118 hb_ot_layout_set_direction (hb_ot_layout_t *layout,
121 layout->gpos_info.r2l = !!r2l;
125 hb_ot_layout_set_hinting (hb_ot_layout_t *layout,
128 layout->gpos_info.dvi = !hinted;
132 hb_ot_layout_set_scale (hb_ot_layout_t *layout,
133 hb_16dot16_t x_scale, hb_16dot16_t y_scale)
135 layout->gpos_info.x_scale = x_scale;
136 layout->gpos_info.y_scale = y_scale;
140 hb_ot_layout_set_ppem (hb_ot_layout_t *layout,
141 unsigned int x_ppem, unsigned int y_ppem)
143 layout->gpos_info.x_ppem = x_ppem;
144 layout->gpos_info.y_ppem = y_ppem;
152 /* TODO the public class_t is a mess */
155 hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout)
157 return layout->gdef->has_glyph_classes ();
160 HB_INTERNAL hb_bool_t
161 _hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout)
163 return layout->new_gdef.len > 0;
166 HB_INTERNAL unsigned int
167 _hb_ot_layout_get_glyph_property (hb_ot_layout_t *layout,
168 hb_codepoint_t glyph)
170 hb_ot_layout_class_t klass;
172 klass = layout->gdef->get_glyph_class (glyph);
174 if (!klass && glyph < layout->new_gdef.len)
175 klass = layout->new_gdef.klasses[glyph];
179 case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
180 case GDEF::BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
181 case GDEF::LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
182 case GDEF::ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
183 case GDEF::MarkGlyph:
184 /* TODO old harfbuzz doesn't always parse mark attachments as it says it was
185 * introduced without a version bump, so it may not be safe */
186 klass = layout->gdef->get_mark_attachment_type (glyph);
187 return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
191 HB_INTERNAL hb_bool_t
192 _hb_ot_layout_check_glyph_property (hb_ot_layout_t *layout,
193 hb_glyph_info_t *ginfo,
194 unsigned int lookup_flags,
195 unsigned int *property_out)
197 unsigned int property;
199 if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
200 ginfo->gproperty = _hb_ot_layout_get_glyph_property (layout, ginfo->gindex);
201 property = ginfo->gproperty;
203 *property_out = property;
205 /* Not covered, if, for example, glyph class is ligature and
206 * lookup_flags includes LookupFlags::IgnoreLigatures
208 if (property & lookup_flags)
211 if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
213 /* If using mark filtering sets, the high short of
214 * lookup_flags has the set index.
216 if (lookup_flags & LookupFlag::UseMarkFilteringSet)
217 return layout->gdef->mark_set_covers (lookup_flags >> 16, ginfo->gindex);
219 /* The second byte of lookup_flags has the meaning
220 * "ignore marks of attachment type different than
221 * the attachment type specified."
223 if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
224 return (lookup_flags & LookupFlag::MarkAttachmentType) == (property & LookupFlag::MarkAttachmentType);
230 HB_INTERNAL hb_bool_t
231 _hb_ot_layout_skip_mark (hb_ot_layout_t *layout,
232 hb_glyph_info_t *ginfo,
233 unsigned int lookup_flags,
234 unsigned int *property_out)
236 unsigned int property;
238 if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
239 ginfo->gproperty = _hb_ot_layout_get_glyph_property (layout, ginfo->gindex);
240 property = ginfo->gproperty;
242 *property_out = property;
244 if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
246 /* Skip mark if lookup_flags includes LookupFlags::IgnoreMarks */
247 if (lookup_flags & LookupFlag::IgnoreMarks)
250 /* If using mark filtering sets, the high short of lookup_flags has the set index. */
251 if (lookup_flags & LookupFlag::UseMarkFilteringSet)
252 return !layout->gdef->mark_set_covers (lookup_flags >> 16, ginfo->gindex);
254 /* The second byte of lookup_flags has the meaning "ignore marks of attachment type
255 * different than the attachment type specified." */
256 if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
257 return (lookup_flags & LookupFlag::MarkAttachmentType) != (property & LookupFlag::MarkAttachmentType);
264 _hb_ot_layout_set_glyph_property (hb_ot_layout_t *layout,
265 hb_codepoint_t glyph,
266 unsigned int property)
267 { hb_ot_layout_set_glyph_class (layout, glyph, (hb_ot_layout_glyph_class_t) (property & 0xff)); }
270 hb_ot_layout_glyph_class_t
271 hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout,
272 hb_codepoint_t glyph)
273 { return (hb_ot_layout_glyph_class_t) (_hb_ot_layout_get_glyph_property (layout, glyph) & 0xff); }
276 hb_ot_layout_set_glyph_class (hb_ot_layout_t *layout,
277 hb_codepoint_t glyph,
278 hb_ot_layout_glyph_class_t klass)
280 /* TODO optimize this, similar to old harfbuzz code for example */
282 hb_ot_layout_class_t gdef_klass;
283 int len = layout->new_gdef.len;
285 if (HB_UNLIKELY (glyph > 65535))
290 unsigned char *new_klasses;
292 new_len = len == 0 ? 120 : 2 * len;
295 new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
297 if (HB_UNLIKELY (!new_klasses))
300 memset (new_klasses + len, 0, new_len - len);
302 layout->new_gdef.klasses = new_klasses;
303 layout->new_gdef.len = new_len;
308 case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: gdef_klass = GDEF::UnclassifiedGlyph; break;
309 case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: gdef_klass = GDEF::BaseGlyph; break;
310 case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: gdef_klass = GDEF::LigatureGlyph; break;
311 case HB_OT_LAYOUT_GLYPH_CLASS_MARK: gdef_klass = GDEF::MarkGlyph; break;
312 case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: gdef_klass = GDEF::ComponentGlyph; break;
315 layout->new_gdef.klasses[glyph] = gdef_klass;
320 hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout,
321 uint16_t num_total_glyphs,
322 hb_codepoint_t *glyphs,
323 unsigned char *klasses,
326 if (HB_UNLIKELY (!count || !glyphs || !klasses))
329 if (layout->new_gdef.len == 0) {
330 layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
331 layout->new_gdef.len = count;
334 for (unsigned int i = 0; i < count; i++)
335 hb_ot_layout_set_glyph_class (layout, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
339 hb_ot_layout_get_attach_points (hb_ot_layout_t *layout,
340 hb_codepoint_t glyph,
341 unsigned int *point_count /* IN/OUT */,
342 unsigned int *point_array /* OUT */)
344 return layout->gdef->get_attach_points (glyph, point_count, point_array);
348 hb_ot_layout_get_lig_carets (hb_ot_layout_t *layout,
349 hb_codepoint_t glyph,
350 unsigned int *caret_count /* IN/OUT */,
351 int *caret_array /* OUT */)
353 return layout->gdef->get_lig_carets (layout, glyph, caret_count, caret_array);
360 static const GSUBGPOS&
361 get_gsubgpos_table (hb_ot_layout_t *layout,
362 hb_ot_layout_table_type_t table_type)
364 switch (table_type) {
365 case HB_OT_LAYOUT_TABLE_TYPE_GSUB: return *(layout->gsub);
366 case HB_OT_LAYOUT_TABLE_TYPE_GPOS: return *(layout->gpos);
367 default: return Null(GSUBGPOS);
373 hb_ot_layout_table_get_script_count (hb_ot_layout_t *layout,
374 hb_ot_layout_table_type_t table_type)
376 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
378 return g.get_script_count ();
382 hb_ot_layout_table_get_script_tag (hb_ot_layout_t *layout,
383 hb_ot_layout_table_type_t table_type,
384 unsigned int script_index)
386 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
388 return g.get_script_tag (script_index);
392 hb_ot_layout_table_find_script (hb_ot_layout_t *layout,
393 hb_ot_layout_table_type_t table_type,
395 unsigned int *script_index)
397 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
398 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
400 if (g.find_script_index (script_tag, script_index))
403 /* try finding 'DFLT' */
404 if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index))
407 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
408 if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index))
411 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
416 hb_ot_layout_table_get_feature_count (hb_ot_layout_t *layout,
417 hb_ot_layout_table_type_t table_type)
419 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
421 return g.get_feature_count ();
425 hb_ot_layout_table_get_feature_tag (hb_ot_layout_t *layout,
426 hb_ot_layout_table_type_t table_type,
427 unsigned int feature_index)
429 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
431 return g.get_feature_tag (feature_index);
435 hb_ot_layout_table_find_feature (hb_ot_layout_t *layout,
436 hb_ot_layout_table_type_t table_type,
437 hb_tag_t feature_tag,
438 unsigned int *feature_index)
440 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
441 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
443 if (g.find_feature_index (feature_tag, feature_index))
446 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
451 hb_ot_layout_table_get_lookup_count (hb_ot_layout_t *layout,
452 hb_ot_layout_table_type_t table_type)
454 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
456 return g.get_lookup_count ();
461 hb_ot_layout_script_get_language_count (hb_ot_layout_t *layout,
462 hb_ot_layout_table_type_t table_type,
463 unsigned int script_index)
465 const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
467 return s.get_lang_sys_count ();
471 hb_ot_layout_script_get_language_tag (hb_ot_layout_t *layout,
472 hb_ot_layout_table_type_t table_type,
473 unsigned int script_index,
474 unsigned int language_index)
476 const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
478 return s.get_lang_sys_tag (language_index);
482 hb_ot_layout_script_find_language (hb_ot_layout_t *layout,
483 hb_ot_layout_table_type_t table_type,
484 unsigned int script_index,
485 hb_tag_t language_tag,
486 unsigned int *language_index)
488 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
489 const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
491 if (s.find_lang_sys_index (language_tag, language_index))
494 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
495 if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index))
498 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
503 hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t *layout,
504 hb_ot_layout_table_type_t table_type,
505 unsigned int script_index,
506 unsigned int language_index,
507 unsigned int *feature_index)
509 const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
511 if (feature_index) *feature_index = l.get_required_feature_index ();
513 return l.has_required_feature ();
517 hb_ot_layout_language_get_feature_count (hb_ot_layout_t *layout,
518 hb_ot_layout_table_type_t table_type,
519 unsigned int script_index,
520 unsigned int language_index)
522 const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
524 return l.get_feature_count ();
528 hb_ot_layout_language_get_feature_index (hb_ot_layout_t *layout,
529 hb_ot_layout_table_type_t table_type,
530 unsigned int script_index,
531 unsigned int language_index,
532 unsigned int num_feature)
534 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
535 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
537 return l.get_feature_index (num_feature);
541 hb_ot_layout_language_get_feature_tag (hb_ot_layout_t *layout,
542 hb_ot_layout_table_type_t table_type,
543 unsigned int script_index,
544 unsigned int language_index,
545 unsigned int num_feature)
547 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
548 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
549 unsigned int feature_index = l.get_feature_index (num_feature);
551 return g.get_feature_tag (feature_index);
556 hb_ot_layout_language_find_feature (hb_ot_layout_t *layout,
557 hb_ot_layout_table_type_t table_type,
558 unsigned int script_index,
559 unsigned int language_index,
560 hb_tag_t feature_tag,
561 unsigned int *feature_index)
563 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
564 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
565 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
567 unsigned int num_features = l.get_feature_count ();
568 for (unsigned int i = 0; i < num_features; i++) {
569 unsigned int f_index = l.get_feature_index (i);
571 if (feature_tag == g.get_feature_tag (f_index)) {
572 if (feature_index) *feature_index = f_index;
577 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
582 hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t *layout,
583 hb_ot_layout_table_type_t table_type,
584 unsigned int feature_index)
586 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
587 const Feature &f = g.get_feature (feature_index);
589 return f.get_lookup_count ();
593 hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t *layout,
594 hb_ot_layout_table_type_t table_type,
595 unsigned int feature_index,
596 unsigned int num_lookup)
598 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
599 const Feature &f = g.get_feature (feature_index);
601 return f.get_lookup_index (num_lookup);
609 hb_ot_layout_substitute_lookup (hb_ot_layout_t *layout,
611 unsigned int lookup_index,
612 hb_ot_layout_feature_mask_t mask)
614 return layout->gsub->substitute_lookup (layout, buffer, lookup_index, mask);
622 hb_ot_layout_position_lookup (hb_ot_layout_t *layout,
624 unsigned int lookup_index,
625 hb_ot_layout_feature_mask_t mask)
627 return layout->gpos->position_lookup (layout, buffer, lookup_index, mask);