/work/workdir/UnpackedTarball/harfbuzz/src/hb-face.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2009 Red Hat, Inc. |
3 | | * Copyright © 2012 Google, Inc. |
4 | | * |
5 | | * This is part of HarfBuzz, a text shaping library. |
6 | | * |
7 | | * Permission is hereby granted, without written agreement and without |
8 | | * license or royalty fees, to use, copy, modify, and distribute this |
9 | | * software and its documentation for any purpose, provided that the |
10 | | * above copyright notice and the following two paragraphs appear in |
11 | | * all copies of this software. |
12 | | * |
13 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | | * DAMAGE. |
18 | | * |
19 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | | * |
25 | | * Red Hat Author(s): Behdad Esfahbod |
26 | | * Google Author(s): Behdad Esfahbod |
27 | | */ |
28 | | |
29 | | #include "hb.hh" |
30 | | |
31 | | #include "hb-face.hh" |
32 | | #include "hb-blob.hh" |
33 | | #include "hb-open-file.hh" |
34 | | #include "hb-ot-face.hh" |
35 | | #include "hb-ot-cmap-table.hh" |
36 | | |
37 | | #ifdef HAVE_FREETYPE |
38 | | #include "hb-ft.h" |
39 | | #endif |
40 | | #ifdef HAVE_CORETEXT |
41 | | #include "hb-coretext.h" |
42 | | #endif |
43 | | #ifdef HAVE_DIRECTWRITE |
44 | | #include "hb-directwrite.h" |
45 | | #endif |
46 | | |
47 | | |
48 | | /** |
49 | | * SECTION:hb-face |
50 | | * @title: hb-face |
51 | | * @short_description: Font face objects |
52 | | * @include: hb.h |
53 | | * |
54 | | * A font face is an object that represents a single face from within a |
55 | | * font family. |
56 | | * |
57 | | * More precisely, a font face represents a single face in a binary font file. |
58 | | * Font faces are typically built from a binary blob and a face index. |
59 | | * Font faces are used to create fonts. |
60 | | * |
61 | | * A font face can be created from a binary blob using hb_face_create(). |
62 | | * The face index is used to select a face from a binary blob that contains |
63 | | * multiple faces. For example, a binary blob that contains both a regular |
64 | | * and a bold face can be used to create two font faces, one for each face |
65 | | * index. |
66 | | **/ |
67 | | |
68 | | |
69 | | /** |
70 | | * hb_face_count: |
71 | | * @blob: a blob. |
72 | | * |
73 | | * Fetches the number of faces in a blob. |
74 | | * |
75 | | * Return value: Number of faces in @blob |
76 | | * |
77 | | * Since: 1.7.7 |
78 | | **/ |
79 | | unsigned int |
80 | | hb_face_count (hb_blob_t *blob) |
81 | 0 | { |
82 | 0 | if (unlikely (!blob)) |
83 | 0 | return 0; |
84 | | |
85 | 0 | hb_sanitize_context_t c (blob); |
86 | |
|
87 | 0 | const char *start = hb_blob_get_data (blob, nullptr); |
88 | 0 | auto *ot = reinterpret_cast<OT::OpenTypeFontFile *> (const_cast<char *> (start)); |
89 | 0 | if (unlikely (!ot->sanitize (&c))) |
90 | 0 | return 0; |
91 | | |
92 | 0 | return ot->get_face_count (); |
93 | 0 | } |
94 | | |
95 | | /* |
96 | | * hb_face_t |
97 | | */ |
98 | | |
99 | | DEFINE_NULL_INSTANCE (hb_face_t) = |
100 | | { |
101 | | HB_OBJECT_HEADER_STATIC, |
102 | | |
103 | | 0, /* index */ |
104 | | 1000, /* upem */ |
105 | | 0, /* num_glyphs */ |
106 | | |
107 | | /* Zero for the rest is fine. */ |
108 | | }; |
109 | | |
110 | | |
111 | | /** |
112 | | * hb_face_create_for_tables: |
113 | | * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function |
114 | | * @user_data: A pointer to the user data |
115 | | * @destroy: (nullable): A callback to call when @data is not needed anymore |
116 | | * |
117 | | * Variant of hb_face_create(), built for those cases where it is more |
118 | | * convenient to provide data for individual tables instead of the whole font |
119 | | * data. With the caveat that hb_face_get_table_tags() would not work |
120 | | * with faces created this way. You can address that by calling the |
121 | | * hb_face_set_get_table_tags_func() function and setting the appropriate callback. |
122 | | * |
123 | | * Creates a new face object from the specified @user_data and @reference_table_func, |
124 | | * with the @destroy callback. |
125 | | * |
126 | | * Return value: (transfer full): The new face object |
127 | | * |
128 | | * Since: 0.9.2 |
129 | | **/ |
130 | | hb_face_t * |
131 | | hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, |
132 | | void *user_data, |
133 | | hb_destroy_func_t destroy) |
134 | 60 | { |
135 | 60 | hb_face_t *face; |
136 | | |
137 | 60 | if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) { |
138 | 0 | if (destroy) |
139 | 0 | destroy (user_data); |
140 | 0 | return hb_face_get_empty (); |
141 | 0 | } |
142 | | |
143 | 60 | face->reference_table_func = reference_table_func; |
144 | 60 | face->user_data = user_data; |
145 | 60 | face->destroy = destroy; |
146 | | |
147 | 60 | face->num_glyphs = -1; |
148 | | |
149 | 60 | face->data.init0 (face); |
150 | 60 | face->table.init0 (face); |
151 | | |
152 | 60 | return face; |
153 | 60 | } |
154 | | |
155 | | |
156 | | typedef struct hb_face_for_data_closure_t { |
157 | | hb_blob_t *blob; |
158 | | uint16_t index; |
159 | | } hb_face_for_data_closure_t; |
160 | | |
161 | | static hb_face_for_data_closure_t * |
162 | | _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) |
163 | 60 | { |
164 | 60 | hb_face_for_data_closure_t *closure; |
165 | | |
166 | 60 | closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t)); |
167 | 60 | if (unlikely (!closure)) |
168 | 0 | return nullptr; |
169 | | |
170 | 60 | closure->blob = blob; |
171 | 60 | closure->index = (uint16_t) (index & 0xFFFFu); |
172 | | |
173 | 60 | return closure; |
174 | 60 | } |
175 | | |
176 | | static void |
177 | | _hb_face_for_data_closure_destroy (void *data) |
178 | 0 | { |
179 | 0 | hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data; |
180 | |
|
181 | 0 | hb_blob_destroy (closure->blob); |
182 | 0 | hb_free (closure); |
183 | 0 | } |
184 | | |
185 | | static hb_blob_t * |
186 | | _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) |
187 | 55.6M | { |
188 | 55.6M | hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; |
189 | | |
190 | 55.6M | if (tag == HB_TAG_NONE) |
191 | 0 | return hb_blob_reference (data->blob); |
192 | | |
193 | 55.6M | const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); |
194 | 55.6M | unsigned int base_offset; |
195 | 55.6M | const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset); |
196 | | |
197 | 55.6M | const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag); |
198 | | |
199 | 55.6M | hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length); |
200 | | |
201 | 55.6M | return blob; |
202 | 55.6M | } |
203 | | |
204 | | static unsigned |
205 | | _hb_face_for_data_get_table_tags (const hb_face_t *face HB_UNUSED, |
206 | | unsigned int start_offset, |
207 | | unsigned int *table_count, |
208 | | hb_tag_t *table_tags, |
209 | | void *user_data) |
210 | 0 | { |
211 | 0 | hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; |
212 | |
|
213 | 0 | const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> (); |
214 | 0 | const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index); |
215 | |
|
216 | 0 | return ot_face.get_table_tags (start_offset, table_count, table_tags); |
217 | 0 | } |
218 | | |
219 | | |
220 | | /** |
221 | | * hb_face_create: |
222 | | * @blob: #hb_blob_t to work upon |
223 | | * @index: The index of the face within @blob |
224 | | * |
225 | | * Constructs a new face object from the specified blob and |
226 | | * a face index into that blob. |
227 | | * |
228 | | * The face index is used for blobs of file formats such as TTC and |
229 | | * DFont that can contain more than one face. Face indices within |
230 | | * such collections are zero-based. |
231 | | * |
232 | | * <note>Note: If the blob font format is not a collection, @index |
233 | | * is ignored. Otherwise, only the lower 16-bits of @index are used. |
234 | | * The unmodified @index can be accessed via hb_face_get_index().</note> |
235 | | * |
236 | | * <note>Note: The high 16-bits of @index, if non-zero, are used by |
237 | | * hb_font_create() to load named-instances in variable fonts. See |
238 | | * hb_font_create() for details.</note> |
239 | | * |
240 | | * Return value: (transfer full): The new face object |
241 | | * |
242 | | * Since: 0.9.2 |
243 | | **/ |
244 | | hb_face_t * |
245 | | hb_face_create (hb_blob_t *blob, |
246 | | unsigned int index) |
247 | 60 | { |
248 | 60 | hb_face_t *face; |
249 | | |
250 | 60 | if (unlikely (!blob)) |
251 | 0 | blob = hb_blob_get_empty (); |
252 | | |
253 | 60 | blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)); |
254 | | |
255 | 60 | hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index); |
256 | | |
257 | 60 | if (unlikely (!closure)) |
258 | 0 | { |
259 | 0 | hb_blob_destroy (blob); |
260 | 0 | return hb_face_get_empty (); |
261 | 0 | } |
262 | | |
263 | 60 | face = hb_face_create_for_tables (_hb_face_for_data_reference_table, |
264 | 60 | closure, |
265 | 60 | _hb_face_for_data_closure_destroy); |
266 | 60 | hb_face_set_get_table_tags_func (face, |
267 | 60 | _hb_face_for_data_get_table_tags, |
268 | 60 | closure, |
269 | 60 | nullptr); |
270 | | |
271 | 60 | face->index = index; |
272 | | |
273 | 60 | return face; |
274 | 60 | } |
275 | | |
276 | | /** |
277 | | * hb_face_create_or_fail: |
278 | | * @blob: #hb_blob_t to work upon |
279 | | * @index: The index of the face within @blob |
280 | | * |
281 | | * Like hb_face_create(), but returns `NULL` if the blob data |
282 | | * contains no usable font face at the specified index. |
283 | | * |
284 | | * Return value: (transfer full): The new face object, or `NULL` if |
285 | | * no face is found at the specified index. |
286 | | * |
287 | | * Since: 10.1.0 |
288 | | **/ |
289 | | hb_face_t * |
290 | | hb_face_create_or_fail (hb_blob_t *blob, |
291 | | unsigned int index) |
292 | 0 | { |
293 | 0 | unsigned num_faces = hb_face_count (blob); |
294 | 0 | if (index >= num_faces) |
295 | 0 | return nullptr; |
296 | | |
297 | 0 | hb_face_t *face = hb_face_create (blob, index); |
298 | 0 | if (hb_object_is_immutable (face)) |
299 | 0 | return nullptr; |
300 | | |
301 | 0 | return face; |
302 | 0 | } |
303 | | |
304 | | #ifndef HB_NO_OPEN |
305 | | /** |
306 | | * hb_face_create_from_file_or_fail: |
307 | | * @file_name: A font filename |
308 | | * @index: The index of the face within the file |
309 | | * |
310 | | * A thin wrapper around hb_blob_create_from_file_or_fail() |
311 | | * followed by hb_face_create_or_fail(). |
312 | | * |
313 | | * Return value: (transfer full): The new face object, or `NULL` if |
314 | | * no face is found at the specified index or the file cannot be read. |
315 | | * |
316 | | * Since: 10.1.0 |
317 | | **/ |
318 | | HB_EXTERN hb_face_t * |
319 | | hb_face_create_from_file_or_fail (const char *file_name, |
320 | | unsigned int index) |
321 | 0 | { |
322 | 0 | hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name); |
323 | 0 | if (unlikely (!blob)) |
324 | 0 | return nullptr; |
325 | | |
326 | 0 | hb_face_t *face = hb_face_create_or_fail (blob, index); |
327 | 0 | hb_blob_destroy (blob); |
328 | |
|
329 | 0 | return face; |
330 | 0 | } |
331 | | |
332 | | static struct supported_face_loaders_t { |
333 | | char name[16]; |
334 | | hb_face_t * (*from_file) (const char *font_file, unsigned face_index); |
335 | | hb_face_t * (*from_blob) (hb_blob_t *blob, unsigned face_index); |
336 | | } supported_face_loaders[] = |
337 | | { |
338 | | {"ot", |
339 | | #ifndef HB_NO_OPEN |
340 | | hb_face_create_from_file_or_fail, |
341 | | #else |
342 | | nullptr, |
343 | | #endif |
344 | | hb_face_create_or_fail |
345 | | }, |
346 | | #ifdef HAVE_FREETYPE |
347 | | {"ft", |
348 | | hb_ft_face_create_from_file_or_fail, |
349 | | hb_ft_face_create_from_blob_or_fail |
350 | | }, |
351 | | #endif |
352 | | #ifdef HAVE_CORETEXT |
353 | | {"coretext", |
354 | | hb_coretext_face_create_from_file_or_fail, |
355 | | hb_coretext_face_create_from_blob_or_fail |
356 | | }, |
357 | | #endif |
358 | | #ifdef HAVE_DIRECTWRITE |
359 | | {"directwrite", |
360 | | hb_directwrite_face_create_from_file_or_fail, |
361 | | hb_directwrite_face_create_from_blob_or_fail |
362 | | }, |
363 | | #endif |
364 | | }; |
365 | | |
366 | | static const char *get_default_loader_name () |
367 | 0 | { |
368 | 0 | static hb_atomic_t<const char *> static_loader_name; |
369 | 0 | const char *loader_name = static_loader_name.get_acquire (); |
370 | 0 | if (!loader_name) |
371 | 0 | { |
372 | 0 | loader_name = getenv ("HB_FACE_LOADER"); |
373 | 0 | if (!loader_name) |
374 | 0 | loader_name = ""; |
375 | 0 | if (!static_loader_name.cmpexch (nullptr, loader_name)) |
376 | 0 | loader_name = static_loader_name.get_acquire (); |
377 | 0 | } |
378 | 0 | return loader_name; |
379 | 0 | } |
380 | | |
381 | | /** |
382 | | * hb_face_create_from_file_or_fail_using: |
383 | | * @file_name: A font filename |
384 | | * @index: The index of the face within the file |
385 | | * @loader_name: (nullable): The name of the loader to use, or `NULL` |
386 | | * |
387 | | * A thin wrapper around the face loader functions registered with HarfBuzz. |
388 | | * If @loader_name is `NULL` or the empty string, the first available loader |
389 | | * is used. |
390 | | * |
391 | | * For example, the FreeType ("ft") loader might be able to load |
392 | | * WOFF and WOFF2 files if FreeType is built with those features, |
393 | | * whereas the OpenType ("ot") loader will not. |
394 | | * |
395 | | * Return value: (transfer full): The new face object, or `NULL` if |
396 | | * the file cannot be read or the loader fails to load the face. |
397 | | * |
398 | | * Since: 11.0.0 |
399 | | **/ |
400 | | hb_face_t * |
401 | | hb_face_create_from_file_or_fail_using (const char *file_name, |
402 | | unsigned int index, |
403 | | const char *loader_name) |
404 | 0 | { |
405 | | // Duplicated in hb_face_create_or_fail_using |
406 | 0 | bool retry = false; |
407 | 0 | if (!loader_name || !*loader_name) |
408 | 0 | { |
409 | 0 | loader_name = get_default_loader_name (); |
410 | 0 | retry = true; |
411 | 0 | } |
412 | 0 | if (loader_name && !*loader_name) loader_name = nullptr; |
413 | |
|
414 | 0 | retry: |
415 | 0 | for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) |
416 | 0 | { |
417 | 0 | if (!loader_name || (supported_face_loaders[i].from_file && !strcmp (supported_face_loaders[i].name, loader_name))) |
418 | 0 | return supported_face_loaders[i].from_file (file_name, index); |
419 | 0 | } |
420 | | |
421 | 0 | if (retry) |
422 | 0 | { |
423 | 0 | retry = false; |
424 | 0 | loader_name = nullptr; |
425 | 0 | goto retry; |
426 | 0 | } |
427 | | |
428 | 0 | return nullptr; |
429 | 0 | } |
430 | | |
431 | | /** |
432 | | * hb_face_create_or_fail_using: |
433 | | * @blob: #hb_blob_t to work upon |
434 | | * @index: The index of the face within @blob |
435 | | * @loader_name: (nullable): The name of the loader to use, or `NULL` |
436 | | * |
437 | | * A thin wrapper around the face loader functions registered with HarfBuzz. |
438 | | * If @loader_name is `NULL` or the empty string, the first available loader |
439 | | * is used. |
440 | | * |
441 | | * For example, the FreeType ("ft") loader might be able to load |
442 | | * WOFF and WOFF2 files if FreeType is built with those features, |
443 | | * whereas the OpenType ("ot") loader will not. |
444 | | * |
445 | | * Return value: (transfer full): The new face object, or `NULL` if |
446 | | * the loader fails to load the face. |
447 | | * |
448 | | * Since: 11.0.0 |
449 | | **/ |
450 | | hb_face_t * |
451 | | hb_face_create_or_fail_using (hb_blob_t *blob, |
452 | | unsigned int index, |
453 | | const char *loader_name) |
454 | 0 | { |
455 | | // Duplicated in hb_face_create_from_file_or_fail_using |
456 | 0 | bool retry = false; |
457 | 0 | if (!loader_name || !*loader_name) |
458 | 0 | { |
459 | 0 | loader_name = get_default_loader_name (); |
460 | 0 | retry = true; |
461 | 0 | } |
462 | 0 | if (loader_name && !*loader_name) loader_name = nullptr; |
463 | |
|
464 | 0 | retry: |
465 | 0 | for (unsigned i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) |
466 | 0 | { |
467 | 0 | if (!loader_name || (supported_face_loaders[i].from_blob && !strcmp (supported_face_loaders[i].name, loader_name))) |
468 | 0 | return supported_face_loaders[i].from_blob (blob, index); |
469 | 0 | } |
470 | | |
471 | 0 | if (retry) |
472 | 0 | { |
473 | 0 | retry = false; |
474 | 0 | loader_name = nullptr; |
475 | 0 | goto retry; |
476 | 0 | } |
477 | | |
478 | 0 | return nullptr; |
479 | 0 | } |
480 | | |
481 | | static inline void free_static_face_loader_list (); |
482 | | |
483 | | static const char * const nil_face_loader_list[] = {nullptr}; |
484 | | |
485 | | static struct hb_face_loader_list_lazy_loader_t : hb_lazy_loader_t<const char *, |
486 | | hb_face_loader_list_lazy_loader_t> |
487 | | { |
488 | | static const char ** create () |
489 | 0 | { |
490 | 0 | const char **face_loader_list = (const char **) hb_calloc (1 + ARRAY_LENGTH (supported_face_loaders), sizeof (const char *)); |
491 | 0 | if (unlikely (!face_loader_list)) |
492 | 0 | return nullptr; |
493 | | |
494 | 0 | unsigned i; |
495 | 0 | for (i = 0; i < ARRAY_LENGTH (supported_face_loaders); i++) |
496 | 0 | face_loader_list[i] = supported_face_loaders[i].name; |
497 | 0 | face_loader_list[i] = nullptr; |
498 | |
|
499 | 0 | hb_atexit (free_static_face_loader_list); |
500 | |
|
501 | 0 | return face_loader_list; |
502 | 0 | } |
503 | | static void destroy (const char **l) |
504 | 0 | { hb_free (l); } |
505 | | static const char * const * get_null () |
506 | 0 | { return nil_face_loader_list; } |
507 | | } static_face_loader_list; |
508 | | |
509 | | static inline |
510 | | void free_static_face_loader_list () |
511 | 0 | { |
512 | 0 | static_face_loader_list.free_instance (); |
513 | 0 | } |
514 | | |
515 | | /** |
516 | | * hb_face_list_loaders: |
517 | | * |
518 | | * Retrieves the list of face loaders supported by HarfBuzz. |
519 | | * |
520 | | * Return value: (transfer none) (array zero-terminated=1): a |
521 | | * `NULL`-terminated array of supported face loaders |
522 | | * constant strings. The returned array is owned by HarfBuzz |
523 | | * and should not be modified or freed. |
524 | | * |
525 | | * Since: 11.0.0 |
526 | | **/ |
527 | | const char ** |
528 | | hb_face_list_loaders () |
529 | 0 | { |
530 | 0 | return static_face_loader_list.get_unconst (); |
531 | 0 | } |
532 | | #endif |
533 | | |
534 | | |
535 | | /** |
536 | | * hb_face_get_empty: |
537 | | * |
538 | | * Fetches the singleton empty face object. |
539 | | * |
540 | | * Return value: (transfer full): The empty face object |
541 | | * |
542 | | * Since: 0.9.2 |
543 | | **/ |
544 | | hb_face_t * |
545 | | hb_face_get_empty () |
546 | 0 | { |
547 | 0 | return const_cast<hb_face_t *> (&Null (hb_face_t)); |
548 | 0 | } |
549 | | |
550 | | |
551 | | /** |
552 | | * hb_face_reference: (skip) |
553 | | * @face: A face object |
554 | | * |
555 | | * Increases the reference count on a face object. |
556 | | * |
557 | | * Return value: The @face object |
558 | | * |
559 | | * Since: 0.9.2 |
560 | | **/ |
561 | | hb_face_t * |
562 | | hb_face_reference (hb_face_t *face) |
563 | 251k | { |
564 | 251k | return hb_object_reference (face); |
565 | 251k | } |
566 | | |
567 | | /** |
568 | | * hb_face_destroy: (skip) |
569 | | * @face: A face object |
570 | | * |
571 | | * Decreases the reference count on a face object. When the |
572 | | * reference count reaches zero, the face is destroyed, |
573 | | * freeing all memory. |
574 | | * |
575 | | * Since: 0.9.2 |
576 | | **/ |
577 | | void |
578 | | hb_face_destroy (hb_face_t *face) |
579 | 250k | { |
580 | 250k | if (!hb_object_destroy (face)) return; |
581 | | |
582 | 0 | #ifndef HB_NO_SHAPER |
583 | 0 | for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) |
584 | 0 | { |
585 | 0 | hb_face_t::plan_node_t *next = node->next; |
586 | 0 | hb_shape_plan_destroy (node->shape_plan); |
587 | 0 | hb_free (node); |
588 | 0 | node = next; |
589 | 0 | } |
590 | 0 | #endif |
591 | |
|
592 | 0 | face->data.fini (); |
593 | 0 | face->table.fini (); |
594 | |
|
595 | 0 | if (face->get_table_tags_destroy) |
596 | 0 | face->get_table_tags_destroy (face->get_table_tags_user_data); |
597 | |
|
598 | 0 | if (face->destroy) |
599 | 0 | face->destroy (face->user_data); |
600 | |
|
601 | 0 | hb_free (face); |
602 | 0 | } |
603 | | |
604 | | /** |
605 | | * hb_face_set_user_data: (skip) |
606 | | * @face: A face object |
607 | | * @key: The user-data key to set |
608 | | * @data: A pointer to the user data |
609 | | * @destroy: (nullable): A callback to call when @data is not needed anymore |
610 | | * @replace: Whether to replace an existing data with the same key |
611 | | * |
612 | | * Attaches a user-data key/data pair to the given face object. |
613 | | * |
614 | | * Return value: `true` if success, `false` otherwise |
615 | | * |
616 | | * Since: 0.9.2 |
617 | | **/ |
618 | | hb_bool_t |
619 | | hb_face_set_user_data (hb_face_t *face, |
620 | | hb_user_data_key_t *key, |
621 | | void * data, |
622 | | hb_destroy_func_t destroy, |
623 | | hb_bool_t replace) |
624 | 0 | { |
625 | 0 | return hb_object_set_user_data (face, key, data, destroy, replace); |
626 | 0 | } |
627 | | |
628 | | /** |
629 | | * hb_face_get_user_data: (skip) |
630 | | * @face: A face object |
631 | | * @key: The user-data key to query |
632 | | * |
633 | | * Fetches the user data associated with the specified key, |
634 | | * attached to the specified face object. |
635 | | * |
636 | | * Return value: (transfer none): A pointer to the user data |
637 | | * |
638 | | * Since: 0.9.2 |
639 | | **/ |
640 | | void * |
641 | | hb_face_get_user_data (const hb_face_t *face, |
642 | | hb_user_data_key_t *key) |
643 | 0 | { |
644 | 0 | return hb_object_get_user_data (face, key); |
645 | 0 | } |
646 | | |
647 | | /** |
648 | | * hb_face_make_immutable: |
649 | | * @face: A face object |
650 | | * |
651 | | * Makes the given face object immutable. |
652 | | * |
653 | | * Since: 0.9.2 |
654 | | **/ |
655 | | void |
656 | | hb_face_make_immutable (hb_face_t *face) |
657 | 243k | { |
658 | 243k | if (hb_object_is_immutable (face)) |
659 | 243k | return; |
660 | | |
661 | 60 | hb_object_make_immutable (face); |
662 | 60 | } |
663 | | |
664 | | /** |
665 | | * hb_face_is_immutable: |
666 | | * @face: A face object |
667 | | * |
668 | | * Tests whether the given face object is immutable. |
669 | | * |
670 | | * Return value: `true` is @face is immutable, `false` otherwise |
671 | | * |
672 | | * Since: 0.9.2 |
673 | | **/ |
674 | | hb_bool_t |
675 | | hb_face_is_immutable (hb_face_t *face) |
676 | 0 | { |
677 | 0 | return hb_object_is_immutable (face); |
678 | 0 | } |
679 | | |
680 | | |
681 | | /** |
682 | | * hb_face_reference_table: |
683 | | * @face: A face object |
684 | | * @tag: The #hb_tag_t of the table to query |
685 | | * |
686 | | * Fetches a reference to the specified table within |
687 | | * the specified face. Returns an empty blob if referencing table data is not |
688 | | * possible. |
689 | | * |
690 | | * Return value: (transfer full): A pointer to the @tag table within @face |
691 | | * |
692 | | * Since: 0.9.2 |
693 | | **/ |
694 | | hb_blob_t * |
695 | | hb_face_reference_table (const hb_face_t *face, |
696 | | hb_tag_t tag) |
697 | 22.5M | { |
698 | 22.5M | if (unlikely (tag == HB_TAG_NONE)) |
699 | 0 | return hb_blob_get_empty (); |
700 | | |
701 | 22.5M | return face->reference_table (tag); |
702 | 22.5M | } |
703 | | |
704 | | /** |
705 | | * hb_face_reference_blob: |
706 | | * @face: A face object |
707 | | * |
708 | | * Fetches a pointer to the binary blob that contains the specified face. |
709 | | * If referencing the face data is not possible, this function creates a blob |
710 | | * out of individual table blobs if hb_face_get_table_tags() works with this |
711 | | * face, otherwise it returns an empty blob. |
712 | | * |
713 | | * Return value: (transfer full): A pointer to the blob for @face |
714 | | * |
715 | | * Since: 0.9.2 |
716 | | **/ |
717 | | hb_blob_t * |
718 | | hb_face_reference_blob (hb_face_t *face) |
719 | 0 | { |
720 | 0 | hb_blob_t *blob = face->reference_table (HB_TAG_NONE); |
721 | |
|
722 | 0 | if (blob == hb_blob_get_empty ()) |
723 | 0 | { |
724 | | // If referencing the face blob is not possible (e.g. not implemented by the |
725 | | // font functions), use face builder to create a blob out of individual |
726 | | // table blobs. |
727 | 0 | unsigned total_count = hb_face_get_table_tags (face, 0, nullptr, nullptr); |
728 | 0 | if (total_count) |
729 | 0 | { |
730 | 0 | hb_tag_t tags[64]; |
731 | 0 | unsigned count = ARRAY_LENGTH (tags); |
732 | 0 | hb_face_t* builder = hb_face_builder_create (); |
733 | |
|
734 | 0 | for (unsigned offset = 0; offset < total_count; offset += count) |
735 | 0 | { |
736 | 0 | hb_face_get_table_tags (face, offset, &count, tags); |
737 | 0 | if (unlikely (!count)) |
738 | 0 | break; // Allocation error |
739 | 0 | for (unsigned i = 0; i < count; i++) |
740 | 0 | { |
741 | 0 | if (unlikely (!tags[i])) |
742 | 0 | continue; |
743 | 0 | hb_blob_t *table = hb_face_reference_table (face, tags[i]); |
744 | 0 | hb_face_builder_add_table (builder, tags[i], table); |
745 | 0 | hb_blob_destroy (table); |
746 | 0 | } |
747 | 0 | } |
748 | |
|
749 | 0 | blob = hb_face_reference_blob (builder); |
750 | 0 | hb_face_destroy (builder); |
751 | 0 | } |
752 | 0 | } |
753 | |
|
754 | 0 | return blob; |
755 | 0 | } |
756 | | |
757 | | /** |
758 | | * hb_face_set_index: |
759 | | * @face: A face object |
760 | | * @index: The index to assign |
761 | | * |
762 | | * Assigns the specified face-index to @face. Fails if the |
763 | | * face is immutable. |
764 | | * |
765 | | * <note>Note: changing the index has no effect on the face itself |
766 | | * This only changes the value returned by hb_face_get_index().</note> |
767 | | * |
768 | | * Since: 0.9.2 |
769 | | **/ |
770 | | void |
771 | | hb_face_set_index (hb_face_t *face, |
772 | | unsigned int index) |
773 | 0 | { |
774 | 0 | if (hb_object_is_immutable (face)) |
775 | 0 | return; |
776 | | |
777 | 0 | face->index = index; |
778 | 0 | } |
779 | | |
780 | | /** |
781 | | * hb_face_get_index: |
782 | | * @face: A face object |
783 | | * |
784 | | * Fetches the face-index corresponding to the given face. |
785 | | * |
786 | | * <note>Note: face indices within a collection are zero-based.</note> |
787 | | * |
788 | | * Return value: The index of @face. |
789 | | * |
790 | | * Since: 0.9.2 |
791 | | **/ |
792 | | unsigned int |
793 | | hb_face_get_index (const hb_face_t *face) |
794 | 0 | { |
795 | 0 | return face->index; |
796 | 0 | } |
797 | | |
798 | | /** |
799 | | * hb_face_set_upem: |
800 | | * @face: A face object |
801 | | * @upem: The units-per-em value to assign |
802 | | * |
803 | | * Sets the units-per-em (upem) for a face object to the specified value. |
804 | | * |
805 | | * This API is used in rare circumstances. |
806 | | * |
807 | | * Since: 0.9.2 |
808 | | **/ |
809 | | void |
810 | | hb_face_set_upem (hb_face_t *face, |
811 | | unsigned int upem) |
812 | 0 | { |
813 | 0 | if (hb_object_is_immutable (face)) |
814 | 0 | return; |
815 | | |
816 | 0 | face->upem = upem; |
817 | 0 | } |
818 | | |
819 | | /** |
820 | | * hb_face_get_upem: |
821 | | * @face: A face object |
822 | | * |
823 | | * Fetches the units-per-em (UPEM) value of the specified face object. |
824 | | * |
825 | | * Typical UPEM values for fonts are 1000, or 2048, but any value |
826 | | * in between 16 and 16,384 is allowed for OpenType fonts. |
827 | | * |
828 | | * Return value: The upem value of @face |
829 | | * |
830 | | * Since: 0.9.2 |
831 | | **/ |
832 | | unsigned int |
833 | | hb_face_get_upem (const hb_face_t *face) |
834 | 42.9M | { |
835 | 42.9M | return face->get_upem (); |
836 | 42.9M | } |
837 | | |
838 | | /** |
839 | | * hb_face_set_glyph_count: |
840 | | * @face: A face object |
841 | | * @glyph_count: The glyph-count value to assign |
842 | | * |
843 | | * Sets the glyph count for a face object to the specified value. |
844 | | * |
845 | | * This API is used in rare circumstances. |
846 | | * |
847 | | * Since: 0.9.7 |
848 | | **/ |
849 | | void |
850 | | hb_face_set_glyph_count (hb_face_t *face, |
851 | | unsigned int glyph_count) |
852 | 0 | { |
853 | 0 | if (hb_object_is_immutable (face)) |
854 | 0 | return; |
855 | | |
856 | 0 | face->num_glyphs = glyph_count; |
857 | 0 | } |
858 | | |
859 | | /** |
860 | | * hb_face_get_glyph_count: |
861 | | * @face: A face object |
862 | | * |
863 | | * Fetches the glyph-count value of the specified face object. |
864 | | * |
865 | | * Return value: The glyph-count value of @face |
866 | | * |
867 | | * Since: 0.9.7 |
868 | | **/ |
869 | | unsigned int |
870 | | hb_face_get_glyph_count (const hb_face_t *face) |
871 | 13.4M | { |
872 | 13.4M | return face->get_num_glyphs (); |
873 | 13.4M | } |
874 | | |
875 | | /** |
876 | | * hb_face_set_get_table_tags_func: |
877 | | * @face: A face object |
878 | | * @func: (closure user_data) (destroy destroy) (scope notified): The table-tag-fetching function |
879 | | * @user_data: A pointer to the user data, to be destroyed by @destroy when not needed anymore |
880 | | * @destroy: (nullable): A callback to call when @func is not needed anymore |
881 | | * |
882 | | * Sets the table-tag-fetching function for the specified face object. |
883 | | * |
884 | | * Since: 10.0.0 |
885 | | */ |
886 | | HB_EXTERN void |
887 | | hb_face_set_get_table_tags_func (hb_face_t *face, |
888 | | hb_get_table_tags_func_t func, |
889 | | void *user_data, |
890 | | hb_destroy_func_t destroy) |
891 | 60 | { |
892 | 60 | if (hb_object_is_immutable (face)) |
893 | 0 | { |
894 | 0 | if (destroy) |
895 | 0 | destroy (user_data); |
896 | 0 | return; |
897 | 0 | } |
898 | | |
899 | 60 | if (face->get_table_tags_destroy) |
900 | 0 | face->get_table_tags_destroy (face->get_table_tags_user_data); |
901 | | |
902 | 60 | face->get_table_tags_func = func; |
903 | 60 | face->get_table_tags_user_data = user_data; |
904 | 60 | face->get_table_tags_destroy = destroy; |
905 | 60 | } |
906 | | |
907 | | /** |
908 | | * hb_face_get_table_tags: |
909 | | * @face: A face object |
910 | | * @start_offset: The index of first table tag to retrieve |
911 | | * @table_count: (inout): Input = the maximum number of table tags to return; |
912 | | * Output = the actual number of table tags returned (may be zero) |
913 | | * @table_tags: (out) (array length=table_count): The array of table tags found |
914 | | * |
915 | | * Fetches a list of all table tags for a face, if possible. The list returned will |
916 | | * begin at the offset provided |
917 | | * |
918 | | * Return value: Total number of tables, or zero if it is not possible to list |
919 | | * |
920 | | * Since: 1.6.0 |
921 | | **/ |
922 | | unsigned int |
923 | | hb_face_get_table_tags (const hb_face_t *face, |
924 | | unsigned int start_offset, |
925 | | unsigned int *table_count, /* IN/OUT */ |
926 | | hb_tag_t *table_tags /* OUT */) |
927 | 0 | { |
928 | 0 | if (!face->get_table_tags_func) |
929 | 0 | { |
930 | 0 | if (table_count) |
931 | 0 | *table_count = 0; |
932 | 0 | return 0; |
933 | 0 | } |
934 | | |
935 | 0 | return face->get_table_tags_func (face, start_offset, table_count, table_tags, face->get_table_tags_user_data); |
936 | 0 | } |
937 | | |
938 | | |
939 | | /* |
940 | | * Character set. |
941 | | */ |
942 | | |
943 | | |
944 | | #ifndef HB_NO_FACE_COLLECT_UNICODES |
945 | | /** |
946 | | * hb_face_collect_unicodes: |
947 | | * @face: A face object |
948 | | * @out: (out): The set to add Unicode characters to |
949 | | * |
950 | | * Collects all of the Unicode characters covered by @face and adds |
951 | | * them to the #hb_set_t set @out. |
952 | | * |
953 | | * Since: 1.9.0 |
954 | | */ |
955 | | void |
956 | | hb_face_collect_unicodes (hb_face_t *face, |
957 | | hb_set_t *out) |
958 | 11 | { |
959 | 11 | face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); |
960 | 11 | } |
961 | | /** |
962 | | * hb_face_collect_nominal_glyph_mapping: |
963 | | * @face: A face object |
964 | | * @mapping: (out): The map to add Unicode-to-glyph mapping to |
965 | | * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL` |
966 | | * |
967 | | * Collects the mapping from Unicode characters to nominal glyphs of the @face, |
968 | | * and optionally all of the Unicode characters covered by @face. |
969 | | * |
970 | | * Since: 7.0.0 |
971 | | */ |
972 | | void |
973 | | hb_face_collect_nominal_glyph_mapping (hb_face_t *face, |
974 | | hb_map_t *mapping, |
975 | | hb_set_t *unicodes) |
976 | 0 | { |
977 | 0 | hb_set_t stack_unicodes; |
978 | 0 | if (!unicodes) |
979 | 0 | unicodes = &stack_unicodes; |
980 | 0 | face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ()); |
981 | 0 | } |
982 | | /** |
983 | | * hb_face_collect_variation_selectors: |
984 | | * @face: A face object |
985 | | * @out: (out): The set to add Variation Selector characters to |
986 | | * |
987 | | * Collects all Unicode "Variation Selector" characters covered by @face and adds |
988 | | * them to the #hb_set_t set @out. |
989 | | * |
990 | | * Since: 1.9.0 |
991 | | */ |
992 | | void |
993 | | hb_face_collect_variation_selectors (hb_face_t *face, |
994 | | hb_set_t *out) |
995 | 0 | { |
996 | 0 | face->table.cmap->collect_variation_selectors (out); |
997 | 0 | } |
998 | | /** |
999 | | * hb_face_collect_variation_unicodes: |
1000 | | * @face: A face object |
1001 | | * @variation_selector: The Variation Selector to query |
1002 | | * @out: (out): The set to add Unicode characters to |
1003 | | * |
1004 | | * Collects all Unicode characters for @variation_selector covered by @face and adds |
1005 | | * them to the #hb_set_t set @out. |
1006 | | * |
1007 | | * Since: 1.9.0 |
1008 | | */ |
1009 | | void |
1010 | | hb_face_collect_variation_unicodes (hb_face_t *face, |
1011 | | hb_codepoint_t variation_selector, |
1012 | | hb_set_t *out) |
1013 | 0 | { |
1014 | 0 | face->table.cmap->collect_variation_unicodes (variation_selector, out); |
1015 | 0 | } |
1016 | | #endif |