[API] One last font-funcs API change
[apps/home/video-player.git] / src / hb-font.cc
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
35 #include <string.h>
36
37 HB_BEGIN_DECLS
38
39
40 /*
41  * hb_font_funcs_t
42  */
43
44 static hb_bool_t
45 hb_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
59 static hb_position_t
60 hb_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
71 static hb_position_t
72 hb_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
83 static hb_bool_t
84 hb_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
104 static hb_bool_t
105 hb_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
125 static hb_position_t
126 hb_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
138 static hb_position_t
139 hb_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
151 static hb_bool_t
152 hb_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
173 static hb_bool_t
174 hb_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
196 static 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
209 hb_font_funcs_t *
210 hb_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
222 hb_font_funcs_t *
223 hb_font_funcs_get_empty (void)
224 {
225   return &_hb_font_funcs_nil;
226 }
227
228 hb_font_funcs_t *
229 hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
230 {
231   return hb_object_reference (ffuncs);
232 }
233
234 void
235 hb_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) ffuncs->destroy.name (ffuncs->user_data.name);
240   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
241 #undef HB_FONT_FUNC_IMPLEMENT
242
243   free (ffuncs);
244 }
245
246 hb_bool_t
247 hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
248                              hb_user_data_key_t *key,
249                              void *              data,
250                              hb_destroy_func_t   destroy)
251 {
252   return hb_object_set_user_data (ffuncs, key, data, destroy);
253 }
254
255 void *
256 hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
257                              hb_user_data_key_t *key)
258 {
259   return hb_object_get_user_data (ffuncs, key);
260 }
261
262
263 void
264 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
265 {
266   if (hb_object_is_inert (ffuncs))
267     return;
268
269   ffuncs->immutable = TRUE;
270 }
271
272 hb_bool_t
273 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
274 {
275   return ffuncs->immutable;
276 }
277
278
279 #define HB_FONT_FUNC_IMPLEMENT(name) \
280                                                                          \
281 void                                                                     \
282 hb_font_funcs_set_##name##_func (hb_font_funcs_t             *ffuncs,    \
283                                  hb_font_get_##name##_func_t  func,      \
284                                  void                        *user_data, \
285                                  hb_destroy_func_t            destroy)   \
286 {                                                                        \
287   if (ffuncs->immutable)                                                 \
288     return;                                                              \
289                                                                          \
290   if (ffuncs->destroy.name)                                              \
291     ffuncs->destroy.name (ffuncs->user_data.name);                       \
292                                                                          \
293   if (func) {                                                            \
294     ffuncs->get.name = func;                                             \
295     ffuncs->user_data.name = user_data;                                  \
296     ffuncs->destroy.name = destroy;                                      \
297   } else {                                                               \
298     ffuncs->get.name = hb_font_get_##name##_nil;                         \
299     ffuncs->user_data.name = NULL;                                       \
300     ffuncs->destroy.name = NULL;                                         \
301   }                                                                      \
302 }
303
304 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
305 #undef HB_FONT_FUNC_IMPLEMENT
306
307
308 hb_bool_t
309 hb_font_get_glyph (hb_font_t *font,
310                    hb_codepoint_t unicode, hb_codepoint_t variation_selector,
311                    hb_codepoint_t *glyph)
312 {
313   *glyph = 0;
314   return font->klass->get.glyph (font, font->user_data,
315                                  unicode, variation_selector, glyph,
316                                  font->klass->user_data.glyph);
317 }
318
319 hb_position_t
320 hb_font_get_glyph_h_advance (hb_font_t *font,
321                              hb_codepoint_t glyph)
322 {
323   return font->klass->get.glyph_h_advance (font, font->user_data,
324                                            glyph,
325                                            font->klass->user_data.glyph_h_advance);
326 }
327
328 hb_position_t
329 hb_font_get_glyph_v_advance (hb_font_t *font,
330                              hb_codepoint_t glyph)
331 {
332   return font->klass->get.glyph_v_advance (font, font->user_data,
333                                            glyph,
334                                            font->klass->user_data.glyph_v_advance);
335 }
336
337 hb_bool_t
338 hb_font_get_glyph_h_origin (hb_font_t *font,
339                             hb_codepoint_t glyph,
340                             hb_position_t *x, hb_position_t *y)
341 {
342   *x = *y = 0;
343   return font->klass->get.glyph_h_origin (font, font->user_data,
344                                            glyph, x, y,
345                                            font->klass->user_data.glyph_h_origin);
346 }
347
348 hb_bool_t
349 hb_font_get_glyph_v_origin (hb_font_t *font,
350                             hb_codepoint_t glyph,
351                             hb_position_t *x, hb_position_t *y)
352 {
353   *x = *y = 0;
354   return font->klass->get.glyph_v_origin (font, font->user_data,
355                                            glyph, x, y,
356                                            font->klass->user_data.glyph_v_origin);
357 }
358
359 hb_position_t
360 hb_font_get_glyph_h_kerning (hb_font_t *font,
361                              hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
362 {
363   return font->klass->get.glyph_h_kerning (font, font->user_data,
364                                            left_glyph, right_glyph,
365                                            font->klass->user_data.glyph_h_kerning);
366 }
367
368 hb_position_t
369 hb_font_get_glyph_v_kerning (hb_font_t *font,
370                              hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
371 {
372   return font->klass->get.glyph_v_kerning (font, font->user_data,
373                                      left_glyph, right_glyph,
374                                      font->klass->user_data.glyph_v_kerning);
375 }
376
377 hb_bool_t
378 hb_font_get_glyph_extents (hb_font_t *font,
379                            hb_codepoint_t glyph,
380                            hb_glyph_extents_t *extents)
381 {
382   memset (extents, 0, sizeof (*extents));
383   return font->klass->get.glyph_extents (font, font->user_data,
384                                          glyph,
385                                          extents,
386                                          font->klass->user_data.glyph_extents);
387 }
388
389 hb_bool_t
390 hb_font_get_glyph_contour_point (hb_font_t *font,
391                                  hb_codepoint_t glyph, unsigned int point_index,
392                                  hb_position_t *x, hb_position_t *y)
393 {
394   *x = *y = 0;
395   return font->klass->get.glyph_contour_point (font, font->user_data,
396                                                glyph, point_index,
397                                                x, y,
398                                                font->klass->user_data.glyph_contour_point);
399 }
400
401
402 /* A bit higher-level, and with fallback */
403
404 void
405 hb_font_get_glyph_advance_for_direction (hb_font_t *font,
406                                          hb_codepoint_t glyph,
407                                          hb_direction_t direction,
408                                          hb_position_t *x, hb_position_t *y)
409 {
410   if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
411     *x = hb_font_get_glyph_h_advance (font, glyph);
412     *y = 0;
413   } else {
414     *x = 0;
415     *y = hb_font_get_glyph_v_advance (font, glyph);
416   }
417 }
418
419 static void
420 guess_v_origin_minus_h_origin (hb_font_t *font,
421                                hb_codepoint_t glyph,
422                                hb_position_t *x, hb_position_t *y)
423 {
424   *x = hb_font_get_glyph_h_advance (font, glyph) / 2;
425
426   /* TODO use font_metics.ascent */
427   *y = font->y_scale;
428 }
429
430
431 void
432 hb_font_get_glyph_origin_for_direction (hb_font_t *font,
433                                         hb_codepoint_t glyph,
434                                         hb_direction_t direction,
435                                         hb_position_t *x, hb_position_t *y)
436 {
437   if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
438     hb_bool_t ret = hb_font_get_glyph_h_origin (font, glyph, x, y);
439     if (!ret && (ret = hb_font_get_glyph_v_origin (font, glyph, x, y))) {
440       hb_position_t dx, dy;
441       guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
442       *x -= dx; *y -= dy;
443     }
444   } else {
445     hb_bool_t ret = hb_font_get_glyph_v_origin (font, glyph, x, y);
446     if (!ret && (ret = hb_font_get_glyph_h_origin (font, glyph, x, y))) {
447       hb_position_t dx, dy;
448       guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
449       *x += dx; *y += dy;
450     }
451   }
452 }
453
454 void
455 hb_font_add_glyph_origin_for_direction (hb_font_t *font,
456                                         hb_codepoint_t glyph,
457                                         hb_direction_t direction,
458                                         hb_position_t *x, hb_position_t *y)
459 {
460   hb_position_t origin_x, origin_y;
461
462   hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
463
464   *x += origin_x;
465   *y += origin_y;
466 }
467
468 void
469 hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
470                                              hb_codepoint_t glyph,
471                                              hb_direction_t direction,
472                                              hb_position_t *x, hb_position_t *y)
473 {
474   hb_position_t origin_x, origin_y;
475
476   hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
477
478   *x -= origin_x;
479   *y -= origin_y;
480 }
481
482 void
483 hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
484                                          hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
485                                          hb_direction_t direction,
486                                          hb_position_t *x, hb_position_t *y)
487 {
488   if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
489     *x = hb_font_get_glyph_h_kerning (font, first_glyph, second_glyph);
490     *y = 0;
491   } else {
492     *x = 0;
493     *y = hb_font_get_glyph_v_kerning (font, first_glyph, second_glyph);
494   }
495 }
496
497 hb_bool_t
498 hb_font_get_glyph_extents_for_origin (hb_font_t *font,
499                                       hb_codepoint_t glyph,
500                                       hb_direction_t direction,
501                                       hb_glyph_extents_t *extents)
502 {
503   hb_bool_t ret = hb_font_get_glyph_extents (font, glyph, extents);
504
505   if (ret)
506     hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, &extents->x_bearing, &extents->y_bearing);
507
508   return ret;
509 }
510
511 hb_bool_t
512 hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
513                                             hb_codepoint_t glyph, unsigned int point_index,
514                                             hb_direction_t direction,
515                                             hb_position_t *x, hb_position_t *y)
516 {
517   hb_bool_t ret = hb_font_get_glyph_contour_point (font, glyph, point_index, x, y);
518
519   if (ret)
520     hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, x, y);
521
522   return ret;
523 }
524
525
526 /*
527  * hb_face_t
528  */
529
530 static hb_face_t _hb_face_nil = {
531   HB_OBJECT_HEADER_STATIC,
532
533   TRUE, /* immutable */
534
535   NULL, /* get_table */
536   NULL, /* user_data */
537   NULL, /* destroy */
538
539   NULL, /* ot_layout */
540
541   1000
542 };
543
544
545 hb_face_t *
546 hb_face_create_for_tables (hb_get_table_func_t  get_table,
547                            void                *user_data,
548                            hb_destroy_func_t    destroy)
549 {
550   hb_face_t *face;
551
552   if (!get_table || !(face = hb_object_create<hb_face_t> ())) {
553     if (destroy)
554       destroy (user_data);
555     return &_hb_face_nil;
556   }
557
558   face->get_table = get_table;
559   face->user_data = user_data;
560   face->destroy = destroy;
561
562   face->ot_layout = _hb_ot_layout_create (face);
563
564   face->upem = _hb_ot_layout_get_upem (face);
565
566   return face;
567 }
568
569
570 typedef struct _hb_face_for_data_closure_t {
571   hb_blob_t *blob;
572   unsigned int  index;
573 } hb_face_for_data_closure_t;
574
575 static hb_face_for_data_closure_t *
576 _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
577 {
578   hb_face_for_data_closure_t *closure;
579
580   closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
581   if (unlikely (!closure))
582     return NULL;
583
584   closure->blob = blob;
585   closure->index = index;
586
587   return closure;
588 }
589
590 static void
591 _hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
592 {
593   hb_blob_destroy (closure->blob);
594   free (closure);
595 }
596
597 static hb_blob_t *
598 _hb_face_for_data_get_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
599 {
600   hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
601
602   const OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob);
603   const OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
604
605   const OpenTypeTable &table = ot_face.get_table_by_tag (tag);
606
607   hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
608
609   return blob;
610 }
611
612 hb_face_t *
613 hb_face_create (hb_blob_t    *blob,
614                 unsigned int  index)
615 {
616   if (unlikely (!blob || !hb_blob_get_length (blob)))
617     return &_hb_face_nil;
618
619   hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
620
621   if (unlikely (!closure))
622     return &_hb_face_nil;
623
624   return hb_face_create_for_tables (_hb_face_for_data_get_table,
625                                     closure,
626                                     (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
627 }
628
629 hb_face_t *
630 hb_face_get_empty (void)
631 {
632   return &_hb_face_nil;
633 }
634
635
636 hb_face_t *
637 hb_face_reference (hb_face_t *face)
638 {
639   return hb_object_reference (face);
640 }
641
642 void
643 hb_face_destroy (hb_face_t *face)
644 {
645   if (!hb_object_destroy (face)) return;
646
647   _hb_ot_layout_destroy (face->ot_layout);
648
649   if (face->destroy)
650     face->destroy (face->user_data);
651
652   free (face);
653 }
654
655 hb_bool_t
656 hb_face_set_user_data (hb_face_t          *face,
657                        hb_user_data_key_t *key,
658                        void *              data,
659                        hb_destroy_func_t   destroy)
660 {
661   return hb_object_set_user_data (face, key, data, destroy);
662 }
663
664 void *
665 hb_face_get_user_data (hb_face_t          *face,
666                        hb_user_data_key_t *key)
667 {
668   return hb_object_get_user_data (face, key);
669 }
670
671 void
672 hb_face_make_immutable (hb_face_t *face)
673 {
674   if (hb_object_is_inert (face))
675     return;
676
677   face->immutable = true;
678 }
679
680 hb_bool_t
681 hb_face_is_immutable (hb_face_t *face)
682 {
683   return face->immutable;
684 }
685
686
687 hb_blob_t *
688 hb_face_reference_table (hb_face_t *face,
689                          hb_tag_t   tag)
690 {
691   hb_blob_t *blob;
692
693   if (unlikely (!face || !face->get_table))
694     return hb_blob_get_empty ();
695
696   blob = face->get_table (face, tag, face->user_data);
697   if (unlikely (!blob))
698     return hb_blob_get_empty ();
699
700   return blob;
701 }
702
703 unsigned int
704 hb_face_get_upem (hb_face_t *face)
705 {
706   return _hb_ot_layout_get_upem (face);
707 }
708
709
710 /*
711  * hb_font_t
712  */
713
714 static hb_font_t _hb_font_nil = {
715   HB_OBJECT_HEADER_STATIC,
716
717   TRUE, /* immutable */
718
719   NULL, /* parent */
720   &_hb_face_nil,
721
722   0, /* x_scale */
723   0, /* y_scale */
724
725   0, /* x_ppem */
726   0, /* y_ppem */
727
728   &_hb_font_funcs_nil, /* klass */
729   NULL, /* user_data */
730   NULL  /* destroy */
731 };
732
733 hb_font_t *
734 hb_font_create (hb_face_t *face)
735 {
736   hb_font_t *font;
737
738   if (unlikely (!face))
739     face = &_hb_face_nil;
740   if (unlikely (hb_object_is_inert (face)))
741     return &_hb_font_nil;
742   if (!(font = hb_object_create<hb_font_t> ()))
743     return &_hb_font_nil;
744
745   hb_face_make_immutable (face);
746   font->face = hb_face_reference (face);
747   font->klass = &_hb_font_funcs_nil;
748
749   return font;
750 }
751
752 hb_font_t *
753 hb_font_create_sub_font (hb_font_t *parent)
754 {
755   if (unlikely (!parent))
756     return &_hb_font_nil;
757
758   hb_font_t *font = hb_font_create (parent->face);
759
760   if (unlikely (hb_object_is_inert (font)))
761     return font;
762
763   hb_font_make_immutable (parent);
764   font->parent = hb_font_reference (parent);
765
766   font->x_scale = parent->x_scale;
767   font->y_scale = parent->y_scale;
768   font->x_ppem = parent->x_ppem;
769   font->y_ppem = parent->y_ppem;
770
771   font->klass = &_hb_font_funcs_nil;
772
773   return font;
774 }
775
776 hb_font_t *
777 hb_font_get_empty (void)
778 {
779   return &_hb_font_nil;
780 }
781
782 hb_font_t *
783 hb_font_reference (hb_font_t *font)
784 {
785   return hb_object_reference (font);
786 }
787
788 void
789 hb_font_destroy (hb_font_t *font)
790 {
791   if (!hb_object_destroy (font)) return;
792
793   hb_font_destroy (font->parent);
794   hb_face_destroy (font->face);
795   hb_font_funcs_destroy (font->klass);
796   if (font->destroy)
797     font->destroy (font->user_data);
798
799   free (font);
800 }
801
802 hb_bool_t
803 hb_font_set_user_data (hb_font_t          *font,
804                        hb_user_data_key_t *key,
805                        void *              data,
806                        hb_destroy_func_t   destroy)
807 {
808   return hb_object_set_user_data (font, key, data, destroy);
809 }
810
811 void *
812 hb_font_get_user_data (hb_font_t          *font,
813                        hb_user_data_key_t *key)
814 {
815   return hb_object_get_user_data (font, key);
816 }
817
818 void
819 hb_font_make_immutable (hb_font_t *font)
820 {
821   if (hb_object_is_inert (font))
822     return;
823
824   font->immutable = true;
825 }
826
827 hb_bool_t
828 hb_font_is_immutable (hb_font_t *font)
829 {
830   return font->immutable;
831 }
832
833 hb_font_t *
834 hb_font_get_parent (hb_font_t *font)
835 {
836   return font->parent;
837 }
838
839 hb_face_t *
840 hb_font_get_face (hb_font_t *font)
841 {
842   return font->face;
843 }
844
845
846 void
847 hb_font_set_funcs (hb_font_t         *font,
848                    hb_font_funcs_t   *klass,
849                    void              *user_data,
850                    hb_destroy_func_t  destroy)
851 {
852   if (font->immutable)
853     return;
854
855   if (font->destroy)
856     font->destroy (font->user_data);
857
858   if (!klass)
859     klass = &_hb_font_funcs_nil;
860
861   hb_font_funcs_reference (klass);
862   hb_font_funcs_destroy (font->klass);
863   font->klass = klass;
864   font->user_data = user_data;
865   font->destroy = destroy;
866 }
867
868
869 void
870 hb_font_set_scale (hb_font_t *font,
871                    int x_scale,
872                    int y_scale)
873 {
874   if (font->immutable)
875     return;
876
877   font->x_scale = x_scale;
878   font->y_scale = y_scale;
879 }
880
881 void
882 hb_font_get_scale (hb_font_t *font,
883                    int *x_scale,
884                    int *y_scale)
885 {
886   if (x_scale) *x_scale = font->x_scale;
887   if (y_scale) *y_scale = font->y_scale;
888 }
889
890 void
891 hb_font_set_ppem (hb_font_t *font,
892                   unsigned int x_ppem,
893                   unsigned int y_ppem)
894 {
895   if (font->immutable)
896     return;
897
898   font->x_ppem = x_ppem;
899   font->y_ppem = y_ppem;
900 }
901
902 void
903 hb_font_get_ppem (hb_font_t *font,
904                   unsigned int *x_ppem,
905                   unsigned int *y_ppem)
906 {
907   if (x_ppem) *x_ppem = font->x_ppem;
908   if (y_ppem) *y_ppem = font->y_ppem;
909 }
910
911
912 HB_END_DECLS