Coverage Report

Created: 2025-07-07 10:01

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