Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. }
  832.