Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/cairo/src/cairo-scaled-font.c
Line
Count
Source
1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/*
3
 * Copyright © 2005 Keith Packard
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is Keith Packard
31
 *
32
 * Contributor(s):
33
 *      Keith Packard <keithp@keithp.com>
34
 *  Carl D. Worth <cworth@cworth.org>
35
 *      Graydon Hoare <graydon@redhat.com>
36
 *      Owen Taylor <otaylor@redhat.com>
37
 *      Behdad Esfahbod <behdad@behdad.org>
38
 *      Chris Wilson <chris@chris-wilson.co.uk>
39
 */
40
41
#include "cairoint.h"
42
#include "cairo-array-private.h"
43
#include "cairo-error-private.h"
44
#include "cairo-image-surface-private.h"
45
#include "cairo-list-inline.h"
46
#include "cairo-pattern-private.h"
47
#include "cairo-scaled-font-private.h"
48
#include "cairo-surface-backend-private.h"
49
50
/**
51
 * SECTION:cairo-scaled-font
52
 * @Title: cairo_scaled_font_t
53
 * @Short_Description: Font face at particular size and options
54
 * @See_Also: #cairo_font_face_t, #cairo_matrix_t, #cairo_font_options_t
55
 *
56
 * #cairo_scaled_font_t represents a realization of a font face at a particular
57
 * size and transformation and a certain set of font options.
58
 **/
59
60
static uintptr_t
61
_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font);
62
63
/* Global Glyph Cache
64
 *
65
 * We maintain a global pool of glyphs split between all active fonts. This
66
 * allows a heavily used individual font to cache more glyphs than we could
67
 * manage if we used per-font glyph caches, but at the same time maintains
68
 * fairness across all fonts and provides a cap on the maximum number of
69
 * global glyphs.
70
 *
71
 * The glyphs are allocated in pages, which are capped in the global pool.
72
 * Using pages means we can reduce the frequency at which we have to probe the
73
 * global pool and ameliorates the memory allocation pressure.
74
 */
75
76
/* XXX: This number is arbitrary---we've never done any measurement of this. */
77
2
#define MAX_GLYPH_PAGES_CACHED 512
78
static cairo_cache_t cairo_scaled_glyph_page_cache;
79
80
60.2k
#define CAIRO_SCALED_GLYPH_PAGE_SIZE 32
81
struct _cairo_scaled_glyph_page {
82
    cairo_cache_entry_t cache_entry;
83
    cairo_scaled_font_t *scaled_font;
84
    cairo_list_t link;
85
86
    unsigned int num_glyphs;
87
    cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE];
88
};
89
90
/*
91
 *  Notes:
92
 *
93
 *  To store rasterizations of glyphs, we use an image surface and the
94
 *  device offset to represent the glyph origin.
95
 *
96
 *  A device_transform converts from device space (a conceptual space) to
97
 *  surface space.  For simple cases of translation only, it's called a
98
 *  device_offset and is public API (cairo_surface_[gs]et_device_offset()).
99
 *  A possibly better name for those functions could have been
100
 *  cairo_surface_[gs]et_origin().  So, that's what they do: they set where
101
 *  the device-space origin (0,0) is in the surface.  If the origin is inside
102
 *  the surface, device_offset values are positive.  It may look like this:
103
 *
104
 *  Device space:
105
 *        (-x,-y) <-- negative numbers
106
 *           +----------------+
107
 *           |      .         |
108
 *           |      .         |
109
 *           |......(0,0) <---|-- device-space origin
110
 *           |                |
111
 *           |                |
112
 *           +----------------+
113
 *                    (width-x,height-y)
114
 *
115
 *  Surface space:
116
 *         (0,0) <-- surface-space origin
117
 *           +---------------+
118
 *           |      .        |
119
 *           |      .        |
120
 *           |......(x,y) <--|-- device_offset
121
 *           |               |
122
 *           |               |
123
 *           +---------------+
124
 *                     (width,height)
125
 *
126
 *  In other words: device_offset is the coordinates of the device-space
127
 *  origin relative to the top-left of the surface.
128
 *
129
 *  We use device offsets in a couple of places:
130
 *
131
 *    - Public API: To let toolkits like Gtk+ give user a surface that
132
 *      only represents part of the final destination (say, the expose
133
 *      area), but has the same device space as the destination.  In these
134
 *      cases device_offset is typically negative.  Example:
135
 *
136
 *           application window
137
 *           +---------------+
138
 *           |      .        |
139
 *           | (x,y).        |
140
 *           |......+---+    |
141
 *           |      |   | <--|-- expose area
142
 *           |      +---+    |
143
 *           +---------------+
144
 *
145
 *      In this case, the user of cairo API can set the device_space on
146
 *      the expose area to (-x,-y) to move the device space origin to that
147
 *      of the application window, such that drawing in the expose area
148
 *      surface and painting it in the application window has the same
149
 *      effect as drawing in the application window directly.  Gtk+ has
150
 *      been using this feature.
151
 *
152
 *    - Glyph surfaces: In most font rendering systems, glyph surfaces
153
 *      have an origin at (0,0) and a bounding box that is typically
154
 *      represented as (x_bearing,y_bearing,width,height).  Depending on
155
 *      which way y progresses in the system, y_bearing may typically be
156
 *      negative (for systems similar to cairo, with origin at top left),
157
 *      or be positive (in systems like PDF with origin at bottom left).
158
 *      No matter which is the case, it is important to note that
159
 *      (x_bearing,y_bearing) is the coordinates of top-left of the glyph
160
 *      relative to the glyph origin.  That is, for example:
161
 *
162
 *      Scaled-glyph space:
163
 *
164
 *        (x_bearing,y_bearing) <-- negative numbers
165
 *           +----------------+
166
 *           |      .         |
167
 *           |      .         |
168
 *           |......(0,0) <---|-- glyph origin
169
 *           |                |
170
 *           |                |
171
 *           +----------------+
172
 *                    (width+x_bearing,height+y_bearing)
173
 *
174
 *      Note the similarity of the origin to the device space.  That is
175
 *      exactly how we use the device_offset to represent scaled glyphs:
176
 *      to use the device-space origin as the glyph origin.
177
 *
178
 *  Now compare the scaled-glyph space to device-space and surface-space
179
 *  and convince yourself that:
180
 *
181
 *  (x_bearing,y_bearing) = (-x,-y) = - device_offset
182
 *
183
 *  That's right.  If you are not convinced yet, contrast the definition
184
 *  of the two:
185
 *
186
 *  "(x_bearing,y_bearing) is the coordinates of top-left of the
187
 *   glyph relative to the glyph origin."
188
 *
189
 *  "In other words: device_offset is the coordinates of the
190
 *   device-space origin relative to the top-left of the surface."
191
 *
192
 *  and note that glyph origin = device-space origin.
193
 */
194
195
static void
196
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
197
198
static void
199
_cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
200
        cairo_scaled_glyph_t *scaled_glyph)
201
45.1k
{
202
90.3k
    while (! cairo_list_is_empty (&scaled_glyph->dev_privates)) {
203
45.1k
  cairo_scaled_glyph_private_t *private =
204
45.1k
      cairo_list_first_entry (&scaled_glyph->dev_privates,
205
45.1k
            cairo_scaled_glyph_private_t,
206
45.1k
            link);
207
45.1k
  private->destroy (private, scaled_glyph, scaled_font);
208
45.1k
    }
209
210
45.1k
    _cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph);
211
212
45.1k
    if (scaled_glyph->surface != NULL)
213
32.6k
  cairo_surface_destroy (&scaled_glyph->surface->base);
214
215
45.1k
    if (scaled_glyph->path != NULL)
216
0
  _cairo_path_fixed_destroy (scaled_glyph->path);
217
218
45.1k
    if (scaled_glyph->recording_surface != NULL) {
219
0
  cairo_status_t status;
220
221
  /* If the recording surface contains other fonts, destroying
222
   * it while holding _cairo_scaled_glyph_page_cache_mutex will
223
   * result in deadlock when the recording surface font is
224
   * destroyed. Instead, move the recording surface to a list of
225
   * surfaces to free and free it in
226
   * _cairo_scaled_font_thaw_cache() after
227
   * _cairo_scaled_glyph_page_cache_mutex is unlocked. */
228
0
  status = _cairo_array_append (&scaled_font->recording_surfaces_to_free, &scaled_glyph->recording_surface);
229
0
  assert (status == CAIRO_STATUS_SUCCESS);
230
0
    }
231
232
45.1k
    if (scaled_glyph->color_surface != NULL)
233
0
  cairo_surface_destroy (&scaled_glyph->color_surface->base);
234
45.1k
}
235
236
1.03M
#define ZOMBIE 0
237
static const cairo_scaled_font_t _cairo_scaled_font_nil = {
238
    { ZOMBIE },     /* hash_entry */
239
    CAIRO_STATUS_NO_MEMORY, /* status */
240
    CAIRO_REFERENCE_COUNT_INVALID,  /* ref_count */
241
    { 0, 0, 0, NULL },    /* user_data */
242
    NULL,     /* original_font_face */
243
    NULL,     /* font_face */
244
    { 1., 0., 0., 1., 0, 0},  /* font_matrix */
245
    { 1., 0., 0., 1., 0, 0},  /* ctm */
246
    { CAIRO_ANTIALIAS_DEFAULT,  /* options */
247
      CAIRO_SUBPIXEL_ORDER_DEFAULT,
248
      CAIRO_HINT_STYLE_DEFAULT,
249
      CAIRO_HINT_METRICS_DEFAULT} ,
250
    FALSE,      /* placeholder */
251
    FALSE,      /* holdover */
252
    TRUE,     /* finished */
253
    { 1., 0., 0., 1., 0, 0},  /* scale */
254
    { 1., 0., 0., 1., 0, 0},  /* scale_inverse */
255
    1.,       /* max_scale */
256
    { 0., 0., 0., 0., 0. }, /* extents */
257
    { 0., 0., 0., 0., 0. }, /* fs_extents */
258
    CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
259
    NULL,     /* glyphs */
260
    { NULL, NULL },   /* pages */
261
    FALSE,      /* cache_frozen */
262
    FALSE,      /* global_cache_frozen */
263
    { 0, 0, sizeof(cairo_surface_t*), NULL }, /* recording_surfaces_to_free */
264
    { NULL, NULL },   /* privates */
265
    NULL      /* backend */
266
};
267
268
/**
269
 * _cairo_scaled_font_set_error:
270
 * @scaled_font: a scaled_font
271
 * @status: a status value indicating an error
272
 *
273
 * Atomically sets scaled_font->status to @status and calls _cairo_error;
274
 * Does nothing if status is %CAIRO_STATUS_SUCCESS.
275
 *
276
 * All assignments of an error status to scaled_font->status should happen
277
 * through _cairo_scaled_font_set_error(). Note that due to the nature of
278
 * the atomic operation, it is not safe to call this function on the nil
279
 * objects.
280
 *
281
 * The purpose of this function is to allow the user to set a
282
 * breakpoint in _cairo_error() to generate a stack trace for when the
283
 * user causes cairo to detect an error.
284
 *
285
 * Return value: the error status.
286
 **/
287
cairo_status_t
288
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
289
            cairo_status_t status)
290
0
{
291
0
    if (status == CAIRO_STATUS_SUCCESS)
292
0
  return status;
293
294
    /* Don't overwrite an existing error. This preserves the first
295
     * error, which is the most significant. */
296
0
    _cairo_status_set_error (&scaled_font->status, status);
297
298
0
    return _cairo_error (status);
299
0
}
300
301
/**
302
 * cairo_scaled_font_get_type:
303
 * @scaled_font: a #cairo_scaled_font_t
304
 *
305
 * This function returns the type of the backend used to create
306
 * a scaled font. See #cairo_font_type_t for available types.
307
 * However, this function never returns %CAIRO_FONT_TYPE_TOY.
308
 *
309
 * Return value: The type of @scaled_font.
310
 *
311
 * Since: 1.2
312
 **/
313
cairo_font_type_t
314
cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
315
0
{
316
0
    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
317
0
  return CAIRO_FONT_TYPE_TOY;
318
319
0
    return scaled_font->backend->type;
320
0
}
321
322
/**
323
 * cairo_scaled_font_status:
324
 * @scaled_font: a #cairo_scaled_font_t
325
 *
326
 * Checks whether an error has previously occurred for this
327
 * scaled_font.
328
 *
329
 * Return value: %CAIRO_STATUS_SUCCESS or another error such as
330
 *   %CAIRO_STATUS_NO_MEMORY.
331
 *
332
 * Since: 1.0
333
 **/
334
cairo_status_t
335
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
336
2.65M
{
337
2.65M
    return scaled_font->status;
338
2.65M
}
339
340
/* Here we keep a unique mapping from
341
 * font_face/matrix/ctm/font_options => #cairo_scaled_font_t.
342
 *
343
 * Here are the things that we want to map:
344
 *
345
 *  a) All otherwise referenced #cairo_scaled_font_t's
346
 *  b) Some number of not otherwise referenced #cairo_scaled_font_t's
347
 *
348
 * The implementation uses a hash table which covers (a)
349
 * completely. Then, for (b) we have an array of otherwise
350
 * unreferenced fonts (holdovers) which are expired in
351
 * least-recently-used order.
352
 *
353
 * The cairo_scaled_font_create() code gets to treat this like a regular
354
 * hash table. All of the magic for the little holdover cache is in
355
 * cairo_scaled_font_reference() and cairo_scaled_font_destroy().
356
 */
357
358
/* This defines the size of the holdover array ... that is, the number
359
 * of scaled fonts we keep around even when not otherwise referenced
360
 */
361
1.03M
#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256
362
363
typedef struct _cairo_scaled_font_map {
364
    cairo_scaled_font_t *mru_scaled_font;
365
    cairo_hash_table_t *hash_table;
366
    cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
367
    int num_holdovers;
368
} cairo_scaled_font_map_t;
369
370
static cairo_scaled_font_map_t *cairo_scaled_font_map;
371
372
static int
373
_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
374
375
static cairo_scaled_font_map_t *
376
_cairo_scaled_font_map_lock (void)
377
5.48M
{
378
5.48M
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
379
380
5.48M
    if (cairo_scaled_font_map == NULL) {
381
2
  cairo_scaled_font_map = _cairo_calloc (sizeof (cairo_scaled_font_map_t));
382
2
  if (unlikely (cairo_scaled_font_map == NULL))
383
0
      goto CLEANUP_MUTEX_LOCK;
384
385
2
  cairo_scaled_font_map->mru_scaled_font = NULL;
386
2
  cairo_scaled_font_map->hash_table =
387
2
      _cairo_hash_table_create (_cairo_scaled_font_keys_equal);
388
389
2
  if (unlikely (cairo_scaled_font_map->hash_table == NULL))
390
0
      goto CLEANUP_SCALED_FONT_MAP;
391
392
2
  cairo_scaled_font_map->num_holdovers = 0;
393
2
    }
394
395
5.48M
    return cairo_scaled_font_map;
396
397
0
 CLEANUP_SCALED_FONT_MAP:
398
0
    free (cairo_scaled_font_map);
399
0
    cairo_scaled_font_map = NULL;
400
0
 CLEANUP_MUTEX_LOCK:
401
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
402
0
    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
403
0
    return NULL;
404
0
}
405
406
static void
407
_cairo_scaled_font_map_unlock (void)
408
5.48M
{
409
5.48M
   CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
410
5.48M
}
411
412
void
413
_cairo_scaled_font_map_destroy (void)
414
0
{
415
0
    cairo_scaled_font_map_t *font_map;
416
0
    cairo_scaled_font_t *scaled_font;
417
418
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
419
420
0
    font_map = cairo_scaled_font_map;
421
0
    if (unlikely (font_map == NULL)) {
422
0
        goto CLEANUP_MUTEX_LOCK;
423
0
    }
424
425
0
    scaled_font = font_map->mru_scaled_font;
426
0
    if (scaled_font != NULL) {
427
0
  CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
428
0
  cairo_scaled_font_destroy (scaled_font);
429
0
  CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
430
0
    }
431
432
    /* remove scaled_fonts starting from the end so that font_map->holdovers
433
     * is always in a consistent state when we release the mutex. */
434
0
    while (font_map->num_holdovers) {
435
0
  scaled_font = font_map->holdovers[font_map->num_holdovers-1];
436
0
  assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
437
0
  _cairo_hash_table_remove (font_map->hash_table,
438
0
          &scaled_font->hash_entry);
439
440
0
  font_map->num_holdovers--;
441
442
  /* This releases the font_map lock to avoid the possibility of a
443
   * recursive deadlock when the scaled font destroy closure gets
444
   * called
445
   */
446
0
  _cairo_scaled_font_fini (scaled_font);
447
448
0
  free (scaled_font);
449
0
    }
450
451
0
    _cairo_hash_table_destroy (font_map->hash_table);
452
453
0
    free (cairo_scaled_font_map);
454
0
    cairo_scaled_font_map = NULL;
455
456
0
 CLEANUP_MUTEX_LOCK:
457
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
458
0
}
459
460
static void
461
_cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font,
462
          cairo_scaled_glyph_page_t *page)
463
1.67k
{
464
1.67k
    unsigned int n;
465
466
1.67k
    assert (!scaled_font->cache_frozen);
467
1.67k
    assert (!scaled_font->global_cache_frozen);
468
469
46.8k
    for (n = 0; n < page->num_glyphs; n++) {
470
45.1k
  _cairo_hash_table_remove (scaled_font->glyphs,
471
45.1k
          &page->glyphs[n].hash_entry);
472
45.1k
  _cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]);
473
45.1k
    }
474
475
1.67k
    cairo_list_del (&page->link);
476
1.67k
    free (page);
477
1.67k
}
478
479
static void
480
_cairo_scaled_glyph_page_pluck (void *closure)
481
1.51k
{
482
1.51k
    cairo_scaled_glyph_page_t *page = closure;
483
1.51k
    cairo_scaled_font_t *scaled_font;
484
485
1.51k
    assert (! cairo_list_is_empty (&page->link));
486
487
1.51k
    scaled_font = page->scaled_font;
488
489
    /* The font is locked in _cairo_scaled_glyph_page_can_remove () */
490
1.51k
    _cairo_scaled_glyph_page_destroy (scaled_font, page);
491
1.51k
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
492
1.51k
}
493
494
/* If a scaled font wants to unlock the font map while still being
495
 * created (needed for user-fonts), we need to take extra care not
496
 * ending up with multiple identical scaled fonts being created.
497
 *
498
 * What we do is, we create a fake identical scaled font, and mark
499
 * it as placeholder, lock its mutex, and insert that in the fontmap
500
 * hash table.  This makes other code trying to create an identical
501
 * scaled font to just wait and retry.
502
 *
503
 * The reason we have to create a fake scaled font instead of just using
504
 * scaled_font is for lifecycle management: we need to (or rather,
505
 * other code needs to) reference the scaled_font in the hash table.
506
 * We can't do that on the input scaled_font as it may be freed by
507
 * font backend upon error.
508
 */
509
510
cairo_status_t
511
_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font)
512
0
{
513
0
    cairo_status_t status;
514
0
    cairo_scaled_font_t *placeholder_scaled_font;
515
516
0
    assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex));
517
518
0
    status = scaled_font->status;
519
0
    if (unlikely (status))
520
0
  return status;
521
522
0
    placeholder_scaled_font = _cairo_calloc (sizeof (cairo_scaled_font_t));
523
0
    if (unlikely (placeholder_scaled_font == NULL))
524
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
525
526
    /* full initialization is wasteful, but who cares... */
527
0
    status = _cairo_scaled_font_init (placeholder_scaled_font,
528
0
              scaled_font->font_face,
529
0
              &scaled_font->font_matrix,
530
0
              &scaled_font->ctm,
531
0
              &scaled_font->options,
532
0
              NULL);
533
0
    if (unlikely (status))
534
0
  goto FREE_PLACEHOLDER;
535
536
0
    placeholder_scaled_font->placeholder = TRUE;
537
538
0
    placeholder_scaled_font->hash_entry.hash
539
0
  = _cairo_scaled_font_compute_hash (placeholder_scaled_font);
540
0
    status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
541
0
               &placeholder_scaled_font->hash_entry);
542
0
    if (unlikely (status))
543
0
  goto FINI_PLACEHOLDER;
544
545
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
546
0
    CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
547
548
0
    return CAIRO_STATUS_SUCCESS;
549
550
0
  FINI_PLACEHOLDER:
551
0
    _cairo_scaled_font_fini_internal (placeholder_scaled_font);
552
0
  FREE_PLACEHOLDER:
553
0
    free (placeholder_scaled_font);
554
555
0
    return _cairo_scaled_font_set_error (scaled_font, status);
556
0
}
557
558
void
559
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
560
0
{
561
0
    cairo_scaled_font_t *placeholder_scaled_font;
562
563
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
564
565
    /* temporary hash value to match the placeholder */
566
0
    scaled_font->hash_entry.hash
567
0
  = _cairo_scaled_font_compute_hash (scaled_font);
568
0
    placeholder_scaled_font =
569
0
  _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
570
0
          &scaled_font->hash_entry);
571
0
    assert (placeholder_scaled_font != NULL);
572
0
    assert (placeholder_scaled_font->placeholder);
573
0
    assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex));
574
575
0
    _cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
576
0
            &placeholder_scaled_font->hash_entry);
577
578
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
579
580
0
    CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
581
0
    cairo_scaled_font_destroy (placeholder_scaled_font);
582
583
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
584
0
}
585
586
static void
587
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *placeholder_scaled_font)
588
0
{
589
    /* reference the place holder so it doesn't go away */
590
0
    cairo_scaled_font_reference (placeholder_scaled_font);
591
592
    /* now unlock the fontmap mutex so creation has a chance to finish */
593
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
594
595
    /* wait on placeholder mutex until we are awaken */
596
0
    CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
597
598
    /* ok, creation done.  just clean up and back out */
599
0
    CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
600
0
    cairo_scaled_font_destroy (placeholder_scaled_font);
601
602
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
603
0
}
604
605
/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
606
 *
607
 * Not necessarily better than a lot of other hashes, but should be OK, and
608
 * well tested with binary data.
609
 */
610
611
99.2M
#define FNV_64_PRIME ((uint64_t)0x00000100000001B3)
612
1.03M
#define FNV1_64_INIT ((uint64_t)0xcbf29ce484222325)
613
614
static uint64_t
615
_hash_matrix_fnv (const cairo_matrix_t  *matrix,
616
      uint64_t     hval)
617
2.06M
{
618
2.06M
    const uint8_t *buffer = (const uint8_t *) matrix;
619
2.06M
    int len = sizeof (cairo_matrix_t);
620
99.2M
    do {
621
99.2M
  hval *= FNV_64_PRIME;
622
99.2M
  hval ^= *buffer++;
623
99.2M
    } while (--len);
624
625
2.06M
    return hval;
626
2.06M
}
627
628
static uint64_t
629
_hash_mix_bits (uint64_t hash)
630
2.06M
{
631
2.06M
    hash += hash << 12;
632
2.06M
    hash ^= hash >> 7;
633
2.06M
    hash += hash << 3;
634
2.06M
    hash ^= hash >> 17;
635
2.06M
    hash += hash << 5;
636
2.06M
    return hash;
637
2.06M
}
638
639
static uintptr_t
640
_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font)
641
1.03M
{
642
1.03M
    uint64_t hash = FNV1_64_INIT;
643
644
    /* We do a bytewise hash on the font matrices */
645
1.03M
    hash = _hash_matrix_fnv (&scaled_font->font_matrix, hash);
646
1.03M
    hash = _hash_matrix_fnv (&scaled_font->ctm, hash);
647
1.03M
    hash = _hash_mix_bits (hash);
648
649
1.03M
    hash ^= (uintptr_t) scaled_font->original_font_face;
650
1.03M
    hash ^= cairo_font_options_hash (&scaled_font->options);
651
652
    /* final mixing of bits */
653
1.03M
    hash = _hash_mix_bits (hash);
654
1.03M
    assert (hash != ZOMBIE);
655
656
1.03M
    return hash;
657
1.03M
}
658
659
static void
660
_cairo_scaled_font_init_key (cairo_scaled_font_t        *scaled_font,
661
           cairo_font_face_t          *font_face,
662
           const cairo_matrix_t       *font_matrix,
663
           const cairo_matrix_t       *ctm,
664
           const cairo_font_options_t *options)
665
1.03M
{
666
1.03M
    scaled_font->status = CAIRO_STATUS_SUCCESS;
667
1.03M
    scaled_font->placeholder = FALSE;
668
1.03M
    scaled_font->font_face = font_face;
669
1.03M
    scaled_font->original_font_face = font_face;
670
1.03M
    scaled_font->font_matrix = *font_matrix;
671
1.03M
    scaled_font->ctm = *ctm;
672
    /* ignore translation values in the ctm */
673
1.03M
    scaled_font->ctm.x0 = 0.;
674
1.03M
    scaled_font->ctm.y0 = 0.;
675
1.03M
    _cairo_font_options_init_copy (&scaled_font->options, options);
676
677
1.03M
    scaled_font->hash_entry.hash =
678
1.03M
  _cairo_scaled_font_compute_hash (scaled_font);
679
1.03M
}
680
681
static void
682
_cairo_scaled_font_fini_key (cairo_scaled_font_t *scaled_font)
683
1.03M
{
684
1.03M
    _cairo_font_options_fini (&scaled_font->options);
685
1.03M
}
686
687
static cairo_bool_t
688
_cairo_scaled_font_keys_equal (const void *abstract_key_a,
689
             const void *abstract_key_b)
690
1.03M
{
691
1.03M
    const cairo_scaled_font_t *key_a = abstract_key_a;
692
1.03M
    const cairo_scaled_font_t *key_b = abstract_key_b;
693
694
1.03M
    return key_a->original_font_face == key_b->original_font_face &&
695
1.03M
      memcmp ((unsigned char *)(&key_a->font_matrix.xx),
696
1.03M
        (unsigned char *)(&key_b->font_matrix.xx),
697
1.03M
        sizeof(cairo_matrix_t)) == 0 &&
698
1.03M
      memcmp ((unsigned char *)(&key_a->ctm.xx),
699
1.03M
        (unsigned char *)(&key_b->ctm.xx),
700
1.03M
        sizeof(cairo_matrix_t)) == 0 &&
701
1.03M
      cairo_font_options_equal (&key_a->options, &key_b->options);
702
1.03M
}
703
704
static cairo_bool_t
705
_cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font,
706
                      const cairo_font_face_t *font_face,
707
          const cairo_matrix_t *font_matrix,
708
          const cairo_matrix_t *ctm,
709
          const cairo_font_options_t *options)
710
2.22M
{
711
2.22M
    return scaled_font->original_font_face == font_face &&
712
2.22M
      memcmp ((unsigned char *)(&scaled_font->font_matrix.xx),
713
2.22M
        (unsigned char *)(&font_matrix->xx),
714
2.22M
        sizeof(cairo_matrix_t)) == 0 &&
715
1.19M
      memcmp ((unsigned char *)(&scaled_font->ctm.xx),
716
1.19M
        (unsigned char *)(&ctm->xx),
717
1.19M
        sizeof(cairo_matrix_t)) == 0 &&
718
1.19M
      cairo_font_options_equal (&scaled_font->options, options);
719
2.22M
}
720
721
/*
722
 * Basic #cairo_scaled_font_t object management
723
 */
724
725
cairo_status_t
726
_cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
727
       cairo_font_face_t       *font_face,
728
       const cairo_matrix_t              *font_matrix,
729
       const cairo_matrix_t              *ctm,
730
       const cairo_font_options_t    *options,
731
       const cairo_scaled_font_backend_t *backend)
732
556
{
733
556
    cairo_status_t status;
734
735
556
    status = cairo_font_options_status ((cairo_font_options_t *) options);
736
556
    if (unlikely (status))
737
0
  return status;
738
739
556
    scaled_font->status = CAIRO_STATUS_SUCCESS;
740
556
    scaled_font->placeholder = FALSE;
741
556
    scaled_font->font_face = font_face;
742
556
    scaled_font->original_font_face = font_face;
743
556
    scaled_font->font_matrix = *font_matrix;
744
556
    scaled_font->ctm = *ctm;
745
    /* ignore translation values in the ctm */
746
556
    scaled_font->ctm.x0 = 0.;
747
556
    scaled_font->ctm.y0 = 0.;
748
556
    _cairo_font_options_init_copy (&scaled_font->options, options);
749
750
556
    cairo_matrix_multiply (&scaled_font->scale,
751
556
         &scaled_font->font_matrix,
752
556
         &scaled_font->ctm);
753
754
556
    scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
755
556
          fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
756
556
    scaled_font->scale_inverse = scaled_font->scale;
757
556
    status = cairo_matrix_invert (&scaled_font->scale_inverse);
758
556
    if (unlikely (status)) {
759
  /* If the font scale matrix is rank 0, just using an all-zero inverse matrix
760
   * makes everything work correctly.  This make font size 0 work without
761
   * producing an error.
762
   *
763
   * FIXME:  If the scale is rank 1, we still go into error mode.  But then
764
   * again, that's what we do everywhere in cairo.
765
   *
766
   * Also, the check for == 0. below may be too harsh...
767
   */
768
0
        if (_cairo_matrix_is_scale_0 (&scaled_font->scale)) {
769
0
      cairo_matrix_init (&scaled_font->scale_inverse,
770
0
             0, 0, 0, 0,
771
0
             -scaled_font->scale.x0,
772
0
             -scaled_font->scale.y0);
773
0
  } else
774
0
      return status;
775
0
    }
776
777
556
    scaled_font->glyphs = _cairo_hash_table_create (NULL);
778
556
    if (unlikely (scaled_font->glyphs == NULL))
779
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
780
781
556
    cairo_list_init (&scaled_font->glyph_pages);
782
556
    scaled_font->cache_frozen = FALSE;
783
556
    scaled_font->global_cache_frozen = FALSE;
784
556
    _cairo_array_init (&scaled_font->recording_surfaces_to_free, sizeof (cairo_surface_t *));
785
786
556
    scaled_font->holdover = FALSE;
787
556
    scaled_font->finished = FALSE;
788
789
556
    CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
790
791
556
    _cairo_user_data_array_init (&scaled_font->user_data);
792
793
556
    cairo_font_face_reference (font_face);
794
556
    scaled_font->original_font_face = NULL;
795
796
556
    CAIRO_RECURSIVE_MUTEX_INIT (scaled_font->mutex);
797
798
556
    cairo_list_init (&scaled_font->dev_privates);
799
800
556
    scaled_font->backend = backend;
801
556
    cairo_list_init (&scaled_font->link);
802
803
556
    return CAIRO_STATUS_SUCCESS;
804
556
}
805
806
static void _cairo_scaled_font_free_recording_surfaces (cairo_scaled_font_t *scaled_font)
807
458k
{
808
458k
    int num_recording_surfaces;
809
458k
    cairo_surface_t *surface;
810
811
458k
    num_recording_surfaces = _cairo_array_num_elements (&scaled_font->recording_surfaces_to_free);
812
458k
    if (num_recording_surfaces > 0) {
813
0
  for (int i = 0; i < num_recording_surfaces; i++) {
814
0
      _cairo_array_copy_element (&scaled_font->recording_surfaces_to_free, i, &surface);
815
0
      cairo_surface_finish (surface);
816
0
      cairo_surface_destroy (surface);
817
0
  }
818
0
  _cairo_array_truncate (&scaled_font->recording_surfaces_to_free, 0);
819
0
    }
820
458k
}
821
822
void
823
_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
824
458k
{
825
    /* ensure we do not modify an error object */
826
458k
    assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
827
828
458k
    CAIRO_MUTEX_LOCK (scaled_font->mutex);
829
458k
    scaled_font->cache_frozen = TRUE;
830
458k
}
831
832
void
833
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
834
458k
{
835
458k
    assert (scaled_font->cache_frozen);
836
837
458k
    if (scaled_font->global_cache_frozen) {
838
1.23k
  CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
839
1.23k
  _cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
840
1.23k
  CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
841
1.23k
  scaled_font->global_cache_frozen = FALSE;
842
1.23k
    }
843
844
458k
    _cairo_scaled_font_free_recording_surfaces (scaled_font);
845
846
458k
    scaled_font->cache_frozen = FALSE;
847
458k
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
848
458k
}
849
850
void
851
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
852
298
{
853
298
    cairo_scaled_glyph_page_t *page;
854
855
298
    CAIRO_MUTEX_LOCK (scaled_font->mutex);
856
298
    assert (! scaled_font->cache_frozen);
857
298
    assert (! scaled_font->global_cache_frozen);
858
298
    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
859
860
298
    cairo_list_foreach_entry (page,
861
298
            cairo_scaled_glyph_page_t,
862
298
            &scaled_font->glyph_pages,
863
298
            link) {
864
159
  cairo_scaled_glyph_page_cache.size -= page->cache_entry.size;
865
159
  _cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table,
866
159
          (cairo_hash_entry_t *) &page->cache_entry);
867
159
    }
868
869
298
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
870
871
    /* Destroy scaled_font's pages while holding its lock only, and not the
872
     * global page cache lock. The destructor can cause us to recurse and
873
     * end up back here for a different scaled_font. */
874
875
457
    while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
876
159
  page = cairo_list_first_entry (&scaled_font->glyph_pages,
877
159
               cairo_scaled_glyph_page_t,
878
159
               link);
879
159
  _cairo_scaled_glyph_page_destroy (scaled_font, page);
880
159
    }
881
882
298
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
883
298
}
884
885
cairo_status_t
886
_cairo_scaled_font_set_metrics (cairo_scaled_font_t     *scaled_font,
887
        cairo_font_extents_t      *fs_metrics)
888
556
{
889
556
    cairo_status_t status;
890
556
    double  font_scale_x, font_scale_y;
891
892
556
    scaled_font->fs_extents = *fs_metrics;
893
894
556
    status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
895
556
              &font_scale_x, &font_scale_y,
896
556
              1);
897
556
    if (unlikely (status))
898
0
  return status;
899
900
    /*
901
     * The font responded in unscaled units, scale by the font
902
     * matrix scale factors to get to user space
903
     */
904
905
556
    scaled_font->extents.ascent = fs_metrics->ascent * font_scale_y;
906
556
    scaled_font->extents.descent = fs_metrics->descent * font_scale_y;
907
556
    scaled_font->extents.height = fs_metrics->height * font_scale_y;
908
556
    scaled_font->extents.max_x_advance = fs_metrics->max_x_advance * font_scale_x;
909
556
    scaled_font->extents.max_y_advance = fs_metrics->max_y_advance * font_scale_y;
910
911
556
    return CAIRO_STATUS_SUCCESS;
912
556
}
913
914
static void
915
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
916
298
{
917
298
    assert (! scaled_font->cache_frozen);
918
298
    assert (! scaled_font->global_cache_frozen);
919
298
    scaled_font->finished = TRUE;
920
921
298
    _cairo_scaled_font_reset_cache (scaled_font);
922
298
    _cairo_hash_table_destroy (scaled_font->glyphs);
923
298
    _cairo_font_options_fini (&scaled_font->options);
924
925
298
    cairo_font_face_destroy (scaled_font->font_face);
926
298
    cairo_font_face_destroy (scaled_font->original_font_face);
927
928
298
    _cairo_scaled_font_free_recording_surfaces (scaled_font);
929
298
    _cairo_array_fini (&scaled_font->recording_surfaces_to_free);
930
931
298
    CAIRO_MUTEX_FINI (scaled_font->mutex);
932
933
298
    while (! cairo_list_is_empty (&scaled_font->dev_privates)) {
934
0
  cairo_scaled_font_private_t *private =
935
0
      cairo_list_first_entry (&scaled_font->dev_privates,
936
0
            cairo_scaled_font_private_t,
937
0
            link);
938
0
  private->destroy (private, scaled_font);
939
0
    }
940
941
298
    if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
942
298
  scaled_font->backend->fini (scaled_font);
943
944
298
    _cairo_user_data_array_fini (&scaled_font->user_data);
945
298
}
946
947
void
948
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
949
0
{
950
    /* Release the lock to avoid the possibility of a recursive
951
     * deadlock when the scaled font destroy closure gets called. */
952
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
953
0
    _cairo_scaled_font_fini_internal (scaled_font);
954
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
955
0
}
956
957
void
958
_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font,
959
           cairo_scaled_font_private_t *private,
960
           const void *key,
961
           void (*destroy) (cairo_scaled_font_private_t *,
962
                cairo_scaled_font_t *))
963
0
{
964
0
    private->key = key;
965
0
    private->destroy = destroy;
966
0
    cairo_list_add (&private->link, &scaled_font->dev_privates);
967
0
}
968
969
cairo_scaled_font_private_t *
970
_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font,
971
         const void *key)
972
0
{
973
0
    cairo_scaled_font_private_t *priv;
974
975
0
    cairo_list_foreach_entry (priv, cairo_scaled_font_private_t,
976
0
            &scaled_font->dev_privates, link)
977
0
    {
978
0
  if (priv->key == key) {
979
0
      if (priv->link.prev != &scaled_font->dev_privates)
980
0
    cairo_list_move (&priv->link, &scaled_font->dev_privates);
981
0
      return priv;
982
0
  }
983
0
    }
984
985
0
    return NULL;
986
0
}
987
988
void
989
_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph,
990
           cairo_scaled_glyph_private_t *private,
991
           const void *key,
992
           void (*destroy) (cairo_scaled_glyph_private_t *,
993
                cairo_scaled_glyph_t *,
994
                cairo_scaled_font_t *))
995
60.6k
{
996
60.6k
    private->key = key;
997
60.6k
    private->destroy = destroy;
998
60.6k
    cairo_list_add (&private->link, &scaled_glyph->dev_privates);
999
60.6k
}
1000
1001
cairo_scaled_glyph_private_t *
1002
_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph,
1003
         const void *key)
1004
233k
{
1005
233k
    cairo_scaled_glyph_private_t *priv;
1006
1007
233k
    cairo_list_foreach_entry (priv, cairo_scaled_glyph_private_t,
1008
233k
            &scaled_glyph->dev_privates, link)
1009
233k
    {
1010
233k
  if (priv->key == key) {
1011
233k
      if (priv->link.prev != &scaled_glyph->dev_privates)
1012
0
    cairo_list_move (&priv->link, &scaled_glyph->dev_privates);
1013
233k
      return priv;
1014
233k
  }
1015
233k
    }
1016
1017
0
    return NULL;
1018
233k
}
1019
1020
/**
1021
 * cairo_scaled_font_create:
1022
 * @font_face: a #cairo_font_face_t
1023
 * @font_matrix: font space to user space transformation matrix for the
1024
 *       font. In the simplest case of a N point font, this matrix is
1025
 *       just a scale by N, but it can also be used to shear the font
1026
 *       or stretch it unequally along the two axes. See
1027
 *       cairo_set_font_matrix().
1028
 * @ctm: user to device transformation matrix with which the font will
1029
 *       be used.
1030
 * @options: options to use when getting metrics for the font and
1031
 *           rendering with it.
1032
 *
1033
 * Creates a #cairo_scaled_font_t object from a font face and matrices that
1034
 * describe the size of the font and the environment in which it will
1035
 * be used.
1036
 *
1037
 * Return value: a newly created #cairo_scaled_font_t. Destroy with
1038
 *  cairo_scaled_font_destroy()
1039
 *
1040
 * Since: 1.0
1041
 **/
1042
cairo_scaled_font_t *
1043
cairo_scaled_font_create (cairo_font_face_t          *font_face,
1044
        const cairo_matrix_t       *font_matrix,
1045
        const cairo_matrix_t       *ctm,
1046
        const cairo_font_options_t *options)
1047
2.22M
{
1048
2.22M
    cairo_status_t status;
1049
2.22M
    cairo_scaled_font_map_t *font_map;
1050
2.22M
    cairo_font_face_t *original_font_face = font_face;
1051
2.22M
    cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL, *dead = NULL;
1052
2.22M
    double det;
1053
1054
2.22M
    status = font_face->status;
1055
2.22M
    if (unlikely (status))
1056
0
  return _cairo_scaled_font_create_in_error (status);
1057
1058
2.22M
    det = _cairo_matrix_compute_determinant (font_matrix);
1059
2.22M
    if (! ISFINITE (det))
1060
0
  return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
1061
1062
2.22M
    det = _cairo_matrix_compute_determinant (ctm);
1063
2.22M
    if (! ISFINITE (det))
1064
0
  return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
1065
1066
2.22M
    status = cairo_font_options_status ((cairo_font_options_t *) options);
1067
2.22M
    if (unlikely (status))
1068
0
  return _cairo_scaled_font_create_in_error (status);
1069
1070
    /* Note that degenerate ctm or font_matrix *are* allowed.
1071
     * We want to support a font size of 0. */
1072
1073
2.22M
    font_map = _cairo_scaled_font_map_lock ();
1074
2.22M
    if (unlikely (font_map == NULL))
1075
0
  return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1076
1077
2.22M
    scaled_font = font_map->mru_scaled_font;
1078
2.22M
    if (scaled_font != NULL &&
1079
2.22M
  _cairo_scaled_font_matches (scaled_font,
1080
2.22M
                              font_face, font_matrix, ctm, options))
1081
1.19M
    {
1082
1.19M
  assert (scaled_font->hash_entry.hash != ZOMBIE);
1083
1.19M
  assert (! scaled_font->placeholder);
1084
1085
1.19M
  if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
1086
      /* We increment the reference count manually here, (rather
1087
       * than calling into cairo_scaled_font_reference), since we
1088
       * must modify the reference count while our lock is still
1089
       * held. */
1090
1.19M
      _cairo_reference_count_inc (&scaled_font->ref_count);
1091
1.19M
      _cairo_scaled_font_map_unlock ();
1092
1.19M
      return scaled_font;
1093
1.19M
  }
1094
1095
  /* the font has been put into an error status - abandon the cache */
1096
0
  _cairo_hash_table_remove (font_map->hash_table,
1097
0
          &scaled_font->hash_entry);
1098
0
  scaled_font->hash_entry.hash = ZOMBIE;
1099
0
  dead = scaled_font;
1100
0
  font_map->mru_scaled_font = NULL;
1101
0
    }
1102
1103
1.03M
    _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options);
1104
1105
1.03M
    while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table,
1106
1.03M
                &key.hash_entry)))
1107
1.03M
    {
1108
1.03M
  if (! scaled_font->placeholder)
1109
1.03M
      break;
1110
1111
  /* If the scaled font is being created (happens for user-font),
1112
   * just wait until it's done, then retry */
1113
0
  _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
1114
0
    }
1115
1.03M
    _cairo_scaled_font_fini_key (&key);
1116
1117
1.03M
    if (scaled_font != NULL) {
1118
  /* If the original reference count is 0, then this font must have
1119
   * been found in font_map->holdovers, (which means this caching is
1120
   * actually working). So now we remove it from the holdovers
1121
   * array, unless we caught the font in the middle of destruction.
1122
   */
1123
1.03M
  if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
1124
1.03M
      if (scaled_font->holdover) {
1125
1.03M
    int i;
1126
1127
263M
    for (i = 0; i < font_map->num_holdovers; i++) {
1128
263M
        if (font_map->holdovers[i] == scaled_font) {
1129
1.03M
      font_map->num_holdovers--;
1130
1.03M
      memmove (&font_map->holdovers[i],
1131
1.03M
         &font_map->holdovers[i+1],
1132
1.03M
         (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
1133
1.03M
      break;
1134
1.03M
        }
1135
263M
    }
1136
1137
1.03M
    scaled_font->holdover = FALSE;
1138
1.03M
      }
1139
1140
      /* reset any error status */
1141
1.03M
      scaled_font->status = CAIRO_STATUS_SUCCESS;
1142
1.03M
  }
1143
1144
1.03M
  if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
1145
      /* We increment the reference count manually here, (rather
1146
       * than calling into cairo_scaled_font_reference), since we
1147
       * must modify the reference count while our lock is still
1148
       * held. */
1149
1150
1.03M
      old = font_map->mru_scaled_font;
1151
1.03M
      font_map->mru_scaled_font = scaled_font;
1152
      /* increment reference count for the mru cache */
1153
1.03M
      _cairo_reference_count_inc (&scaled_font->ref_count);
1154
      /* and increment for the returned reference */
1155
1.03M
      _cairo_reference_count_inc (&scaled_font->ref_count);
1156
1.03M
      _cairo_scaled_font_map_unlock ();
1157
1158
1.03M
      cairo_scaled_font_destroy (old);
1159
1.03M
      if (font_face != original_font_face)
1160
0
    cairo_font_face_destroy (font_face);
1161
1162
1.03M
      return scaled_font;
1163
1.03M
  }
1164
1165
  /* the font has been put into an error status - abandon the cache */
1166
0
  _cairo_hash_table_remove (font_map->hash_table,
1167
0
          &scaled_font->hash_entry);
1168
0
  scaled_font->hash_entry.hash = ZOMBIE;
1169
0
    }
1170
1171
1172
    /* Otherwise create it and insert it into the hash table. */
1173
556
    if (font_face->backend->get_implementation != NULL) {
1174
556
  font_face = font_face->backend->get_implementation (font_face,
1175
556
                  font_matrix,
1176
556
                  ctm,
1177
556
                  options);
1178
556
  if (unlikely (font_face->status)) {
1179
0
      _cairo_scaled_font_map_unlock ();
1180
0
      return _cairo_scaled_font_create_in_error (font_face->status);
1181
0
  }
1182
556
    }
1183
1184
556
    status = font_face->backend->scaled_font_create (font_face, font_matrix,
1185
556
                 ctm, options, &scaled_font);
1186
556
    if (unlikely (status)) {
1187
0
  _cairo_scaled_font_map_unlock ();
1188
0
  if (font_face != original_font_face)
1189
0
      cairo_font_face_destroy (font_face);
1190
1191
0
  if (dead != NULL)
1192
0
      cairo_scaled_font_destroy (dead);
1193
1194
0
  return _cairo_scaled_font_create_in_error (status);
1195
0
    }
1196
    /* Or did we encounter an error whilst constructing the scaled font? */
1197
556
    if (unlikely (scaled_font->status)) {
1198
0
  _cairo_scaled_font_map_unlock ();
1199
0
  if (font_face != original_font_face)
1200
0
      cairo_font_face_destroy (font_face);
1201
1202
0
  if (dead != NULL)
1203
0
      cairo_scaled_font_destroy (dead);
1204
1205
0
  return scaled_font;
1206
0
    }
1207
1208
    /* Our caching above is defeated if the backend switches fonts on us -
1209
     * e.g. old incarnations of toy-font-face and lazily resolved
1210
     * ft-font-faces
1211
     */
1212
556
    assert (scaled_font->font_face == font_face);
1213
556
    assert (! scaled_font->cache_frozen);
1214
556
    assert (! scaled_font->global_cache_frozen);
1215
1216
556
    scaled_font->original_font_face =
1217
556
  cairo_font_face_reference (original_font_face);
1218
1219
556
    scaled_font->hash_entry.hash = _cairo_scaled_font_compute_hash(scaled_font);
1220
1221
556
    status = _cairo_hash_table_insert (font_map->hash_table,
1222
556
               &scaled_font->hash_entry);
1223
556
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
1224
556
  old = font_map->mru_scaled_font;
1225
556
  font_map->mru_scaled_font = scaled_font;
1226
556
  _cairo_reference_count_inc (&scaled_font->ref_count);
1227
556
    }
1228
1229
556
    _cairo_scaled_font_map_unlock ();
1230
1231
556
    cairo_scaled_font_destroy (old);
1232
556
    if (font_face != original_font_face)
1233
0
  cairo_font_face_destroy (font_face);
1234
1235
556
    if (dead != NULL)
1236
0
  cairo_scaled_font_destroy (dead);
1237
1238
556
    if (unlikely (status)) {
1239
  /* We can't call _cairo_scaled_font_destroy here since it expects
1240
   * that the font has already been successfully inserted into the
1241
   * hash table. */
1242
0
  _cairo_scaled_font_fini_internal (scaled_font);
1243
0
  free (scaled_font);
1244
0
  return _cairo_scaled_font_create_in_error (status);
1245
0
    }
1246
1247
556
    return scaled_font;
1248
556
}
1249
1250
static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
1251
1252
/* XXX This should disappear in favour of a common pool of error objects. */
1253
cairo_scaled_font_t *
1254
_cairo_scaled_font_create_in_error (cairo_status_t status)
1255
0
{
1256
0
    cairo_scaled_font_t *scaled_font;
1257
1258
0
    assert (status != CAIRO_STATUS_SUCCESS);
1259
1260
0
    if (status == CAIRO_STATUS_NO_MEMORY)
1261
0
  return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
1262
1263
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
1264
0
    scaled_font = _cairo_scaled_font_nil_objects[status];
1265
0
    if (unlikely (scaled_font == NULL)) {
1266
0
  scaled_font = _cairo_calloc (sizeof (cairo_scaled_font_t));
1267
0
  if (unlikely (scaled_font == NULL)) {
1268
0
      CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1269
0
      _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1270
0
      return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
1271
0
  }
1272
1273
0
  *scaled_font = _cairo_scaled_font_nil;
1274
0
  scaled_font->status = status;
1275
0
  _cairo_scaled_font_nil_objects[status] = scaled_font;
1276
0
    }
1277
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1278
1279
0
    return scaled_font;
1280
0
}
1281
1282
void
1283
_cairo_scaled_font_reset_static_data (void)
1284
0
{
1285
0
    int status;
1286
1287
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
1288
0
    for (status = CAIRO_STATUS_SUCCESS;
1289
0
   status <= CAIRO_STATUS_LAST_STATUS;
1290
0
   status++)
1291
0
    {
1292
0
  free (_cairo_scaled_font_nil_objects[status]);
1293
0
  _cairo_scaled_font_nil_objects[status] = NULL;
1294
0
    }
1295
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1296
1297
0
    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
1298
0
    if (cairo_scaled_glyph_page_cache.hash_table != NULL) {
1299
0
  _cairo_cache_fini (&cairo_scaled_glyph_page_cache);
1300
0
  cairo_scaled_glyph_page_cache.hash_table = NULL;
1301
0
    }
1302
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
1303
0
}
1304
1305
/**
1306
 * cairo_scaled_font_reference:
1307
 * @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
1308
 * this function does nothing)
1309
 *
1310
 * Increases the reference count on @scaled_font by one. This prevents
1311
 * @scaled_font from being destroyed until a matching call to
1312
 * cairo_scaled_font_destroy() is made.
1313
 *
1314
 * Use cairo_scaled_font_get_reference_count() to get the number of
1315
 * references to a #cairo_scaled_font_t.
1316
 *
1317
 * Returns: the referenced #cairo_scaled_font_t
1318
 *
1319
 * Since: 1.0
1320
 **/
1321
cairo_scaled_font_t *
1322
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
1323
36.7k
{
1324
36.7k
    if (scaled_font == NULL ||
1325
0
      CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1326
36.7k
  return scaled_font;
1327
1328
36.7k
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
1329
1330
0
    _cairo_reference_count_inc (&scaled_font->ref_count);
1331
1332
0
    return scaled_font;
1333
0
}
1334
1335
/**
1336
 * cairo_scaled_font_destroy:
1337
 * @scaled_font: a #cairo_scaled_font_t
1338
 *
1339
 * Decreases the reference count on @font by one. If the result
1340
 * is zero, then @font and all associated resources are freed.
1341
 * See cairo_scaled_font_reference().
1342
 *
1343
 * Since: 1.0
1344
 **/
1345
void
1346
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
1347
32.4M
{
1348
32.4M
    cairo_scaled_font_t *lru = NULL;
1349
32.4M
    cairo_scaled_font_map_t *font_map;
1350
1351
32.4M
    assert (CAIRO_MUTEX_IS_UNLOCKED (_cairo_scaled_font_map_mutex));
1352
1353
32.4M
    if (scaled_font == NULL ||
1354
3.26M
      CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1355
29.1M
  return;
1356
1357
32.4M
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
1358
1359
3.26M
    font_map = _cairo_scaled_font_map_lock ();
1360
3.26M
    assert (font_map != NULL);
1361
1362
3.26M
    if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
1363
2.22M
  goto unlock;
1364
1365
3.26M
    assert (! scaled_font->cache_frozen);
1366
1.03M
    assert (! scaled_font->global_cache_frozen);
1367
1368
    /* Another thread may have resurrected the font whilst we waited */
1369
1.03M
    if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
1370
1.03M
  if (! scaled_font->placeholder &&
1371
1.03M
      scaled_font->hash_entry.hash != ZOMBIE)
1372
1.03M
  {
1373
      /* Another thread may have already inserted us into the holdovers */
1374
1.03M
      if (scaled_font->holdover)
1375
0
    goto unlock;
1376
1377
      /* Rather than immediately destroying this object, we put it into
1378
       * the font_map->holdovers array in case it will get used again
1379
       * soon (and is why we must hold the lock over the atomic op on
1380
       * the reference count). To make room for it, we do actually
1381
       * destroy the least-recently-used holdover.
1382
       */
1383
1384
1.03M
      if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
1385
298
    lru = font_map->holdovers[0];
1386
298
    assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
1387
1388
298
    _cairo_hash_table_remove (font_map->hash_table,
1389
298
            &lru->hash_entry);
1390
1391
298
    font_map->num_holdovers--;
1392
298
    memmove (&font_map->holdovers[0],
1393
298
       &font_map->holdovers[1],
1394
298
       font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
1395
298
      }
1396
1397
1.03M
      font_map->holdovers[font_map->num_holdovers++] = scaled_font;
1398
1.03M
      scaled_font->holdover = TRUE;
1399
1.03M
  } else
1400
0
      lru = scaled_font;
1401
1.03M
    }
1402
1403
3.26M
  unlock:
1404
3.26M
    _cairo_scaled_font_map_unlock ();
1405
1406
    /* If we pulled an item from the holdovers array, (while the font
1407
     * map lock was held, of course), then there is no way that anyone
1408
     * else could have acquired a reference to it. So we can now
1409
     * safely call fini on it without any lock held. This is desirable
1410
     * as we never want to call into any backend function with a lock
1411
     * held. */
1412
3.26M
    if (lru != NULL) {
1413
298
  _cairo_scaled_font_fini_internal (lru);
1414
298
  free (lru);
1415
298
    }
1416
3.26M
}
1417
1418
/**
1419
 * cairo_scaled_font_get_reference_count:
1420
 * @scaled_font: a #cairo_scaled_font_t
1421
 *
1422
 * Returns the current reference count of @scaled_font.
1423
 *
1424
 * Return value: the current reference count of @scaled_font.  If the
1425
 * object is a nil object, 0 will be returned.
1426
 *
1427
 * Since: 1.4
1428
 **/
1429
unsigned int
1430
cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
1431
0
{
1432
0
    if (scaled_font == NULL ||
1433
0
      CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1434
0
  return 0;
1435
1436
0
    return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count);
1437
0
}
1438
1439
/**
1440
 * cairo_scaled_font_get_user_data:
1441
 * @scaled_font: a #cairo_scaled_font_t
1442
 * @key: the address of the #cairo_user_data_key_t the user data was
1443
 * attached to
1444
 *
1445
 * Return user data previously attached to @scaled_font using the
1446
 * specified key.  If no user data has been attached with the given
1447
 * key this function returns %NULL.
1448
 *
1449
 * Return value: the user data previously attached or %NULL.
1450
 *
1451
 * Since: 1.4
1452
 **/
1453
void *
1454
cairo_scaled_font_get_user_data (cairo_scaled_font_t       *scaled_font,
1455
         const cairo_user_data_key_t *key)
1456
0
{
1457
0
    return _cairo_user_data_array_get_data (&scaled_font->user_data,
1458
0
              key);
1459
0
}
1460
1461
/**
1462
 * cairo_scaled_font_set_user_data:
1463
 * @scaled_font: a #cairo_scaled_font_t
1464
 * @key: the address of a #cairo_user_data_key_t to attach the user data to
1465
 * @user_data: the user data to attach to the #cairo_scaled_font_t
1466
 * @destroy: a #cairo_destroy_func_t which will be called when the
1467
 * #cairo_t is destroyed or when new user data is attached using the
1468
 * same key.
1469
 *
1470
 * Attach user data to @scaled_font.  To remove user data from a surface,
1471
 * call this function with the key that was used to set it and %NULL
1472
 * for @data.
1473
 *
1474
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
1475
 * slot could not be allocated for the user data.
1476
 *
1477
 * Since: 1.4
1478
 **/
1479
cairo_status_t
1480
cairo_scaled_font_set_user_data (cairo_scaled_font_t       *scaled_font,
1481
         const cairo_user_data_key_t *key,
1482
         void          *user_data,
1483
         cairo_destroy_func_t       destroy)
1484
0
{
1485
0
    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1486
0
  return scaled_font->status;
1487
1488
0
    return _cairo_user_data_array_set_data (&scaled_font->user_data,
1489
0
              key, user_data, destroy);
1490
0
}
1491
1492
/* Public font API follows. */
1493
1494
/**
1495
 * cairo_scaled_font_extents:
1496
 * @scaled_font: a #cairo_scaled_font_t
1497
 * @extents: a #cairo_font_extents_t which to store the retrieved extents.
1498
 *
1499
 * Gets the metrics for a #cairo_scaled_font_t.
1500
 *
1501
 * Since: 1.0
1502
 **/
1503
void
1504
cairo_scaled_font_extents (cairo_scaled_font_t  *scaled_font,
1505
         cairo_font_extents_t *extents)
1506
0
{
1507
0
    if (scaled_font->status) {
1508
0
  extents->ascent  = 0.0;
1509
0
  extents->descent = 0.0;
1510
0
  extents->height  = 0.0;
1511
0
  extents->max_x_advance = 0.0;
1512
0
  extents->max_y_advance = 0.0;
1513
0
  return;
1514
0
    }
1515
1516
0
    *extents = scaled_font->extents;
1517
0
}
1518
1519
/**
1520
 * cairo_scaled_font_text_extents:
1521
 * @scaled_font: a #cairo_scaled_font_t
1522
 * @utf8: a NUL-terminated string of text, encoded in UTF-8
1523
 * @extents: a #cairo_text_extents_t which to store the retrieved extents.
1524
 *
1525
 * Gets the extents for a string of text. The extents describe a
1526
 * user-space rectangle that encloses the "inked" portion of the text
1527
 * drawn at the origin (0,0) (as it would be drawn by cairo_show_text()
1528
 * if the cairo graphics state were set to the same font_face,
1529
 * font_matrix, ctm, and font_options as @scaled_font).  Additionally,
1530
 * the x_advance and y_advance values indicate the amount by which the
1531
 * current point would be advanced by cairo_show_text().
1532
 *
1533
 * Note that whitespace characters do not directly contribute to the
1534
 * size of the rectangle (extents.width and extents.height). They do
1535
 * contribute indirectly by changing the position of non-whitespace
1536
 * characters. In particular, trailing whitespace characters are
1537
 * likely to not affect the size of the rectangle, though they will
1538
 * affect the x_advance and y_advance values.
1539
 *
1540
 * Since: 1.2
1541
 **/
1542
void
1543
cairo_scaled_font_text_extents (cairo_scaled_font_t   *scaled_font,
1544
        const char            *utf8,
1545
        cairo_text_extents_t  *extents)
1546
0
{
1547
0
    cairo_status_t status;
1548
0
    cairo_glyph_t *glyphs = NULL;
1549
0
    int num_glyphs;
1550
1551
0
    if (scaled_font->status)
1552
0
  goto ZERO_EXTENTS;
1553
1554
0
    if (utf8 == NULL)
1555
0
  goto ZERO_EXTENTS;
1556
1557
0
    status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0.,
1558
0
                 utf8, -1,
1559
0
                 &glyphs, &num_glyphs,
1560
0
                 NULL, NULL,
1561
0
                 NULL);
1562
0
    if (unlikely (status)) {
1563
0
  status = _cairo_scaled_font_set_error (scaled_font, status);
1564
0
  goto ZERO_EXTENTS;
1565
0
    }
1566
1567
0
    cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents);
1568
0
    free (glyphs);
1569
1570
0
    return;
1571
1572
0
ZERO_EXTENTS:
1573
0
    extents->x_bearing = 0.0;
1574
0
    extents->y_bearing = 0.0;
1575
0
    extents->width  = 0.0;
1576
0
    extents->height = 0.0;
1577
0
    extents->x_advance = 0.0;
1578
0
    extents->y_advance = 0.0;
1579
0
}
1580
1581
/**
1582
 * cairo_scaled_font_glyph_extents:
1583
 * @scaled_font: a #cairo_scaled_font_t
1584
 * @glyphs: an array of glyph IDs with X and Y offsets.
1585
 * @num_glyphs: the number of glyphs in the @glyphs array
1586
 * @extents: a #cairo_text_extents_t which to store the retrieved extents.
1587
 *
1588
 * Gets the extents for an array of glyphs. The extents describe a
1589
 * user-space rectangle that encloses the "inked" portion of the
1590
 * glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo
1591
 * graphics state were set to the same font_face, font_matrix, ctm,
1592
 * and font_options as @scaled_font).  Additionally, the x_advance and
1593
 * y_advance values indicate the amount by which the current point
1594
 * would be advanced by cairo_show_glyphs().
1595
 *
1596
 * Note that whitespace glyphs do not contribute to the size of the
1597
 * rectangle (extents.width and extents.height).
1598
 *
1599
 * Since: 1.0
1600
 **/
1601
void
1602
cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
1603
         const cairo_glyph_t   *glyphs,
1604
         int                    num_glyphs,
1605
         cairo_text_extents_t  *extents)
1606
0
{
1607
0
    cairo_status_t status;
1608
0
    int i;
1609
0
    double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
1610
0
    cairo_bool_t visible = FALSE;
1611
0
    cairo_scaled_glyph_t *scaled_glyph = NULL;
1612
1613
0
    extents->x_bearing = 0.0;
1614
0
    extents->y_bearing = 0.0;
1615
0
    extents->width  = 0.0;
1616
0
    extents->height = 0.0;
1617
0
    extents->x_advance = 0.0;
1618
0
    extents->y_advance = 0.0;
1619
1620
0
    if (unlikely (scaled_font->status))
1621
0
  goto ZERO_EXTENTS;
1622
1623
0
    if (num_glyphs == 0)
1624
0
  goto ZERO_EXTENTS;
1625
1626
0
    if (unlikely (num_glyphs < 0)) {
1627
0
  _cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
1628
  /* XXX Can't propagate error */
1629
0
  goto ZERO_EXTENTS;
1630
0
    }
1631
1632
0
    if (unlikely (glyphs == NULL)) {
1633
0
  _cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
1634
  /* XXX Can't propagate error */
1635
0
  goto ZERO_EXTENTS;
1636
0
    }
1637
1638
0
    _cairo_scaled_font_freeze_cache (scaled_font);
1639
1640
0
    for (i = 0; i < num_glyphs; i++) {
1641
0
  double      left, top, right, bottom;
1642
1643
0
  status = _cairo_scaled_glyph_lookup (scaled_font,
1644
0
               glyphs[i].index,
1645
0
               CAIRO_SCALED_GLYPH_INFO_METRICS,
1646
0
               NULL, /* foreground color */
1647
0
               &scaled_glyph);
1648
0
  if (unlikely (status)) {
1649
0
      status = _cairo_scaled_font_set_error (scaled_font, status);
1650
0
      goto UNLOCK;
1651
0
  }
1652
1653
  /* "Ink" extents should skip "invisible" glyphs */
1654
0
  if (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)
1655
0
      continue;
1656
1657
0
  left = scaled_glyph->metrics.x_bearing + glyphs[i].x;
1658
0
  right = left + scaled_glyph->metrics.width;
1659
0
  top = scaled_glyph->metrics.y_bearing + glyphs[i].y;
1660
0
  bottom = top + scaled_glyph->metrics.height;
1661
1662
0
  if (!visible) {
1663
0
      visible = TRUE;
1664
0
      min_x = left;
1665
0
      max_x = right;
1666
0
      min_y = top;
1667
0
      max_y = bottom;
1668
0
  } else {
1669
0
      if (left < min_x) min_x = left;
1670
0
      if (right > max_x) max_x = right;
1671
0
      if (top < min_y) min_y = top;
1672
0
      if (bottom > max_y) max_y = bottom;
1673
0
  }
1674
0
    }
1675
1676
0
    if (visible) {
1677
0
  extents->x_bearing = min_x - glyphs[0].x;
1678
0
  extents->y_bearing = min_y - glyphs[0].y;
1679
0
  extents->width = max_x - min_x;
1680
0
  extents->height = max_y - min_y;
1681
0
    } else {
1682
0
  extents->x_bearing = 0.0;
1683
0
  extents->y_bearing = 0.0;
1684
0
  extents->width = 0.0;
1685
0
  extents->height = 0.0;
1686
0
    }
1687
1688
0
    if (num_glyphs) {
1689
0
        double x0, y0, x1, y1;
1690
1691
0
  x0 = glyphs[0].x;
1692
0
  y0 = glyphs[0].y;
1693
1694
  /* scaled_glyph contains the glyph for num_glyphs - 1 already. */
1695
0
  x1 = glyphs[num_glyphs - 1].x + scaled_glyph->metrics.x_advance;
1696
0
  y1 = glyphs[num_glyphs - 1].y + scaled_glyph->metrics.y_advance;
1697
1698
0
  extents->x_advance = x1 - x0;
1699
0
  extents->y_advance = y1 - y0;
1700
0
    } else {
1701
0
  extents->x_advance = 0.0;
1702
0
  extents->y_advance = 0.0;
1703
0
    }
1704
1705
0
 UNLOCK:
1706
0
    _cairo_scaled_font_thaw_cache (scaled_font);
1707
0
    return;
1708
1709
0
ZERO_EXTENTS:
1710
0
    extents->x_bearing = 0.0;
1711
0
    extents->y_bearing = 0.0;
1712
0
    extents->width  = 0.0;
1713
0
    extents->height = 0.0;
1714
0
    extents->x_advance = 0.0;
1715
0
    extents->y_advance = 0.0;
1716
0
}
1717
1718
0
#define GLYPH_LUT_SIZE 64
1719
static cairo_status_t
1720
cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t    *scaled_font,
1721
                double        x,
1722
                double        y,
1723
                const char       *utf8,
1724
                cairo_glyph_t    *glyphs,
1725
                cairo_text_cluster_t  **clusters,
1726
                int         num_chars)
1727
0
{
1728
0
    struct glyph_lut_elt {
1729
0
  unsigned long index;
1730
0
  double x_advance;
1731
0
  double y_advance;
1732
0
    } glyph_lut[GLYPH_LUT_SIZE];
1733
0
    uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE];
1734
0
    cairo_status_t status;
1735
0
    const char *p;
1736
0
    int i;
1737
1738
0
    for (i = 0; i < GLYPH_LUT_SIZE; i++)
1739
0
  glyph_lut_unicode[i] = ~0U;
1740
1741
0
    p = utf8;
1742
0
    for (i = 0; i < num_chars; i++) {
1743
0
  int idx, num_bytes;
1744
0
  uint32_t unicode;
1745
0
  cairo_scaled_glyph_t *scaled_glyph;
1746
0
  struct glyph_lut_elt *glyph_slot;
1747
1748
0
  num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
1749
0
  p += num_bytes;
1750
1751
0
  glyphs[i].x = x;
1752
0
  glyphs[i].y = y;
1753
1754
0
  idx = unicode % ARRAY_LENGTH (glyph_lut);
1755
0
  glyph_slot = &glyph_lut[idx];
1756
0
  if (glyph_lut_unicode[idx] == unicode) {
1757
0
      glyphs[i].index = glyph_slot->index;
1758
0
      x += glyph_slot->x_advance;
1759
0
      y += glyph_slot->y_advance;
1760
0
  } else {
1761
0
      unsigned long g;
1762
1763
0
      g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
1764
0
      status = _cairo_scaled_glyph_lookup (scaled_font,
1765
0
             g,
1766
0
             CAIRO_SCALED_GLYPH_INFO_METRICS,
1767
0
             NULL, /* foreground color */
1768
0
             &scaled_glyph);
1769
0
      if (unlikely (status))
1770
0
    return status;
1771
1772
0
      x += scaled_glyph->metrics.x_advance;
1773
0
      y += scaled_glyph->metrics.y_advance;
1774
1775
0
      glyph_lut_unicode[idx] = unicode;
1776
0
      glyph_slot->index = g;
1777
0
      glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
1778
0
      glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
1779
1780
0
      glyphs[i].index = g;
1781
0
  }
1782
1783
0
  if (clusters) {
1784
0
      (*clusters)[i].num_bytes  = num_bytes;
1785
0
      (*clusters)[i].num_glyphs = 1;
1786
0
  }
1787
0
    }
1788
1789
0
    return CAIRO_STATUS_SUCCESS;
1790
0
}
1791
1792
static cairo_status_t
1793
cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t  *scaled_font,
1794
              double      x,
1795
              double      y,
1796
              const char     *utf8,
1797
              cairo_glyph_t    *glyphs,
1798
              cairo_text_cluster_t  **clusters,
1799
              int       num_chars)
1800
0
{
1801
0
    const char *p;
1802
0
    int i;
1803
1804
0
    p = utf8;
1805
0
    for (i = 0; i < num_chars; i++) {
1806
0
  unsigned long g;
1807
0
  int num_bytes;
1808
0
  uint32_t unicode;
1809
0
  cairo_scaled_glyph_t *scaled_glyph;
1810
0
  cairo_status_t status;
1811
1812
0
  num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
1813
0
  p += num_bytes;
1814
1815
0
  glyphs[i].x = x;
1816
0
  glyphs[i].y = y;
1817
1818
0
  g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
1819
1820
  /*
1821
   * No advance needed for a single character string. So, let's speed up
1822
   * one-character strings by skipping glyph lookup.
1823
   */
1824
0
  if (num_chars > 1) {
1825
0
      status = _cairo_scaled_glyph_lookup (scaled_font,
1826
0
               g,
1827
0
               CAIRO_SCALED_GLYPH_INFO_METRICS,
1828
0
               NULL, /* foreground color */
1829
0
               &scaled_glyph);
1830
0
      if (unlikely (status))
1831
0
    return status;
1832
1833
0
      x += scaled_glyph->metrics.x_advance;
1834
0
      y += scaled_glyph->metrics.y_advance;
1835
0
  }
1836
1837
0
  glyphs[i].index = g;
1838
1839
0
  if (clusters) {
1840
0
      (*clusters)[i].num_bytes  = num_bytes;
1841
0
      (*clusters)[i].num_glyphs = 1;
1842
0
  }
1843
0
    }
1844
1845
0
    return CAIRO_STATUS_SUCCESS;
1846
0
}
1847
1848
/**
1849
 * cairo_scaled_font_text_to_glyphs:
1850
 * @scaled_font: a #cairo_scaled_font_t
1851
 * @x: X position to place first glyph
1852
 * @y: Y position to place first glyph
1853
 * @utf8: a string of text encoded in UTF-8
1854
 * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
1855
 * @glyphs: pointer to array of glyphs to fill
1856
 * @num_glyphs: pointer to number of glyphs
1857
 * @clusters: pointer to array of cluster mapping information to fill, or %NULL
1858
 * @num_clusters: pointer to number of clusters, or %NULL
1859
 * @cluster_flags: pointer to location to store cluster flags corresponding to the
1860
 *                 output @clusters, or %NULL
1861
 *
1862
 * Converts UTF-8 text to an array of glyphs, optionally with cluster
1863
 * mapping, that can be used to render later using @scaled_font.
1864
 *
1865
 * If @glyphs initially points to a non-%NULL value, that array is used
1866
 * as a glyph buffer, and @num_glyphs should point to the number of glyph
1867
 * entries available there.  If the provided glyph array is too short for
1868
 * the conversion, a new glyph array is allocated using cairo_glyph_allocate()
1869
 * and placed in @glyphs.  Upon return, @num_glyphs always contains the
1870
 * number of generated glyphs.  If the value @glyphs points to has changed
1871
 * after the call, the user is responsible for freeing the allocated glyph
1872
 * array using cairo_glyph_free().  This may happen even if the provided
1873
 * array was large enough.
1874
 *
1875
 * If @clusters is not %NULL, @num_clusters and @cluster_flags should not be %NULL,
1876
 * and cluster mapping will be computed.
1877
 * The semantics of how cluster array allocation works is similar to the glyph
1878
 * array.  That is,
1879
 * if @clusters initially points to a non-%NULL value, that array is used
1880
 * as a cluster buffer, and @num_clusters should point to the number of cluster
1881
 * entries available there.  If the provided cluster array is too short for
1882
 * the conversion, a new cluster array is allocated using cairo_text_cluster_allocate()
1883
 * and placed in @clusters.  Upon return, @num_clusters always contains the
1884
 * number of generated clusters.  If the value @clusters points at has changed
1885
 * after the call, the user is responsible for freeing the allocated cluster
1886
 * array using cairo_text_cluster_free().  This may happen even if the provided
1887
 * array was large enough.
1888
 *
1889
 * In the simplest case, @glyphs and @clusters can point to %NULL initially
1890
 * and a suitable array will be allocated.  In code:
1891
 * <informalexample><programlisting>
1892
 * cairo_status_t status;
1893
 *
1894
 * cairo_glyph_t *glyphs = NULL;
1895
 * int num_glyphs;
1896
 * cairo_text_cluster_t *clusters = NULL;
1897
 * int num_clusters;
1898
 * cairo_text_cluster_flags_t cluster_flags;
1899
 *
1900
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1901
 *                                            x, y,
1902
 *                                            utf8, utf8_len,
1903
 *                                            &amp;glyphs, &amp;num_glyphs,
1904
 *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
1905
 *
1906
 * if (status == CAIRO_STATUS_SUCCESS) {
1907
 *     cairo_show_text_glyphs (cr,
1908
 *                             utf8, utf8_len,
1909
 *                             glyphs, num_glyphs,
1910
 *                             clusters, num_clusters, cluster_flags);
1911
 *
1912
 *     cairo_glyph_free (glyphs);
1913
 *     cairo_text_cluster_free (clusters);
1914
 * }
1915
 * </programlisting></informalexample>
1916
 *
1917
 * If no cluster mapping is needed:
1918
 * <informalexample><programlisting>
1919
 * cairo_status_t status;
1920
 *
1921
 * cairo_glyph_t *glyphs = NULL;
1922
 * int num_glyphs;
1923
 *
1924
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1925
 *                                            x, y,
1926
 *                                            utf8, utf8_len,
1927
 *                                            &amp;glyphs, &amp;num_glyphs,
1928
 *                                            NULL, NULL,
1929
 *                                            NULL);
1930
 *
1931
 * if (status == CAIRO_STATUS_SUCCESS) {
1932
 *     cairo_show_glyphs (cr, glyphs, num_glyphs);
1933
 *     cairo_glyph_free (glyphs);
1934
 * }
1935
 * </programlisting></informalexample>
1936
 *
1937
 * If stack-based glyph and cluster arrays are to be used for small
1938
 * arrays:
1939
 * <informalexample><programlisting>
1940
 * cairo_status_t status;
1941
 *
1942
 * cairo_glyph_t stack_glyphs[40];
1943
 * cairo_glyph_t *glyphs = stack_glyphs;
1944
 * int num_glyphs = sizeof (stack_glyphs) / sizeof (stack_glyphs[0]);
1945
 * cairo_text_cluster_t stack_clusters[40];
1946
 * cairo_text_cluster_t *clusters = stack_clusters;
1947
 * int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]);
1948
 * cairo_text_cluster_flags_t cluster_flags;
1949
 *
1950
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1951
 *                                            x, y,
1952
 *                                            utf8, utf8_len,
1953
 *                                            &amp;glyphs, &amp;num_glyphs,
1954
 *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
1955
 *
1956
 * if (status == CAIRO_STATUS_SUCCESS) {
1957
 *     cairo_show_text_glyphs (cr,
1958
 *                             utf8, utf8_len,
1959
 *                             glyphs, num_glyphs,
1960
 *                             clusters, num_clusters, cluster_flags);
1961
 *
1962
 *     if (glyphs != stack_glyphs)
1963
 *         cairo_glyph_free (glyphs);
1964
 *     if (clusters != stack_clusters)
1965
 *         cairo_text_cluster_free (clusters);
1966
 * }
1967
 * </programlisting></informalexample>
1968
 *
1969
 * For details of how @clusters, @num_clusters, and @cluster_flags map input
1970
 * UTF-8 text to the output glyphs see cairo_show_text_glyphs().
1971
 *
1972
 * The output values can be readily passed to cairo_show_text_glyphs()
1973
 * cairo_show_glyphs(), or related functions, assuming that the exact
1974
 * same @scaled_font is used for the operation.
1975
 *
1976
 * Return value: %CAIRO_STATUS_SUCCESS upon success, or an error status
1977
 * if the input values are wrong or if conversion failed.  If the input
1978
 * values are correct but the conversion failed, the error status is also
1979
 * set on @scaled_font.
1980
 *
1981
 * Since: 1.8
1982
 **/
1983
0
#define CACHING_THRESHOLD 16
1984
cairo_status_t
1985
cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
1986
          double     x,
1987
          double     y,
1988
          const char          *utf8,
1989
          int            utf8_len,
1990
          cairo_glyph_t        **glyphs,
1991
          int           *num_glyphs,
1992
          cairo_text_cluster_t **clusters,
1993
          int           *num_clusters,
1994
          cairo_text_cluster_flags_t *cluster_flags)
1995
0
{
1996
0
    int num_chars = 0;
1997
0
    cairo_int_status_t status;
1998
0
    cairo_glyph_t *orig_glyphs;
1999
0
    cairo_text_cluster_t *orig_clusters;
2000
2001
0
    status = scaled_font->status;
2002
0
    if (unlikely (status))
2003
0
  return status;
2004
2005
    /* A slew of sanity checks */
2006
2007
    /* glyphs and num_glyphs can't be NULL */
2008
0
    if (glyphs     == NULL ||
2009
0
  num_glyphs == NULL) {
2010
0
  status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
2011
0
  goto BAIL;
2012
0
    }
2013
2014
    /* Special case for NULL and -1 */
2015
0
    if (utf8 == NULL && utf8_len == -1)
2016
0
  utf8_len = 0;
2017
2018
    /* No NULLs for non-NULLs! */
2019
0
    if ((utf8_len && utf8          == NULL) ||
2020
0
  (clusters && num_clusters  == NULL) ||
2021
0
  (clusters && cluster_flags == NULL)) {
2022
0
  status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
2023
0
  goto BAIL;
2024
0
    }
2025
2026
    /* A -1 for utf8_len means NUL-terminated */
2027
0
    if (utf8_len == -1)
2028
0
  utf8_len = strlen (utf8);
2029
2030
    /* A NULL *glyphs means no prealloced glyphs array */
2031
0
    if (glyphs && *glyphs == NULL)
2032
0
  *num_glyphs = 0;
2033
2034
    /* A NULL *clusters means no prealloced clusters array */
2035
0
    if (clusters && *clusters == NULL)
2036
0
  *num_clusters = 0;
2037
2038
0
    if (!clusters && num_clusters) {
2039
0
  num_clusters = NULL;
2040
0
    }
2041
2042
0
    if (cluster_flags) {
2043
0
  *cluster_flags = FALSE;
2044
0
    }
2045
2046
0
    if (!clusters && cluster_flags) {
2047
0
  cluster_flags = NULL;
2048
0
    }
2049
2050
    /* Apart from that, no negatives */
2051
0
    if (utf8_len < 0 ||
2052
0
  *num_glyphs < 0 ||
2053
0
  (num_clusters && *num_clusters < 0)) {
2054
0
  status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
2055
0
  goto BAIL;
2056
0
    }
2057
2058
0
    if (utf8_len == 0) {
2059
0
  status = CAIRO_STATUS_SUCCESS;
2060
0
  goto BAIL;
2061
0
    }
2062
2063
    /* validate input so backend does not have to */
2064
0
    status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars);
2065
0
    if (unlikely (status))
2066
0
  goto BAIL;
2067
2068
0
    _cairo_scaled_font_freeze_cache (scaled_font);
2069
2070
0
    orig_glyphs = *glyphs;
2071
0
    orig_clusters = clusters ? *clusters : NULL;
2072
2073
0
    if (scaled_font->backend->text_to_glyphs) {
2074
0
  status = scaled_font->backend->text_to_glyphs (scaled_font, x, y,
2075
0
                   utf8, utf8_len,
2076
0
                   glyphs, num_glyphs,
2077
0
                   clusters, num_clusters,
2078
0
                   cluster_flags);
2079
0
        if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
2080
0
      if (status == CAIRO_INT_STATUS_SUCCESS) {
2081
          /* The checks here are crude; we only should do them in
2082
     * user-font backend, but they don't hurt here.  This stuff
2083
     * can be hard to get right. */
2084
2085
0
          if (*num_glyphs < 0) {
2086
0
        status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
2087
0
        goto DONE;
2088
0
    }
2089
0
    if (*num_glyphs != 0 && *glyphs == NULL) {
2090
0
        status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
2091
0
        goto DONE;
2092
0
    }
2093
2094
0
    if (clusters) {
2095
0
        if (*num_clusters < 0) {
2096
0
      status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
2097
0
      goto DONE;
2098
0
        }
2099
0
        if (*num_clusters != 0 && *clusters == NULL) {
2100
0
      status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
2101
0
      goto DONE;
2102
0
        }
2103
2104
        /* Don't trust the backend, validate clusters! */
2105
0
        status =
2106
0
      _cairo_validate_text_clusters (utf8, utf8_len,
2107
0
                   *glyphs, *num_glyphs,
2108
0
                   *clusters, *num_clusters,
2109
0
                   *cluster_flags);
2110
0
    }
2111
0
      }
2112
2113
0
            goto DONE;
2114
0
  }
2115
0
    }
2116
2117
0
    if (*num_glyphs < num_chars) {
2118
0
  *glyphs = cairo_glyph_allocate (num_chars);
2119
0
  if (unlikely (*glyphs == NULL)) {
2120
0
      status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2121
0
      goto DONE;
2122
0
  }
2123
0
    }
2124
0
    *num_glyphs = num_chars;
2125
2126
0
    if (clusters) {
2127
0
  if (*num_clusters < num_chars) {
2128
0
      *clusters = cairo_text_cluster_allocate (num_chars);
2129
0
      if (unlikely (*clusters == NULL)) {
2130
0
    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2131
0
    goto DONE;
2132
0
      }
2133
0
  }
2134
0
  *num_clusters = num_chars;
2135
0
    }
2136
2137
0
    if (num_chars > CACHING_THRESHOLD)
2138
0
  status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font,
2139
0
                     x, y,
2140
0
                     utf8,
2141
0
                     *glyphs,
2142
0
                     clusters,
2143
0
                     num_chars);
2144
0
    else
2145
0
  status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font,
2146
0
                   x, y,
2147
0
                   utf8,
2148
0
                   *glyphs,
2149
0
                   clusters,
2150
0
                   num_chars);
2151
2152
0
 DONE: /* error that should be logged on scaled_font happened */
2153
0
    _cairo_scaled_font_thaw_cache (scaled_font);
2154
2155
0
    if (unlikely (status)) {
2156
0
  *num_glyphs = 0;
2157
0
  if (*glyphs != orig_glyphs) {
2158
0
      cairo_glyph_free (*glyphs);
2159
0
      *glyphs = orig_glyphs;
2160
0
  }
2161
2162
0
  if (clusters) {
2163
0
      *num_clusters = 0;
2164
0
      if (*clusters != orig_clusters) {
2165
0
    cairo_text_cluster_free (*clusters);
2166
0
    *clusters = orig_clusters;
2167
0
      }
2168
0
  }
2169
0
    }
2170
2171
0
    return _cairo_scaled_font_set_error (scaled_font, status);
2172
2173
0
 BAIL: /* error with input arguments */
2174
2175
0
    if (num_glyphs)
2176
0
  *num_glyphs = 0;
2177
2178
0
    if (num_clusters)
2179
0
  *num_clusters = 0;
2180
2181
0
    return status;
2182
0
}
2183
2184
static inline cairo_bool_t
2185
_range_contains_glyph (const cairo_box_t *extents,
2186
           cairo_fixed_t left,
2187
           cairo_fixed_t top,
2188
           cairo_fixed_t right,
2189
           cairo_fixed_t bottom)
2190
132k
{
2191
132k
    if (left == right || top == bottom)
2192
56.8k
  return FALSE;
2193
2194
75.1k
    return right > extents->p1.x &&
2195
45.0k
     left < extents->p2.x &&
2196
31.1k
     bottom > extents->p1.y &&
2197
28.5k
     top < extents->p2.y;
2198
132k
}
2199
2200
static cairo_status_t
2201
_cairo_scaled_font_single_glyph_device_extents (cairo_scaled_font_t  *scaled_font,
2202
            const cairo_glyph_t  *glyph,
2203
            cairo_rectangle_int_t   *extents)
2204
384k
{
2205
384k
    cairo_scaled_glyph_t *scaled_glyph;
2206
384k
    cairo_status_t status;
2207
2208
384k
    _cairo_scaled_font_freeze_cache (scaled_font);
2209
384k
    status = _cairo_scaled_glyph_lookup (scaled_font,
2210
384k
           glyph->index,
2211
384k
           CAIRO_SCALED_GLYPH_INFO_METRICS,
2212
384k
           NULL, /* foreground color */
2213
384k
           &scaled_glyph);
2214
384k
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
2215
384k
  cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON;
2216
384k
  cairo_box_t box;
2217
384k
  cairo_fixed_t v;
2218
2219
384k
  if (round_xy)
2220
58.6k
      v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
2221
325k
  else
2222
325k
      v = _cairo_fixed_from_double (glyph->x);
2223
384k
  box.p1.x = v + scaled_glyph->bbox.p1.x;
2224
384k
  box.p2.x = v + scaled_glyph->bbox.p2.x;
2225
2226
384k
  if (round_xy)
2227
58.6k
      v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
2228
325k
  else
2229
325k
      v = _cairo_fixed_from_double (glyph->y);
2230
384k
  box.p1.y = v + scaled_glyph->bbox.p1.y;
2231
384k
  box.p2.y = v + scaled_glyph->bbox.p2.y;
2232
2233
384k
  _cairo_box_round_to_rectangle (&box, extents);
2234
384k
    }
2235
384k
    _cairo_scaled_font_thaw_cache (scaled_font);
2236
384k
    return status;
2237
384k
}
2238
2239
/*
2240
 * Compute a device-space bounding box for the glyphs.
2241
 */
2242
cairo_status_t
2243
_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t   *scaled_font,
2244
           const cairo_glyph_t   *glyphs,
2245
           int                      num_glyphs,
2246
           cairo_rectangle_int_t   *extents,
2247
           cairo_bool_t *overlap_out)
2248
429k
{
2249
429k
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
2250
429k
    cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }};
2251
429k
    cairo_scaled_glyph_t *glyph_cache[64];
2252
429k
    cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
2253
429k
    cairo_round_glyph_positions_t round_glyph_positions = _cairo_font_options_get_round_glyph_positions (&scaled_font->options);
2254
429k
    int i;
2255
2256
429k
    if (unlikely (scaled_font->status))
2257
0
  return scaled_font->status;
2258
2259
429k
    if (num_glyphs == 1) {
2260
384k
  if (overlap_out)
2261
384k
      *overlap_out = FALSE;
2262
384k
  return _cairo_scaled_font_single_glyph_device_extents (scaled_font,
2263
384k
                     glyphs,
2264
384k
                     extents);
2265
384k
    }
2266
2267
45.2k
    _cairo_scaled_font_freeze_cache (scaled_font);
2268
2269
45.2k
    memset (glyph_cache, 0, sizeof (glyph_cache));
2270
2271
3.35M
    for (i = 0; i < num_glyphs; i++) {
2272
3.30M
  cairo_scaled_glyph_t  *scaled_glyph;
2273
3.30M
  cairo_fixed_t x, y, x1, y1, x2, y2;
2274
3.30M
  int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
2275
2276
3.30M
  scaled_glyph = glyph_cache[cache_index];
2277
3.30M
  if (scaled_glyph == NULL ||
2278
3.09M
      _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
2279
490k
  {
2280
490k
      status = _cairo_scaled_glyph_lookup (scaled_font,
2281
490k
             glyphs[i].index,
2282
490k
             CAIRO_SCALED_GLYPH_INFO_METRICS,
2283
490k
             NULL, /* foreground color */
2284
490k
             &scaled_glyph);
2285
490k
      if (unlikely (status))
2286
0
    break;
2287
2288
490k
      glyph_cache[cache_index] = scaled_glyph;
2289
490k
  }
2290
2291
3.30M
  if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
2292
147k
      x = _cairo_fixed_from_int (_cairo_lround (glyphs[i].x));
2293
3.15M
  else
2294
3.15M
      x = _cairo_fixed_from_double (glyphs[i].x);
2295
3.30M
  x1 = x + scaled_glyph->bbox.p1.x;
2296
3.30M
  x2 = x + scaled_glyph->bbox.p2.x;
2297
2298
3.30M
  if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
2299
147k
      y = _cairo_fixed_from_int (_cairo_lround (glyphs[i].y));
2300
3.15M
  else
2301
3.15M
      y = _cairo_fixed_from_double (glyphs[i].y);
2302
3.30M
  y1 = y + scaled_glyph->bbox.p1.y;
2303
3.30M
  y2 = y + scaled_glyph->bbox.p2.y;
2304
2305
3.30M
  if (overlap == FALSE)
2306
132k
      overlap = _range_contains_glyph (&box, x1, y1, x2, y2);
2307
2308
3.30M
  if (x1 < box.p1.x) box.p1.x = x1;
2309
3.30M
  if (x2 > box.p2.x) box.p2.x = x2;
2310
3.30M
  if (y1 < box.p1.y) box.p1.y = y1;
2311
3.30M
  if (y2 > box.p2.y) box.p2.y = y2;
2312
3.30M
    }
2313
2314
45.2k
    _cairo_scaled_font_thaw_cache (scaled_font);
2315
45.2k
    if (unlikely (status))
2316
0
  return _cairo_scaled_font_set_error (scaled_font, status);
2317
2318
45.2k
    if (box.p1.x < box.p2.x) {
2319
43.5k
  _cairo_box_round_to_rectangle (&box, extents);
2320
43.5k
    } else {
2321
1.71k
  extents->x = extents->y = 0;
2322
1.71k
  extents->width = extents->height = 0;
2323
1.71k
    }
2324
2325
45.2k
    if (overlap_out != NULL)
2326
45.2k
  *overlap_out = overlap;
2327
2328
45.2k
    return CAIRO_STATUS_SUCCESS;
2329
45.2k
}
2330
2331
cairo_bool_t
2332
_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t  *scaled_font,
2333
                const cairo_glyph_t  *glyphs,
2334
                int                      num_glyphs,
2335
                cairo_rectangle_int_t   *extents)
2336
0
{
2337
0
    double x0, x1, y0, y1, pad;
2338
0
    int i;
2339
2340
    /* If any of the factors are suspect (i.e. the font is broken), bail */
2341
0
    if (scaled_font->fs_extents.max_x_advance == 0 ||
2342
0
  scaled_font->fs_extents.height == 0 ||
2343
0
  scaled_font->max_scale == 0)
2344
0
    {
2345
0
  return FALSE;
2346
0
    }
2347
2348
0
    assert (num_glyphs);
2349
2350
0
    x0 = x1 = glyphs[0].x;
2351
0
    y0 = y1 = glyphs[0].y;
2352
0
    for (i = 1; i < num_glyphs; i++) {
2353
0
  double g;
2354
2355
0
  g = glyphs[i].x;
2356
0
  if (g < x0) x0 = g;
2357
0
  if (g > x1) x1 = g;
2358
2359
0
  g = glyphs[i].y;
2360
0
  if (g < y0) y0 = g;
2361
0
  if (g > y1) y1 = g;
2362
0
    }
2363
2364
0
    pad = MAX(scaled_font->fs_extents.max_x_advance,
2365
0
        scaled_font->fs_extents.height);
2366
0
    pad *= scaled_font->max_scale;
2367
2368
0
    extents->x = floor (x0 - pad);
2369
0
    extents->width = ceil (x1 + pad) - extents->x;
2370
0
    extents->y = floor (y0 - pad);
2371
0
    extents->height = ceil (y1 + pad) - extents->y;
2372
0
    return TRUE;
2373
0
}
2374
2375
/* Add a single-device-unit rectangle to a path. */
2376
static cairo_status_t
2377
_add_unit_rectangle_to_path (cairo_path_fixed_t *path,
2378
           cairo_fixed_t x,
2379
           cairo_fixed_t y)
2380
0
{
2381
0
    cairo_status_t status;
2382
2383
0
    status = _cairo_path_fixed_move_to (path, x, y);
2384
0
    if (unlikely (status))
2385
0
  return status;
2386
2387
0
    status = _cairo_path_fixed_rel_line_to (path,
2388
0
              _cairo_fixed_from_int (1),
2389
0
              _cairo_fixed_from_int (0));
2390
0
    if (unlikely (status))
2391
0
  return status;
2392
2393
0
    status = _cairo_path_fixed_rel_line_to (path,
2394
0
              _cairo_fixed_from_int (0),
2395
0
              _cairo_fixed_from_int (1));
2396
0
    if (unlikely (status))
2397
0
  return status;
2398
2399
0
    status = _cairo_path_fixed_rel_line_to (path,
2400
0
              _cairo_fixed_from_int (-1),
2401
0
              _cairo_fixed_from_int (0));
2402
0
    if (unlikely (status))
2403
0
  return status;
2404
2405
0
    return _cairo_path_fixed_close_path (path);
2406
0
}
2407
2408
/**
2409
 * _trace_mask_to_path:
2410
 * @bitmap: An alpha mask (either %CAIRO_FORMAT_A1 or %CAIRO_FORMAT_A8)
2411
 * @path: An initialized path to hold the result
2412
 *
2413
 * Given a mask surface, (an alpha image), fill out the provided path
2414
 * so that when filled it would result in something that approximates
2415
 * the mask.
2416
 *
2417
 * Note: The current tracing code here is extremely primitive. It
2418
 * operates only on an A1 surface, (converting an A8 surface to A1 if
2419
 * necessary), and performs the tracing by drawing a little square
2420
 * around each pixel that is on in the mask. We do not pretend that
2421
 * this is a high-quality result. But we are leaving it up to someone
2422
 * who cares enough about getting a better result to implement
2423
 * something more sophisticated.
2424
 **/
2425
static cairo_status_t
2426
_trace_mask_to_path (cairo_image_surface_t *mask,
2427
         cairo_path_fixed_t *path,
2428
         double tx, double ty)
2429
0
{
2430
0
    const uint8_t *row;
2431
0
    int rows, cols, bytes_per_row;
2432
0
    int x, y, bit;
2433
0
    double xoff, yoff;
2434
0
    cairo_fixed_t x0, y0;
2435
0
    cairo_fixed_t px, py;
2436
0
    cairo_status_t status;
2437
2438
0
    mask = _cairo_image_surface_coerce_to_format (mask, CAIRO_FORMAT_A1);
2439
0
    status = mask->base.status;
2440
0
    if (unlikely (status))
2441
0
  return status;
2442
2443
0
    cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
2444
0
    x0 = _cairo_fixed_from_double (tx - xoff);
2445
0
    y0 = _cairo_fixed_from_double (ty - yoff);
2446
2447
0
    bytes_per_row = (mask->width + 7) / 8;
2448
0
    row = mask->data;
2449
0
    for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) {
2450
0
  const uint8_t *byte_ptr = row;
2451
0
  x = 0;
2452
0
  py = _cairo_fixed_from_int (y);
2453
0
  for (cols = bytes_per_row; cols--; ) {
2454
0
      uint8_t byte = *byte_ptr++;
2455
0
      if (byte == 0) {
2456
0
    x += 8;
2457
0
    continue;
2458
0
      }
2459
2460
0
      byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
2461
0
      for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) {
2462
0
    if (byte & bit) {
2463
0
        px = _cairo_fixed_from_int (x);
2464
0
        status = _add_unit_rectangle_to_path (path,
2465
0
                px + x0,
2466
0
                py + y0);
2467
0
        if (unlikely (status))
2468
0
      goto BAIL;
2469
0
    }
2470
0
      }
2471
0
  }
2472
0
    }
2473
2474
0
BAIL:
2475
0
    cairo_surface_destroy (&mask->base);
2476
2477
0
    return status;
2478
0
}
2479
2480
cairo_status_t
2481
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
2482
             const cairo_glyph_t *glyphs,
2483
             int        num_glyphs,
2484
             cairo_path_fixed_t  *path)
2485
0
{
2486
0
    cairo_int_status_t status;
2487
0
    int i;
2488
2489
0
    status = scaled_font->status;
2490
0
    if (unlikely (status))
2491
0
  return status;
2492
2493
0
    _cairo_scaled_font_freeze_cache (scaled_font);
2494
0
    for (i = 0; i < num_glyphs; i++) {
2495
0
  cairo_scaled_glyph_t *scaled_glyph;
2496
2497
0
  status = _cairo_scaled_glyph_lookup (scaled_font,
2498
0
               glyphs[i].index,
2499
0
               CAIRO_SCALED_GLYPH_INFO_PATH,
2500
0
               NULL, /* foreground color */
2501
0
               &scaled_glyph);
2502
0
  if (status == CAIRO_INT_STATUS_SUCCESS) {
2503
0
      status = _cairo_path_fixed_append (path,
2504
0
                 scaled_glyph->path,
2505
0
                 _cairo_fixed_from_double (glyphs[i].x),
2506
0
                 _cairo_fixed_from_double (glyphs[i].y));
2507
2508
0
  } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2509
      /* If the font is incapable of providing a path, then we'll
2510
       * have to trace our own from a surface.
2511
       */
2512
0
      status = _cairo_scaled_glyph_lookup (scaled_font,
2513
0
             glyphs[i].index,
2514
0
             CAIRO_SCALED_GLYPH_INFO_SURFACE,
2515
0
             NULL, /* foreground color */
2516
0
             &scaled_glyph);
2517
0
      if (unlikely (status))
2518
0
    goto BAIL;
2519
2520
0
      status = _trace_mask_to_path (scaled_glyph->surface, path,
2521
0
            glyphs[i].x, glyphs[i].y);
2522
0
  }
2523
2524
0
  if (unlikely (status))
2525
0
      goto BAIL;
2526
0
    }
2527
0
  BAIL:
2528
0
    _cairo_scaled_font_thaw_cache (scaled_font);
2529
2530
0
    return _cairo_scaled_font_set_error (scaled_font, status);
2531
0
}
2532
2533
/**
2534
 * _cairo_scaled_glyph_set_metrics:
2535
 * @scaled_glyph: a #cairo_scaled_glyph_t
2536
 * @scaled_font: a #cairo_scaled_font_t
2537
 * @fs_metrics: a #cairo_text_extents_t in font space
2538
 *
2539
 * _cairo_scaled_glyph_set_metrics() stores user space metrics
2540
 * for the specified glyph given font space metrics. It is
2541
 * called by the font backend when initializing a glyph with
2542
 * %CAIRO_SCALED_GLYPH_INFO_METRICS.
2543
 **/
2544
void
2545
_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
2546
         cairo_scaled_font_t *scaled_font,
2547
         cairo_text_extents_t *fs_metrics)
2548
60.6k
{
2549
60.6k
    cairo_bool_t first = TRUE;
2550
60.6k
    double hm, wm;
2551
60.6k
    double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0;
2552
60.6k
    double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
2553
60.6k
    double device_x_advance, device_y_advance;
2554
2555
60.6k
    scaled_glyph->fs_metrics = *fs_metrics;
2556
2557
181k
    for (hm = 0.0; hm <= 1.0; hm += 1.0)
2558
363k
  for (wm = 0.0; wm <= 1.0; wm += 1.0) {
2559
242k
      double x, y;
2560
2561
      /* Transform this corner to user space */
2562
242k
      x = fs_metrics->x_bearing + fs_metrics->width * wm;
2563
242k
      y = fs_metrics->y_bearing + fs_metrics->height * hm;
2564
242k
      cairo_matrix_transform_point (&scaled_font->font_matrix,
2565
242k
            &x, &y);
2566
242k
      if (first) {
2567
60.6k
    min_user_x = max_user_x = x;
2568
60.6k
    min_user_y = max_user_y = y;
2569
181k
      } else {
2570
181k
    if (x < min_user_x) min_user_x = x;
2571
181k
    if (x > max_user_x) max_user_x = x;
2572
181k
    if (y < min_user_y) min_user_y = y;
2573
181k
    if (y > max_user_y) max_user_y = y;
2574
181k
      }
2575
2576
      /* Transform this corner to device space from glyph origin */
2577
242k
      x = fs_metrics->x_bearing + fs_metrics->width * wm;
2578
242k
      y = fs_metrics->y_bearing + fs_metrics->height * hm;
2579
242k
      cairo_matrix_transform_distance (&scaled_font->scale,
2580
242k
               &x, &y);
2581
2582
242k
      if (first) {
2583
60.6k
    min_device_x = max_device_x = x;
2584
60.6k
    min_device_y = max_device_y = y;
2585
181k
      } else {
2586
181k
    if (x < min_device_x) min_device_x = x;
2587
181k
    if (x > max_device_x) max_device_x = x;
2588
181k
    if (y < min_device_y) min_device_y = y;
2589
181k
    if (y > max_device_y) max_device_y = y;
2590
181k
      }
2591
242k
      first = FALSE;
2592
242k
  }
2593
60.6k
    scaled_glyph->metrics.x_bearing = min_user_x;
2594
60.6k
    scaled_glyph->metrics.y_bearing = min_user_y;
2595
60.6k
    scaled_glyph->metrics.width = max_user_x - min_user_x;
2596
60.6k
    scaled_glyph->metrics.height = max_user_y - min_user_y;
2597
2598
60.6k
    scaled_glyph->metrics.x_advance = fs_metrics->x_advance;
2599
60.6k
    scaled_glyph->metrics.y_advance = fs_metrics->y_advance;
2600
60.6k
    cairo_matrix_transform_distance (&scaled_font->font_matrix,
2601
60.6k
             &scaled_glyph->metrics.x_advance,
2602
60.6k
             &scaled_glyph->metrics.y_advance);
2603
2604
60.6k
    device_x_advance = fs_metrics->x_advance;
2605
60.6k
    device_y_advance = fs_metrics->y_advance;
2606
60.6k
    cairo_matrix_transform_distance (&scaled_font->scale,
2607
60.6k
             &device_x_advance,
2608
60.6k
             &device_y_advance);
2609
2610
60.6k
    scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x);
2611
60.6k
    scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y);
2612
60.6k
    scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x);
2613
60.6k
    scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y);
2614
2615
60.6k
    scaled_glyph->x_advance = _cairo_lround (device_x_advance);
2616
60.6k
    scaled_glyph->y_advance = _cairo_lround (device_y_advance);
2617
2618
60.6k
    scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
2619
60.6k
}
2620
2621
void
2622
_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
2623
         cairo_scaled_font_t *scaled_font,
2624
         cairo_image_surface_t *surface)
2625
44.5k
{
2626
44.5k
    if (scaled_glyph->surface != NULL)
2627
0
  cairo_surface_destroy (&scaled_glyph->surface->base);
2628
2629
    /* sanity check the backend glyph contents */
2630
44.5k
    _cairo_debug_check_image_surface_is_defined (&surface->base);
2631
44.5k
    scaled_glyph->surface = surface;
2632
2633
44.5k
    if (surface != NULL)
2634
44.5k
  scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE;
2635
0
    else
2636
0
  scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_SURFACE;
2637
44.5k
}
2638
2639
void
2640
_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
2641
            cairo_scaled_font_t *scaled_font,
2642
            cairo_path_fixed_t *path)
2643
0
{
2644
0
    if (scaled_glyph->path != NULL)
2645
0
  _cairo_path_fixed_destroy (scaled_glyph->path);
2646
2647
0
    scaled_glyph->path = path;
2648
2649
0
    if (path != NULL)
2650
0
  scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
2651
0
    else
2652
0
  scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH;
2653
0
}
2654
2655
/**
2656
 * _cairo_scaled_glyph_set_recording_surface:
2657
 * @scaled_glyph: a #cairo_scaled_glyph_t
2658
 * @scaled_font: a #cairo_scaled_font_t
2659
 * @recording_surface: The recording surface
2660
 * @foreground_color: The foreground color that was used to record the
2661
 * glyph, or NULL if foreground color not required.
2662
 *
2663
 * Sets the surface that was used to record the glyph.
2664
 **/
2665
void
2666
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
2667
             cairo_scaled_font_t  *scaled_font,
2668
             cairo_surface_t      *recording_surface,
2669
             const cairo_color_t * foreground_color)
2670
0
{
2671
0
    if (scaled_glyph->recording_surface != NULL) {
2672
0
  cairo_surface_finish (scaled_glyph->recording_surface);
2673
0
  cairo_surface_destroy (scaled_glyph->recording_surface);
2674
0
    }
2675
2676
0
    scaled_glyph->recording_surface = recording_surface;
2677
0
    scaled_glyph->recording_uses_foreground_color = foreground_color != NULL;
2678
0
    if (foreground_color)
2679
0
  scaled_glyph->foreground_color = *foreground_color;
2680
2681
0
    if (recording_surface != NULL)
2682
0
  scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
2683
0
    else
2684
0
  scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
2685
0
}
2686
2687
/**
2688
 * _cairo_scaled_glyph_set_color_surface:
2689
 * @scaled_glyph: a #cairo_scaled_glyph_t
2690
 * @scaled_font: a #cairo_scaled_font_t
2691
 * @surface: The image surface
2692
 * @foreground_marker_color: The foreground color that was used to
2693
 * substitute the foreground_marker, or NULL if foreground_marker not
2694
 * used when rendering the surface color.
2695
 *
2696
 * Sets the color surface of the glyph.
2697
 **/
2698
void
2699
_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t  *scaled_glyph,
2700
                                 cairo_scaled_font_t   *scaled_font,
2701
                                 cairo_image_surface_t *surface,
2702
               const cairo_color_t   *foreground_marker_color)
2703
0
{
2704
0
    if (scaled_glyph->color_surface != NULL)
2705
0
  cairo_surface_destroy (&scaled_glyph->color_surface->base);
2706
2707
    /* sanity check the backend glyph contents */
2708
0
    _cairo_debug_check_image_surface_is_defined (&surface->base);
2709
0
    scaled_glyph->color_surface = surface;
2710
0
    scaled_glyph->recording_uses_foreground_marker = foreground_marker_color != NULL;
2711
0
    if (foreground_marker_color)
2712
0
  scaled_glyph->foreground_color = *foreground_marker_color;
2713
2714
0
    if (surface != NULL)
2715
0
  scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
2716
0
    else
2717
0
  scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
2718
0
}
2719
2720
/* _cairo_hash_table_random_entry () predicate. To avoid race conditions,
2721
 * the font is locked when tested. The font is unlocked in
2722
 * _cairo_scaled_glyph_page_pluck. */
2723
static cairo_bool_t
2724
_cairo_scaled_glyph_page_can_remove (const void *closure)
2725
1.58k
{
2726
1.58k
    const cairo_scaled_glyph_page_t *page = closure;
2727
1.58k
    cairo_scaled_font_t *scaled_font;
2728
2729
1.58k
    scaled_font = page->scaled_font;
2730
2731
1.58k
    if (!CAIRO_MUTEX_TRY_LOCK (scaled_font->mutex))
2732
0
       return FALSE;
2733
2734
1.58k
    if (scaled_font->cache_frozen != 0) {
2735
74
       CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
2736
74
       return FALSE;
2737
74
    }
2738
2739
1.51k
    return TRUE;
2740
1.58k
}
2741
2742
static cairo_status_t
2743
_cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
2744
           cairo_scaled_glyph_t **scaled_glyph)
2745
60.6k
{
2746
60.6k
    cairo_scaled_glyph_page_t *page;
2747
60.6k
    cairo_status_t status;
2748
2749
60.6k
    assert (scaled_font->cache_frozen);
2750
2751
    /* only the first page in the list may contain available slots */
2752
60.6k
    if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
2753
60.2k
        page = cairo_list_last_entry (&scaled_font->glyph_pages,
2754
60.2k
                                      cairo_scaled_glyph_page_t,
2755
60.2k
                                      link);
2756
60.2k
        if (page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) {
2757
58.4k
            *scaled_glyph = &page->glyphs[page->num_glyphs++];
2758
58.4k
            return CAIRO_STATUS_SUCCESS;
2759
58.4k
        }
2760
60.2k
    }
2761
2762
2.18k
    page = _cairo_calloc (sizeof (cairo_scaled_glyph_page_t));
2763
2.18k
    if (unlikely (page == NULL))
2764
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2765
2766
2.18k
    page->cache_entry.hash = (uintptr_t) scaled_font;
2767
2.18k
    page->scaled_font = scaled_font;
2768
2.18k
    page->cache_entry.size = 1; /* XXX occupancy weighting? */
2769
2.18k
    page->num_glyphs = 0;
2770
2771
2.18k
    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
2772
2.18k
    if (scaled_font->global_cache_frozen == FALSE) {
2773
1.23k
  if (unlikely (cairo_scaled_glyph_page_cache.hash_table == NULL)) {
2774
2
      status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
2775
2
          NULL,
2776
2
          _cairo_scaled_glyph_page_can_remove,
2777
2
          _cairo_scaled_glyph_page_pluck,
2778
2
          MAX_GLYPH_PAGES_CACHED);
2779
2
      if (unlikely (status)) {
2780
0
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2781
0
    free (page);
2782
0
    return status;
2783
0
      }
2784
2
  }
2785
2786
1.23k
  _cairo_cache_freeze (&cairo_scaled_glyph_page_cache);
2787
1.23k
  scaled_font->global_cache_frozen = TRUE;
2788
1.23k
    }
2789
2790
2.18k
    status = _cairo_cache_insert (&cairo_scaled_glyph_page_cache,
2791
2.18k
          &page->cache_entry);
2792
2.18k
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2793
2.18k
    if (unlikely (status)) {
2794
0
  free (page);
2795
0
  return status;
2796
0
    }
2797
2798
2.18k
    cairo_list_add_tail (&page->link, &scaled_font->glyph_pages);
2799
2800
2.18k
    *scaled_glyph = &page->glyphs[page->num_glyphs++];
2801
2.18k
    return CAIRO_STATUS_SUCCESS;
2802
2.18k
}
2803
2804
static void
2805
_cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
2806
                 cairo_scaled_glyph_t *scaled_glyph)
2807
0
{
2808
0
    cairo_scaled_glyph_page_t *page;
2809
2810
0
    assert (scaled_font->cache_frozen);
2811
0
    assert (! cairo_list_is_empty (&scaled_font->glyph_pages));
2812
0
    page = cairo_list_last_entry (&scaled_font->glyph_pages,
2813
0
                                  cairo_scaled_glyph_page_t,
2814
0
                                  link);
2815
0
    assert (scaled_glyph == &page->glyphs[page->num_glyphs-1]);
2816
2817
0
    _cairo_scaled_glyph_fini (scaled_font, scaled_glyph);
2818
2819
0
    if (--page->num_glyphs == 0) {
2820
0
  _cairo_scaled_font_thaw_cache (scaled_font);
2821
0
  CAIRO_MUTEX_LOCK (scaled_font->mutex);
2822
2823
0
  CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
2824
  /* Temporarily disconnect callback to avoid recursive locking */
2825
0
  cairo_scaled_glyph_page_cache.entry_destroy = NULL;
2826
0
  _cairo_cache_remove (&cairo_scaled_glyph_page_cache,
2827
0
                 &page->cache_entry);
2828
0
  _cairo_scaled_glyph_page_destroy (scaled_font, page);
2829
0
  cairo_scaled_glyph_page_cache.entry_destroy = _cairo_scaled_glyph_page_pluck;
2830
0
  CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2831
2832
0
  CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
2833
0
  _cairo_scaled_font_freeze_cache (scaled_font);
2834
0
    }
2835
0
}
2836
2837
/**
2838
 * _cairo_scaled_glyph_lookup:
2839
 * @scaled_font: a #cairo_scaled_font_t
2840
 * @index: the glyph to create
2841
 * @info: a #cairo_scaled_glyph_info_t marking which portions of
2842
 * the glyph should be filled in.
2843
 * @foreground_color - foreground color to use when rendering color
2844
 * fonts. Use NULL if not requesting
2845
 * CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE or
2846
 * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, or foreground color is
2847
 * unknown.
2848
 * @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph
2849
 * is returned.
2850
 *
2851
 * If the desired info is not available, (for example, when trying to
2852
 * get INFO_PATH with a bitmapped font), this function will return
2853
 * %CAIRO_INT_STATUS_UNSUPPORTED.
2854
 *
2855
 * Note: This function must be called with the scaled font frozen, and it must
2856
 * remain frozen for as long as the @scaled_glyph_ret is alive. (If the scaled
2857
 * font was not frozen, then there is no guarantee that the glyph would not be
2858
 * evicted before you tried to access it.) See
2859
 * _cairo_scaled_font_freeze_cache() and _cairo_scaled_font_thaw_cache().
2860
 *
2861
 * Returns: a glyph with the requested portions filled in. Glyph
2862
 * lookup is cached and glyph will be automatically freed along
2863
 * with the scaled_font so no explicit free is required.
2864
 * @info can be one or more of:
2865
 *  %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box
2866
 *  %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image
2867
 *  %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space
2868
 *  %CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE - surface holding recording of glyph
2869
 *  %CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE - surface holding color glyph image
2870
 **/
2871
cairo_int_status_t
2872
_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
2873
          unsigned long index,
2874
          cairo_scaled_glyph_info_t info,
2875
          const cairo_color_t   *foreground_color,
2876
          cairo_scaled_glyph_t **scaled_glyph_ret)
2877
1.00M
{
2878
1.00M
    cairo_int_status_t     status = CAIRO_INT_STATUS_SUCCESS;
2879
1.00M
    cairo_scaled_glyph_t  *scaled_glyph;
2880
1.00M
    cairo_scaled_glyph_info_t  need_info;
2881
1.00M
    cairo_hash_entry_t           key;
2882
2883
1.00M
    *scaled_glyph_ret = NULL;
2884
2885
1.00M
    if (unlikely (scaled_font->status))
2886
0
  return scaled_font->status;
2887
2888
1.00M
    assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex));
2889
1.00M
    assert (scaled_font->cache_frozen);
2890
2891
1.00M
    if (CAIRO_INJECT_FAULT ())
2892
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2893
2894
1.00M
    if (foreground_color == NULL)
2895
1.00M
  foreground_color = CAIRO_COLOR_BLACK;
2896
2897
    /*
2898
     * Check cache for glyph
2899
     */
2900
1.00M
    key.hash = index;
2901
1.00M
    scaled_glyph = _cairo_hash_table_lookup (scaled_font->glyphs, &key);
2902
1.00M
    if (scaled_glyph == NULL) {
2903
60.6k
  status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph);
2904
60.6k
  if (unlikely (status))
2905
0
      goto err;
2906
2907
60.6k
  memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
2908
60.6k
  _cairo_scaled_glyph_set_index (scaled_glyph, index);
2909
60.6k
  cairo_list_init (&scaled_glyph->dev_privates);
2910
2911
  /* ask backend to initialize metrics and shape fields */
2912
60.6k
  status =
2913
60.6k
      scaled_font->backend->scaled_glyph_init (scaled_font,
2914
60.6k
                 scaled_glyph,
2915
60.6k
                 info | CAIRO_SCALED_GLYPH_INFO_METRICS,
2916
60.6k
                 foreground_color);
2917
60.6k
  if (unlikely (status)) {
2918
0
      _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
2919
0
      goto err;
2920
0
  }
2921
2922
60.6k
  status = _cairo_hash_table_insert (scaled_font->glyphs,
2923
60.6k
             &scaled_glyph->hash_entry);
2924
60.6k
  if (unlikely (status)) {
2925
0
      _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
2926
0
      goto err;
2927
0
  }
2928
60.6k
    }
2929
2930
    /*
2931
     * Check and see if the glyph, as provided,
2932
     * already has the requested data and amend it if not
2933
     */
2934
1.00M
    need_info = info & ~scaled_glyph->has_info;
2935
2936
    /* If this is not a color glyph, don't try loading the color surface again. */
2937
1.00M
    if ((need_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) &&
2938
0
  scaled_glyph->color_glyph_set && !scaled_glyph->color_glyph)
2939
0
  return CAIRO_INT_STATUS_UNSUPPORTED;
2940
2941
    /* If requesting a color surface or recording for a glyph that has
2942
     * used the foreground color to render the recording, and the
2943
     * foreground color has changed, request a new  recording. */
2944
1.00M
    if ((info & (CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) &&
2945
0
  scaled_glyph->recording_uses_foreground_color &&
2946
0
  !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
2947
0
    {
2948
0
  need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
2949
0
    }
2950
2951
    /* If requesting a color surface for a glyph that has
2952
     * used the foreground color to render the color_surface, and the
2953
     * foreground color has changed, request a new image. */
2954
1.00M
    if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE &&
2955
0
  (scaled_glyph->recording_uses_foreground_marker || scaled_glyph->recording_uses_foreground_color) &&
2956
0
  !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
2957
0
    {
2958
0
      need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
2959
0
    }
2960
2961
1.00M
    if (need_info) {
2962
12.4k
  status = scaled_font->backend->scaled_glyph_init (scaled_font,
2963
12.4k
                scaled_glyph,
2964
12.4k
                need_info,
2965
12.4k
                foreground_color);
2966
12.4k
  if (unlikely (status))
2967
0
      goto err;
2968
2969
  /* Don't trust the scaled_glyph_init() return value, the font
2970
   * backend may not even know about some of the info.  For example,
2971
   * no backend other than the user-fonts knows about recording-surface
2972
   * glyph info. */
2973
12.4k
  if (info & ~scaled_glyph->has_info)
2974
0
      return CAIRO_INT_STATUS_UNSUPPORTED;
2975
12.4k
    }
2976
2977
1.00M
    *scaled_glyph_ret = scaled_glyph;
2978
1.00M
    return CAIRO_STATUS_SUCCESS;
2979
2980
0
err:
2981
    /* It's not an error for the backend to not support the info we want. */
2982
0
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2983
0
  status = _cairo_scaled_font_set_error (scaled_font, status);
2984
0
    return status;
2985
1.00M
}
2986
2987
double
2988
_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
2989
2.65M
{
2990
2.65M
    return scaled_font->max_scale;
2991
2.65M
}
2992
2993
/**
2994
 * cairo_scaled_font_get_font_face:
2995
 * @scaled_font: a #cairo_scaled_font_t
2996
 *
2997
 * Gets the font face that this scaled font uses.  This might be the
2998
 * font face passed to cairo_scaled_font_create(), but this does not
2999
 * hold true for all possible cases.
3000
 *
3001
 * Return value: The #cairo_font_face_t with which @scaled_font was
3002
 * created.  This object is owned by cairo. To keep a reference to it,
3003
 * you must call cairo_scaled_font_reference().
3004
 *
3005
 * Since: 1.2
3006
 **/
3007
cairo_font_face_t *
3008
cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font)
3009
0
{
3010
0
    if (scaled_font->status)
3011
0
  return (cairo_font_face_t*) &_cairo_font_face_nil;
3012
3013
0
    if (scaled_font->original_font_face != NULL)
3014
0
  return scaled_font->original_font_face;
3015
3016
0
    return scaled_font->font_face;
3017
0
}
3018
3019
/**
3020
 * cairo_scaled_font_get_font_matrix:
3021
 * @scaled_font: a #cairo_scaled_font_t
3022
 * @font_matrix: return value for the matrix
3023
 *
3024
 * Stores the font matrix with which @scaled_font was created into
3025
 * @matrix.
3026
 *
3027
 * Since: 1.2
3028
 **/
3029
void
3030
cairo_scaled_font_get_font_matrix (cairo_scaled_font_t  *scaled_font,
3031
           cairo_matrix_t *font_matrix)
3032
0
{
3033
0
    if (scaled_font->status) {
3034
0
  cairo_matrix_init_identity (font_matrix);
3035
0
  return;
3036
0
    }
3037
3038
0
    *font_matrix = scaled_font->font_matrix;
3039
0
}
3040
3041
/**
3042
 * cairo_scaled_font_get_ctm:
3043
 * @scaled_font: a #cairo_scaled_font_t
3044
 * @ctm: return value for the CTM
3045
 *
3046
 * Stores the CTM with which @scaled_font was created into @ctm.
3047
 * Note that the translation offsets (x0, y0) of the CTM are ignored
3048
 * by cairo_scaled_font_create().  So, the matrix this
3049
 * function returns always has 0,0 as x0,y0.
3050
 *
3051
 * Since: 1.2
3052
 **/
3053
void
3054
cairo_scaled_font_get_ctm (cairo_scaled_font_t  *scaled_font,
3055
         cairo_matrix_t *ctm)
3056
0
{
3057
0
    if (scaled_font->status) {
3058
0
  cairo_matrix_init_identity (ctm);
3059
0
  return;
3060
0
    }
3061
3062
0
    *ctm = scaled_font->ctm;
3063
0
}
3064
3065
/**
3066
 * cairo_scaled_font_get_scale_matrix:
3067
 * @scaled_font: a #cairo_scaled_font_t
3068
 * @scale_matrix: return value for the matrix
3069
 *
3070
 * Stores the scale matrix of @scaled_font into @matrix.
3071
 * The scale matrix is product of the font matrix and the ctm
3072
 * associated with the scaled font, and hence is the matrix mapping from
3073
 * font space to device space.
3074
 *
3075
 * Since: 1.8
3076
 **/
3077
void
3078
cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font,
3079
            cairo_matrix_t  *scale_matrix)
3080
0
{
3081
0
    if (scaled_font->status) {
3082
0
  cairo_matrix_init_identity (scale_matrix);
3083
0
  return;
3084
0
    }
3085
3086
0
    *scale_matrix = scaled_font->scale;
3087
0
}
3088
3089
/**
3090
 * cairo_scaled_font_get_font_options:
3091
 * @scaled_font: a #cairo_scaled_font_t
3092
 * @options: return value for the font options
3093
 *
3094
 * Stores the font options with which @scaled_font was created into
3095
 * @options.
3096
 *
3097
 * Since: 1.2
3098
 **/
3099
void
3100
cairo_scaled_font_get_font_options (cairo_scaled_font_t   *scaled_font,
3101
            cairo_font_options_t  *options)
3102
0
{
3103
0
    if (cairo_font_options_status (options))
3104
0
  return;
3105
3106
0
    if (scaled_font->status) {
3107
0
  _cairo_font_options_init_default (options);
3108
0
  return;
3109
0
    }
3110
3111
0
    _cairo_font_options_fini (options);
3112
0
    _cairo_font_options_init_copy (options, &scaled_font->options);
3113
0
}
3114
3115
cairo_bool_t
3116
_cairo_scaled_font_has_color_glyphs (cairo_scaled_font_t *scaled_font)
3117
859k
{
3118
859k
    if (scaled_font->backend != NULL && scaled_font->backend->has_color_glyphs != NULL)
3119
859k
        return scaled_font->backend->has_color_glyphs (scaled_font);
3120
0
    else
3121
0
       return FALSE;
3122
859k
}