Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-user-font.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2006, 2008 Red Hat, Inc
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Red Hat, Inc.
32
 *
33
 * Contributor(s):
34
 *      Kristian Høgsberg <krh@redhat.com>
35
 *      Behdad Esfahbod <behdad@behdad.org>
36
 */
37
38
#include "cairoint.h"
39
#include "cairo-user-font-private.h"
40
#include "cairo-recording-surface-private.h"
41
#include "cairo-analysis-surface-private.h"
42
#include "cairo-error-private.h"
43
44
/**
45
 * SECTION:cairo-user-fonts
46
 * @Title:User Fonts
47
 * @Short_Description: Font support with font data provided by the user
48
 *
49
 * The user-font feature allows the cairo user to provide drawings for glyphs
50
 * in a font.  This is most useful in implementing fonts in non-standard
51
 * formats, like SVG fonts and Flash fonts, but can also be used by games and
52
 * other application to draw "funky" fonts.
53
 **/
54
55
/**
56
 * CAIRO_HAS_USER_FONT:
57
 *
58
 * Defined if the user font backend is available.
59
 * This macro can be used to conditionally compile backend-specific code.
60
 * The user font backend is always built in versions of cairo that support
61
 * this feature (1.8 and later).
62
 *
63
 * Since: 1.8
64
 **/
65
66
typedef struct _cairo_user_scaled_font_methods {
67
    cairo_user_scaled_font_init_func_t      init;
68
    cairo_user_scaled_font_render_glyph_func_t    render_color_glyph;
69
    cairo_user_scaled_font_render_glyph_func_t    render_glyph;
70
    cairo_user_scaled_font_unicode_to_glyph_func_t  unicode_to_glyph;
71
    cairo_user_scaled_font_text_to_glyphs_func_t  text_to_glyphs;
72
} cairo_user_scaled_font_methods_t;
73
74
typedef struct _cairo_user_font_face {
75
    cairo_font_face_t              base;
76
77
    /* Set to true after first scaled font is created.  At that point,
78
     * the scaled_font_methods cannot change anymore. */
79
    cairo_bool_t         immutable;
80
    cairo_bool_t                     has_color;
81
    cairo_user_scaled_font_methods_t scaled_font_methods;
82
} cairo_user_font_face_t;
83
84
typedef struct _cairo_user_scaled_font {
85
    cairo_scaled_font_t  base;
86
87
    cairo_text_extents_t default_glyph_extents;
88
89
    /* space to compute extents in, and factors to convert back to user space */
90
    cairo_matrix_t extent_scale;
91
    double extent_x_scale;
92
    double extent_y_scale;
93
94
    /* multiplier for metrics hinting */
95
    double snap_x_scale;
96
    double snap_y_scale;
97
98
} cairo_user_scaled_font_t;
99
100
/* #cairo_user_scaled_font_t */
101
102
static cairo_surface_t *
103
_cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t *scaled_font,
104
              cairo_bool_t                    color)
105
0
{
106
0
    cairo_content_t content;
107
108
0
    if (color) {
109
0
  content = CAIRO_CONTENT_COLOR_ALPHA;
110
0
    } else {
111
0
  content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ?
112
0
                     CAIRO_CONTENT_COLOR_ALPHA :
113
0
                     CAIRO_CONTENT_ALPHA;
114
0
    }
115
116
0
    return cairo_recording_surface_create (content, NULL);
117
0
}
118
119
120
static cairo_t *
121
_cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t *scaled_font,
122
              cairo_surface_t                *recording_surface,
123
              cairo_bool_t                    color)
124
0
{
125
0
    cairo_t *cr;
126
127
0
    cr = cairo_create (recording_surface);
128
129
0
    if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
130
0
        cairo_matrix_t scale;
131
0
  scale = scaled_font->base.scale;
132
0
  scale.x0 = scale.y0 = 0.;
133
0
  cairo_set_matrix (cr, &scale);
134
0
    }
135
136
0
    cairo_set_font_size (cr, 1.0);
137
0
    cairo_set_font_options (cr, &scaled_font->base.options);
138
0
    if (!color)
139
0
  cairo_set_source_rgb (cr, 1., 1., 1.);
140
141
0
    return cr;
142
0
}
143
144
static cairo_int_status_t
145
_cairo_user_scaled_glyph_init (void      *abstract_font,
146
             cairo_scaled_glyph_t  *scaled_glyph,
147
             cairo_scaled_glyph_info_t  info,
148
             const cairo_color_t       *foreground_color)
149
0
{
150
0
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
151
0
    cairo_user_scaled_font_t *scaled_font = abstract_font;
152
0
    cairo_surface_t *recording_surface = scaled_glyph->recording_surface;
153
154
0
    if (!scaled_glyph->recording_surface) {
155
0
  cairo_user_font_face_t *face =
156
0
      (cairo_user_font_face_t *) scaled_font->base.font_face;
157
0
  cairo_text_extents_t extents = scaled_font->default_glyph_extents;
158
0
  cairo_t *cr;
159
160
0
  recording_surface = NULL;
161
0
  if (!face->scaled_font_methods.render_color_glyph && !face->scaled_font_methods.render_glyph)
162
0
      return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
163
164
  /* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */
165
0
        if (_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
166
0
      recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE);
167
0
      _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
168
0
                   &scaled_font->base,
169
0
                   recording_surface);
170
0
  } else {
171
0
      status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
172
173
0
      if (face->scaled_font_methods.render_color_glyph) {
174
0
    cairo_pattern_t *pattern;
175
176
0
    recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE);
177
178
0
    cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, TRUE);
179
0
    pattern = cairo_pattern_create_rgb (0, 0, 0);
180
0
    pattern->is_userfont_foreground = TRUE;
181
0
    cairo_set_source (cr, pattern);
182
0
    cairo_pattern_destroy (pattern);
183
0
    status = face->scaled_font_methods.render_color_glyph ((cairo_scaled_font_t *)scaled_font,
184
0
                       _cairo_scaled_glyph_index(scaled_glyph),
185
0
                       cr, &extents);
186
0
    if (status == CAIRO_INT_STATUS_SUCCESS) {
187
0
        status = cairo_status (cr);
188
0
        scaled_glyph->recording_is_color = TRUE;
189
0
    }
190
0
    cairo_destroy (cr);
191
0
      }
192
193
0
      if (status == (cairo_int_status_t)CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED &&
194
0
    face->scaled_font_methods.render_glyph) {
195
0
                if (recording_surface)
196
0
                    cairo_surface_destroy (recording_surface);
197
0
    recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE);
198
0
    recording_surface->device_transform.x0 = .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
199
0
    recording_surface->device_transform.y0 = .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
200
201
0
    cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, FALSE);
202
203
0
    status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font,
204
0
                 _cairo_scaled_glyph_index(scaled_glyph),
205
0
                 cr, &extents);
206
0
    if (status == CAIRO_INT_STATUS_SUCCESS)
207
0
        status = cairo_status (cr);
208
209
0
    cairo_destroy (cr);
210
0
      }
211
212
0
      if (status != CAIRO_INT_STATUS_SUCCESS) {
213
0
    if (recording_surface)
214
0
        cairo_surface_destroy (recording_surface);
215
0
    return status;
216
0
      }
217
218
0
      _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
219
0
                   &scaled_font->base,
220
0
                   recording_surface);
221
0
  }
222
223
  /* set metrics */
224
225
0
  if (extents.width == 0.) {
226
0
      cairo_box_t bbox;
227
0
      double x1, y1, x2, y2;
228
0
      double x_scale, y_scale;
229
230
      /* Compute extents.x/y/width/height from recording_surface,
231
       * in font space.
232
       */
233
0
      status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
234
0
              &bbox,
235
0
              &scaled_font->extent_scale);
236
0
      if (unlikely (status))
237
0
    return status;
238
239
0
      _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
240
241
0
      x_scale = scaled_font->extent_x_scale;
242
0
      y_scale = scaled_font->extent_y_scale;
243
0
      extents.x_bearing = x1 * x_scale;
244
0
      extents.y_bearing = y1 * y_scale;
245
0
      extents.width     = (x2 - x1) * x_scale;
246
0
      extents.height    = (y2 - y1) * y_scale;
247
0
  }
248
249
0
  if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
250
0
      extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale;
251
0
      extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale;
252
0
  }
253
254
0
  _cairo_scaled_glyph_set_metrics (scaled_glyph,
255
0
           &scaled_font->base,
256
0
           &extents);
257
0
    }
258
259
0
    if (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) {
260
0
  cairo_surface_t *surface;
261
0
  cairo_format_t format;
262
0
  int width, height;
263
264
  /* TODO
265
   * extend the glyph cache to support argb glyphs.
266
   * need to figure out the semantics and interaction with subpixel
267
   * rendering first.
268
   */
269
270
0
  width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) -
271
0
    _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
272
0
  height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) -
273
0
    _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
274
275
0
  if (scaled_glyph->recording_is_color) {
276
0
            format = CAIRO_FORMAT_ARGB32;
277
0
        } else {
278
0
            switch (scaled_font->base.options.antialias) {
279
0
                default:
280
0
                case CAIRO_ANTIALIAS_DEFAULT:
281
0
                case CAIRO_ANTIALIAS_FAST:
282
0
                case CAIRO_ANTIALIAS_GOOD:
283
0
                case CAIRO_ANTIALIAS_GRAY:
284
0
                    format = CAIRO_FORMAT_A8;
285
0
                    break;
286
0
                case CAIRO_ANTIALIAS_NONE:
287
0
                    format = CAIRO_FORMAT_A1;
288
0
                    break;
289
0
                case CAIRO_ANTIALIAS_BEST:
290
0
                case CAIRO_ANTIALIAS_SUBPIXEL:
291
0
                    format = CAIRO_FORMAT_ARGB32;
292
0
                    break;
293
0
            }
294
0
        }
295
0
  surface = cairo_image_surface_create (format, width, height);
296
297
0
  cairo_surface_set_device_offset (surface,
298
0
                                   - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
299
0
                                   - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
300
301
0
  if (scaled_glyph->recording_is_color) {
302
0
      status = _cairo_recording_surface_replay_with_foreground_color (recording_surface,
303
0
                      surface,
304
0
                      foreground_color);
305
0
  } else {
306
0
      status = _cairo_recording_surface_replay (recording_surface, surface);
307
0
  }
308
309
0
  if (unlikely (status)) {
310
0
      cairo_surface_destroy(surface);
311
0
      return status;
312
0
  }
313
314
0
  if (!scaled_glyph->recording_is_color && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE)) {
315
0
            _cairo_scaled_glyph_set_surface (scaled_glyph,
316
0
                                             &scaled_font->base,
317
0
                                             (cairo_image_surface_t *) surface);
318
0
            surface = NULL;
319
0
        }
320
321
0
        if (scaled_glyph->recording_is_color && (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) {
322
0
            _cairo_scaled_glyph_set_color_surface (scaled_glyph,
323
0
                                                   &scaled_font->base,
324
0
                                                   (cairo_image_surface_t *)surface,
325
0
               FALSE);
326
0
            surface = NULL;
327
0
        }
328
329
0
        if (surface)
330
0
            cairo_surface_destroy (surface);
331
0
    }
332
333
0
    if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
334
0
  cairo_path_fixed_t *path = _cairo_path_fixed_create ();
335
0
  if (!path)
336
0
      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
337
338
0
  status = _cairo_recording_surface_get_path (recording_surface, path);
339
0
  if (unlikely (status)) {
340
0
      _cairo_path_fixed_destroy (path);
341
0
      return status;
342
0
  }
343
344
0
  _cairo_scaled_glyph_set_path (scaled_glyph,
345
0
              &scaled_font->base,
346
0
              path);
347
0
    }
348
349
0
    return status;
350
0
}
351
352
static unsigned long
353
_cairo_user_ucs4_to_index (void     *abstract_font,
354
         uint32_t  ucs4)
355
0
{
356
0
    cairo_user_scaled_font_t *scaled_font = abstract_font;
357
0
    cairo_user_font_face_t *face =
358
0
  (cairo_user_font_face_t *) scaled_font->base.font_face;
359
0
    unsigned long glyph = 0;
360
361
0
    if (face->scaled_font_methods.unicode_to_glyph) {
362
0
  cairo_status_t status;
363
364
0
  status = face->scaled_font_methods.unicode_to_glyph (&scaled_font->base,
365
0
                   ucs4, &glyph);
366
367
0
  if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
368
0
      goto not_implemented;
369
370
0
  if (status != CAIRO_STATUS_SUCCESS) {
371
0
      status = _cairo_scaled_font_set_error (&scaled_font->base, status);
372
0
      glyph = 0;
373
0
  }
374
375
0
    } else {
376
0
not_implemented:
377
0
  glyph = ucs4;
378
0
    }
379
380
0
    return glyph;
381
0
}
382
383
static cairo_bool_t
384
_cairo_user_has_color_glyphs (void         *abstract_font)
385
0
{
386
0
    cairo_user_scaled_font_t *scaled_font = abstract_font;
387
0
    cairo_user_font_face_t *face =
388
0
  (cairo_user_font_face_t *) scaled_font->base.font_face;
389
390
0
    return face->has_color;
391
0
}
392
393
static cairo_int_status_t
394
_cairo_user_text_to_glyphs (void          *abstract_font,
395
          double           x,
396
          double           y,
397
          const char          *utf8,
398
          int            utf8_len,
399
          cairo_glyph_t      **glyphs,
400
          int            *num_glyphs,
401
          cairo_text_cluster_t      **clusters,
402
          int            *num_clusters,
403
          cairo_text_cluster_flags_t *cluster_flags)
404
0
{
405
0
    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
406
407
0
    cairo_user_scaled_font_t *scaled_font = abstract_font;
408
0
    cairo_user_font_face_t *face =
409
0
  (cairo_user_font_face_t *) scaled_font->base.font_face;
410
411
0
    if (face->scaled_font_methods.text_to_glyphs) {
412
0
  int i;
413
0
  cairo_glyph_t *orig_glyphs = *glyphs;
414
0
  int orig_num_glyphs = *num_glyphs;
415
416
0
  status = face->scaled_font_methods.text_to_glyphs (&scaled_font->base,
417
0
                 utf8, utf8_len,
418
0
                 glyphs, num_glyphs,
419
0
                 clusters, num_clusters, cluster_flags);
420
421
0
  if (status != CAIRO_INT_STATUS_SUCCESS &&
422
0
      status != CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED)
423
0
      return status;
424
425
0
  if (status == CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED ||
426
0
      *num_glyphs < 0) {
427
0
      if (orig_glyphs != *glyphs) {
428
0
    cairo_glyph_free (*glyphs);
429
0
    *glyphs = orig_glyphs;
430
0
      }
431
0
      *num_glyphs = orig_num_glyphs;
432
0
      return CAIRO_INT_STATUS_UNSUPPORTED;
433
0
  }
434
435
  /* Convert from font space to user space and add x,y */
436
0
  for (i = 0; i < *num_glyphs; i++) {
437
0
      double gx = (*glyphs)[i].x;
438
0
      double gy = (*glyphs)[i].y;
439
440
0
      cairo_matrix_transform_point (&scaled_font->base.font_matrix,
441
0
            &gx, &gy);
442
443
0
      (*glyphs)[i].x = gx + x;
444
0
      (*glyphs)[i].y = gy + y;
445
0
  }
446
0
    }
447
448
0
    return status;
449
0
}
450
451
static cairo_status_t
452
_cairo_user_font_face_scaled_font_create (void                        *abstract_face,
453
            const cairo_matrix_t        *font_matrix,
454
            const cairo_matrix_t        *ctm,
455
            const cairo_font_options_t  *options,
456
            cairo_scaled_font_t        **scaled_font);
457
458
static cairo_status_t
459
_cairo_user_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
460
              cairo_font_face_t      **font_face)
461
0
{
462
0
    return _cairo_font_face_twin_create_for_toy (toy_face, font_face);
463
0
}
464
465
static const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
466
    CAIRO_FONT_TYPE_USER,
467
    NULL, /* scaled_font_fini */
468
    _cairo_user_scaled_glyph_init,
469
    _cairo_user_text_to_glyphs,
470
    _cairo_user_ucs4_to_index,
471
    NULL, /* load_truetype_table */
472
    NULL, /* index_to_ucs4 */
473
    NULL,       /* is_synthetic */
474
    NULL,       /* index_to_glyph_name */
475
    NULL,       /* load_type1_data */
476
    _cairo_user_has_color_glyphs,
477
};
478
479
/* #cairo_user_font_face_t */
480
481
static cairo_status_t
482
_cairo_user_font_face_scaled_font_create (void                        *abstract_face,
483
            const cairo_matrix_t        *font_matrix,
484
            const cairo_matrix_t        *ctm,
485
            const cairo_font_options_t  *options,
486
            cairo_scaled_font_t        **scaled_font)
487
0
{
488
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
489
0
    cairo_user_font_face_t *font_face = abstract_face;
490
0
    cairo_user_scaled_font_t *user_scaled_font = NULL;
491
0
    cairo_font_extents_t font_extents = {1., 0., 1., 1., 0.};
492
493
0
    font_face->immutable = TRUE;
494
495
0
    user_scaled_font = _cairo_malloc (sizeof (cairo_user_scaled_font_t));
496
0
    if (unlikely (user_scaled_font == NULL))
497
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
498
499
0
    status = _cairo_scaled_font_init (&user_scaled_font->base,
500
0
              &font_face->base,
501
0
              font_matrix, ctm, options,
502
0
              &_cairo_user_scaled_font_backend);
503
504
0
    if (unlikely (status)) {
505
0
  free (user_scaled_font);
506
0
  return status;
507
0
    }
508
509
    /* XXX metrics hinting? */
510
511
    /* compute a normalized version of font scale matrix to compute
512
     * extents in.  This is to minimize error caused by the cairo_fixed_t
513
     * representation. */
514
0
    {
515
0
  double fixed_scale, x_scale, y_scale;
516
517
0
  user_scaled_font->extent_scale = user_scaled_font->base.scale_inverse;
518
0
  status = _cairo_matrix_compute_basis_scale_factors (&user_scaled_font->extent_scale,
519
0
                  &x_scale, &y_scale,
520
0
                  1);
521
0
  if (status == CAIRO_STATUS_SUCCESS) {
522
523
0
      if (x_scale == 0) x_scale = 1.;
524
0
      if (y_scale == 0) y_scale = 1.;
525
526
0
      user_scaled_font->snap_x_scale = x_scale;
527
0
      user_scaled_font->snap_y_scale = y_scale;
528
529
      /* since glyphs are pretty much 1.0x1.0, we can reduce error by
530
       * scaling to a larger square.  say, 1024.x1024. */
531
0
      fixed_scale = 1024.;
532
0
      x_scale /= fixed_scale;
533
0
      y_scale /= fixed_scale;
534
535
0
      cairo_matrix_scale (&user_scaled_font->extent_scale, 1. / x_scale, 1. / y_scale);
536
537
0
      user_scaled_font->extent_x_scale = x_scale;
538
0
      user_scaled_font->extent_y_scale = y_scale;
539
0
  }
540
0
    }
541
542
0
    if (status == CAIRO_STATUS_SUCCESS &&
543
0
  font_face->scaled_font_methods.init != NULL)
544
0
    {
545
  /* Lock the scaled_font mutex such that user doesn't accidentally try
546
         * to use it just yet. */
547
0
  CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex);
548
549
  /* Give away fontmap lock such that user-font can use other fonts */
550
0
  status = _cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base);
551
0
  if (status == CAIRO_STATUS_SUCCESS) {
552
0
      cairo_surface_t *recording_surface;
553
0
      cairo_t *cr;
554
555
0
      recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font, FALSE);
556
0
      cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font, recording_surface, FALSE);
557
0
      cairo_surface_destroy (recording_surface);
558
559
0
      status = font_face->scaled_font_methods.init (&user_scaled_font->base,
560
0
                cr,
561
0
                &font_extents);
562
563
0
      if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED)
564
0
    status = CAIRO_STATUS_SUCCESS;
565
566
0
      if (status == CAIRO_STATUS_SUCCESS)
567
0
    status = cairo_status (cr);
568
569
0
      cairo_destroy (cr);
570
571
0
      _cairo_scaled_font_unregister_placeholder_and_lock_font_map (&user_scaled_font->base);
572
0
  }
573
574
0
  CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex);
575
0
    }
576
577
0
    if (status == CAIRO_STATUS_SUCCESS)
578
0
  status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents);
579
580
0
    if (status != CAIRO_STATUS_SUCCESS) {
581
0
        _cairo_scaled_font_fini (&user_scaled_font->base);
582
0
  free (user_scaled_font);
583
0
    } else {
584
0
        user_scaled_font->default_glyph_extents.x_bearing = 0.;
585
0
        user_scaled_font->default_glyph_extents.y_bearing = -font_extents.ascent;
586
0
        user_scaled_font->default_glyph_extents.width = 0.;
587
0
        user_scaled_font->default_glyph_extents.height = font_extents.ascent + font_extents.descent;
588
0
        user_scaled_font->default_glyph_extents.x_advance = font_extents.max_x_advance;
589
0
        user_scaled_font->default_glyph_extents.y_advance = 0.;
590
591
0
  *scaled_font = &user_scaled_font->base;
592
0
    }
593
594
0
    return status;
595
0
}
596
597
const cairo_font_face_backend_t _cairo_user_font_face_backend = {
598
    CAIRO_FONT_TYPE_USER,
599
    _cairo_user_font_face_create_for_toy,
600
    _cairo_font_face_destroy,
601
    _cairo_user_font_face_scaled_font_create
602
};
603
604
605
cairo_bool_t
606
_cairo_font_face_is_user (cairo_font_face_t *font_face)
607
0
{
608
0
    return font_face->backend == &_cairo_user_font_face_backend;
609
0
}
610
611
/* Implement the public interface */
612
613
/**
614
 * cairo_user_font_face_create:
615
 *
616
 * Creates a new user font-face.
617
 *
618
 * Use the setter functions to associate callbacks with the returned
619
 * user font.  The only mandatory callback is render_glyph.
620
 *
621
 * After the font-face is created, the user can attach arbitrary data
622
 * (the actual font data) to it using cairo_font_face_set_user_data()
623
 * and access it from the user-font callbacks by using
624
 * cairo_scaled_font_get_font_face() followed by
625
 * cairo_font_face_get_user_data().
626
 *
627
 * Return value: a newly created #cairo_font_face_t. Free with
628
 *  cairo_font_face_destroy() when you are done using it.
629
 *
630
 * Since: 1.8
631
 **/
632
cairo_font_face_t *
633
cairo_user_font_face_create (void)
634
0
{
635
0
    cairo_user_font_face_t *font_face;
636
637
0
    font_face = _cairo_malloc (sizeof (cairo_user_font_face_t));
638
0
    if (!font_face) {
639
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
640
0
  return (cairo_font_face_t *)&_cairo_font_face_nil;
641
0
    }
642
643
0
    _cairo_font_face_init (&font_face->base, &_cairo_user_font_face_backend);
644
645
0
    font_face->immutable = FALSE;
646
0
    font_face->has_color = FALSE;
647
0
    memset (&font_face->scaled_font_methods, 0, sizeof (font_face->scaled_font_methods));
648
649
0
    return &font_face->base;
650
0
}
651
slim_hidden_def(cairo_user_font_face_create);
652
653
/* User-font method setters */
654
655
656
/**
657
 * cairo_user_font_face_set_init_func:
658
 * @font_face: A user font face
659
 * @init_func: The init callback, or %NULL
660
 *
661
 * Sets the scaled-font initialization function of a user-font.
662
 * See #cairo_user_scaled_font_init_func_t for details of how the callback
663
 * works.
664
 *
665
 * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
666
 * error will occur.  A user font-face is immutable as soon as a scaled-font
667
 * is created from it.
668
 *
669
 * Since: 1.8
670
 **/
671
void
672
cairo_user_font_face_set_init_func (cairo_font_face_t                  *font_face,
673
            cairo_user_scaled_font_init_func_t  init_func)
674
0
{
675
0
    cairo_user_font_face_t *user_font_face;
676
677
0
    if (font_face->status)
678
0
  return;
679
680
0
    if (! _cairo_font_face_is_user (font_face)) {
681
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
682
0
      return;
683
0
    }
684
685
0
    user_font_face = (cairo_user_font_face_t *) font_face;
686
0
    if (user_font_face->immutable) {
687
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
688
0
      return;
689
0
    }
690
0
    user_font_face->scaled_font_methods.init = init_func;
691
0
}
692
slim_hidden_def(cairo_user_font_face_set_init_func);
693
694
/**
695
 * cairo_user_font_face_set_render_color_glyph_func:
696
 * @font_face: A user font face
697
 * @render_glyph_func: The render_glyph callback, or %NULL
698
 *
699
 * Sets the color glyph rendering function of a user-font.
700
 * See #cairo_user_scaled_font_render_glyph_func_t for details of how the callback
701
 * works.
702
 *
703
 * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
704
 * error will occur.  A user font-face is immutable as soon as a scaled-font
705
 * is created from it.
706
 *
707
 * The render_glyph callback is the only mandatory callback of a
708
 * user-font. At least one of
709
 * cairo_user_font_face_set_render_color_glyph_func() or
710
 * cairo_user_font_face_set_render_glyph_func() must be called to set
711
 * a render callback. If both callbacks are set, the color glyph
712
 * render callback is invoked first. If the color glyph render
713
 * callback returns %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, the
714
 * non-color version of the callback is invoked.
715
 *
716
 * If the callback is %NULL and a glyph is tried to be rendered using
717
 * @font_face, a %CAIRO_STATUS_USER_FONT_ERROR will occur.
718
 *
719
 * Since: 1.18
720
 **/
721
void
722
cairo_user_font_face_set_render_color_glyph_func (cairo_font_face_t                          *font_face,
723
                                                  cairo_user_scaled_font_render_glyph_func_t  render_glyph_func)
724
0
{
725
0
    cairo_user_font_face_t *user_font_face;
726
727
0
    if (font_face->status)
728
0
  return;
729
730
0
    if (! _cairo_font_face_is_user (font_face)) {
731
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
732
0
      return;
733
0
    }
734
735
0
    user_font_face = (cairo_user_font_face_t *) font_face;
736
0
    if (user_font_face->immutable) {
737
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
738
0
      return;
739
0
    }
740
0
    user_font_face->scaled_font_methods.render_color_glyph = render_glyph_func;
741
0
    user_font_face->has_color = render_glyph_func ? TRUE : FALSE;
742
0
}
743
slim_hidden_def(cairo_user_font_face_set_render_color_glyph_func);
744
745
/**
746
 * cairo_user_font_face_set_render_glyph_func:
747
 * @font_face: A user font face
748
 * @render_glyph_func: The render_glyph callback, or %NULL
749
 *
750
 * Sets the glyph rendering function of a user-font.
751
 * See #cairo_user_scaled_font_render_glyph_func_t for details of how the callback
752
 * works.
753
 *
754
 * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
755
 * error will occur.  A user font-face is immutable as soon as a scaled-font
756
 * is created from it.
757
 *
758
 * The render_glyph callback is the only mandatory callback of a
759
 * user-font. At least one of
760
 * cairo_user_font_face_set_render_color_glyph_func() or
761
 * cairo_user_font_face_set_render_glyph_func() must be called to set
762
 * a render callback. If both callbacks are set, the color glyph
763
 * render callback is invoked first. If the color glyph render
764
 * callback returns %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, the
765
 * non-color version of the callback is invoked.
766
 *
767
 * If the callback is %NULL and a glyph is tried to be rendered using
768
 * @font_face, a %CAIRO_STATUS_USER_FONT_ERROR will occur.
769
 *
770
 * Since: 1.8
771
 **/
772
void
773
cairo_user_font_face_set_render_glyph_func (cairo_font_face_t                          *font_face,
774
              cairo_user_scaled_font_render_glyph_func_t  render_glyph_func)
775
0
{
776
0
    cairo_user_font_face_t *user_font_face;
777
778
0
    if (font_face->status)
779
0
  return;
780
781
0
    if (! _cairo_font_face_is_user (font_face)) {
782
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
783
0
      return;
784
0
    }
785
786
0
    user_font_face = (cairo_user_font_face_t *) font_face;
787
0
    if (user_font_face->immutable) {
788
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
789
0
      return;
790
0
    }
791
0
    user_font_face->scaled_font_methods.render_glyph = render_glyph_func;
792
0
}
793
slim_hidden_def(cairo_user_font_face_set_render_glyph_func);
794
795
/**
796
 * cairo_user_font_face_set_text_to_glyphs_func:
797
 * @font_face: A user font face
798
 * @text_to_glyphs_func: The text_to_glyphs callback, or %NULL
799
 *
800
 * Sets th text-to-glyphs conversion function of a user-font.
801
 * See #cairo_user_scaled_font_text_to_glyphs_func_t for details of how the callback
802
 * works.
803
 *
804
 * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
805
 * error will occur.  A user font-face is immutable as soon as a scaled-font
806
 * is created from it.
807
 *
808
 * Since: 1.8
809
 **/
810
void
811
cairo_user_font_face_set_text_to_glyphs_func (cairo_font_face_t                            *font_face,
812
                cairo_user_scaled_font_text_to_glyphs_func_t  text_to_glyphs_func)
813
0
{
814
0
    cairo_user_font_face_t *user_font_face;
815
816
0
    if (font_face->status)
817
0
  return;
818
819
0
    if (! _cairo_font_face_is_user (font_face)) {
820
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
821
0
      return;
822
0
    }
823
824
0
    user_font_face = (cairo_user_font_face_t *) font_face;
825
0
    if (user_font_face->immutable) {
826
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
827
0
      return;
828
0
    }
829
0
    user_font_face->scaled_font_methods.text_to_glyphs = text_to_glyphs_func;
830
0
}
831
832
/**
833
 * cairo_user_font_face_set_unicode_to_glyph_func:
834
 * @font_face: A user font face
835
 * @unicode_to_glyph_func: The unicode_to_glyph callback, or %NULL
836
 *
837
 * Sets the unicode-to-glyph conversion function of a user-font.
838
 * See #cairo_user_scaled_font_unicode_to_glyph_func_t for details of how the callback
839
 * works.
840
 *
841
 * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
842
 * error will occur.  A user font-face is immutable as soon as a scaled-font
843
 * is created from it.
844
 *
845
 * Since: 1.8
846
 **/
847
void
848
cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t                              *font_face,
849
            cairo_user_scaled_font_unicode_to_glyph_func_t  unicode_to_glyph_func)
850
0
{
851
0
    cairo_user_font_face_t *user_font_face;
852
0
    if (font_face->status)
853
0
  return;
854
855
0
    if (! _cairo_font_face_is_user (font_face)) {
856
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
857
0
      return;
858
0
    }
859
860
0
    user_font_face = (cairo_user_font_face_t *) font_face;
861
0
    if (user_font_face->immutable) {
862
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
863
0
      return;
864
0
    }
865
0
    user_font_face->scaled_font_methods.unicode_to_glyph = unicode_to_glyph_func;
866
0
}
867
slim_hidden_def(cairo_user_font_face_set_unicode_to_glyph_func);
868
869
/* User-font method getters */
870
871
/**
872
 * cairo_user_font_face_get_init_func:
873
 * @font_face: A user font face
874
 *
875
 * Gets the scaled-font initialization function of a user-font.
876
 *
877
 * Return value: The init callback of @font_face
878
 * or %NULL if none set or an error has occurred.
879
 *
880
 * Since: 1.8
881
 **/
882
cairo_user_scaled_font_init_func_t
883
cairo_user_font_face_get_init_func (cairo_font_face_t *font_face)
884
0
{
885
0
    cairo_user_font_face_t *user_font_face;
886
887
0
    if (font_face->status)
888
0
  return NULL;
889
890
0
    if (! _cairo_font_face_is_user (font_face)) {
891
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
892
0
      return NULL;
893
0
    }
894
895
0
    user_font_face = (cairo_user_font_face_t *) font_face;
896
0
    return user_font_face->scaled_font_methods.init;
897
0
}
898
899
/**
900
 * cairo_user_font_face_get_render_color_glyph_func:
901
 * @font_face: A user font face
902
 *
903
 * Gets the color glyph rendering function of a user-font.
904
 *
905
 * Return value: The render_glyph callback of @font_face
906
 * or %NULL if none set or an error has occurred.
907
 *
908
 * Since: 1.18
909
 **/
910
cairo_user_scaled_font_render_glyph_func_t
911
cairo_user_font_face_get_render_color_glyph_func (cairo_font_face_t *font_face)
912
0
{
913
0
    cairo_user_font_face_t *user_font_face;
914
915
0
    if (font_face->status)
916
0
  return NULL;
917
918
0
    if (! _cairo_font_face_is_user (font_face)) {
919
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
920
0
      return NULL;
921
0
    }
922
923
0
    user_font_face = (cairo_user_font_face_t *) font_face;
924
0
    return user_font_face->scaled_font_methods.render_color_glyph;
925
0
}
926
927
/**
928
 * cairo_user_font_face_get_render_glyph_func:
929
 * @font_face: A user font face
930
 *
931
 * Gets the glyph rendering function of a user-font.
932
 *
933
 * Return value: The render_glyph callback of @font_face
934
 * or %NULL if none set or an error has occurred.
935
 *
936
 * Since: 1.8
937
 **/
938
cairo_user_scaled_font_render_glyph_func_t
939
cairo_user_font_face_get_render_glyph_func (cairo_font_face_t *font_face)
940
0
{
941
0
    cairo_user_font_face_t *user_font_face;
942
943
0
    if (font_face->status)
944
0
  return NULL;
945
946
0
    if (! _cairo_font_face_is_user (font_face)) {
947
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
948
0
      return NULL;
949
0
    }
950
951
0
    user_font_face = (cairo_user_font_face_t *) font_face;
952
0
    return user_font_face->scaled_font_methods.render_glyph;
953
0
}
954
955
/**
956
 * cairo_user_font_face_get_text_to_glyphs_func:
957
 * @font_face: A user font face
958
 *
959
 * Gets the text-to-glyphs conversion function of a user-font.
960
 *
961
 * Return value: The text_to_glyphs callback of @font_face
962
 * or %NULL if none set or an error occurred.
963
 *
964
 * Since: 1.8
965
 **/
966
cairo_user_scaled_font_text_to_glyphs_func_t
967
cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face)
968
0
{
969
0
    cairo_user_font_face_t *user_font_face;
970
971
0
    if (font_face->status)
972
0
  return NULL;
973
974
0
    if (! _cairo_font_face_is_user (font_face)) {
975
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
976
0
      return NULL;
977
0
    }
978
979
0
    user_font_face = (cairo_user_font_face_t *) font_face;
980
0
    return user_font_face->scaled_font_methods.text_to_glyphs;
981
0
}
982
983
/**
984
 * cairo_user_font_face_get_unicode_to_glyph_func:
985
 * @font_face: A user font face
986
 *
987
 * Gets the unicode-to-glyph conversion function of a user-font.
988
 *
989
 * Return value: The unicode_to_glyph callback of @font_face
990
 * or %NULL if none set or an error occurred.
991
 *
992
 * Since: 1.8
993
 **/
994
cairo_user_scaled_font_unicode_to_glyph_func_t
995
cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face)
996
0
{
997
0
    cairo_user_font_face_t *user_font_face;
998
999
0
    if (font_face->status)
1000
0
  return NULL;
1001
1002
0
    if (! _cairo_font_face_is_user (font_face)) {
1003
0
  if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
1004
0
      return NULL;
1005
0
    }
1006
1007
0
    user_font_face = (cairo_user_font_face_t *) font_face;
1008
0
    return user_font_face->scaled_font_methods.unicode_to_glyph;
1009
0
}