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_scale (hb_ot_layout_t *layout,
119 hb_16dot16_t x_scale, hb_16dot16_t y_scale)
121 layout->gpos_info.x_scale = x_scale;
122 layout->gpos_info.y_scale = y_scale;
126 hb_ot_layout_set_ppem (hb_ot_layout_t *layout,
127 unsigned int x_ppem, unsigned int y_ppem)
129 layout->gpos_info.x_ppem = x_ppem;
130 layout->gpos_info.y_ppem = y_ppem;
138 /* TODO the public class_t is a mess */
141 hb_ot_layout_has_font_glyph_classes (hb_ot_layout_t *layout)
143 return layout->gdef->has_glyph_classes ();
146 HB_INTERNAL hb_bool_t
147 _hb_ot_layout_has_new_glyph_classes (hb_ot_layout_t *layout)
149 return layout->new_gdef.len > 0;
152 HB_INTERNAL unsigned int
153 _hb_ot_layout_get_glyph_property (hb_ot_layout_t *layout,
154 hb_codepoint_t glyph)
156 hb_ot_layout_class_t klass;
158 klass = layout->gdef->get_glyph_class (glyph);
160 if (!klass && glyph < layout->new_gdef.len)
161 klass = layout->new_gdef.klasses[glyph];
165 case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
166 case GDEF::BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
167 case GDEF::LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
168 case GDEF::ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
169 case GDEF::MarkGlyph:
170 /* TODO old harfbuzz doesn't always parse mark attachments as it says it was
171 * introduced without a version bump, so it may not be safe */
172 klass = layout->gdef->get_mark_attachment_type (glyph);
173 return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
177 HB_INTERNAL hb_bool_t
178 _hb_ot_layout_check_glyph_property (hb_ot_layout_t *layout,
179 hb_glyph_info_t *ginfo,
180 unsigned int lookup_flags,
181 unsigned int *property_out)
183 unsigned int property;
185 if (ginfo->internal == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
186 ginfo->internal = _hb_ot_layout_get_glyph_property (layout, ginfo->gindex);
187 property = ginfo->internal;
189 *property_out = property;
191 /* Not covered, if, for example, glyph class is ligature and
192 * lookup_flags includes LookupFlags::IgnoreLigatures
194 if (property & lookup_flags)
197 if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
199 /* If using mark filtering sets, the high short of
200 * lookup_flags has the set index.
202 if (lookup_flags & LookupFlag::UseMarkFilteringSet)
203 return layout->gdef->mark_set_covers (lookup_flags >> 16, ginfo->gindex);
205 /* The second byte of lookup_flags has the meaning
206 * "ignore marks of attachment type different than
207 * the attachment type specified."
209 if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
210 return (lookup_flags & LookupFlag::MarkAttachmentType) == (property & LookupFlag::MarkAttachmentType);
216 HB_INTERNAL hb_bool_t
217 _hb_ot_layout_skip_mark (hb_ot_layout_t *layout,
218 hb_glyph_info_t *ginfo,
219 unsigned int lookup_flags,
220 unsigned int *property_out)
222 unsigned int property;
224 if (ginfo->internal == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
225 ginfo->internal = _hb_ot_layout_get_glyph_property (layout, ginfo->gindex);
226 property = ginfo->internal;
228 *property_out = property;
230 if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
232 /* Skip mark if lookup_flags includes LookupFlags::IgnoreMarks */
233 if (lookup_flags & LookupFlag::IgnoreMarks)
236 /* If using mark filtering sets, the high short of lookup_flags has the set index. */
237 if (lookup_flags & LookupFlag::UseMarkFilteringSet)
238 return !layout->gdef->mark_set_covers (lookup_flags >> 16, ginfo->gindex);
240 /* The second byte of lookup_flags has the meaning "ignore marks of attachment type
241 * different than the attachment type specified." */
242 if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
243 return (lookup_flags & LookupFlag::MarkAttachmentType) != (property & LookupFlag::MarkAttachmentType);
250 _hb_ot_layout_set_glyph_property (hb_ot_layout_t *layout,
251 hb_codepoint_t glyph,
252 unsigned int property)
253 { hb_ot_layout_set_glyph_class (layout, glyph, (hb_ot_layout_glyph_class_t) (property & 0xff)); }
256 hb_ot_layout_glyph_class_t
257 hb_ot_layout_get_glyph_class (hb_ot_layout_t *layout,
258 hb_codepoint_t glyph)
259 { return (hb_ot_layout_glyph_class_t) (_hb_ot_layout_get_glyph_property (layout, glyph) & 0xff); }
262 hb_ot_layout_set_glyph_class (hb_ot_layout_t *layout,
263 hb_codepoint_t glyph,
264 hb_ot_layout_glyph_class_t klass)
266 /* TODO optimize this, similar to old harfbuzz code for example */
268 hb_ot_layout_class_t gdef_klass;
269 int len = layout->new_gdef.len;
271 if (HB_UNLIKELY (glyph > 65535))
276 unsigned char *new_klasses;
278 new_len = len == 0 ? 120 : 2 * len;
281 new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
283 if (HB_UNLIKELY (!new_klasses))
286 memset (new_klasses + len, 0, new_len - len);
288 layout->new_gdef.klasses = new_klasses;
289 layout->new_gdef.len = new_len;
294 case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: gdef_klass = GDEF::UnclassifiedGlyph; break;
295 case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: gdef_klass = GDEF::BaseGlyph; break;
296 case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: gdef_klass = GDEF::LigatureGlyph; break;
297 case HB_OT_LAYOUT_GLYPH_CLASS_MARK: gdef_klass = GDEF::MarkGlyph; break;
298 case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: gdef_klass = GDEF::ComponentGlyph; break;
301 layout->new_gdef.klasses[glyph] = gdef_klass;
306 hb_ot_layout_build_glyph_classes (hb_ot_layout_t *layout,
307 uint16_t num_total_glyphs,
308 hb_codepoint_t *glyphs,
309 unsigned char *klasses,
312 if (HB_UNLIKELY (!count || !glyphs || !klasses))
315 if (layout->new_gdef.len == 0) {
316 layout->new_gdef.klasses = (unsigned char *) calloc (num_total_glyphs, sizeof (unsigned char));
317 layout->new_gdef.len = count;
320 for (unsigned int i = 0; i < count; i++)
321 hb_ot_layout_set_glyph_class (layout, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
325 hb_ot_layout_get_attach_points (hb_ot_layout_t *layout,
326 hb_codepoint_t glyph,
327 unsigned int *point_count /* IN/OUT */,
328 unsigned int *point_array /* OUT */)
330 return layout->gdef->get_attach_points (glyph, point_count, point_array);
334 hb_ot_layout_get_lig_carets (hb_ot_layout_t *layout,
335 hb_codepoint_t glyph,
336 unsigned int *caret_count /* IN/OUT */,
337 int *caret_array /* OUT */)
339 return layout->gdef->get_lig_carets (layout, glyph, caret_count, caret_array);
346 static const GSUBGPOS&
347 get_gsubgpos_table (hb_ot_layout_t *layout,
348 hb_ot_layout_table_type_t table_type)
350 switch (table_type) {
351 case HB_OT_LAYOUT_TABLE_TYPE_GSUB: return *(layout->gsub);
352 case HB_OT_LAYOUT_TABLE_TYPE_GPOS: return *(layout->gpos);
353 default: return Null(GSUBGPOS);
359 hb_ot_layout_table_get_script_count (hb_ot_layout_t *layout,
360 hb_ot_layout_table_type_t table_type)
362 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
364 return g.get_script_count ();
368 hb_ot_layout_table_get_script_tag (hb_ot_layout_t *layout,
369 hb_ot_layout_table_type_t table_type,
370 unsigned int script_index)
372 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
374 return g.get_script_tag (script_index);
378 hb_ot_layout_table_find_script (hb_ot_layout_t *layout,
379 hb_ot_layout_table_type_t table_type,
381 unsigned int *script_index)
383 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
384 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
386 if (g.find_script_index (script_tag, script_index))
389 /* try finding 'DFLT' */
390 if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_SCRIPT, script_index))
393 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
394 if (g.find_script_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, script_index))
397 if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
402 hb_ot_layout_table_get_feature_count (hb_ot_layout_t *layout,
403 hb_ot_layout_table_type_t table_type)
405 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
407 return g.get_feature_count ();
411 hb_ot_layout_table_get_feature_tag (hb_ot_layout_t *layout,
412 hb_ot_layout_table_type_t table_type,
413 unsigned int feature_index)
415 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
417 return g.get_feature_tag (feature_index);
421 hb_ot_layout_table_find_feature (hb_ot_layout_t *layout,
422 hb_ot_layout_table_type_t table_type,
423 hb_tag_t feature_tag,
424 unsigned int *feature_index)
426 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
427 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
429 if (g.find_feature_index (feature_tag, feature_index))
432 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
437 hb_ot_layout_table_get_lookup_count (hb_ot_layout_t *layout,
438 hb_ot_layout_table_type_t table_type)
440 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
442 return g.get_lookup_count ();
447 hb_ot_layout_script_get_language_count (hb_ot_layout_t *layout,
448 hb_ot_layout_table_type_t table_type,
449 unsigned int script_index)
451 const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
453 return s.get_lang_sys_count ();
457 hb_ot_layout_script_get_language_tag (hb_ot_layout_t *layout,
458 hb_ot_layout_table_type_t table_type,
459 unsigned int script_index,
460 unsigned int language_index)
462 const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
464 return s.get_lang_sys_tag (language_index);
468 hb_ot_layout_script_find_language (hb_ot_layout_t *layout,
469 hb_ot_layout_table_type_t table_type,
470 unsigned int script_index,
471 hb_tag_t language_tag,
472 unsigned int *language_index)
474 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
475 const Script &s = get_gsubgpos_table (layout, table_type).get_script (script_index);
477 if (s.find_lang_sys_index (language_tag, language_index))
480 /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
481 if (s.find_lang_sys_index (HB_OT_LAYOUT_TAG_DEFAULT_LANGUAGE, language_index))
484 if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
489 hb_ot_layout_language_get_required_feature_index (hb_ot_layout_t *layout,
490 hb_ot_layout_table_type_t table_type,
491 unsigned int script_index,
492 unsigned int language_index,
493 unsigned int *feature_index)
495 const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
497 if (feature_index) *feature_index = l.get_required_feature_index ();
499 return l.has_required_feature ();
503 hb_ot_layout_language_get_feature_count (hb_ot_layout_t *layout,
504 hb_ot_layout_table_type_t table_type,
505 unsigned int script_index,
506 unsigned int language_index)
508 const LangSys &l = get_gsubgpos_table (layout, table_type).get_script (script_index).get_lang_sys (language_index);
510 return l.get_feature_count ();
514 hb_ot_layout_language_get_feature_index (hb_ot_layout_t *layout,
515 hb_ot_layout_table_type_t table_type,
516 unsigned int script_index,
517 unsigned int language_index,
518 unsigned int num_feature)
520 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
521 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
523 return l.get_feature_index (num_feature);
527 hb_ot_layout_language_get_feature_tag (hb_ot_layout_t *layout,
528 hb_ot_layout_table_type_t table_type,
529 unsigned int script_index,
530 unsigned int language_index,
531 unsigned int num_feature)
533 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
534 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
535 unsigned int feature_index = l.get_feature_index (num_feature);
537 return g.get_feature_tag (feature_index);
542 hb_ot_layout_language_find_feature (hb_ot_layout_t *layout,
543 hb_ot_layout_table_type_t table_type,
544 unsigned int script_index,
545 unsigned int language_index,
546 hb_tag_t feature_tag,
547 unsigned int *feature_index)
549 ASSERT_STATIC (NO_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
550 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
551 const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
553 unsigned int num_features = l.get_feature_count ();
554 for (unsigned int i = 0; i < num_features; i++) {
555 unsigned int f_index = l.get_feature_index (i);
557 if (feature_tag == g.get_feature_tag (f_index)) {
558 if (feature_index) *feature_index = f_index;
563 if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
568 hb_ot_layout_feature_get_lookup_count (hb_ot_layout_t *layout,
569 hb_ot_layout_table_type_t table_type,
570 unsigned int feature_index)
572 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
573 const Feature &f = g.get_feature (feature_index);
575 return f.get_lookup_count ();
579 hb_ot_layout_feature_get_lookup_index (hb_ot_layout_t *layout,
580 hb_ot_layout_table_type_t table_type,
581 unsigned int feature_index,
582 unsigned int num_lookup)
584 const GSUBGPOS &g = get_gsubgpos_table (layout, table_type);
585 const Feature &f = g.get_feature (feature_index);
587 return f.get_lookup_index (num_lookup);
595 hb_ot_layout_substitute_lookup (hb_ot_layout_t *layout,
597 unsigned int lookup_index,
598 hb_ot_layout_feature_mask_t mask)
600 return layout->gsub->substitute_lookup (layout, buffer, lookup_index, mask);
608 hb_ot_layout_position_lookup (hb_ot_layout_t *layout,
610 unsigned int lookup_index,
611 hb_ot_layout_feature_mask_t mask)
613 return layout->gpos->position_lookup (layout, buffer, lookup_index, mask);