tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-font-face-twin.c
1 /*
2  * Copyright © 2004 Keith Packard
3  * Copyright © 2008 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it either under the terms of the GNU Lesser General Public
7  * License version 2.1 as published by the Free Software Foundation
8  * (the "LGPL") or, at your option, under the terms of the Mozilla
9  * Public License Version 1.1 (the "MPL"). If you do not alter this
10  * notice, a recipient may use your version of this file under either
11  * the MPL or the LGPL.
12  *
13  * You should have received a copy of the LGPL along with this library
14  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
19  * The contents of this file are subject to the Mozilla Public License
20  * Version 1.1 (the "License"); you may not use this file except in
21  * compliance with the License. You may obtain a copy of the License at
22  * http://www.mozilla.org/MPL/
23  *
24  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26  * the specific language governing rights and limitations.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * The Initial Developer of the Original Code is Keith Packard
31  *
32  * Contributor(s):
33  *      Keith Packard <keithp@keithp.com>
34  *      Behdad Esfahbod <behdad@behdad.org>
35  */
36
37 #include "cairoint.h"
38 #include "cairo-error-private.h"
39
40 #include <math.h>
41
42 /*
43  * This file implements a user-font rendering the descendant of the Hershey
44  * font coded by Keith Packard for use in the Twin window system.
45  * The actual font data is in cairo-font-face-twin-data.c
46  *
47  * Ported to cairo user font and extended by Behdad Esfahbod.
48  */
49
50
51
52 static cairo_user_data_key_t twin_properties_key;
53
54
55 /*
56  * Face properties
57  */
58
59 /* We synthesize multiple faces from the twin data.  Here is the parameters. */
60
61 /* The following tables and matching code are copied from Pango */
62
63 /* CSS weight */
64 typedef enum {
65   TWIN_WEIGHT_THIN = 100,
66   TWIN_WEIGHT_ULTRALIGHT = 200,
67   TWIN_WEIGHT_LIGHT = 300,
68   TWIN_WEIGHT_BOOK = 380,
69   TWIN_WEIGHT_NORMAL = 400,
70   TWIN_WEIGHT_MEDIUM = 500,
71   TWIN_WEIGHT_SEMIBOLD = 600,
72   TWIN_WEIGHT_BOLD = 700,
73   TWIN_WEIGHT_ULTRABOLD = 800,
74   TWIN_WEIGHT_HEAVY = 900,
75   TWIN_WEIGHT_ULTRAHEAVY = 1000
76 } twin_face_weight_t;
77
78 /* CSS stretch */
79 typedef enum {
80   TWIN_STRETCH_ULTRA_CONDENSED,
81   TWIN_STRETCH_EXTRA_CONDENSED,
82   TWIN_STRETCH_CONDENSED,
83   TWIN_STRETCH_SEMI_CONDENSED,
84   TWIN_STRETCH_NORMAL,
85   TWIN_STRETCH_SEMI_EXPANDED,
86   TWIN_STRETCH_EXPANDED,
87   TWIN_STRETCH_EXTRA_EXPANDED,
88   TWIN_STRETCH_ULTRA_EXPANDED
89 } twin_face_stretch_t;
90
91 typedef struct
92 {
93   int value;
94   const char str[16];
95 } FieldMap;
96
97 static const FieldMap slant_map[] = {
98   { CAIRO_FONT_SLANT_NORMAL, "" },
99   { CAIRO_FONT_SLANT_NORMAL, "Roman" },
100   { CAIRO_FONT_SLANT_OBLIQUE, "Oblique" },
101   { CAIRO_FONT_SLANT_ITALIC, "Italic" }
102 };
103
104 static const FieldMap smallcaps_map[] = {
105   { FALSE, "" },
106   { TRUE, "Small-Caps" }
107 };
108
109 static const FieldMap weight_map[] = {
110   { TWIN_WEIGHT_THIN, "Thin" },
111   { TWIN_WEIGHT_ULTRALIGHT, "Ultra-Light" },
112   { TWIN_WEIGHT_ULTRALIGHT, "Extra-Light" },
113   { TWIN_WEIGHT_LIGHT, "Light" },
114   { TWIN_WEIGHT_BOOK, "Book" },
115   { TWIN_WEIGHT_NORMAL, "" },
116   { TWIN_WEIGHT_NORMAL, "Regular" },
117   { TWIN_WEIGHT_MEDIUM, "Medium" },
118   { TWIN_WEIGHT_SEMIBOLD, "Semi-Bold" },
119   { TWIN_WEIGHT_SEMIBOLD, "Demi-Bold" },
120   { TWIN_WEIGHT_BOLD, "Bold" },
121   { TWIN_WEIGHT_ULTRABOLD, "Ultra-Bold" },
122   { TWIN_WEIGHT_ULTRABOLD, "Extra-Bold" },
123   { TWIN_WEIGHT_HEAVY, "Heavy" },
124   { TWIN_WEIGHT_HEAVY, "Black" },
125   { TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Heavy" },
126   { TWIN_WEIGHT_ULTRAHEAVY, "Extra-Heavy" },
127   { TWIN_WEIGHT_ULTRAHEAVY, "Ultra-Black" },
128   { TWIN_WEIGHT_ULTRAHEAVY, "Extra-Black" }
129 };
130
131 static const FieldMap stretch_map[] = {
132   { TWIN_STRETCH_ULTRA_CONDENSED, "Ultra-Condensed" },
133   { TWIN_STRETCH_EXTRA_CONDENSED, "Extra-Condensed" },
134   { TWIN_STRETCH_CONDENSED,       "Condensed" },
135   { TWIN_STRETCH_SEMI_CONDENSED,  "Semi-Condensed" },
136   { TWIN_STRETCH_NORMAL,          "" },
137   { TWIN_STRETCH_SEMI_EXPANDED,   "Semi-Expanded" },
138   { TWIN_STRETCH_EXPANDED,        "Expanded" },
139   { TWIN_STRETCH_EXTRA_EXPANDED,  "Extra-Expanded" },
140   { TWIN_STRETCH_ULTRA_EXPANDED,  "Ultra-Expanded" }
141 };
142
143 static const FieldMap monospace_map[] = {
144   { FALSE, "" },
145   { TRUE, "Mono" },
146   { TRUE, "Monospace" }
147 };
148
149
150 typedef struct _twin_face_properties {
151     cairo_font_slant_t  slant;
152     twin_face_weight_t  weight;
153     twin_face_stretch_t stretch;
154
155     /* lets have some fun */
156     cairo_bool_t monospace;
157     cairo_bool_t smallcaps;
158 } twin_face_properties_t;
159
160 static cairo_bool_t
161 field_matches (const char *s1,
162                const char *s2,
163                int len)
164 {
165   int c1, c2;
166
167   while (len && *s1 && *s2)
168     {
169 #define TOLOWER(c) \
170    (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
171
172       c1 = TOLOWER (*s1);
173       c2 = TOLOWER (*s2);
174       if (c1 != c2) {
175         if (c1 == '-') {
176           s1++;
177           continue;
178         }
179         return FALSE;
180       }
181       s1++; s2++;
182       len--;
183     }
184
185   return len == 0 && *s1 == '\0';
186 }
187
188 static cairo_bool_t
189 parse_int (const char *word,
190            size_t      wordlen,
191            int        *out)
192 {
193   char *end;
194   long val = strtol (word, &end, 10);
195   int i = val;
196
197   if (end != word && (end == word + wordlen) && val >= 0 && val == i)
198     {
199       if (out)
200         *out = i;
201
202       return TRUE;
203     }
204
205   return FALSE;
206 }
207
208 static cairo_bool_t
209 find_field (const char *what,
210             const FieldMap *map,
211             int n_elements,
212             const char *str,
213             int len,
214             int *val)
215 {
216   int i;
217   cairo_bool_t had_prefix = FALSE;
218
219   if (what)
220     {
221       i = strlen (what);
222       if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
223         {
224           str += i + 1;
225           len -= i + 1;
226           had_prefix = TRUE;
227         }
228     }
229
230   for (i=0; i<n_elements; i++)
231     {
232       if (map[i].str[0] && field_matches (map[i].str, str, len))
233         {
234           if (val)
235             *val = map[i].value;
236           return TRUE;
237         }
238     }
239
240   if (!what || had_prefix)
241     return parse_int (str, len, val);
242
243   return FALSE;
244 }
245
246 static void
247 parse_field (twin_face_properties_t *props,
248              const char *str,
249              int len)
250 {
251   if (field_matches ("Normal", str, len))
252     return;
253
254 #define FIELD(NAME) \
255   if (find_field (STRINGIFY (NAME), NAME##_map, ARRAY_LENGTH (NAME##_map), str, len, \
256                   (int *)(void *)&props->NAME)) \
257       return; \
258
259   FIELD (weight);
260   FIELD (slant);
261   FIELD (stretch);
262   FIELD (smallcaps);
263   FIELD (monospace);
264
265 #undef FIELD
266 }
267
268 static void
269 face_props_parse (twin_face_properties_t *props,
270              const char *s)
271 {
272     const char *start, *end;
273
274     for (start = end = s; *end; end++) {
275         if (*end != ' ' && *end != ':')
276             continue;
277
278         if (start < end)
279                 parse_field (props, start, end - start);
280         start = end + 1;
281     }
282     if (start < end)
283             parse_field (props, start, end - start);
284 }
285
286 static twin_face_properties_t *
287 twin_font_face_create_properties (cairo_font_face_t *twin_face)
288 {
289     twin_face_properties_t *props;
290
291     props = malloc (sizeof (twin_face_properties_t));
292     if (unlikely (props == NULL))
293         return NULL;
294
295     props->stretch  = TWIN_STRETCH_NORMAL;
296     props->slant = CAIRO_FONT_SLANT_NORMAL;
297     props->weight = TWIN_WEIGHT_NORMAL;
298     props->monospace = FALSE;
299     props->smallcaps = FALSE;
300
301     if (unlikely (cairo_font_face_set_user_data (twin_face,
302                                             &twin_properties_key,
303                                             props, free))) {
304         free (props);
305         return NULL;
306     }
307
308     return props;
309 }
310
311 static cairo_status_t
312 twin_font_face_set_properties_from_toy (cairo_font_face_t *twin_face,
313                                         cairo_toy_font_face_t *toy_face)
314 {
315     twin_face_properties_t *props;
316
317     props = twin_font_face_create_properties (twin_face);
318     if (unlikely (props == NULL))
319         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
320
321     props->slant = toy_face->slant;
322     props->weight = toy_face->weight == CAIRO_FONT_WEIGHT_NORMAL ?
323                     TWIN_WEIGHT_NORMAL : TWIN_WEIGHT_BOLD;
324     face_props_parse (props, toy_face->family);
325
326     return CAIRO_STATUS_SUCCESS;
327 }
328
329
330 /*
331  * Scaled properties
332  */
333
334 typedef struct _twin_scaled_properties {
335         twin_face_properties_t *face_props;
336
337         cairo_bool_t snap; /* hint outlines */
338
339         double weight; /* unhinted pen width */
340         double penx, peny; /* hinted pen width */
341         double marginl, marginr; /* hinted side margins */
342
343         double stretch; /* stretch factor */
344 } twin_scaled_properties_t;
345
346 static void
347 compute_hinting_scale (cairo_t *cr,
348                        double x, double y,
349                        double *scale, double *inv)
350 {
351     cairo_user_to_device_distance (cr, &x, &y);
352     *scale = x == 0 ? y : y == 0 ? x :sqrt (x*x + y*y);
353     *inv = 1 / *scale;
354 }
355
356 static void
357 compute_hinting_scales (cairo_t *cr,
358                         double *x_scale, double *x_scale_inv,
359                         double *y_scale, double *y_scale_inv)
360 {
361     double x, y;
362
363     x = 1; y = 0;
364     compute_hinting_scale (cr, x, y, x_scale, x_scale_inv);
365
366     x = 0; y = 1;
367     compute_hinting_scale (cr, x, y, y_scale, y_scale_inv);
368 }
369
370 #define SNAPXI(p)       (_cairo_round ((p) * x_scale) * x_scale_inv)
371 #define SNAPYI(p)       (_cairo_round ((p) * y_scale) * y_scale_inv)
372
373 /* This controls the global font size */
374 #define F(g)            ((g) / 72.)
375
376 static void
377 twin_hint_pen_and_margins(cairo_t *cr,
378                           double *penx, double *peny,
379                           double *marginl, double *marginr)
380 {
381     double x_scale, x_scale_inv;
382     double y_scale, y_scale_inv;
383     double margin;
384
385     compute_hinting_scales (cr,
386                             &x_scale, &x_scale_inv,
387                             &y_scale, &y_scale_inv);
388
389     *penx = SNAPXI (*penx);
390     if (*penx < x_scale_inv)
391         *penx = x_scale_inv;
392
393     *peny = SNAPYI (*peny);
394     if (*peny < y_scale_inv)
395         *peny = y_scale_inv;
396
397     margin = *marginl + *marginr;
398     *marginl = SNAPXI (*marginl);
399     if (*marginl < x_scale_inv)
400         *marginl = x_scale_inv;
401
402     *marginr = margin - *marginl;
403     if (*marginr < 0)
404         *marginr = 0;
405     *marginr = SNAPXI (*marginr);
406 }
407
408 static cairo_status_t
409 twin_scaled_font_compute_properties (cairo_scaled_font_t *scaled_font,
410                                      cairo_t           *cr)
411 {
412     cairo_status_t status;
413     twin_scaled_properties_t *props;
414
415     props = malloc (sizeof (twin_scaled_properties_t));
416     if (unlikely (props == NULL))
417         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
418
419
420     props->face_props = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font),
421                                                        &twin_properties_key);
422     if (props->face_props == NULL) {
423         status = CAIRO_STATUS_NULL_POINTER;
424         goto FREE_PROPS;
425     }
426
427     props->snap = scaled_font->options.hint_style > CAIRO_HINT_STYLE_NONE;
428
429     /* weight */
430     props->weight = props->face_props->weight * (F (4) / TWIN_WEIGHT_NORMAL);
431
432     /* pen & margins */
433     props->penx = props->peny = props->weight;
434     props->marginl = props->marginr = F (4);
435     if (scaled_font->options.hint_style > CAIRO_HINT_STYLE_SLIGHT)
436         twin_hint_pen_and_margins(cr,
437                                   &props->penx, &props->peny,
438                                   &props->marginl, &props->marginr);
439
440     /* stretch */
441     props->stretch = 1 + .1 * ((int) props->face_props->stretch - (int) TWIN_STRETCH_NORMAL);
442
443
444     /* Save it */
445     status = cairo_scaled_font_set_user_data (scaled_font,
446                                               &twin_properties_key,
447                                               props, free);
448     if (unlikely (status))
449         goto FREE_PROPS;
450
451     return CAIRO_STATUS_SUCCESS;
452
453 FREE_PROPS:
454     free (props);
455     return status;
456 }
457
458
459 /*
460  * User-font implementation
461  */
462
463 static cairo_status_t
464 twin_scaled_font_init (cairo_scaled_font_t  *scaled_font,
465                        cairo_t              *cr,
466                        cairo_font_extents_t *metrics)
467 {
468   metrics->ascent  = F (54);
469   metrics->descent = 1 - metrics->ascent;
470
471   return twin_scaled_font_compute_properties (scaled_font, cr);
472 }
473
474 #define TWIN_GLYPH_MAX_SNAP_X 4
475 #define TWIN_GLYPH_MAX_SNAP_Y 7
476
477 typedef struct {
478     int n_snap_x;
479     int8_t snap_x[TWIN_GLYPH_MAX_SNAP_X];
480     double snapped_x[TWIN_GLYPH_MAX_SNAP_X];
481     int n_snap_y;
482     int8_t snap_y[TWIN_GLYPH_MAX_SNAP_Y];
483     double snapped_y[TWIN_GLYPH_MAX_SNAP_Y];
484 } twin_snap_info_t;
485
486 #define twin_glyph_left(g)      ((g)[0])
487 #define twin_glyph_right(g)     ((g)[1])
488 #define twin_glyph_ascent(g)    ((g)[2])
489 #define twin_glyph_descent(g)   ((g)[3])
490
491 #define twin_glyph_n_snap_x(g)  ((g)[4])
492 #define twin_glyph_n_snap_y(g)  ((g)[5])
493 #define twin_glyph_snap_x(g)    (&g[6])
494 #define twin_glyph_snap_y(g)    (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
495 #define twin_glyph_draw(g)      (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
496
497 static void
498 twin_compute_snap (cairo_t             *cr,
499                    twin_snap_info_t    *info,
500                    const signed char   *b)
501 {
502     int                 s, n;
503     const signed char   *snap;
504     double x_scale, x_scale_inv;
505     double y_scale, y_scale_inv;
506
507     compute_hinting_scales (cr,
508                             &x_scale, &x_scale_inv,
509                             &y_scale, &y_scale_inv);
510
511     snap = twin_glyph_snap_x (b);
512     n = twin_glyph_n_snap_x (b);
513     info->n_snap_x = n;
514     assert (n <= TWIN_GLYPH_MAX_SNAP_X);
515     for (s = 0; s < n; s++) {
516         info->snap_x[s] = snap[s];
517         info->snapped_x[s] = SNAPXI (F (snap[s]));
518     }
519
520     snap = twin_glyph_snap_y (b);
521     n = twin_glyph_n_snap_y (b);
522     info->n_snap_y = n;
523     assert (n <= TWIN_GLYPH_MAX_SNAP_Y);
524     for (s = 0; s < n; s++) {
525         info->snap_y[s] = snap[s];
526         info->snapped_y[s] = SNAPYI (F (snap[s]));
527     }
528 }
529
530 static double
531 twin_snap (int8_t v, int n, int8_t *snap, double *snapped)
532 {
533     int s;
534
535     if (!n)
536         return F(v);
537
538     if (snap[0] == v)
539         return snapped[0];
540
541     for (s = 0; s < n - 1; s++)
542     {
543         if (snap[s+1] == v)
544             return snapped[s+1];
545
546         if (snap[s] <= v && v <= snap[s+1])
547         {
548             int before = snap[s];
549             int after = snap[s+1];
550             int dist = after - before;
551             double snap_before = snapped[s];
552             double snap_after = snapped[s+1];
553             double dist_before = v - before;
554             return snap_before + (snap_after - snap_before) * dist_before / dist;
555         }
556     }
557     return F(v);
558 }
559
560 #define SNAPX(p)        twin_snap (p, info.n_snap_x, info.snap_x, info.snapped_x)
561 #define SNAPY(p)        twin_snap (p, info.n_snap_y, info.snap_y, info.snapped_y)
562
563 static cairo_status_t
564 twin_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
565                                unsigned long         glyph,
566                                cairo_t              *cr,
567                                cairo_text_extents_t *metrics)
568 {
569     double x1, y1, x2, y2, x3, y3;
570     double marginl;
571     twin_scaled_properties_t *props;
572     twin_snap_info_t info;
573     const int8_t *b;
574     const int8_t *g;
575     int8_t w;
576     double gw;
577
578     props = cairo_scaled_font_get_user_data (scaled_font, &twin_properties_key);
579     if (props == NULL)
580         return _cairo_error (CAIRO_STATUS_NULL_POINTER);
581
582     /* Save glyph space, we need it when stroking */
583     cairo_save (cr);
584
585     /* center the pen */
586     cairo_translate (cr, props->penx * .5, -props->peny * .5);
587
588     /* small-caps */
589     if (props->face_props->smallcaps && glyph >= 'a' && glyph <= 'z') {
590         glyph += 'A' - 'a';
591         /* 28 and 42 are small and capital letter heights of the glyph data */
592         cairo_scale (cr, 1, 28. / 42);
593     }
594
595     /* slant */
596     if (props->face_props->slant != CAIRO_FONT_SLANT_NORMAL) {
597         cairo_matrix_t shear = { 1, 0, -.2, 1, 0, 0};
598         cairo_transform (cr, &shear);
599     }
600
601     b = _cairo_twin_outlines +
602         _cairo_twin_charmap[unlikely (glyph >= ARRAY_LENGTH (_cairo_twin_charmap)) ? 0 : glyph];
603     g = twin_glyph_draw(b);
604     w = twin_glyph_right(b);
605     gw = F(w);
606
607     marginl = props->marginl;
608
609     /* monospace */
610     if (props->face_props->monospace) {
611         double monow = F(24);
612         double extra =  props->penx + props->marginl + props->marginr;
613         cairo_scale (cr, (monow + extra) / (gw + extra), 1);
614         gw = monow;
615
616         /* resnap margin for new transform */
617         {
618             double x, y, x_scale, x_scale_inv;
619             x = 1; y = 0;
620             compute_hinting_scale (cr, x, y, &x_scale, &x_scale_inv);
621             marginl = SNAPXI (marginl);
622         }
623     }
624
625     cairo_translate (cr, marginl, 0);
626
627     /* stretch */
628     cairo_scale (cr, props->stretch, 1);
629
630     if (props->snap)
631         twin_compute_snap (cr, &info, b);
632     else
633         info.n_snap_x = info.n_snap_y = 0;
634
635     /* advance width */
636     metrics->x_advance = gw * props->stretch + props->penx + props->marginl + props->marginr;
637
638     /* glyph shape */
639     for (;;) {
640         switch (*g++) {
641         case 'M':
642             cairo_close_path (cr);
643             /* fall through */
644         case 'm':
645             x1 = SNAPX(*g++);
646             y1 = SNAPY(*g++);
647             cairo_move_to (cr, x1, y1);
648             continue;
649         case 'L':
650             cairo_close_path (cr);
651             /* fall through */
652         case 'l':
653             x1 = SNAPX(*g++);
654             y1 = SNAPY(*g++);
655             cairo_line_to (cr, x1, y1);
656             continue;
657         case 'C':
658             cairo_close_path (cr);
659             /* fall through */
660         case 'c':
661             x1 = SNAPX(*g++);
662             y1 = SNAPY(*g++);
663             x2 = SNAPX(*g++);
664             y2 = SNAPY(*g++);
665             x3 = SNAPX(*g++);
666             y3 = SNAPY(*g++);
667             cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
668             continue;
669         case 'E':
670             cairo_close_path (cr);
671             /* fall through */
672         case 'e':
673             cairo_restore (cr); /* restore glyph space */
674             cairo_set_tolerance (cr, 0.01);
675             cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
676             cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
677             cairo_set_line_width (cr, 1);
678             cairo_scale (cr, props->penx, props->peny);
679             cairo_stroke (cr);
680             break;
681         case 'X':
682             /* filler */
683             continue;
684         }
685         break;
686     }
687
688     return CAIRO_STATUS_SUCCESS;
689 }
690
691 static cairo_status_t
692 twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
693                                    unsigned long        unicode,
694                                    unsigned long       *glyph)
695 {
696     /* We use an identity charmap.  Which means we could live
697      * with no unicode_to_glyph method too.  But we define this
698      * to map all unknown chars to a single unknown glyph to
699      * reduce pressure on cache. */
700
701     if (likely (unicode < ARRAY_LENGTH (_cairo_twin_charmap)))
702         *glyph = unicode;
703     else
704         *glyph = 0;
705
706     return CAIRO_STATUS_SUCCESS;
707 }
708
709
710 /*
711  * Face constructor
712  */
713
714 static cairo_font_face_t *
715 _cairo_font_face_twin_create_internal (void)
716 {
717     cairo_font_face_t *twin_font_face;
718
719     twin_font_face = cairo_user_font_face_create ();
720     cairo_user_font_face_set_init_func             (twin_font_face, twin_scaled_font_init);
721     cairo_user_font_face_set_render_glyph_func     (twin_font_face, twin_scaled_font_render_glyph);
722     cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
723
724     return twin_font_face;
725 }
726
727 cairo_font_face_t *
728 _cairo_font_face_twin_create_fallback (void)
729 {
730     cairo_font_face_t *twin_font_face;
731
732     twin_font_face = _cairo_font_face_twin_create_internal ();
733     if (! twin_font_face_create_properties (twin_font_face)) {
734         cairo_font_face_destroy (twin_font_face);
735         return (cairo_font_face_t *) &_cairo_font_face_nil;
736     }
737
738     return twin_font_face;
739 }
740
741 cairo_status_t
742 _cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t   *toy_face,
743                                       cairo_font_face_t      **font_face)
744 {
745     cairo_status_t status;
746     cairo_font_face_t *twin_font_face;
747
748     twin_font_face = _cairo_font_face_twin_create_internal ();
749     status = twin_font_face_set_properties_from_toy (twin_font_face, toy_face);
750     if (status) {
751         cairo_font_face_destroy (twin_font_face);
752         return status;
753     }
754
755     *font_face = twin_font_face;
756
757     return CAIRO_STATUS_SUCCESS;
758 }