4 * Copyright (C) 2011-2019 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 /* originally file `afglobal.c' (2011-Mar-28) from FreeType */
18 /* heavily modified 2011 by Werner Lemberg <wl@gnu.org> */
27 #define SCRIPT(s, S, d, h, H, ss) \
28 const TA_ScriptClassRec ta_ ## s ## _script_class = \
31 ta_ ## s ## _uniranges, \
32 ta_ ## s ## _nonbase_uniranges, \
37 #include <ttfautohint-scripts.h>
41 #define STYLE(s, S, d, ws, sc, ss, c) \
42 const TA_StyleClassRec ta_ ## s ## _style_class = \
54 /* get writing system specific header files */
56 #define WRITING_SYSTEM(ws, WS) /* empty */
61 #define WRITING_SYSTEM(ws, WS) \
62 &ta_ ## ws ## _writing_system_class,
64 TA_WritingSystemClass
const ta_writing_system_classes
[] =
69 NULL
/* do not remove */
74 #define SCRIPT(s, S, d, h, H, ss) \
75 &ta_ ## s ## _script_class,
77 TA_ScriptClass
const ta_script_classes
[] =
80 #include <ttfautohint-scripts.h>
82 NULL
/* do not remove */
87 #define STYLE(s, S, d, ws, sc, ss, c) \
88 &ta_ ## s ## _style_class,
90 TA_StyleClass
const ta_style_classes
[] =
95 NULL
/* do not remove */
102 #define STYLE(s, S, d, ws, sc, ss, c) #s,
104 const char* ta_style_names
[] =
107 #include <tastyles.h>
111 #endif /* TA_DEBUG */
114 /* Recursively assign a style to all components of a composite glyph. */
117 ta_face_globals_scan_composite(FT_Face face
,
121 FT_Int nesting_level
)
128 FT_Int
* subglyph_indices
= NULL
;
129 FT_UInt used_subglyphs
;
135 FT_Matrix p_transform
;
138 /* limit recursion arbitrarily */
139 if (nesting_level
> 100)
140 return FT_Err_Invalid_Table
;
142 error
= FT_Load_Glyph(face
, (FT_UInt
)gindex
, FT_LOAD_NO_RECURSE
);
148 /* in FreeType < 2.5.4, FT_Get_SubGlyph_Info always returns an error */
149 /* due to a bug even if the call was successful; */
150 /* for this reason we do the argument checking by ourselves */
151 /* and ignore the returned error code of FT_Get_SubGlyph_Info */
152 if (!glyph
->subglyphs
153 || glyph
->format
!= FT_GLYPH_FORMAT_COMPOSITE
)
156 /* since a call to FT_Load_Glyph changes `glyph', */
157 /* we have to first store the subglyph indices, then do the recursion */
158 subglyph_indices
= (FT_Int
*)malloc(sizeof (FT_Int
) * glyph
->num_subglyphs
);
159 if (!subglyph_indices
)
160 return FT_Err_Out_Of_Memory
;
163 for (i
= 0; i
< glyph
->num_subglyphs
; i
++)
165 (void)FT_Get_SubGlyph_Info(glyph
,
173 if (p_index
>= face
->num_glyphs
174 || (gstyles
[p_index
] & TA_STYLE_MASK
) != TA_STYLE_UNASSIGNED
)
177 /* only take subglyphs that are not shifted vertically; */
178 /* otherwise blue zones don't fit */
179 if (p_flags
& ARGS_ARE_XY_VALUES
182 gstyles
[p_index
] = gstyle
;
183 subglyph_indices
[used_subglyphs
++] = p_index
;
188 for (i
= 0; i
< used_subglyphs
; i
++)
190 error
= ta_face_globals_scan_composite(face
,
199 free(subglyph_indices
);
205 /* Compute the style index of each glyph within a given face. */
208 ta_face_globals_compute_style_coverage(TA_FaceGlobals globals
)
211 FT_Face face
= globals
->face
;
212 FT_CharMap old_charmap
= face
->charmap
;
213 FT_UShort
* gstyles
= globals
->glyph_styles
;
216 FT_UInt dflt
= ~0U; /* a non-valid value */
219 /* the value TA_STYLE_UNASSIGNED means `uncovered glyph' */
220 for (i
= 0; i
< (unsigned int)globals
->glyph_count
; i
++)
221 gstyles
[i
] = TA_STYLE_UNASSIGNED
;
223 error
= FT_Select_Charmap(face
, FT_ENCODING_UNICODE
);
226 /* ignore this error; we simply use the fallback style */
227 /* XXX: Shouldn't we rather disable hinting? */
232 /* scan each style in a Unicode charmap */
233 for (ss
= 0; ta_style_classes
[ss
]; ss
++)
235 TA_StyleClass style_class
= ta_style_classes
[ss
];
236 FT_UInt
* sample_glyph
= &globals
->sample_glyphs
[ss
];
237 TA_ScriptClass script_class
= ta_script_classes
[style_class
->script
];
238 TA_Script_UniRange range
;
241 if (!script_class
->script_uni_ranges
->first
)
244 /* scan all Unicode points in the range and */
245 /* set the corresponding glyph style index */
246 if (style_class
->coverage
== TA_COVERAGE_DEFAULT
)
248 if ((FT_UInt
)style_class
->script
== globals
->font
->default_script
)
251 for (range
= script_class
->script_uni_ranges
;
255 FT_ULong charcode
= range
->first
;
259 gindex
= FT_Get_Char_Index(face
, charcode
);
262 && gindex
< (FT_ULong
)globals
->glyph_count
263 && (gstyles
[gindex
] & TA_STYLE_MASK
) == TA_STYLE_UNASSIGNED
)
265 gstyles
[gindex
] = (FT_UShort
)ss
;
267 *sample_glyph
= gindex
;
272 charcode
= FT_Get_Next_Char(face
, charcode
, &gindex
);
274 if (gindex
== 0 || charcode
> range
->last
)
277 if (gindex
< (FT_ULong
)globals
->glyph_count
278 && (gstyles
[gindex
] & TA_STYLE_MASK
) == TA_STYLE_UNASSIGNED
)
280 gstyles
[gindex
] = (FT_UShort
)ss
;
282 *sample_glyph
= gindex
;
287 /* do the same for the script's non-base characters */
288 for (range
= script_class
->script_uni_nonbase_ranges
;
292 FT_ULong charcode
= range
->first
;
296 gindex
= FT_Get_Char_Index(face
, charcode
);
299 && gindex
< (FT_ULong
)globals
->glyph_count
300 && (gstyles
[gindex
] & TA_STYLE_MASK
) == (FT_UShort
)ss
)
302 gstyles
[gindex
] |= TA_NONBASE
;
304 *sample_glyph
= gindex
;
309 charcode
= FT_Get_Next_Char(face
, charcode
, &gindex
);
311 if (gindex
== 0 || charcode
> range
->last
)
314 if (gindex
< (FT_ULong
)globals
->glyph_count
315 && (gstyles
[gindex
] & TA_STYLE_MASK
) == (FT_UShort
)ss
)
317 gstyles
[gindex
] |= TA_NONBASE
;
319 *sample_glyph
= gindex
;
326 /* get glyphs not directly addressable by cmap */
327 ta_shaper_get_coverage(globals
,
335 /* handle the remaining default OpenType features ... */
336 for (ss
= 0; ta_style_classes
[ss
]; ss
++)
338 TA_StyleClass style_class
= ta_style_classes
[ss
];
339 FT_UInt
* sample_glyph
= &globals
->sample_glyphs
[ss
];
342 if (style_class
->coverage
== TA_COVERAGE_DEFAULT
)
343 ta_shaper_get_coverage(globals
,
350 /* ... and finally the default OpenType features of the default script */
351 ta_shaper_get_coverage(globals
,
352 ta_style_classes
[dflt
],
354 &globals
->sample_glyphs
[dflt
],
357 /* mark ASCII digits */
358 for (i
= 0x30; i
<= 0x39; i
++)
360 FT_UInt gindex
= FT_Get_Char_Index(face
, i
);
364 && gindex
< (FT_ULong
)globals
->glyph_count
)
365 gstyles
[gindex
] |= TA_DIGIT
;
368 /* now walk over all glyphs and check for composites: */
369 /* since subglyphs are hinted separately if option `hint-composites' */
370 /* isn't set, we have to tag them with style indices, too */
375 /* no need for updating `sample_glyphs'; */
376 /* the composite itself is certainly a valid sample glyph */
378 for (nn
= 0; nn
< globals
->glyph_count
; nn
++)
380 if ((gstyles
[nn
] & TA_STYLE_MASK
) == TA_STYLE_UNASSIGNED
)
383 error
= ta_face_globals_scan_composite(globals
->face
,
394 /* by default, all uncovered glyphs are set to the fallback style */
395 /* XXX: Shouldn't we disable hinting or do something similar? */
396 if (globals
->font
->fallback_style
!= (TA_Style
)TA_STYLE_UNASSIGNED
)
401 for (nn
= 0; nn
< globals
->glyph_count
; nn
++)
403 if ((gstyles
[nn
] & TA_STYLE_MASK
) == TA_STYLE_UNASSIGNED
)
405 gstyles
[nn
] &= ~TA_STYLE_MASK
;
406 gstyles
[nn
] |= globals
->font
->fallback_style
;
413 if (face
->num_faces
> 1)
415 "style coverage (subfont %d, glyf table index %d)\n"
416 "================================================\n"
419 globals
->font
->sfnts
[face
->face_index
].glyf_idx
));
426 for (ss
= 0; ta_style_classes
[ss
]; ss
++)
428 TA_StyleClass style_class
= ta_style_classes
[ss
];
433 TA_LOG_GLOBAL(("%s:\n", ta_style_names
[style_class
->style
]));
435 for (idx
= 0; idx
< globals
->glyph_count
; idx
++)
437 if ((gstyles
[idx
] & TA_STYLE_MASK
) == style_class
->style
)
440 TA_LOG_GLOBAL((" "));
442 TA_LOG_GLOBAL((" %d", idx
));
446 TA_LOG_GLOBAL(("\n"));
451 TA_LOG_GLOBAL((" (none)\n"));
453 TA_LOG_GLOBAL(("\n"));
456 #endif /* TA_DEBUG */
458 FT_Set_Charmap(face
, old_charmap
);
464 ta_face_globals_new(FT_Face face
,
465 TA_FaceGlobals
*aglobals
,
469 TA_FaceGlobals globals
;
472 /* we allocate an TA_FaceGlobals structure together */
473 /* with the glyph_styles array */
474 globals
= (TA_FaceGlobals
)calloc(
475 1, sizeof (TA_FaceGlobalsRec
) +
476 (FT_ULong
)face
->num_glyphs
* sizeof (FT_UShort
));
479 error
= FT_Err_Out_Of_Memory
;
483 globals
->face
= face
;
484 globals
->glyph_count
= face
->num_glyphs
;
485 /* right after the globals structure come the glyph styles */
486 globals
->glyph_styles
= (FT_UShort
*)(globals
+ 1);
487 globals
->font
= font
;
488 globals
->hb_font
= hb_ft_font_create(face
, NULL
);
489 globals
->hb_buf
= hb_buffer_create();
491 error
= ta_face_globals_compute_style_coverage(globals
);
494 ta_face_globals_free(globals
);
498 globals
->increase_x_height
= TA_PROP_INCREASE_X_HEIGHT_MAX
;
507 ta_face_globals_free(TA_FaceGlobals globals
)
514 for (nn
= 0; nn
< TA_STYLE_MAX
; nn
++)
516 if (globals
->metrics
[nn
])
518 TA_StyleClass style_class
=
519 ta_style_classes
[nn
];
520 TA_WritingSystemClass writing_system_class
=
521 ta_writing_system_classes
[style_class
->writing_system
];
524 if (writing_system_class
->style_metrics_done
)
525 writing_system_class
->style_metrics_done(globals
->metrics
[nn
]);
527 free(globals
->metrics
[nn
]);
531 hb_font_destroy(globals
->hb_font
);
532 hb_buffer_destroy(globals
->hb_buf
);
534 /* no need to free `globals->glyph_styles'; */
535 /* it is part of the `globals' array */
542 ta_face_globals_get_metrics(TA_FaceGlobals globals
,
545 TA_StyleMetrics
*ametrics
)
547 TA_StyleMetrics metrics
= NULL
;
548 TA_Style style
= (TA_Style
)options
;
549 TA_WritingSystemClass writing_system_class
;
550 TA_StyleClass style_class
;
551 FT_Error error
= FT_Err_Ok
;
554 if (gindex
>= (FT_ULong
)globals
->glyph_count
)
556 error
= FT_Err_Invalid_Argument
;
560 /* if we have a forced style (via `options'), use it, */
561 /* otherwise look into `glyph_styles' array */
562 if (style
== TA_STYLE_NONE_DFLT
|| style
+ 1 >= TA_STYLE_MAX
)
563 style
= (TA_Style
)(globals
->glyph_styles
[gindex
]
564 & TA_STYLE_UNASSIGNED
);
567 ta_style_classes
[style
];
568 writing_system_class
=
569 ta_writing_system_classes
[style_class
->writing_system
];
571 metrics
= globals
->metrics
[style
];
574 /* create the global metrics object if necessary */
575 metrics
= (TA_StyleMetrics
)
576 calloc(1, writing_system_class
->style_metrics_size
);
579 error
= FT_Err_Out_Of_Memory
;
583 metrics
->style_class
= style_class
;
584 metrics
->globals
= globals
;
586 if (writing_system_class
->style_metrics_init
)
588 error
= writing_system_class
->style_metrics_init(
591 globals
->font
->reference
);
594 if (writing_system_class
->style_metrics_done
)
595 writing_system_class
->style_metrics_done(metrics
);
603 globals
->metrics
[style
] = metrics
;
614 ta_face_globals_is_digit(TA_FaceGlobals globals
,
617 if (gindex
< (FT_ULong
)globals
->glyph_count
)
618 return (FT_Bool
)(globals
->glyph_styles
[gindex
] & TA_DIGIT
);
623 /* end of taglobal.c */