Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-user-font.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2006, 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 Red Hat, Inc.
31  *
32  * Contributor(s):
33  *      Kristian Høgsberg <krh@redhat.com>
34  *      Behdad Esfahbod <behdad@behdad.org>
35  */
36
37 #include "cairoint.h"
38 #include "cairo-user-font-private.h"
39 #include "cairo-recording-surface-private.h"
40 #include "cairo-analysis-surface-private.h"
41 #include "cairo-error-private.h"
42
43 /**
44  * SECTION:cairo-user-fonts
45  * @Title:User Fonts
46  * @Short_Description: Font support with font data provided by the user
47  * 
48  * The user-font feature allows the cairo user to provide drawings for glyphs
49  * in a font.  This is most useful in implementing fonts in non-standard
50  * formats, like SVG fonts and Flash fonts, but can also be used by games and
51  * other application to draw "funky" fonts.
52  **/
53
54 /**
55  * CAIRO_HAS_USER_FONT:
56  *
57  * Defined if the user font backend is available.
58  * This macro can be used to conditionally compile backend-specific code.
59  * The user font backend is always built in versions of cairo that support
60  * this feature (1.8 and later).
61  *
62  * Since: 1.8
63  **/
64
65 typedef struct _cairo_user_scaled_font_methods {
66     cairo_user_scaled_font_init_func_t                  init;
67     cairo_user_scaled_font_render_glyph_func_t          render_glyph;
68     cairo_user_scaled_font_unicode_to_glyph_func_t      unicode_to_glyph;
69     cairo_user_scaled_font_text_to_glyphs_func_t        text_to_glyphs;
70 } cairo_user_scaled_font_methods_t;
71
72 typedef struct _cairo_user_font_face {
73     cairo_font_face_t                base;
74
75     /* Set to true after first scaled font is created.  At that point,
76      * the scaled_font_methods cannot change anymore. */
77     cairo_bool_t                     immutable;
78
79     cairo_user_scaled_font_methods_t scaled_font_methods;
80 } cairo_user_font_face_t;
81
82 typedef struct _cairo_user_scaled_font {
83     cairo_scaled_font_t  base;
84
85     cairo_text_extents_t default_glyph_extents;
86
87     /* space to compute extents in, and factors to convert back to user space */
88     cairo_matrix_t extent_scale;
89     double extent_x_scale;
90     double extent_y_scale;
91
92     /* multiplier for metrics hinting */
93     double snap_x_scale;
94     double snap_y_scale;
95
96 } cairo_user_scaled_font_t;
97
98 /* #cairo_user_scaled_font_t */
99
100 static cairo_surface_t *
101 _cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t *scaled_font)
102 {
103     cairo_content_t content;
104
105     content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ?
106                                                      CAIRO_CONTENT_COLOR_ALPHA :
107                                                      CAIRO_CONTENT_ALPHA;
108
109     return cairo_recording_surface_create (content, NULL);
110 }
111
112
113 static cairo_t *
114 _cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t *scaled_font,
115                                                   cairo_surface_t                *recording_surface)
116 {
117     cairo_t *cr;
118
119     cr = cairo_create (recording_surface);
120
121     if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
122         cairo_matrix_t scale;
123         scale = scaled_font->base.scale;
124         scale.x0 = scale.y0 = 0.;
125         cairo_set_matrix (cr, &scale);
126     }
127
128     cairo_set_font_size (cr, 1.0);
129     cairo_set_font_options (cr, &scaled_font->base.options);
130     cairo_set_source_rgb (cr, 1., 1., 1.);
131
132     return cr;
133 }
134
135 static cairo_int_status_t
136 _cairo_user_scaled_glyph_init (void                      *abstract_font,
137                                cairo_scaled_glyph_t      *scaled_glyph,
138                                cairo_scaled_glyph_info_t  info)
139 {
140     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
141     cairo_user_scaled_font_t *scaled_font = abstract_font;
142     cairo_surface_t *recording_surface = scaled_glyph->recording_surface;
143
144     if (!scaled_glyph->recording_surface) {
145         cairo_user_font_face_t *face =
146             (cairo_user_font_face_t *) scaled_font->base.font_face;
147         cairo_text_extents_t extents = scaled_font->default_glyph_extents;
148         cairo_t *cr;
149
150         if (!face->scaled_font_methods.render_glyph)
151             return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
152
153         recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font);
154
155         /* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */
156         if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
157             cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface);
158             status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font,
159                                                              _cairo_scaled_glyph_index(scaled_glyph),
160                                                              cr, &extents);
161             if (status == CAIRO_INT_STATUS_SUCCESS)
162                 status = cairo_status (cr);
163
164             cairo_destroy (cr);
165
166             if (unlikely (status)) {
167                 cairo_surface_destroy (recording_surface);
168                 return status;
169             }
170         }
171
172         _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
173                                                    &scaled_font->base,
174                                                    recording_surface);
175
176
177         /* set metrics */
178
179         if (extents.width == 0.) {
180             cairo_box_t bbox;
181             double x1, y1, x2, y2;
182             double x_scale, y_scale;
183
184             /* Compute extents.x/y/width/height from recording_surface,
185              * in font space.
186              */
187             status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
188                                                         &bbox,
189                                                         &scaled_font->extent_scale);
190             if (unlikely (status))
191                 return status;
192
193             _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
194
195             x_scale = scaled_font->extent_x_scale;
196             y_scale = scaled_font->extent_y_scale;
197             extents.x_bearing = x1 * x_scale;
198             extents.y_bearing = y1 * y_scale;
199             extents.width     = (x2 - x1) * x_scale;
200             extents.height    = (y2 - y1) * y_scale;
201         }
202
203         if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
204             extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale;
205             extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale;
206         }
207
208         _cairo_scaled_glyph_set_metrics (scaled_glyph,
209                                          &scaled_font->base,
210                                          &extents);
211     }
212
213     if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
214         cairo_surface_t *surface;
215         cairo_format_t format;
216         int width, height;
217
218         /* TODO
219          * extend the glyph cache to support argb glyphs.
220          * need to figure out the semantics and interaction with subpixel
221          * rendering first.
222          */
223
224         width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) -
225           _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
226         height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) -
227           _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
228
229         switch (scaled_font->base.options.antialias) {
230         default:
231         case CAIRO_ANTIALIAS_DEFAULT:
232         case CAIRO_ANTIALIAS_FAST:
233         case CAIRO_ANTIALIAS_GOOD:
234         case CAIRO_ANTIALIAS_GRAY:      format = CAIRO_FORMAT_A8;       break;
235         case CAIRO_ANTIALIAS_NONE:      format = CAIRO_FORMAT_A1;       break;
236         case CAIRO_ANTIALIAS_BEST:
237         case CAIRO_ANTIALIAS_SUBPIXEL:  format = CAIRO_FORMAT_ARGB32;   break;
238         }
239         surface = cairo_image_surface_create (format, width, height);
240
241         cairo_surface_set_device_offset (surface,
242                                          - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
243                                          - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
244         status = _cairo_recording_surface_replay (recording_surface, surface);
245
246         if (unlikely (status)) {
247             cairo_surface_destroy(surface);
248             return status;
249         }
250
251         _cairo_scaled_glyph_set_surface (scaled_glyph,
252                                          &scaled_font->base,
253                                          (cairo_image_surface_t *) surface);
254     }
255
256     if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
257         cairo_path_fixed_t *path = _cairo_path_fixed_create ();
258         if (!path)
259             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
260
261         status = _cairo_recording_surface_get_path (recording_surface, path);
262         if (unlikely (status)) {
263             _cairo_path_fixed_destroy (path);
264             return status;
265         }
266
267         _cairo_scaled_glyph_set_path (scaled_glyph,
268                                       &scaled_font->base,
269                                       path);
270     }
271
272     return status;
273 }
274
275 static unsigned long
276 _cairo_user_ucs4_to_index (void     *abstract_font,
277                            uint32_t  ucs4)
278 {
279     cairo_user_scaled_font_t *scaled_font = abstract_font;
280     cairo_user_font_face_t *face =
281         (cairo_user_font_face_t *) scaled_font->base.font_face;
282     unsigned long glyph = 0;
283
284     if (face->scaled_font_methods.unicode_to_glyph) {
285         cairo_status_t status;
286
287         status = face->scaled_font_methods.unicode_to_glyph (&scaled_font->base,
288                                                              ucs4, &glyph);
289
290         if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
291             goto not_implemented;
292
293         if (status != CAIRO_STATUS_SUCCESS) {
294             status = _cairo_scaled_font_set_error (&scaled_font->base, status);
295             glyph = 0;
296         }
297
298     } else {
299 not_implemented:
300         glyph = ucs4;
301     }
302
303     return glyph;
304 }
305
306 static cairo_int_status_t
307 _cairo_user_text_to_glyphs (void                      *abstract_font,
308                             double                     x,
309                             double                     y,
310                             const char                *utf8,
311                             int                        utf8_len,
312                             cairo_glyph_t            **glyphs,
313                             int                        *num_glyphs,
314                             cairo_text_cluster_t      **clusters,
315                             int                        *num_clusters,
316                             cairo_text_cluster_flags_t *cluster_flags)
317 {
318     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
319
320     cairo_user_scaled_font_t *scaled_font = abstract_font;
321     cairo_user_font_face_t *face =
322         (cairo_user_font_face_t *) scaled_font->base.font_face;
323
324     if (face->scaled_font_methods.text_to_glyphs) {
325         int i;
326         cairo_glyph_t *orig_glyphs = *glyphs;
327         int orig_num_glyphs = *num_glyphs;
328
329         status = face->scaled_font_methods.text_to_glyphs (&scaled_font->base,
330                                                            utf8, utf8_len,
331                                                            glyphs, num_glyphs,
332                                                            clusters, num_clusters, cluster_flags);
333
334         if (status != CAIRO_INT_STATUS_SUCCESS &&
335             status != CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED)
336             return status;
337
338         if (status == CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED ||
339             *num_glyphs < 0) {
340             if (orig_glyphs != *glyphs) {
341                 cairo_glyph_free (*glyphs);
342                 *glyphs = orig_glyphs;
343             }
344             *num_glyphs = orig_num_glyphs;
345             return CAIRO_INT_STATUS_UNSUPPORTED;
346         }
347
348         /* Convert from font space to user space and add x,y */
349         for (i = 0; i < *num_glyphs; i++) {
350             double gx = (*glyphs)[i].x;
351             double gy = (*glyphs)[i].y;
352
353             cairo_matrix_transform_point (&scaled_font->base.font_matrix,
354                                           &gx, &gy);
355
356             (*glyphs)[i].x = gx + x;
357             (*glyphs)[i].y = gy + y;
358         }
359     }
360
361     return status;
362 }
363
364 static cairo_status_t
365 _cairo_user_font_face_scaled_font_create (void                        *abstract_face,
366                                           const cairo_matrix_t        *font_matrix,
367                                           const cairo_matrix_t        *ctm,
368                                           const cairo_font_options_t  *options,
369                                           cairo_scaled_font_t        **scaled_font);
370
371 static cairo_status_t
372 _cairo_user_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
373                                       cairo_font_face_t      **font_face)
374 {
375     return _cairo_font_face_twin_create_for_toy (toy_face, font_face);
376 }
377
378 static const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
379     CAIRO_FONT_TYPE_USER,
380     NULL,       /* scaled_font_fini */
381     _cairo_user_scaled_glyph_init,
382     _cairo_user_text_to_glyphs,
383     _cairo_user_ucs4_to_index,
384     NULL,       /* show_glyphs */
385     NULL,       /* load_truetype_table */
386     NULL        /* index_to_ucs4 */
387 };
388
389 /* #cairo_user_font_face_t */
390
391 static cairo_status_t
392 _cairo_user_font_face_scaled_font_create (void                        *abstract_face,
393                                           const cairo_matrix_t        *font_matrix,
394                                           const cairo_matrix_t        *ctm,
395                                           const cairo_font_options_t  *options,
396                                           cairo_scaled_font_t        **scaled_font)
397 {
398     cairo_status_t status = CAIRO_STATUS_SUCCESS;
399     cairo_user_font_face_t *font_face = abstract_face;
400     cairo_user_scaled_font_t *user_scaled_font = NULL;
401     cairo_font_extents_t font_extents = {1., 0., 1., 1., 0.};
402
403     font_face->immutable = TRUE;
404
405     user_scaled_font = malloc (sizeof (cairo_user_scaled_font_t));
406     if (unlikely (user_scaled_font == NULL))
407         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
408
409     status = _cairo_scaled_font_init (&user_scaled_font->base,
410                                       &font_face->base,
411                                       font_matrix, ctm, options,
412                                       &_cairo_user_scaled_font_backend);
413
414     if (unlikely (status)) {
415         free (user_scaled_font);
416         return status;
417     }
418
419     /* XXX metrics hinting? */
420
421     /* compute a normalized version of font scale matrix to compute
422      * extents in.  This is to minimize error caused by the cairo_fixed_t
423      * representation. */
424     {
425         double fixed_scale, x_scale, y_scale;
426
427         user_scaled_font->extent_scale = user_scaled_font->base.scale_inverse;
428         status = _cairo_matrix_compute_basis_scale_factors (&user_scaled_font->extent_scale,
429                                                       &x_scale, &y_scale,
430                                                       1);
431         if (status == CAIRO_STATUS_SUCCESS) {
432
433             if (x_scale == 0) x_scale = 1.;
434             if (y_scale == 0) y_scale = 1.;
435
436             user_scaled_font->snap_x_scale = x_scale;
437             user_scaled_font->snap_y_scale = y_scale;
438
439             /* since glyphs are pretty much 1.0x1.0, we can reduce error by
440              * scaling to a larger square.  say, 1024.x1024. */
441             fixed_scale = 1024.;
442             x_scale /= fixed_scale;
443             y_scale /= fixed_scale;
444
445             cairo_matrix_scale (&user_scaled_font->extent_scale, 1. / x_scale, 1. / y_scale);
446
447             user_scaled_font->extent_x_scale = x_scale;
448             user_scaled_font->extent_y_scale = y_scale;
449         }
450     }
451
452     if (status == CAIRO_STATUS_SUCCESS &&
453         font_face->scaled_font_methods.init != NULL)
454     {
455         /* Lock the scaled_font mutex such that user doesn't accidentally try
456          * to use it just yet. */
457         CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex);
458
459         /* Give away fontmap lock such that user-font can use other fonts */
460         status = _cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base);
461         if (status == CAIRO_STATUS_SUCCESS) {
462             cairo_surface_t *recording_surface;
463             cairo_t *cr;
464
465             recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font);
466             cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font, recording_surface);
467             cairo_surface_destroy (recording_surface);
468
469             status = font_face->scaled_font_methods.init (&user_scaled_font->base,
470                                                           cr,
471                                                           &font_extents);
472
473             if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
474                 status = CAIRO_STATUS_SUCCESS;
475
476             if (status == CAIRO_STATUS_SUCCESS)
477                 status = cairo_status (cr);
478
479             cairo_destroy (cr);
480
481             _cairo_scaled_font_unregister_placeholder_and_lock_font_map (&user_scaled_font->base);
482         }
483
484         CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex);
485     }
486
487     if (status == CAIRO_STATUS_SUCCESS)
488         status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents);
489
490     if (status != CAIRO_STATUS_SUCCESS) {
491         _cairo_scaled_font_fini (&user_scaled_font->base);
492         free (user_scaled_font);
493     } else {
494         user_scaled_font->default_glyph_extents.x_bearing = 0.;
495         user_scaled_font->default_glyph_extents.y_bearing = -font_extents.ascent;
496         user_scaled_font->default_glyph_extents.width = 0.;
497         user_scaled_font->default_glyph_extents.height = font_extents.ascent + font_extents.descent;
498         user_scaled_font->default_glyph_extents.x_advance = font_extents.max_x_advance;
499         user_scaled_font->default_glyph_extents.y_advance = 0.;
500
501         *scaled_font = &user_scaled_font->base;
502     }
503
504     return status;
505 }
506
507 const cairo_font_face_backend_t _cairo_user_font_face_backend = {
508     CAIRO_FONT_TYPE_USER,
509     _cairo_user_font_face_create_for_toy,
510     NULL,       /* destroy */
511     _cairo_user_font_face_scaled_font_create
512 };
513
514
515 cairo_bool_t
516 _cairo_font_face_is_user (cairo_font_face_t *font_face)
517 {
518     return font_face->backend == &_cairo_user_font_face_backend;
519 }
520
521 /* Implement the public interface */
522
523 /**
524  * cairo_user_font_face_create:
525  *
526  * Creates a new user font-face.
527  *
528  * Use the setter functions to associate callbacks with the returned
529  * user font.  The only mandatory callback is render_glyph.
530  *
531  * After the font-face is created, the user can attach arbitrary data
532  * (the actual font data) to it using cairo_font_face_set_user_data()
533  * and access it from the user-font callbacks by using
534  * cairo_scaled_font_get_font_face() followed by
535  * cairo_font_face_get_user_data().
536  *
537  * Return value: a newly created #cairo_font_face_t. Free with
538  *  cairo_font_face_destroy() when you are done using it.
539  *
540  * Since: 1.8
541  **/
542 cairo_font_face_t *
543 cairo_user_font_face_create (void)
544 {
545     cairo_user_font_face_t *font_face;
546
547     font_face = malloc (sizeof (cairo_user_font_face_t));
548     if (!font_face) {
549         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
550         return (cairo_font_face_t *)&_cairo_font_face_nil;
551     }
552
553     _cairo_font_face_init (&font_face->base, &_cairo_user_font_face_backend);
554
555     font_face->immutable = FALSE;
556     memset (&font_face->scaled_font_methods, 0, sizeof (font_face->scaled_font_methods));
557
558     return &font_face->base;
559 }
560 slim_hidden_def(cairo_user_font_face_create);
561
562 /* User-font method setters */
563
564
565 /**
566  * cairo_user_font_face_set_init_func:
567  * @font_face: A user font face
568  * @init_func: The init callback, or %NULL
569  *
570  * Sets the scaled-font initialization function of a user-font.
571  * See #cairo_user_scaled_font_init_func_t for details of how the callback
572  * works.
573  *
574  * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
575  * error will occur.  A user font-face is immutable as soon as a scaled-font
576  * is created from it.
577  *
578  * Since: 1.8
579  **/
580 void
581 cairo_user_font_face_set_init_func (cairo_font_face_t                  *font_face,
582                                     cairo_user_scaled_font_init_func_t  init_func)
583 {
584     cairo_user_font_face_t *user_font_face;
585
586     if (font_face->status)
587         return;
588
589     if (! _cairo_font_face_is_user (font_face)) {
590         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
591             return;
592     }
593
594     user_font_face = (cairo_user_font_face_t *) font_face;
595     if (user_font_face->immutable) {
596         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
597             return;
598     }
599     user_font_face->scaled_font_methods.init = init_func;
600 }
601 slim_hidden_def(cairo_user_font_face_set_init_func);
602
603 /**
604  * cairo_user_font_face_set_render_glyph_func:
605  * @font_face: A user font face
606  * @render_glyph_func: The render_glyph callback, or %NULL
607  *
608  * Sets the glyph rendering function of a user-font.
609  * See #cairo_user_scaled_font_render_glyph_func_t for details of how the callback
610  * works.
611  *
612  * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
613  * error will occur.  A user font-face is immutable as soon as a scaled-font
614  * is created from it.
615  *
616  * The render_glyph callback is the only mandatory callback of a user-font.
617  * If the callback is %NULL and a glyph is tried to be rendered using
618  * @font_face, a %CAIRO_STATUS_USER_FONT_ERROR will occur.
619  *
620  * Since: 1.8
621  **/
622 void
623 cairo_user_font_face_set_render_glyph_func (cairo_font_face_t                          *font_face,
624                                             cairo_user_scaled_font_render_glyph_func_t  render_glyph_func)
625 {
626     cairo_user_font_face_t *user_font_face;
627
628     if (font_face->status)
629         return;
630
631     if (! _cairo_font_face_is_user (font_face)) {
632         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
633             return;
634     }
635
636     user_font_face = (cairo_user_font_face_t *) font_face;
637     if (user_font_face->immutable) {
638         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
639             return;
640     }
641     user_font_face->scaled_font_methods.render_glyph = render_glyph_func;
642 }
643 slim_hidden_def(cairo_user_font_face_set_render_glyph_func);
644
645 /**
646  * cairo_user_font_face_set_text_to_glyphs_func:
647  * @font_face: A user font face
648  * @text_to_glyphs_func: The text_to_glyphs callback, or %NULL
649  *
650  * Sets th text-to-glyphs conversion function of a user-font.
651  * See #cairo_user_scaled_font_text_to_glyphs_func_t for details of how the callback
652  * works.
653  *
654  * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
655  * error will occur.  A user font-face is immutable as soon as a scaled-font
656  * is created from it.
657  *
658  * Since: 1.8
659  **/
660 void
661 cairo_user_font_face_set_text_to_glyphs_func (cairo_font_face_t                            *font_face,
662                                               cairo_user_scaled_font_text_to_glyphs_func_t  text_to_glyphs_func)
663 {
664     cairo_user_font_face_t *user_font_face;
665
666     if (font_face->status)
667         return;
668
669     if (! _cairo_font_face_is_user (font_face)) {
670         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
671             return;
672     }
673
674     user_font_face = (cairo_user_font_face_t *) font_face;
675     if (user_font_face->immutable) {
676         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
677             return;
678     }
679     user_font_face->scaled_font_methods.text_to_glyphs = text_to_glyphs_func;
680 }
681
682 /**
683  * cairo_user_font_face_set_unicode_to_glyph_func:
684  * @font_face: A user font face
685  * @unicode_to_glyph_func: The unicode_to_glyph callback, or %NULL
686  *
687  * Sets the unicode-to-glyph conversion function of a user-font.
688  * See #cairo_user_scaled_font_unicode_to_glyph_func_t for details of how the callback
689  * works.
690  *
691  * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
692  * error will occur.  A user font-face is immutable as soon as a scaled-font
693  * is created from it.
694  *
695  * Since: 1.8
696  **/
697 void
698 cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t                              *font_face,
699                                                 cairo_user_scaled_font_unicode_to_glyph_func_t  unicode_to_glyph_func)
700 {
701     cairo_user_font_face_t *user_font_face;
702     if (font_face->status)
703         return;
704
705     if (! _cairo_font_face_is_user (font_face)) {
706         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
707             return;
708     }
709
710     user_font_face = (cairo_user_font_face_t *) font_face;
711     if (user_font_face->immutable) {
712         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
713             return;
714     }
715     user_font_face->scaled_font_methods.unicode_to_glyph = unicode_to_glyph_func;
716 }
717 slim_hidden_def(cairo_user_font_face_set_unicode_to_glyph_func);
718
719 /* User-font method getters */
720
721 /**
722  * cairo_user_font_face_get_init_func:
723  * @font_face: A user font face
724  *
725  * Gets the scaled-font initialization function of a user-font.
726  *
727  * Return value: The init callback of @font_face
728  * or %NULL if none set or an error has occurred.
729  *
730  * Since: 1.8
731  **/
732 cairo_user_scaled_font_init_func_t
733 cairo_user_font_face_get_init_func (cairo_font_face_t *font_face)
734 {
735     cairo_user_font_face_t *user_font_face;
736
737     if (font_face->status)
738         return NULL;
739
740     if (! _cairo_font_face_is_user (font_face)) {
741         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
742             return NULL;
743     }
744
745     user_font_face = (cairo_user_font_face_t *) font_face;
746     return user_font_face->scaled_font_methods.init;
747 }
748
749 /**
750  * cairo_user_font_face_get_render_glyph_func:
751  * @font_face: A user font face
752  *
753  * Gets the glyph rendering function of a user-font.
754  *
755  * Return value: The render_glyph callback of @font_face
756  * or %NULL if none set or an error has occurred.
757  *
758  * Since: 1.8
759  **/
760 cairo_user_scaled_font_render_glyph_func_t
761 cairo_user_font_face_get_render_glyph_func (cairo_font_face_t *font_face)
762 {
763     cairo_user_font_face_t *user_font_face;
764
765     if (font_face->status)
766         return NULL;
767
768     if (! _cairo_font_face_is_user (font_face)) {
769         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
770             return NULL;
771     }
772
773     user_font_face = (cairo_user_font_face_t *) font_face;
774     return user_font_face->scaled_font_methods.render_glyph;
775 }
776
777 /**
778  * cairo_user_font_face_get_text_to_glyphs_func:
779  * @font_face: A user font face
780  *
781  * Gets the text-to-glyphs conversion function of a user-font.
782  *
783  * Return value: The text_to_glyphs callback of @font_face
784  * or %NULL if none set or an error occurred.
785  *
786  * Since: 1.8
787  **/
788 cairo_user_scaled_font_text_to_glyphs_func_t
789 cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face)
790 {
791     cairo_user_font_face_t *user_font_face;
792
793     if (font_face->status)
794         return NULL;
795
796     if (! _cairo_font_face_is_user (font_face)) {
797         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
798             return NULL;
799     }
800
801     user_font_face = (cairo_user_font_face_t *) font_face;
802     return user_font_face->scaled_font_methods.text_to_glyphs;
803 }
804
805 /**
806  * cairo_user_font_face_get_unicode_to_glyph_func:
807  * @font_face: A user font face
808  *
809  * Gets the unicode-to-glyph conversion function of a user-font.
810  *
811  * Return value: The unicode_to_glyph callback of @font_face
812  * or %NULL if none set or an error occurred.
813  *
814  * Since: 1.8
815  **/
816 cairo_user_scaled_font_unicode_to_glyph_func_t
817 cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face)
818 {
819     cairo_user_font_face_t *user_font_face;
820
821     if (font_face->status)
822         return NULL;
823
824     if (! _cairo_font_face_is_user (font_face)) {
825         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
826             return NULL;
827     }
828
829     user_font_face = (cairo_user_font_face_t *) font_face;
830     return user_font_face->scaled_font_methods.unicode_to_glyph;
831 }