Subversion Repositories Kolibri OS

Rev

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