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 if (unlikely (tag == HB_TAG_NONE))
371 return hb_blob_get_empty ();
372
373 return face->reference_table (tag);
374}
375
376/**
377 * hb_face_reference_blob:
378 * @face: a face.
379 *
380 *
381 *
382 * Return value: (transfer full):
383 *
384 * Since: 0.9.2
385 **/
386hb_blob_t *
387hb_face_reference_blob (hb_face_t *face)
388{
389 return face->reference_table (HB_TAG_NONE);
390}
391
392/**
393 * hb_face_set_index:
394 * @face: a face.
395 * @index:
396 *
397 *
398 *
399 * Since: 0.9.2
400 **/
401void
402hb_face_set_index (hb_face_t *face,
403 unsigned int index)
404{
405 if (hb_object_is_immutable (face))
406 return;
407
408 face->index = index;
409}
410
411/**
412 * hb_face_get_index:
413 * @face: a face.
414 *
415 *
416 *
417 * Return value:
418 *
419 * Since: 0.9.2
420 **/
421unsigned int
422hb_face_get_index (const hb_face_t *face)
423{
424 return face->index;
425}
426
427/**
428 * hb_face_set_upem:
429 * @face: a face.
430 * @upem:
431 *
432 *
433 *
434 * Since: 0.9.2
435 **/
436void
437hb_face_set_upem (hb_face_t *face,
438 unsigned int upem)
439{
440 if (hb_object_is_immutable (face))
441 return;
442
443 face->upem.set_relaxed (upem);
444}
445
446/**
447 * hb_face_get_upem:
448 * @face: a face.
449 *
450 *
451 *
452 * Return value:
453 *
454 * Since: 0.9.2
455 **/
456unsigned int
457hb_face_get_upem (const hb_face_t *face)
458{
459 return face->get_upem ();
460}
461
462/**
463 * hb_face_set_glyph_count:
464 * @face: a face.
465 * @glyph_count:
466 *
467 *
468 *
469 * Since: 0.9.7
470 **/
471void
472hb_face_set_glyph_count (hb_face_t *face,
473 unsigned int glyph_count)
474{
475 if (hb_object_is_immutable (face))
476 return;
477
478 face->num_glyphs.set_relaxed (glyph_count);
479}
480
481/**
482 * hb_face_get_glyph_count:
483 * @face: a face.
484 *
485 *
486 *
487 * Return value:
488 *
489 * Since: 0.9.7
490 **/
491unsigned int
492hb_face_get_glyph_count (const hb_face_t *face)
493{
494 return face->get_num_glyphs ();
495}
496
497/**
498 * hb_face_get_table_tags:
499 * @face: a face.
500 * @start_offset: index of first tag to return.
501 * @table_count: input length of @table_tags array, output number of items written.
502 * @table_tags: array to write tags into.
503 *
504 * Retrieves table tags for a face, if possible.
505 *
506 * Return value: total number of tables, or 0 if not possible to list.
507 *
508 * Since: 1.6.0
509 **/
510unsigned int
511hb_face_get_table_tags (const hb_face_t *face,
512 unsigned int start_offset,
513 unsigned int *table_count, /* IN/OUT */
514 hb_tag_t *table_tags /* OUT */)
515{
516 if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
517 {
518 if (table_count)
519 *table_count = 0;
520 return 0;
521 }
522
523 hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
524
525 const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
526 const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
527
528 return ot_face.get_table_tags (start_offset, table_count, table_tags);
529}
530
531
532/*
533 * Character set.
534 */
535
536
537#ifndef HB_NO_FACE_COLLECT_UNICODES
538/**
539 * hb_face_collect_unicodes:
540 * @face: font face.
541 * @out: set to add Unicode characters covered by @face to.
542 *
543 * Since: 1.9.0
544 */
545void
546hb_face_collect_unicodes (hb_face_t *face,
547 hb_set_t *out)
548{
549 face->table.cmap->collect_unicodes (out);
550}
551/**
552 * hb_face_collect_variation_selectors:
553 * @face: font face.
554 * @out: set to add Variation Selector characters covered by @face to.
555 *
556 *
557 *
558 * Since: 1.9.0
559 */
560void
561hb_face_collect_variation_selectors (hb_face_t *face,
562 hb_set_t *out)
563{
564 face->table.cmap->collect_variation_selectors (out);
565}
566/**
567 * hb_face_collect_variation_unicodes:
568 * @face: font face.
569 * @out: set to add Unicode characters for @variation_selector covered by @face to.
570 *
571 *
572 *
573 * Since: 1.9.0
574 */
575void
576hb_face_collect_variation_unicodes (hb_face_t *face,
577 hb_codepoint_t variation_selector,
578 hb_set_t *out)
579{
580 face->table.cmap->collect_variation_unicodes (variation_selector, out);
581}
582#endif
583
584
585/*
586 * face-builder: A face that has add_table().
587 */
588
589struct hb_face_builder_data_t
590{
591 struct table_entry_t
592 {
593 int cmp (hb_tag_t t) const
594 {
595 if (t < tag) return -1;
596 if (t > tag) return -1;
597 return 0;
598 }
599
600 hb_tag_t tag;
601 hb_blob_t *blob;
602 };
603
604 hb_vector_t<table_entry_t> tables;
605};
606
607static hb_face_builder_data_t *
608_hb_face_builder_data_create ()
609{
610 hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
611 if (unlikely (!data))
612 return nullptr;
613
614 data->tables.init ();
615
616 return data;
617}
618
619static void
620_hb_face_builder_data_destroy (void *user_data)
621{
622 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
623
624 for (unsigned int i = 0; i < data->tables.length; i++)
625 hb_blob_destroy (data->tables[i].blob);
626
627 data->tables.fini ();
628
629 free (data);
630}
631
632static hb_blob_t *
633_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
634{
635
636 unsigned int table_count = data->tables.length;
637 unsigned int face_length = table_count * 16 + 12;
638
639 for (unsigned int i = 0; i < table_count; i++)
640 face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
641
642 char *buf = (char *) malloc (face_length);
643 if (unlikely (!buf))
644 return nullptr;
645
646 hb_serialize_context_t c (buf, face_length);
647 c.propagate_error (data->tables);
648 OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
649
650 bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
651 hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
652
653 bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
654
655 c.end_serialize ();
656
657 if (unlikely (!ret))
658 {
659 free (buf);
660 return nullptr;
661 }
662
663 return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
664}
665
666static hb_blob_t *
667_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
668{
669 hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
670
671 if (!tag)
672 return _hb_face_builder_data_reference_blob (data);
673
674 hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
675 if (entry)
676 return hb_blob_reference (entry->blob);
677
678 return nullptr;
679}
680
681
682/**
683 * hb_face_builder_create:
684 *
685 * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
686 * After tables are added to the face, it can be compiled to a binary
687 * font file by calling hb_face_reference_blob().
688 *
689 * Return value: (transfer full): New face.
690 *
691 * Since: 1.9.0
692 **/
693hb_face_t *
694hb_face_builder_create ()
695{
696 hb_face_builder_data_t *data = _hb_face_builder_data_create ();
697 if (unlikely (!data)) return hb_face_get_empty ();
698
699 return hb_face_create_for_tables (_hb_face_builder_reference_table,
700 data,
701 _hb_face_builder_data_destroy);
702}
703
704/**
705 * hb_face_builder_add_table:
706 *
707 * Add table for @tag with data provided by @blob to the face. @face must
708 * be created using hb_face_builder_create().
709 *
710 * Since: 1.9.0
711 **/
712hb_bool_t
713hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
714{
715 if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
716 return false;
717
718 hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
719 hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
720
721 entry->tag = tag;
722 entry->blob = hb_blob_reference (blob);
723
724 return true;
725}
726