2 * pango-ot-info.c: Store tables for OpenType
4 * Copyright (C) 2000 Red Hat Software
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
24 #include "pango-ot-private.h"
25 #include "pango-impl-utils.h"
26 #include FT_TRUETYPE_TABLES_H
28 static void pango_ot_info_class_init (GObjectClass *object_class);
29 static void pango_ot_info_finalize (GObject *object);
31 static void synthesize_class_def (PangoOTInfo *info);
33 static GObjectClass *parent_class;
36 pango_ot_info_get_type (void)
38 static GType object_type = 0;
40 if (G_UNLIKELY (!object_type))
42 const GTypeInfo object_info =
44 sizeof (PangoOTInfoClass),
46 (GBaseFinalizeFunc) NULL,
47 (GClassInitFunc)pango_ot_info_class_init,
48 NULL, /* class_finalize */
49 NULL, /* class_data */
53 NULL, /* value_table */
56 object_type = g_type_register_static (G_TYPE_OBJECT,
65 pango_ot_info_class_init (GObjectClass *object_class)
67 parent_class = g_type_class_peek_parent (object_class);
69 object_class->finalize = pango_ot_info_finalize;
73 pango_ot_info_finalize (GObject *object)
75 PangoOTInfo *info = PANGO_OT_INFO (object);
78 hb_face_destroy (info->hb_face);
80 parent_class->finalize (object);
84 pango_ot_info_finalizer (void *object)
86 FT_Face face = object;
87 PangoOTInfo *info = face->generic.data;
90 g_object_unref (info);
94 _get_table (hb_tag_t tag, void *user_data)
96 PangoOTInfo *info = (PangoOTInfo *) user_data;
101 error = FT_Load_Sfnt_Table (info->face, tag, 0, NULL, &length);
103 return hb_blob_create_empty ();
105 buffer = g_malloc (length);
107 return hb_blob_create_empty ();
109 error = FT_Load_Sfnt_Table (info->face, tag, 0, buffer, &length);
111 return hb_blob_create_empty ();
113 return hb_blob_create ((const char *) buffer, length,
114 HB_MEMORY_MODE_WRITABLE,
121 * @face: a <type>FT_Face</type>.
123 * Returns the #PangoOTInfo structure for the given FreeType font face.
125 * Return value: the #PangoOTInfo for @face. This object will have
126 * the same lifetime as @face.
131 pango_ot_info_get (FT_Face face)
135 if (G_LIKELY (face->generic.data && face->generic.finalizer == pango_ot_info_finalizer))
136 return face->generic.data;
139 if (face->generic.finalizer)
140 face->generic.finalizer (face->generic.data);
142 info = face->generic.data = g_object_new (PANGO_TYPE_OT_INFO, NULL);
143 face->generic.finalizer = pango_ot_info_finalizer;
147 if (face->stream->base != NULL) {
150 blob = hb_blob_create ((const char *) face->stream->base,
151 (unsigned int) face->stream->size,
152 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
154 info->hb_face = hb_face_create_for_data (blob, face->face_index);
155 hb_blob_destroy (blob);
157 info->hb_face = hb_face_create_for_tables (_get_table, NULL, info);
161 hb_face_set_unicode_funcs (info->hb_face, hb_glib_get_unicode_funcs ());
163 /* XXX this is such a waste if not SFNT */
164 if (!hb_ot_layout_has_font_glyph_classes (info->hb_face))
165 synthesize_class_def (info);
172 _pango_ot_info_get_hb_face (PangoOTInfo *info)
174 return info->hb_face;
177 typedef struct _GlyphInfo GlyphInfo;
180 unsigned short glyph;
181 unsigned short class;
185 compare_glyph_info (gconstpointer a,
188 const GlyphInfo *info_a = a;
189 const GlyphInfo *info_b = b;
191 return (info_a->glyph < info_b->glyph) ? -1 :
192 (info_a->glyph == info_b->glyph) ? 0 : 1;
195 /* Make a guess at the appropriate class for a glyph given
196 * a character code that maps to the glyph
199 get_glyph_class (gunichar charcode,
200 unsigned short *class)
202 /* For characters mapped into the Arabic Presentation forms, using properties
203 * derived as we apply GSUB substitutions will be more reliable
205 if ((charcode >= 0xFB50 && charcode <= 0xFDFF) || /* Arabic Presentation Forms-A */
206 (charcode >= 0xFE70 && charcode <= 0XFEFF)) /* Arabic Presentation Forms-B */
209 switch ((int) g_unichar_type (charcode))
211 case G_UNICODE_COMBINING_MARK:
212 case G_UNICODE_ENCLOSING_MARK:
213 case G_UNICODE_NON_SPACING_MARK:
214 *class = 3; /* Mark glyph (non-spacing combining glyph) */
216 case G_UNICODE_UNASSIGNED:
217 case G_UNICODE_PRIVATE_USE:
218 return FALSE; /* Unknown, don't assign a class; classes get
219 * propagated during GSUB application */
221 *class = 1; /* Base glyph (single character, spacing glyph) */
227 set_unicode_charmap (FT_Face face)
231 for (charmap = 0; charmap < face->num_charmaps; charmap++)
232 if (face->charmaps[charmap]->encoding == ft_encoding_unicode)
234 FT_Error error = FT_Set_Charmap(face, face->charmaps[charmap]);
235 return error == FT_Err_Ok;
241 /* Synthesize a GDEF table using the font's charmap and the
242 * Unicode property database. We'll fill in class definitions
243 * for glyphs not in the charmap as we walk through the tables.
246 synthesize_class_def (PangoOTInfo *info)
249 hb_codepoint_t *glyph_indices;
250 unsigned char *classes;
254 FT_CharMap old_charmap;
256 old_charmap = info->face->charmap;
258 if (!old_charmap || !old_charmap->encoding != ft_encoding_unicode)
259 if (!set_unicode_charmap (info->face))
262 glyph_infos = g_array_new (FALSE, FALSE, sizeof (GlyphInfo));
264 /* Collect all the glyphs in the charmap, and guess
265 * the appropriate classes for them
267 charcode = FT_Get_First_Char (info->face, &glyph);
270 GlyphInfo glyph_info;
274 glyph_info.glyph = glyph;
275 if (get_glyph_class (charcode, &glyph_info.class))
276 g_array_append_val (glyph_infos, glyph_info);
279 charcode = FT_Get_Next_Char (info->face, charcode, &glyph);
282 /* Sort and remove duplicates
284 g_array_sort (glyph_infos, compare_glyph_info);
286 glyph_indices = g_new (hb_codepoint_t, glyph_infos->len);
287 classes = g_new (unsigned char, glyph_infos->len);
289 for (i = 0, j = 0; i < glyph_infos->len; i++)
291 GlyphInfo *info = &g_array_index (glyph_infos, GlyphInfo, i);
293 if (j == 0 || info->glyph != glyph_indices[j - 1])
295 glyph_indices[j] = info->glyph;
296 classes[j] = info->class;
302 g_array_free (glyph_infos, TRUE);
304 hb_ot_layout_build_glyph_classes (info->hb_face, info->face->num_glyphs,
305 glyph_indices, classes, j);
307 g_free (glyph_indices);
310 if (old_charmap && info->face->charmap != old_charmap)
311 FT_Set_Charmap (info->face, old_charmap);
315 get_hb_table_type (PangoOTTableType table_type)
317 switch (table_type) {
318 case PANGO_OT_TABLE_GSUB: return HB_OT_TAG_GSUB;
319 case PANGO_OT_TABLE_GPOS: return HB_OT_TAG_GPOS;
320 default: return HB_TAG_NONE;
325 * pango_ot_info_find_script:
326 * @info: a #PangoOTInfo.
327 * @table_type: the table type to obtain information about.
328 * @script_tag: the tag of the script to find.
329 * @script_index: location to store the index of the script, or %NULL.
331 * Finds the index of a script. If not found, tries to find the 'DFLT'
332 * and then 'dflt' scripts and return the index of that in @script_index.
333 * If none of those is found either, %PANGO_OT_NO_SCRIPT is placed in
336 * All other functions taking an input script_index parameter know
337 * how to handle %PANGO_OT_NO_SCRIPT, so one can ignore the return
338 * value of this function completely and proceed, to enjoy the automatic
339 * fallback to the 'DFLT'/'dflt' script.
341 * Return value: %TRUE if the script was found.
344 pango_ot_info_find_script (PangoOTInfo *info,
345 PangoOTTableType table_type,
346 PangoOTTag script_tag,
349 hb_tag_t tt = get_hb_table_type (table_type);
351 return hb_ot_layout_table_find_script (info->hb_face, tt,
357 * pango_ot_info_find_language:
358 * @info: a #PangoOTInfo.
359 * @table_type: the table type to obtain information about.
360 * @script_index: the index of the script whose languages are searched.
361 * @language_tag: the tag of the language to find.
362 * @language_index: location to store the index of the language, or %NULL.
363 * @required_feature_index: location to store the required feature index of
364 * the language, or %NULL.
366 * Finds the index of a language and its required feature index.
367 * If the language is not found, sets @language_index to
368 * PANGO_OT_DEFAULT_LANGUAGE and the required feature of the default language
369 * system is returned in required_feature_index. For best compatibility with
370 * some fonts, also searches the language system tag 'dflt' before falling
371 * back to the default language system, but that is transparent to the user.
372 * The user can simply ignore the return value of this function to
373 * automatically fall back to the default language system.
375 * Return value: %TRUE if the language was found.
378 pango_ot_info_find_language (PangoOTInfo *info,
379 PangoOTTableType table_type,
381 PangoOTTag language_tag,
382 guint *language_index,
383 guint *required_feature_index)
387 hb_tag_t tt = get_hb_table_type (table_type);
389 ret = hb_ot_layout_script_find_language (info->hb_face, tt,
393 if (language_index) *language_index = l_index;
395 hb_ot_layout_language_get_required_feature_index (info->hb_face, tt,
398 required_feature_index);
404 * pango_ot_info_find_feature:
405 * @info: a #PangoOTInfo.
406 * @table_type: the table type to obtain information about.
407 * @feature_tag: the tag of the feature to find.
408 * @script_index: the index of the script.
409 * @language_index: the index of the language whose features are searched,
410 * or %PANGO_OT_DEFAULT_LANGUAGE to use the default language of the script.
411 * @feature_index: location to store the index of the feature, or %NULL.
413 * Finds the index of a feature. If the feature is not found, sets
414 * @feature_index to PANGO_OT_NO_FEATURE, which is safe to pass to
415 * pango_ot_ruleset_add_feature() and similar functions.
417 * In the future, this may set @feature_index to an special value that if used
418 * in pango_ot_ruleset_add_feature() will ask Pango to synthesize the
419 * requested feature based on Unicode properties and data. However, this
420 * function will still return %FALSE in those cases. So, users may want to
421 * ignore the return value of this function in certain cases.
423 * Return value: %TRUE if the feature was found.
426 pango_ot_info_find_feature (PangoOTInfo *info,
427 PangoOTTableType table_type,
428 PangoOTTag feature_tag,
430 guint language_index,
431 guint *feature_index)
433 hb_tag_t tt = get_hb_table_type (table_type);
435 return hb_ot_layout_language_find_feature (info->hb_face, tt,
443 * pango_ot_info_list_scripts:
444 * @info: a #PangoOTInfo.
445 * @table_type: the table type to obtain information about.
447 * Obtains the list of available scripts.
449 * Return value: a newly-allocated zero-terminated array containing the tags of the
450 * available scripts. Should be freed using g_free().
453 pango_ot_info_list_scripts (PangoOTInfo *info,
454 PangoOTTableType table_type)
456 hb_tag_t tt = get_hb_table_type (table_type);
458 unsigned int count = 0;
460 hb_ot_layout_table_get_script_tags (info->hb_face, tt, &count, NULL);
461 result = g_new (PangoOTTag, count + 1);
462 hb_ot_layout_table_get_script_tags (info->hb_face, tt, &count, result);
469 * pango_ot_info_list_languages:
470 * @info: a #PangoOTInfo.
471 * @table_type: the table type to obtain information about.
472 * @script_index: the index of the script to list languages for.
473 * @language_tag: unused parameter.
475 * Obtains the list of available languages for a given script.
477 * Return value: a newly-allocated zero-terminated array containing the tags of the
478 * available languages. Should be freed using g_free().
481 pango_ot_info_list_languages (PangoOTInfo *info,
482 PangoOTTableType table_type,
484 PangoOTTag language_tag G_GNUC_UNUSED)
486 hb_tag_t tt = get_hb_table_type (table_type);
488 unsigned int count = 0;
490 hb_ot_layout_script_get_language_tags (info->hb_face, tt, script_index, &count, NULL);
491 result = g_new (PangoOTTag, count + 1);
492 hb_ot_layout_script_get_language_tags (info->hb_face, tt, script_index, &count, result);
499 * pango_ot_info_list_features:
500 * @info: a #PangoOTInfo.
501 * @table_type: the table type to obtain information about.
502 * @tag: unused parameter.
503 * @script_index: the index of the script to obtain information about.
504 * @language_index: the index of the language to list features for, or
505 * %PANGO_OT_DEFAULT_LANGUAGE, to list features for the default
506 * language of the script.
508 * Obtains the list of features for the given language of the given script.
510 * Return value: a newly-allocated zero-terminated array containing the tags of the
511 * available features. Should be freed using g_free().
514 pango_ot_info_list_features (PangoOTInfo *info,
515 PangoOTTableType table_type,
516 PangoOTTag tag G_GNUC_UNUSED,
518 guint language_index)
520 hb_tag_t tt = get_hb_table_type (table_type);
522 unsigned int count = 0;
524 hb_ot_layout_language_get_feature_tags (info->hb_face, tt, script_index, language_index, &count, NULL);
525 result = g_new (PangoOTTag, count + 1);
526 hb_ot_layout_language_get_feature_tags (info->hb_face, tt, script_index, language_index, &count, result);
533 _pango_ot_info_substitute (const PangoOTInfo *info,
534 const PangoOTRuleset *ruleset,
535 PangoOTBuffer *buffer)
539 for (i = 0; i < ruleset->rules->len; i++)
541 PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
543 unsigned int lookup_count, j;
544 unsigned int lookup_indexes[1000];
546 if (rule->table_type != PANGO_OT_TABLE_GSUB)
549 mask = rule->property_bit;
550 lookup_count = G_N_ELEMENTS (lookup_indexes);
551 hb_ot_layout_feature_get_lookup_indexes (info->hb_face,
557 lookup_count = MIN (G_N_ELEMENTS (lookup_indexes), lookup_count);
558 for (j = 0; j < lookup_count; j++)
559 hb_ot_layout_substitute_lookup (info->hb_face,
567 _pango_ot_info_position (const PangoOTInfo *info,
568 const PangoOTRuleset *ruleset,
569 PangoOTBuffer *buffer)
575 hb_buffer_clear_positions (buffer->buffer);
577 /* XXX reuse hb_font */
578 hb_font = hb_font_create ();
579 hb_font_set_scale (hb_font,
580 info->face->size->metrics.x_scale,
581 info->face->size->metrics.y_scale);
582 is_hinted = buffer->font->is_hinted;
583 hb_font_set_ppem (hb_font,
584 is_hinted ? info->face->size->metrics.x_ppem : 0,
585 is_hinted ? info->face->size->metrics.y_ppem : 0);
587 for (i = 0; i < ruleset->rules->len; i++)
589 PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
591 unsigned int lookup_count, j;
592 unsigned int lookup_indexes[1000];
594 if (rule->table_type != PANGO_OT_TABLE_GPOS)
597 mask = rule->property_bit;
598 lookup_count = G_N_ELEMENTS (lookup_indexes);
599 hb_ot_layout_feature_get_lookup_indexes (info->hb_face,
605 lookup_count = MIN (G_N_ELEMENTS (lookup_indexes), lookup_count);
606 for (j = 0; j < lookup_count; j++)
607 hb_ot_layout_position_lookup (info->hb_face, hb_font,
612 buffer->applied_gpos = TRUE;
615 if (buffer->applied_gpos)
618 unsigned int len = hb_buffer_get_len (buffer->buffer);
619 hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer->buffer);
621 /* First handle all left-to-right connections */
622 for (j = 0; j < len; j++)
624 if (positions[j].cursive_chain > 0)
625 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
628 /* Then handle all right-to-left connections */
629 for (i = len; i > 0; i--)
633 if (positions[j].cursive_chain < 0)
634 positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
638 hb_font_destroy (hb_font);