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
38/**
39 * SECTION:hb-face
40 * @title: hb-face
41 * @short_description: Font face objects
42 * @include: hb.h
43 *
44 * Font face is objects represent a single face in a font family.
45 * More exactly, a font face represents a single face in a binary font file.
46 * Font faces are typically built from a binary blob and a face index.
47 * Font faces are used to create fonts.
48 **/
49
50
51/**
52 * hb_face_count:
53 * @blob: a blob.
54 *
55 * Get number of faces in a blob.
56 *
57 * Return value: Number of faces in @blob
58 *
59 * Since: 1.7.7
60 **/
61unsigned int
62hb_face_count (hb_blob_t *blob)
63{
64 if (unlikely (!blob))
65 return 0;
66
67 /* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
68 /* Make API signature const after. */
69 hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
70 const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
71 unsigned int ret = ot.get_face_count ();
72 hb_blob_destroy (sanitized);
73
74 return ret;
75}
76
77/*
78 * hb_face_t
79 */
80
81DEFINE_NULL_INSTANCE (hb_face_t) =
82{
83 HB_OBJECT_HEADER_STATIC,
84
85 nullptr, /* reference_table_func */
86 nullptr, /* user_data */
87 nullptr, /* destroy */
88
89 0, /* index */
90 HB_ATOMIC_INT_INIT (1000), /* upem */
91 HB_ATOMIC_INT_INIT (0), /* num_glyphs */
92
93 /* Zero for the rest is fine. */
94};
95
96
97/**
98 * hb_face_create_for_tables:
99 * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
100 * @user_data:
101 * @destroy:
102 *
103 *
104 *
105 * Return value: (transfer full)
106 *
107 * Since: 0.9.2
108 **/
109hb_face_t *
110hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
111 void *user_data,
112 hb_destroy_func_t destroy)
113{
114 hb_face_t *face;
115
116 if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
117 if (destroy)
118 destroy (user_data);
119 return hb_face_get_empty ();
120 }
121
122 face->reference_table_func = reference_table_func;
123 face->user_data = user_data;
124 face->destroy = destroy;
125
126 face->num_glyphs.set_relaxed (-1);
127
128 face->data.init0 (face);
129 face->table.init0 (face);
130
131 return face;
132}
133
134
135typedef struct hb_face_for_data_closure_t {
136 hb_blob_t *blob;
137 unsigned int index;
138} hb_face_for_data_closure_t;
139
140static hb_face_for_data_closure_t *
141_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
142{
143 hb_face_for_data_closure_t *closure;
144
145 closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
146 if (unlikely (!closure))
147 return nullptr;
148
149 closure->blob = blob;
150 closure->index = index;
151
152 return closure;
153}
154
155static void
156_hb_face_for_data_closure_destroy (void *data)
157{
158 hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
159
160 hb_blob_destroy (closure->blob);
161 free (closure);
162}
163
164static hb_blob_t *
165_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
166{
167 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
168
169 if (tag == HB_TAG_NONE)
170 return hb_blob_reference (data->blob);
171
172 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
173 unsigned int base_offset;
174 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);
175
176 const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
177
178 hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);
179
180 return blob;
181}
182
183/**
184 * hb_face_create: (Xconstructor)
185 * @blob:
186 * @index:
187 *
188 *
189 *
190 * Return value: (transfer full):
191 *
192 * Since: 0.9.2
193 **/
194hb_face_t *
195hb_face_create (hb_blob_t *blob,
196 unsigned int index)
197{
198 hb_face_t *face;
199
200 if (unlikely (!blob))
201 blob = hb_blob_get_empty ();
202
203 blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
204
205 hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index);
206
207 if (unlikely (!closure))
208 {
209 hb_blob_destroy (blob);
210 return hb_face_get_empty ();
211 }
212
213 face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
214 closure,
215 _hb_face_for_data_closure_destroy);
216
217 face->index = index;
218
219 return face;
220}
221
222/**
223 * hb_face_get_empty:
224 *
225 *
226 *
227 * Return value: (transfer full)
228 *
229 * Since: 0.9.2
230 **/
231hb_face_t *
232hb_face_get_empty ()
233{
234 return const_cast<hb_face_t *> (&Null (hb_face_t));
235}
236
237
238/**
239 * hb_face_reference: (skip)
240 * @face: a face.
241 *
242 *
243 *
244 * Return value:
245 *
246 * Since: 0.9.2
247 **/
248hb_face_t *
249hb_face_reference (hb_face_t *face)
250{
251 return hb_object_reference (face);
252}
253
254/**
255 * hb_face_destroy: (skip)
256 * @face: a face.
257 *
258 *
259 *
260 * Since: 0.9.2
261 **/
262void
263hb_face_destroy (hb_face_t *face)
264{
265 if (!hb_object_destroy (face)) return;
266
267 for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
268 {
269 hb_face_t::plan_node_t *next = node->next;
270 hb_shape_plan_destroy (node->shape_plan);
271 free (node);
272 node = next;
273 }
274
275 face->data.fini ();
276 face->table.fini ();
277
278 if (face->destroy)
279 face->destroy (face->user_data);
280
281 free (face);
282}
283
284/**
285 * hb_face_set_user_data: (skip)
286 * @face: a face.
287 * @key:
288 * @data:
289 * @destroy:
290 * @replace:
291 *
292 *
293 *
294 * Return value:
295 *
296 * Since: 0.9.2
297 **/
298hb_bool_t
299hb_face_set_user_data (hb_face_t *face,
300 hb_user_data_key_t *key,
301 void * data,
302 hb_destroy_func_t destroy,
303 hb_bool_t replace)
304{
305 return hb_object_set_user_data (face, key, data, destroy, replace);
306}
307
308/**
309 * hb_face_get_user_data: (skip)
310 * @face: a face.
311 * @key:
312 *
313 *
314 *
315 * Return value: (transfer none):
316 *
317 * Since: 0.9.2
318 **/
319void *
320hb_face_get_user_data (const hb_face_t *face,
321 hb_user_data_key_t *key)
322{
323 return hb_object_get_user_data (face, key);
324}
325
326/**
327 * hb_face_make_immutable:
328 * @face: a face.
329 *
330 *
331 *
332 * Since: 0.9.2
333 **/
334void
335hb_face_make_immutable (hb_face_t *face)
336{
337 if (hb_object_is_immutable (face))
338 return;
339
340 hb_object_make_immutable (face);
341}
342
343/**
344 * hb_face_is_immutable:
345 * @face: a face.
346 *
347 *
348 *
349 * Return value:
350 *
351 * Since: 0.9.2
352 **/
353hb_bool_t
354hb_face_is_immutable (const hb_face_t *face)
355{
356 return hb_object_is_immutable (face);
357}
358
359
360/**
361 * hb_face_reference_table:
362 * @face: a face.
363 * @tag:
364 *
365 *
366 *
367 * Return value: (transfer full):
368 *
369 * Since: 0.9.2
370 **/
371hb_blob_t *
372hb_face_reference_table (const hb_face_t *face,
373 hb_tag_t tag)
374{
375 if (unlikely (tag == HB_TAG_NONE))
376 return hb_blob_get_empty ();
377
378 return face->reference_table (tag);
379}
380
381/**
382 * hb_face_reference_blob:
383 * @face: a face.
384 *
385 *
386 *
387 * Return value: (transfer full):
388 *
389 * Since: 0.9.2
390 **/
391hb_blob_t *
392hb_face_reference_blob (hb_face_t *face)
393{
394 return face->reference_table (HB_TAG_NONE);
395}
396
397/**
398 * hb_face_set_index:
399 * @face: a face.
400 * @index:
401 *
402 *
403 *
404 * Since: 0.9.2
405 **/
406void
407hb_face_set_index (hb_face_t *face,
408 unsigned int index)
409{
410 if (hb_object_is_immutable (face))
411 return;
412
413 face->index = index;
414}
415
416/**
417 * hb_face_get_index:
418 * @face: a face.
419 *
420 *
421 *
422 * Return value:
423 *
424 * Since: 0.9.2
425 **/
426unsigned int
427hb_face_get_index (const hb_face_t *face)
428{
429 return face->index;
430}
431
432/**
433 * hb_face_set_upem:
434 * @face: a face.
435 * @upem:
436 *
437 *
438 *
439 * Since: 0.9.2
440 **/
441void
442hb_face_set_upem (hb_face_t *face,
443 unsigned int upem)
444{
445 if (hb_object_is_immutable (face))
446 return;
447
448 face->upem.set_relaxed (upem);
449}
450
451/**
452 * hb_face_get_upem:
453 * @face: a face.
454 *
455 *
456 *
457 * Return value:
458 *
459 * Since: 0.9.2
460 **/
461unsigned int
462hb_face_get_upem (const hb_face_t *face)
463{
464 return face->get_upem ();
465}
466
467/**
468 * hb_face_set_glyph_count:
469 * @face: a face.
470 * @glyph_count:
471 *
472 *
473 *
474 * Since: 0.9.7
475 **/
476void
477hb_face_set_glyph_count (hb_face_t *face,
478 unsigned int glyph_count)
479{
480 if (hb_object_is_immutable (face))
481 return;
482
483 face->num_glyphs.set_relaxed (glyph_count);
484}
485
486/**
487 * hb_face_get_glyph_count:
488 * @face: a face.
489 *
490 *
491 *
492 * Return value:
493 *
494 * Since: 0.9.7
495 **/
496unsigned int
497hb_face_get_glyph_count (const hb_face_t *face)
498{
499 return face->get_num_glyphs ();
500}
501
502/**
503 * hb_face_get_table_tags:
504 * @face: a face.
505 * @start_offset: index of first tag to return.
506 * @table_count: input length of @table_tags array, output number of items written.
507 * @table_tags: array to write tags into.
508 *
509 * Retrieves table tags for a face, if possible.
510 *
511 * Return value: total number of tables, or 0 if not possible to list.
512 *
513 * Since: 1.6.0
514 **/
515unsigned int
516hb_face_get_table_tags (const hb_face_t *face,
517 unsigned int start_offset,
518 unsigned int *table_count, /* IN/OUT */
519 hb_tag_t *table_tags /* OUT */)
520{
521 if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
522 {
523 if (table_count)
524 *table_count = 0;
525 return 0;
526 }
527
528 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
529
530 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
531 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
532
533 return ot_face.get_table_tags (start_offset, table_count, table_tags);
534}
535
536
537/*
538 * Character set.
539 */
540
541
542#ifndef HB_NO_FACE_COLLECT_UNICODES
543/**
544 * hb_face_collect_unicodes:
545 * @face: font face.
546 * @out: set to add Unicode characters covered by @face to.
547 *
548 * Since: 1.9.0
549 */
550void
551hb_face_collect_unicodes (hb_face_t *face,
552 hb_set_t *out)
553{
554 face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
555}
556/**
557 * hb_face_collect_variation_selectors:
558 * @face: font face.
559 * @out: set to add Variation Selector characters covered by @face to.
560 *
561 *
562 *
563 * Since: 1.9.0
564 */
565void
566hb_face_collect_variation_selectors (hb_face_t *face,
567 hb_set_t *out)
568{
569 face->table.cmap->collect_variation_selectors (out);
570}
571/**
572 * hb_face_collect_variation_unicodes:
573 * @face: font face.
574 * @out: set to add Unicode characters for @variation_selector covered by @face to.
575 *
576 *
577 *
578 * Since: 1.9.0
579 */
580void
581hb_face_collect_variation_unicodes (hb_face_t *face,
582 hb_codepoint_t variation_selector,
583 hb_set_t *out)
584{
585 face->table.cmap->collect_variation_unicodes (variation_selector, out);
586}
587#endif
588
589
590/*
591 * face-builder: A face that has add_table().
592 */
593
594struct hb_face_builder_data_t
595{
596 struct table_entry_t
597 {
598 int cmp (hb_tag_t t) const
599 {
600 if (t < tag) return -1;
601 if (t > tag) return -1;
602 return 0;
603 }
604
605 hb_tag_t tag;
606 hb_blob_t *blob;
607 };
608
609 hb_vector_t<table_entry_t> tables;
610};
611
612static hb_face_builder_data_t *
613_hb_face_builder_data_create ()
614{
615 hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
616 if (unlikely (!data))
617 return nullptr;
618
619 data->tables.init ();
620
621 return data;
622}
623
624static void
625_hb_face_builder_data_destroy (void *user_data)
626{
627 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
628
629 for (unsigned int i = 0; i < data->tables.length; i++)
630 hb_blob_destroy (data->tables[i].blob);
631
632 data->tables.fini ();
633
634 free (data);
635}
636
637static hb_blob_t *
638_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
639{
640
641 unsigned int table_count = data->tables.length;
642 unsigned int face_length = table_count * 16 + 12;
643
644 for (unsigned int i = 0; i < table_count; i++)
645 face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
646
647 char *buf = (char *) malloc (face_length);
648 if (unlikely (!buf))
649 return nullptr;
650
651 hb_serialize_context_t c (buf, face_length);
652 c.propagate_error (data->tables);
653 OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
654
655 bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
656 hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
657
658 bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
659
660 c.end_serialize ();
661
662 if (unlikely (!ret))
663 {
664 free (buf);
665 return nullptr;
666 }
667
668 return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
669}
670
671static hb_blob_t *
672_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
673{
674 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
675
676 if (!tag)
677 return _hb_face_builder_data_reference_blob (data);
678
679 hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
680 if (entry)
681 return hb_blob_reference (entry->blob);
682
683 return nullptr;
684}
685
686
687/**
688 * hb_face_builder_create:
689 *
690 * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
691 * After tables are added to the face, it can be compiled to a binary
692 * font file by calling hb_face_reference_blob().
693 *
694 * Return value: (transfer full): New face.
695 *
696 * Since: 1.9.0
697 **/
698hb_face_t *
699hb_face_builder_create ()
700{
701 hb_face_builder_data_t *data = _hb_face_builder_data_create ();
702 if (unlikely (!data)) return hb_face_get_empty ();
703
704 return hb_face_create_for_tables (_hb_face_builder_reference_table,
705 data,
706 _hb_face_builder_data_destroy);
707}
708
709/**
710 * hb_face_builder_add_table:
711 *
712 * Add table for @tag with data provided by @blob to the face. @face must
713 * be created using hb_face_builder_create().
714 *
715 * Since: 1.9.0
716 **/
717hb_bool_t
718hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
719{
720 if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
721 return false;
722
723 hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
724 hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
725
726 entry->tag = tag;
727 entry->blob = hb_blob_reference (blob);
728
729 return true;
730}
731