Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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