hb-font.cc revision 7a750ac33ec482e2c4856c19ea607f3563741c24
1/*
2 * Copyright © 2009  Red Hat, Inc.
3 *
4 *  This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Red Hat Author(s): Behdad Esfahbod
25 */
26
27#include "hb-private.hh"
28
29#include "hb-ot-layout-private.hh"
30
31#include "hb-font-private.hh"
32#include "hb-blob.h"
33#include "hb-open-file-private.hh"
34#include "hb-ot-head-table.hh"
35
36#include <string.h>
37
38
39
40/*
41 * hb_font_funcs_t
42 */
43
44static hb_bool_t
45hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
46		       void *font_data HB_UNUSED,
47		       hb_codepoint_t unicode,
48		       hb_codepoint_t variation_selector,
49		       hb_codepoint_t *glyph,
50		       void *user_data HB_UNUSED)
51{
52  if (font->parent)
53    return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph);
54
55  *glyph = 0;
56  return FALSE;
57}
58
59static hb_position_t
60hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
61				 void *font_data HB_UNUSED,
62				 hb_codepoint_t glyph,
63				 void *user_data HB_UNUSED)
64{
65  if (font->parent)
66    return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph));
67
68  return font->x_scale;
69}
70
71static hb_position_t
72hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
73				 void *font_data HB_UNUSED,
74				 hb_codepoint_t glyph,
75				 void *user_data HB_UNUSED)
76{
77  if (font->parent)
78    return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph));
79
80  return font->y_scale;
81}
82
83static hb_bool_t
84hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
85				void *font_data HB_UNUSED,
86				hb_codepoint_t glyph,
87				hb_position_t *x,
88				hb_position_t *y,
89				void *user_data HB_UNUSED)
90{
91  if (font->parent) {
92    hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent,
93						glyph,
94						x, y);
95    if (ret)
96      font->parent_scale_position (x, y);
97    return ret;
98  }
99
100  *x = *y = 0;
101  return FALSE;
102}
103
104static hb_bool_t
105hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
106				void *font_data HB_UNUSED,
107				hb_codepoint_t glyph,
108				hb_position_t *x,
109				hb_position_t *y,
110				void *user_data HB_UNUSED)
111{
112  if (font->parent) {
113    hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent,
114						glyph,
115						x, y);
116    if (ret)
117      font->parent_scale_position (x, y);
118    return ret;
119  }
120
121  *x = *y = 0;
122  return FALSE;
123}
124
125static hb_position_t
126hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
127				 void *font_data HB_UNUSED,
128				 hb_codepoint_t left_glyph,
129				 hb_codepoint_t right_glyph,
130				 void *user_data HB_UNUSED)
131{
132  if (font->parent)
133    return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph));
134
135  return 0;
136}
137
138static hb_position_t
139hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
140				 void *font_data HB_UNUSED,
141				 hb_codepoint_t top_glyph,
142				 hb_codepoint_t bottom_glyph,
143				 void *user_data HB_UNUSED)
144{
145  if (font->parent)
146    return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph));
147
148  return 0;
149}
150
151static hb_bool_t
152hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
153			       void *font_data HB_UNUSED,
154			       hb_codepoint_t glyph,
155			       hb_glyph_extents_t *extents,
156			       void *user_data HB_UNUSED)
157{
158  if (font->parent) {
159    hb_bool_t ret = hb_font_get_glyph_extents (font->parent,
160					       glyph,
161					       extents);
162    if (ret) {
163      font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
164      font->parent_scale_distance (&extents->width, &extents->height);
165    }
166    return ret;
167  }
168
169  memset (extents, 0, sizeof (*extents));
170  return FALSE;
171}
172
173static hb_bool_t
174hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
175				     void *font_data HB_UNUSED,
176				     hb_codepoint_t glyph,
177				     unsigned int point_index,
178				     hb_position_t *x,
179				     hb_position_t *y,
180				     void *user_data HB_UNUSED)
181{
182  if (font->parent) {
183    hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent,
184						     glyph, point_index,
185						     x, y);
186    if (ret)
187      font->parent_scale_position (x, y);
188    return ret;
189  }
190
191  *x = *y = 0;
192  return FALSE;
193}
194
195
196static hb_font_funcs_t _hb_font_funcs_nil = {
197  HB_OBJECT_HEADER_STATIC,
198
199  TRUE, /* immutable */
200
201  {
202#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
203    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
204#undef HB_FONT_FUNC_IMPLEMENT
205  }
206};
207
208
209hb_font_funcs_t *
210hb_font_funcs_create (void)
211{
212  hb_font_funcs_t *ffuncs;
213
214  if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
215    return &_hb_font_funcs_nil;
216
217  ffuncs->get = _hb_font_funcs_nil.get;
218
219  return ffuncs;
220}
221
222hb_font_funcs_t *
223hb_font_funcs_get_empty (void)
224{
225  return &_hb_font_funcs_nil;
226}
227
228hb_font_funcs_t *
229hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
230{
231  return hb_object_reference (ffuncs);
232}
233
234void
235hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
236{
237  if (!hb_object_destroy (ffuncs)) return;
238
239#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \
240  ffuncs->destroy.name (ffuncs->user_data.name);
241  HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
242#undef HB_FONT_FUNC_IMPLEMENT
243
244  free (ffuncs);
245}
246
247hb_bool_t
248hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
249			     hb_user_data_key_t *key,
250			     void *              data,
251			     hb_destroy_func_t   destroy,
252			     hb_bool_t           replace)
253{
254  return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
255}
256
257void *
258hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
259			     hb_user_data_key_t *key)
260{
261  return hb_object_get_user_data (ffuncs, key);
262}
263
264
265void
266hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
267{
268  if (hb_object_is_inert (ffuncs))
269    return;
270
271  ffuncs->immutable = TRUE;
272}
273
274hb_bool_t
275hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
276{
277  return ffuncs->immutable;
278}
279
280
281#define HB_FONT_FUNC_IMPLEMENT(name) \
282                                                                         \
283void                                                                     \
284hb_font_funcs_set_##name##_func (hb_font_funcs_t             *ffuncs,    \
285                                 hb_font_get_##name##_func_t  func,      \
286                                 void                        *user_data, \
287                                 hb_destroy_func_t            destroy)   \
288{                                                                        \
289  if (ffuncs->immutable)                                                 \
290    return;                                                              \
291                                                                         \
292  if (ffuncs->destroy.name)                                              \
293    ffuncs->destroy.name (ffuncs->user_data.name);                       \
294                                                                         \
295  if (func) {                                                            \
296    ffuncs->get.name = func;                                             \
297    ffuncs->user_data.name = user_data;                                  \
298    ffuncs->destroy.name = destroy;                                      \
299  } else {                                                               \
300    ffuncs->get.name = hb_font_get_##name##_nil;                         \
301    ffuncs->user_data.name = NULL;                                       \
302    ffuncs->destroy.name = NULL;                                         \
303  }                                                                      \
304}
305
306HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
307#undef HB_FONT_FUNC_IMPLEMENT
308
309
310hb_bool_t
311hb_font_get_glyph (hb_font_t *font,
312		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
313		   hb_codepoint_t *glyph)
314{
315  *glyph = 0;
316  return font->klass->get.glyph (font, font->user_data,
317				 unicode, variation_selector, glyph,
318				 font->klass->user_data.glyph);
319}
320
321hb_position_t
322hb_font_get_glyph_h_advance (hb_font_t *font,
323			     hb_codepoint_t glyph)
324{
325  return font->klass->get.glyph_h_advance (font, font->user_data,
326					   glyph,
327					   font->klass->user_data.glyph_h_advance);
328}
329
330hb_position_t
331hb_font_get_glyph_v_advance (hb_font_t *font,
332			     hb_codepoint_t glyph)
333{
334  return font->klass->get.glyph_v_advance (font, font->user_data,
335					   glyph,
336					   font->klass->user_data.glyph_v_advance);
337}
338
339hb_bool_t
340hb_font_get_glyph_h_origin (hb_font_t *font,
341			    hb_codepoint_t glyph,
342			    hb_position_t *x, hb_position_t *y)
343{
344  *x = *y = 0;
345  return font->klass->get.glyph_h_origin (font, font->user_data,
346					   glyph, x, y,
347					   font->klass->user_data.glyph_h_origin);
348}
349
350hb_bool_t
351hb_font_get_glyph_v_origin (hb_font_t *font,
352			    hb_codepoint_t glyph,
353			    hb_position_t *x, hb_position_t *y)
354{
355  *x = *y = 0;
356  return font->klass->get.glyph_v_origin (font, font->user_data,
357					   glyph, x, y,
358					   font->klass->user_data.glyph_v_origin);
359}
360
361hb_position_t
362hb_font_get_glyph_h_kerning (hb_font_t *font,
363			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
364{
365  return font->klass->get.glyph_h_kerning (font, font->user_data,
366					   left_glyph, right_glyph,
367					   font->klass->user_data.glyph_h_kerning);
368}
369
370hb_position_t
371hb_font_get_glyph_v_kerning (hb_font_t *font,
372			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
373{
374  return font->klass->get.glyph_v_kerning (font, font->user_data,
375				     left_glyph, right_glyph,
376				     font->klass->user_data.glyph_v_kerning);
377}
378
379hb_bool_t
380hb_font_get_glyph_extents (hb_font_t *font,
381			   hb_codepoint_t glyph,
382			   hb_glyph_extents_t *extents)
383{
384  memset (extents, 0, sizeof (*extents));
385  return font->klass->get.glyph_extents (font, font->user_data,
386					 glyph,
387					 extents,
388					 font->klass->user_data.glyph_extents);
389}
390
391hb_bool_t
392hb_font_get_glyph_contour_point (hb_font_t *font,
393				 hb_codepoint_t glyph, unsigned int point_index,
394				 hb_position_t *x, hb_position_t *y)
395{
396  *x = *y = 0;
397  return font->klass->get.glyph_contour_point (font, font->user_data,
398					       glyph, point_index,
399					       x, y,
400					       font->klass->user_data.glyph_contour_point);
401}
402
403
404/* A bit higher-level, and with fallback */
405
406void
407hb_font_get_glyph_advance_for_direction (hb_font_t *font,
408					 hb_codepoint_t glyph,
409					 hb_direction_t direction,
410					 hb_position_t *x, hb_position_t *y)
411{
412  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
413    *x = hb_font_get_glyph_h_advance (font, glyph);
414    *y = 0;
415  } else {
416    *x = 0;
417    *y = hb_font_get_glyph_v_advance (font, glyph);
418  }
419}
420
421static void
422guess_v_origin_minus_h_origin (hb_font_t *font,
423			       hb_codepoint_t glyph,
424			       hb_position_t *x, hb_position_t *y)
425{
426  *x = hb_font_get_glyph_h_advance (font, glyph) / 2;
427
428  /* TODO use font_metics.ascent */
429  *y = font->y_scale;
430}
431
432
433void
434hb_font_get_glyph_origin_for_direction (hb_font_t *font,
435					hb_codepoint_t glyph,
436					hb_direction_t direction,
437					hb_position_t *x, hb_position_t *y)
438{
439  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
440    hb_bool_t ret = hb_font_get_glyph_h_origin (font, glyph, x, y);
441    if (!ret && (ret = hb_font_get_glyph_v_origin (font, glyph, x, y))) {
442      hb_position_t dx, dy;
443      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
444      *x -= dx; *y -= dy;
445    }
446  } else {
447    hb_bool_t ret = hb_font_get_glyph_v_origin (font, glyph, x, y);
448    if (!ret && (ret = hb_font_get_glyph_h_origin (font, glyph, x, y))) {
449      hb_position_t dx, dy;
450      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
451      *x += dx; *y += dy;
452    }
453  }
454}
455
456void
457hb_font_add_glyph_origin_for_direction (hb_font_t *font,
458					hb_codepoint_t glyph,
459					hb_direction_t direction,
460					hb_position_t *x, hb_position_t *y)
461{
462  hb_position_t origin_x, origin_y;
463
464  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
465
466  *x += origin_x;
467  *y += origin_y;
468}
469
470void
471hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
472					     hb_codepoint_t glyph,
473					     hb_direction_t direction,
474					     hb_position_t *x, hb_position_t *y)
475{
476  hb_position_t origin_x, origin_y;
477
478  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
479
480  *x -= origin_x;
481  *y -= origin_y;
482}
483
484void
485hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
486					 hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
487					 hb_direction_t direction,
488					 hb_position_t *x, hb_position_t *y)
489{
490  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
491    *x = hb_font_get_glyph_h_kerning (font, first_glyph, second_glyph);
492    *y = 0;
493  } else {
494    *x = 0;
495    *y = hb_font_get_glyph_v_kerning (font, first_glyph, second_glyph);
496  }
497}
498
499hb_bool_t
500hb_font_get_glyph_extents_for_origin (hb_font_t *font,
501				      hb_codepoint_t glyph,
502				      hb_direction_t direction,
503				      hb_glyph_extents_t *extents)
504{
505  hb_bool_t ret = hb_font_get_glyph_extents (font, glyph, extents);
506
507  if (ret)
508    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, &extents->x_bearing, &extents->y_bearing);
509
510  return ret;
511}
512
513hb_bool_t
514hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
515					    hb_codepoint_t glyph, unsigned int point_index,
516					    hb_direction_t direction,
517					    hb_position_t *x, hb_position_t *y)
518{
519  hb_bool_t ret = hb_font_get_glyph_contour_point (font, glyph, point_index, x, y);
520
521  if (ret)
522    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, x, y);
523
524  return ret;
525}
526
527
528/*
529 * hb_face_t
530 */
531
532static hb_face_t _hb_face_nil = {
533  HB_OBJECT_HEADER_STATIC,
534
535  TRUE, /* immutable */
536
537  NULL, /* reference_table */
538  NULL, /* user_data */
539  NULL, /* destroy */
540
541  NULL, /* ot_layout */
542
543  0,    /* index */
544  1000  /* upem */
545};
546
547
548hb_face_t *
549hb_face_create_for_tables (hb_reference_table_func_t  reference_table,
550			   void                      *user_data,
551			   hb_destroy_func_t          destroy)
552{
553  hb_face_t *face;
554
555  if (!reference_table || !(face = hb_object_create<hb_face_t> ())) {
556    if (destroy)
557      destroy (user_data);
558    return &_hb_face_nil;
559  }
560
561  face->reference_table = reference_table;
562  face->user_data = user_data;
563  face->destroy = destroy;
564
565  face->ot_layout = _hb_ot_layout_create (face);
566
567  face->upem = 0;
568
569  return face;
570}
571
572
573typedef struct _hb_face_for_data_closure_t {
574  hb_blob_t *blob;
575  unsigned int  index;
576} hb_face_for_data_closure_t;
577
578static hb_face_for_data_closure_t *
579_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
580{
581  hb_face_for_data_closure_t *closure;
582
583  closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
584  if (unlikely (!closure))
585    return NULL;
586
587  closure->blob = blob;
588  closure->index = index;
589
590  return closure;
591}
592
593static void
594_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
595{
596  hb_blob_destroy (closure->blob);
597  free (closure);
598}
599
600static hb_blob_t *
601_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
602{
603  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
604
605  if (tag == HB_TAG_NONE)
606    return hb_blob_reference (data->blob);
607
608  const OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob);
609  const OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
610
611  const OpenTypeTable &table = ot_face.get_table_by_tag (tag);
612
613  hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
614
615  return blob;
616}
617
618hb_face_t *
619hb_face_create (hb_blob_t    *blob,
620		unsigned int  index)
621{
622  hb_face_t *face;
623
624  if (unlikely (!blob || !hb_blob_get_length (blob)))
625    return &_hb_face_nil;
626
627  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
628
629  if (unlikely (!closure))
630    return &_hb_face_nil;
631
632  face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
633				    closure,
634				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
635
636  hb_face_set_index (face, index);
637
638  return face;
639}
640
641hb_face_t *
642hb_face_get_empty (void)
643{
644  return &_hb_face_nil;
645}
646
647
648hb_face_t *
649hb_face_reference (hb_face_t *face)
650{
651  return hb_object_reference (face);
652}
653
654void
655hb_face_destroy (hb_face_t *face)
656{
657  if (!hb_object_destroy (face)) return;
658
659  _hb_ot_layout_destroy (face->ot_layout);
660
661  if (face->destroy)
662    face->destroy (face->user_data);
663
664  free (face);
665}
666
667hb_bool_t
668hb_face_set_user_data (hb_face_t          *face,
669		       hb_user_data_key_t *key,
670		       void *              data,
671		       hb_destroy_func_t   destroy,
672		       hb_bool_t           replace)
673{
674  return hb_object_set_user_data (face, key, data, destroy, replace);
675}
676
677void *
678hb_face_get_user_data (hb_face_t          *face,
679		       hb_user_data_key_t *key)
680{
681  return hb_object_get_user_data (face, key);
682}
683
684void
685hb_face_make_immutable (hb_face_t *face)
686{
687  if (hb_object_is_inert (face))
688    return;
689
690  face->immutable = true;
691}
692
693hb_bool_t
694hb_face_is_immutable (hb_face_t *face)
695{
696  return face->immutable;
697}
698
699
700hb_blob_t *
701hb_face_reference_table (hb_face_t *face,
702			 hb_tag_t   tag)
703{
704  hb_blob_t *blob;
705
706  if (unlikely (!face || !face->reference_table))
707    return hb_blob_get_empty ();
708
709  blob = face->reference_table (face, tag, face->user_data);
710  if (unlikely (!blob))
711    return hb_blob_get_empty ();
712
713  return blob;
714}
715
716hb_blob_t *
717hb_face_reference_blob (hb_face_t *face)
718{
719  return hb_face_reference_table (face, HB_TAG_NONE);
720}
721
722void
723hb_face_set_index (hb_face_t    *face,
724		   unsigned int  index)
725{
726  if (hb_object_is_inert (face))
727    return;
728
729  face->index = 0;
730}
731
732unsigned int
733hb_face_get_index (hb_face_t    *face)
734{
735  return face->index;
736}
737
738void
739hb_face_set_upem (hb_face_t    *face,
740		  unsigned int  upem)
741{
742  if (hb_object_is_inert (face))
743    return;
744
745  face->upem = upem;
746}
747
748unsigned int
749hb_face_get_upem (hb_face_t *face)
750{
751  if (unlikely (!face->upem)) {
752    hb_blob_t *head_blob = Sanitizer<head>::sanitize (hb_face_reference_table (face, HB_OT_TAG_head));
753    const head *head_table = Sanitizer<head>::lock_instance (head_blob);
754    face->upem = head_table->get_upem ();
755    hb_blob_destroy (head_blob);
756  }
757  return face->upem;
758}
759
760
761/*
762 * hb_font_t
763 */
764
765static hb_font_t _hb_font_nil = {
766  HB_OBJECT_HEADER_STATIC,
767
768  TRUE, /* immutable */
769
770  NULL, /* parent */
771  &_hb_face_nil,
772
773  0, /* x_scale */
774  0, /* y_scale */
775
776  0, /* x_ppem */
777  0, /* y_ppem */
778
779  &_hb_font_funcs_nil, /* klass */
780  NULL, /* user_data */
781  NULL  /* destroy */
782};
783
784hb_font_t *
785hb_font_create (hb_face_t *face)
786{
787  hb_font_t *font;
788
789  if (unlikely (!face))
790    face = &_hb_face_nil;
791  if (unlikely (hb_object_is_inert (face)))
792    return &_hb_font_nil;
793  if (!(font = hb_object_create<hb_font_t> ()))
794    return &_hb_font_nil;
795
796  hb_face_make_immutable (face);
797  font->face = hb_face_reference (face);
798  font->klass = &_hb_font_funcs_nil;
799
800  return font;
801}
802
803hb_font_t *
804hb_font_create_sub_font (hb_font_t *parent)
805{
806  if (unlikely (!parent))
807    return &_hb_font_nil;
808
809  hb_font_t *font = hb_font_create (parent->face);
810
811  if (unlikely (hb_object_is_inert (font)))
812    return font;
813
814  hb_font_make_immutable (parent);
815  font->parent = hb_font_reference (parent);
816
817  font->x_scale = parent->x_scale;
818  font->y_scale = parent->y_scale;
819  font->x_ppem = parent->x_ppem;
820  font->y_ppem = parent->y_ppem;
821
822  font->klass = &_hb_font_funcs_nil;
823
824  return font;
825}
826
827hb_font_t *
828hb_font_get_empty (void)
829{
830  return &_hb_font_nil;
831}
832
833hb_font_t *
834hb_font_reference (hb_font_t *font)
835{
836  return hb_object_reference (font);
837}
838
839void
840hb_font_destroy (hb_font_t *font)
841{
842  if (!hb_object_destroy (font)) return;
843
844  hb_font_destroy (font->parent);
845  hb_face_destroy (font->face);
846  hb_font_funcs_destroy (font->klass);
847  if (font->destroy)
848    font->destroy (font->user_data);
849
850  free (font);
851}
852
853hb_bool_t
854hb_font_set_user_data (hb_font_t          *font,
855		       hb_user_data_key_t *key,
856		       void *              data,
857		       hb_destroy_func_t   destroy,
858		       hb_bool_t           replace)
859{
860  return hb_object_set_user_data (font, key, data, destroy, replace);
861}
862
863void *
864hb_font_get_user_data (hb_font_t          *font,
865		       hb_user_data_key_t *key)
866{
867  return hb_object_get_user_data (font, key);
868}
869
870void
871hb_font_make_immutable (hb_font_t *font)
872{
873  if (hb_object_is_inert (font))
874    return;
875
876  font->immutable = true;
877}
878
879hb_bool_t
880hb_font_is_immutable (hb_font_t *font)
881{
882  return font->immutable;
883}
884
885hb_font_t *
886hb_font_get_parent (hb_font_t *font)
887{
888  return font->parent;
889}
890
891hb_face_t *
892hb_font_get_face (hb_font_t *font)
893{
894  return font->face;
895}
896
897
898void
899hb_font_set_funcs (hb_font_t         *font,
900		   hb_font_funcs_t   *klass,
901		   void              *user_data,
902		   hb_destroy_func_t  destroy)
903{
904  if (font->immutable)
905    return;
906
907  if (font->destroy)
908    font->destroy (font->user_data);
909
910  if (!klass)
911    klass = &_hb_font_funcs_nil;
912
913  hb_font_funcs_reference (klass);
914  hb_font_funcs_destroy (font->klass);
915  font->klass = klass;
916  font->user_data = user_data;
917  font->destroy = destroy;
918}
919
920
921void
922hb_font_set_scale (hb_font_t *font,
923		   int x_scale,
924		   int y_scale)
925{
926  if (font->immutable)
927    return;
928
929  font->x_scale = x_scale;
930  font->y_scale = y_scale;
931}
932
933void
934hb_font_get_scale (hb_font_t *font,
935		   int *x_scale,
936		   int *y_scale)
937{
938  if (x_scale) *x_scale = font->x_scale;
939  if (y_scale) *y_scale = font->y_scale;
940}
941
942void
943hb_font_set_ppem (hb_font_t *font,
944		  unsigned int x_ppem,
945		  unsigned int y_ppem)
946{
947  if (font->immutable)
948    return;
949
950  font->x_ppem = x_ppem;
951  font->y_ppem = y_ppem;
952}
953
954void
955hb_font_get_ppem (hb_font_t *font,
956		  unsigned int *x_ppem,
957		  unsigned int *y_ppem)
958{
959  if (x_ppem) *x_ppem = font->x_ppem;
960  if (y_ppem) *y_ppem = font->y_ppem;
961}
962
963
964