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