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 hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)), index);
204
205 if (unlikely (!closure))
206 return hb_face_get_empty ();
207
208 face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
209 closure,
210 _hb_face_for_data_closure_destroy);
211
212 face->index = index;
213
214 return face;
215}
216
217/**
218 * hb_face_get_empty:
219 *
220 *
221 *
222 * Return value: (transfer full)
223 *
224 * Since: 0.9.2
225 **/
226hb_face_t *
227hb_face_get_empty ()
228{
229 return const_cast<hb_face_t *> (&Null(hb_face_t));
230}
231
232
233/**
234 * hb_face_reference: (skip)
235 * @face: a face.
236 *
237 *
238 *
239 * Return value:
240 *
241 * Since: 0.9.2
242 **/
243hb_face_t *
244hb_face_reference (hb_face_t *face)
245{
246 return hb_object_reference (face);
247}
248
249/**
250 * hb_face_destroy: (skip)
251 * @face: a face.
252 *
253 *
254 *
255 * Since: 0.9.2
256 **/
257void
258hb_face_destroy (hb_face_t *face)
259{
260 if (!hb_object_destroy (face)) return;
261
262 for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
263 {
264 hb_face_t::plan_node_t *next = node->next;
265 hb_shape_plan_destroy (node->shape_plan);
266 free (node);
267 node = next;
268 }
269
270 face->data.fini ();
271 face->table.fini ();
272
273 if (face->destroy)
274 face->destroy (face->user_data);
275
276 free (face);
277}
278
279/**
280 * hb_face_set_user_data: (skip)
281 * @face: a face.
282 * @key:
283 * @data:
284 * @destroy:
285 * @replace:
286 *
287 *
288 *
289 * Return value:
290 *
291 * Since: 0.9.2
292 **/
293hb_bool_t
294hb_face_set_user_data (hb_face_t *face,
295 hb_user_data_key_t *key,
296 void * data,
297 hb_destroy_func_t destroy,
298 hb_bool_t replace)
299{
300 return hb_object_set_user_data (face, key, data, destroy, replace);
301}
302
303/**
304 * hb_face_get_user_data: (skip)
305 * @face: a face.
306 * @key:
307 *
308 *
309 *
310 * Return value: (transfer none):
311 *
312 * Since: 0.9.2
313 **/
314void *
315hb_face_get_user_data (const hb_face_t *face,
316 hb_user_data_key_t *key)
317{
318 return hb_object_get_user_data (face, key);
319}
320
321/**
322 * hb_face_make_immutable:
323 * @face: a face.
324 *
325 *
326 *
327 * Since: 0.9.2
328 **/
329void
330hb_face_make_immutable (hb_face_t *face)
331{
332 if (hb_object_is_immutable (face))
333 return;
334
335 hb_object_make_immutable (face);
336}
337
338/**
339 * hb_face_is_immutable:
340 * @face: a face.
341 *
342 *
343 *
344 * Return value:
345 *
346 * Since: 0.9.2
347 **/
348hb_bool_t
349hb_face_is_immutable (const hb_face_t *face)
350{
351 return hb_object_is_immutable (face);
352}
353
354
355/**
356 * hb_face_reference_table:
357 * @face: a face.
358 * @tag:
359 *
360 *
361 *
362 * Return value: (transfer full):
363 *
364 * Since: 0.9.2
365 **/
366hb_blob_t *
367hb_face_reference_table (const hb_face_t *face,
368 hb_tag_t tag)
369{
370 return face->reference_table (tag);
371}
372
373/**
374 * hb_face_reference_blob:
375 * @face: a face.
376 *
377 *
378 *
379 * Return value: (transfer full):
380 *
381 * Since: 0.9.2
382 **/
383hb_blob_t *
384hb_face_reference_blob (hb_face_t *face)
385{
386 return face->reference_table (HB_TAG_NONE);
387}
388
389/**
390 * hb_face_set_index:
391 * @face: a face.
392 * @index:
393 *
394 *
395 *
396 * Since: 0.9.2
397 **/
398void
399hb_face_set_index (hb_face_t *face,
400 unsigned int index)
401{
402 if (hb_object_is_immutable (face))
403 return;
404
405 face->index = index;
406}
407
408/**
409 * hb_face_get_index:
410 * @face: a face.
411 *
412 *
413 *
414 * Return value:
415 *
416 * Since: 0.9.2
417 **/
418unsigned int
419hb_face_get_index (const hb_face_t *face)
420{
421 return face->index;
422}
423
424/**
425 * hb_face_set_upem:
426 * @face: a face.
427 * @upem:
428 *
429 *
430 *
431 * Since: 0.9.2
432 **/
433void
434hb_face_set_upem (hb_face_t *face,
435 unsigned int upem)
436{
437 if (hb_object_is_immutable (face))
438 return;
439
440 face->upem.set_relaxed (upem);
441}
442
443/**
444 * hb_face_get_upem:
445 * @face: a face.
446 *
447 *
448 *
449 * Return value:
450 *
451 * Since: 0.9.2
452 **/
453unsigned int
454hb_face_get_upem (const hb_face_t *face)
455{
456 return face->get_upem ();
457}
458
459/**
460 * hb_face_set_glyph_count:
461 * @face: a face.
462 * @glyph_count:
463 *
464 *
465 *
466 * Since: 0.9.7
467 **/
468void
469hb_face_set_glyph_count (hb_face_t *face,
470 unsigned int glyph_count)
471{
472 if (hb_object_is_immutable (face))
473 return;
474
475 face->num_glyphs.set_relaxed (glyph_count);
476}
477
478/**
479 * hb_face_get_glyph_count:
480 * @face: a face.
481 *
482 *
483 *
484 * Return value:
485 *
486 * Since: 0.9.7
487 **/
488unsigned int
489hb_face_get_glyph_count (const hb_face_t *face)
490{
491 return face->get_num_glyphs ();
492}
493
494/**
495 * hb_face_get_table_tags:
496 * @face: a face.
497 * @start_offset: index of first tag to return.
498 * @table_count: input length of @table_tags array, output number of items written.
499 * @table_tags: array to write tags into.
500 *
501 * Retrieves table tags for a face, if possible.
502 *
503 * Return value: total number of tables, or 0 if not possible to list.
504 *
505 * Since: 1.6.0
506 **/
507unsigned int
508hb_face_get_table_tags (const hb_face_t *face,
509 unsigned int start_offset,
510 unsigned int *table_count, /* IN/OUT */
511 hb_tag_t *table_tags /* OUT */)
512{
513 if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
514 {
515 if (table_count)
516 *table_count = 0;
517 return 0;
518 }
519
520 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
521
522 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
523 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
524
525 return ot_face.get_table_tags (start_offset, table_count, table_tags);
526}
527
528
529/*
530 * Character set.
531 */
532
533
534/**
535 * hb_face_collect_unicodes:
536 * @face: font face.
537 * @out: set to add Unicode characters covered by @face to.
538 *
539 * Since: 1.9.0
540 */
541void
542hb_face_collect_unicodes (hb_face_t *face,
543 hb_set_t *out)
544{
545 face->table.cmap->collect_unicodes (out);
546}
547
548/**
549 * hb_face_collect_variation_selectors:
550 * @face: font face.
551 * @out: set to add Variation Selector characters covered by @face to.
552 *
553 *
554 *
555 * Since: 1.9.0
556 */
557void
558hb_face_collect_variation_selectors (hb_face_t *face,
559 hb_set_t *out)
560{
561 face->table.cmap->collect_variation_selectors (out);
562}
563
564/**
565 * hb_face_collect_variation_unicodes:
566 * @face: font face.
567 * @out: set to add Unicode characters for @variation_selector covered by @face to.
568 *
569 *
570 *
571 * Since: 1.9.0
572 */
573void
574hb_face_collect_variation_unicodes (hb_face_t *face,
575 hb_codepoint_t variation_selector,
576 hb_set_t *out)
577{
578 face->table.cmap->collect_variation_unicodes (variation_selector, out);
579}
580
581
582
583/*
584 * face-builder: A face that has add_table().
585 */
586
587struct hb_face_builder_data_t
588{
589 struct table_entry_t
590 {
591 int cmp (hb_tag_t t) const
592 {
593 if (t < tag) return -1;
594 if (t > tag) return -1;
595 return 0;
596 }
597
598 hb_tag_t tag;
599 hb_blob_t *blob;
600 };
601
602 hb_vector_t<table_entry_t> tables;
603};
604
605static hb_face_builder_data_t *
606_hb_face_builder_data_create ()
607{
608 hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
609 if (unlikely (!data))
610 return nullptr;
611
612 data->tables.init ();
613
614 return data;
615}
616
617static void
618_hb_face_builder_data_destroy (void *user_data)
619{
620 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
621
622 for (unsigned int i = 0; i < data->tables.length; i++)
623 hb_blob_destroy (data->tables[i].blob);
624
625 data->tables.fini ();
626
627 free (data);
628}
629
630static hb_blob_t *
631_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
632{
633
634 unsigned int table_count = data->tables.length;
635 unsigned int face_length = table_count * 16 + 12;
636
637 for (unsigned int i = 0; i < table_count; i++)
638 face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
639
640 char *buf = (char *) malloc (face_length);
641 if (unlikely (!buf))
642 return nullptr;
643
644 hb_serialize_context_t c (buf, face_length);
645 c.propagate_error (data->tables);
646 OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
647
648 bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
649 hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
650
651 bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
652
653 c.end_serialize ();
654
655 if (unlikely (!ret))
656 {
657 free (buf);
658 return nullptr;
659 }
660
661 return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
662}
663
664static hb_blob_t *
665_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
666{
667 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
668
669 if (!tag)
670 return _hb_face_builder_data_reference_blob (data);
671
672 hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
673 if (entry)
674 return hb_blob_reference (entry->blob);
675
676 return nullptr;
677}
678
679
680/**
681 * hb_face_builder_create:
682 *
683 * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
684 * After tables are added to the face, it can be compiled to a binary
685 * font file by calling hb_face_reference_blob().
686 *
687 * Return value: (transfer full): New face.
688 *
689 * Since: 1.9.0
690 **/
691hb_face_t *
692hb_face_builder_create ()
693{
694 hb_face_builder_data_t *data = _hb_face_builder_data_create ();
695 if (unlikely (!data)) return hb_face_get_empty ();
696
697 return hb_face_create_for_tables (_hb_face_builder_reference_table,
698 data,
699 _hb_face_builder_data_destroy);
700}
701
702/**
703 * hb_face_builder_add_table:
704 *
705 * Add table for @tag with data provided by @blob to the face. @face must
706 * be created using hb_face_builder_create().
707 *
708 * Since: 1.9.0
709 **/
710hb_bool_t
711hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
712{
713 if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
714 return false;
715
716 hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
717 hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
718
719 entry->tag = tag;
720 entry->blob = hb_blob_reference (blob);
721
722 return true;
723}
724