Back to index

lightning-sunbird  0.9+nobinonly
cairo-font.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2002 University of Southern California
00004  * Copyright © 2005 Red Hat Inc.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it either under the terms of the GNU Lesser General Public
00008  * License version 2.1 as published by the Free Software Foundation
00009  * (the "LGPL") or, at your option, under the terms of the Mozilla
00010  * Public License Version 1.1 (the "MPL"). If you do not alter this
00011  * notice, a recipient may use your version of this file under either
00012  * the MPL or the LGPL.
00013  *
00014  * You should have received a copy of the LGPL along with this library
00015  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00017  * You should have received a copy of the MPL along with this library
00018  * in the file COPYING-MPL-1.1
00019  *
00020  * The contents of this file are subject to the Mozilla Public License
00021  * Version 1.1 (the "License"); you may not use this file except in
00022  * compliance with the License. You may obtain a copy of the License at
00023  * http://www.mozilla.org/MPL/
00024  *
00025  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00026  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00027  * the specific language governing rights and limitations.
00028  *
00029  * The Original Code is the cairo graphics library.
00030  *
00031  * The Initial Developer of the Original Code is University of Southern
00032  * California.
00033  *
00034  * Contributor(s):
00035  *     Carl D. Worth <cworth@cworth.org>
00036  *      Graydon Hoare <graydon@redhat.com>
00037  *      Owen Taylor <otaylor@redhat.com>
00038  */
00039 
00040 #include "cairoint.h"
00041 
00042 /* Forward declare so we can use it as an arbitrary backend for
00043  * _cairo_font_face_nil.
00044  */
00045 static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
00046 
00047 /* cairo_font_face_t */
00048 
00049 const cairo_font_face_t _cairo_font_face_nil = {
00050     { 0 },                  /* hash_entry */
00051     CAIRO_STATUS_NO_MEMORY, /* status */
00052     -1,                              /* ref_count */
00053     { 0, 0, 0, NULL },             /* user_data */
00054     &_cairo_toy_font_face_backend
00055 };
00056 
00057 void
00058 _cairo_font_face_init (cairo_font_face_t               *font_face, 
00059                      const cairo_font_face_backend_t *backend)
00060 {
00061     font_face->status = CAIRO_STATUS_SUCCESS;
00062     font_face->ref_count = 1;
00063     font_face->backend = backend;
00064 
00065     _cairo_user_data_array_init (&font_face->user_data);
00066 }
00067 
00079 cairo_font_face_t *
00080 cairo_font_face_reference (cairo_font_face_t *font_face)
00081 {
00082     if (font_face == NULL)
00083        return NULL;
00084 
00085     if (font_face->ref_count == (unsigned int)-1)
00086        return font_face;
00087 
00088     /* We would normally assert (font_face->ref_count >0) here but we
00089      * can't get away with that due to the zombie case as documented
00090      * in _cairo_ft_font_face_destroy. */
00091 
00092     font_face->ref_count++;
00093 
00094     return font_face;
00095 }
00096 
00105 void
00106 cairo_font_face_destroy (cairo_font_face_t *font_face)
00107 {
00108     if (font_face == NULL)
00109        return;
00110 
00111     if (font_face->ref_count == (unsigned int)-1)
00112        return;
00113 
00114     assert (font_face->ref_count > 0);
00115 
00116     if (--(font_face->ref_count) > 0)
00117        return;
00118 
00119     font_face->backend->destroy (font_face);
00120 
00121     /* We allow resurrection to deal with some memory management for the
00122      * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
00123      * need to effectively mutually reference each other
00124      */
00125     if (font_face->ref_count > 0)
00126        return;
00127 
00128     _cairo_user_data_array_fini (&font_face->user_data);
00129 
00130     free (font_face);
00131 }
00132 
00143 cairo_status_t
00144 cairo_font_face_status (cairo_font_face_t *font_face)
00145 {
00146     return font_face->status;
00147 }
00148 
00161 void *
00162 cairo_font_face_get_user_data (cairo_font_face_t    *font_face,
00163                             const cairo_user_data_key_t *key)
00164 {
00165     return _cairo_user_data_array_get_data (&font_face->user_data,
00166                                        key);
00167 }
00168 
00185 cairo_status_t
00186 cairo_font_face_set_user_data (cairo_font_face_t    *font_face,
00187                             const cairo_user_data_key_t *key,
00188                             void                    *user_data,
00189                             cairo_destroy_func_t     destroy)
00190 {
00191     if (font_face->ref_count == -1)
00192        return CAIRO_STATUS_NO_MEMORY;
00193     
00194     return _cairo_user_data_array_set_data (&font_face->user_data,
00195                                        key, user_data, destroy);
00196 }
00197 
00198 static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
00199 
00200 static int
00201 _cairo_toy_font_face_keys_equal (void *key_a,
00202                              void *key_b);
00203 
00204 /* We maintain a hash table from family/weight/slant =>
00205  * cairo_font_face_t for cairo_toy_font_t. The primary purpose of
00206  * this mapping is to provide unique cairo_font_face_t values so that
00207  * our cache and mapping from cairo_font_face_t => cairo_scaled_font_t
00208  * works. Once the corresponding cairo_font_face_t objects fall out of
00209  * downstream caches, we don't need them in this hash table anymore.
00210  */
00211 
00212 static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL;
00213 
00214 CAIRO_MUTEX_DECLARE (cairo_toy_font_face_hash_table_mutex);
00215 
00216 static cairo_hash_table_t *
00217 _cairo_toy_font_face_hash_table_lock (void)
00218 {
00219     CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex);
00220 
00221     if (cairo_toy_font_face_hash_table == NULL)
00222     {
00223        cairo_toy_font_face_hash_table =
00224            _cairo_hash_table_create (_cairo_toy_font_face_keys_equal);
00225 
00226        if (cairo_toy_font_face_hash_table == NULL) {
00227            CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex);
00228            return NULL;
00229        }
00230     }
00231 
00232     return cairo_toy_font_face_hash_table;
00233 }
00234 
00235 static void
00236 _cairo_toy_font_face_hash_table_unlock (void)
00237 {
00238     CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex);
00239 }
00240 
00250 static void
00251 _cairo_toy_font_face_init_key (cairo_toy_font_face_t *key,
00252                             const char         *family,
00253                             cairo_font_slant_t     slant,
00254                             cairo_font_weight_t    weight)
00255 {
00256     unsigned long hash;
00257 
00258     key->family = family;
00259     key->owns_family = FALSE;
00260 
00261     key->slant = slant;
00262     key->weight = weight;
00263 
00264     /* 1607 and 1451 are just a couple of arbitrary primes. */
00265     hash = _cairo_hash_string (family);
00266     hash += ((unsigned long) slant) * 1607;
00267     hash += ((unsigned long) weight) * 1451;
00268     
00269     key->base.hash_entry.hash = hash;
00270 }
00271 
00272 static cairo_status_t
00273 _cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
00274                         const char          *family,
00275                         cairo_font_slant_t         slant,
00276                         cairo_font_weight_t        weight)
00277 {
00278     char *family_copy;
00279 
00280     family_copy = strdup (family);
00281     if (family_copy == NULL)
00282        return CAIRO_STATUS_NO_MEMORY;
00283 
00284     _cairo_toy_font_face_init_key (font_face, family_copy,
00285                                   slant, weight);
00286     font_face->owns_family = TRUE;
00287 
00288     _cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend);
00289 
00290     return CAIRO_STATUS_SUCCESS;
00291 }
00292 
00293 static void
00294 _cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face)
00295 {
00296     /* We assert here that we own font_face->family before casting
00297      * away the const qualifer. */
00298     assert (font_face->owns_family);
00299     free ((char*) font_face->family);
00300 }
00301 
00302 static int
00303 _cairo_toy_font_face_keys_equal (void *key_a,
00304                              void *key_b)
00305 {
00306     cairo_toy_font_face_t *face_a = key_a;
00307     cairo_toy_font_face_t *face_b = key_b;
00308 
00309     return (strcmp (face_a->family, face_b->family) == 0 &&
00310            face_a->slant == face_b->slant &&
00311            face_a->weight == face_b->weight);
00312 }
00313 
00327 cairo_font_face_t *
00328 _cairo_toy_font_face_create (const char          *family, 
00329                           cairo_font_slant_t   slant, 
00330                           cairo_font_weight_t  weight)
00331 {
00332     cairo_status_t status;
00333     cairo_toy_font_face_t key, *font_face;
00334     cairo_hash_table_t *hash_table;
00335 
00336     hash_table = _cairo_toy_font_face_hash_table_lock ();
00337     if (hash_table == NULL)
00338        goto UNWIND;
00339 
00340     _cairo_toy_font_face_init_key (&key, family, slant, weight);
00341     
00342     /* Return existing font_face if it exists in the hash table. */
00343     if (_cairo_hash_table_lookup (hash_table,
00344                               &key.base.hash_entry,
00345                               (cairo_hash_entry_t **) &font_face))
00346     {
00347        _cairo_toy_font_face_hash_table_unlock ();
00348        return cairo_font_face_reference (&font_face->base);
00349     }
00350 
00351     /* Otherwise create it and insert into hash table. */
00352     font_face = malloc (sizeof (cairo_toy_font_face_t));
00353     if (font_face == NULL)
00354        goto UNWIND_HASH_TABLE_LOCK;
00355 
00356     status = _cairo_toy_font_face_init (font_face, family, slant, weight);
00357     if (status)
00358        goto UNWIND_FONT_FACE_MALLOC;
00359 
00360     status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
00361     if (status)
00362        goto UNWIND_FONT_FACE_INIT;
00363 
00364     _cairo_toy_font_face_hash_table_unlock ();
00365 
00366     return &font_face->base;
00367 
00368  UNWIND_FONT_FACE_INIT:
00369  UNWIND_FONT_FACE_MALLOC:
00370     free (font_face);
00371  UNWIND_HASH_TABLE_LOCK:
00372     _cairo_toy_font_face_hash_table_unlock ();
00373  UNWIND:
00374     return (cairo_font_face_t*) &_cairo_font_face_nil;
00375 }
00376 
00377 static void
00378 _cairo_toy_font_face_destroy (void *abstract_face)
00379 {
00380     cairo_toy_font_face_t *font_face = abstract_face;
00381     cairo_hash_table_t *hash_table;
00382 
00383     if (font_face == NULL)
00384        return;
00385 
00386     hash_table = _cairo_toy_font_face_hash_table_lock ();
00387     /* All created objects must have been mapped in the hash table. */
00388     assert (hash_table != NULL);
00389 
00390     _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
00391     
00392     _cairo_toy_font_face_hash_table_unlock ();
00393     
00394     _cairo_toy_font_face_fini (font_face);
00395 }
00396 
00397 static cairo_status_t
00398 _cairo_toy_font_face_scaled_font_create (void                *abstract_font_face,
00399                                     const cairo_matrix_t       *font_matrix,
00400                                     const cairo_matrix_t       *ctm,
00401                                     const cairo_font_options_t *options,
00402                                     cairo_scaled_font_t    **scaled_font)
00403 {
00404     cairo_toy_font_face_t *font_face = abstract_font_face;
00405     const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
00406 
00407     return backend->create_toy (font_face,
00408                             font_matrix, ctm, options, scaled_font);
00409 }
00410 
00411 static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
00412     _cairo_toy_font_face_destroy,
00413     _cairo_toy_font_face_scaled_font_create
00414 };
00415 
00416 /* cairo_scaled_font_t */
00417 
00418 static const cairo_scaled_font_t _cairo_scaled_font_nil = {
00419     { 0 },                  /* hash_entry */
00420     CAIRO_STATUS_NO_MEMORY, /* status */
00421     -1,                            /* ref_count */
00422     NULL,                   /* font_face */
00423     { 1., 0., 0., 1., 0, 0},       /* font_matrix */
00424     { 1., 0., 0., 1., 0, 0},       /* ctm */
00425     { 1., 0., 0., 1., 0, 0},       /* scale */
00426     { CAIRO_ANTIALIAS_DEFAULT,     /* options */
00427       CAIRO_SUBPIXEL_ORDER_DEFAULT,
00428       CAIRO_HINT_STYLE_DEFAULT,
00429       CAIRO_HINT_METRICS_DEFAULT} ,
00430     CAIRO_SCALED_FONT_BACKEND_DEFAULT,
00431 };
00432 
00449 void
00450 _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
00451                            cairo_status_t status)
00452 {
00453     /* Don't overwrite an existing error. This preserves the first
00454      * error, which is the most significant. It also avoids attempting
00455      * to write to read-only data (eg. from a nil scaled_font). */
00456     if (scaled_font->status == CAIRO_STATUS_SUCCESS)
00457        scaled_font->status = status;
00458 
00459     _cairo_error (status);
00460 }
00461 
00472 cairo_status_t
00473 cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
00474 {
00475     return scaled_font->status;
00476 }
00477 
00478 /* Here we keep a unique mapping from
00479  * cairo_font_face_t/matrix/ctm/options => cairo_scaled_font_t.
00480  *
00481  * Here are the things that we want to map:
00482  *
00483  *  a) All otherwise referenced cairo_scaled_font_t's
00484  *  b) Some number of not otherwise referenced cairo_scaled_font_t's
00485  *
00486  * The implementation uses a hash table which covers (a)
00487  * completely. Then, for (b) we have an array of otherwise
00488  * unreferenced fonts (holdovers) which are expired in
00489  * least-recently-used order.
00490  *
00491  * The cairo_scaled_font_create code gets to treat this like a regular
00492  * hash table. All of the magic for the little holdover cache is in
00493  * cairo_scaled_font_reference and cairo_scaled_font_destroy.
00494  */
00495 
00496 /* This defines the size of the holdover array ... that is, the number
00497  * of scaled fonts we keep around even when not otherwise referenced
00498  */
00499 #define CAIRO_SCALED_FONT_MAX_HOLDOVERS 24
00500  
00501 typedef struct _cairo_scaled_font_map {
00502     cairo_hash_table_t *hash_table;
00503     cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
00504     int num_holdovers;
00505 } cairo_scaled_font_map_t;
00506 
00507 static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL;
00508 
00509 CAIRO_MUTEX_DECLARE (cairo_scaled_font_map_mutex);
00510 
00511 static int
00512 _cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b);
00513 
00514 static cairo_scaled_font_map_t *
00515 _cairo_scaled_font_map_lock (void)
00516 {
00517     CAIRO_MUTEX_LOCK (cairo_scaled_font_map_mutex);
00518 
00519     if (cairo_scaled_font_map == NULL)
00520     {
00521        cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
00522        if (cairo_scaled_font_map == NULL)
00523            goto CLEANUP_MUTEX_LOCK;
00524 
00525        cairo_scaled_font_map->hash_table =
00526            _cairo_hash_table_create (_cairo_scaled_font_keys_equal);
00527 
00528        if (cairo_scaled_font_map->hash_table == NULL)
00529            goto CLEANUP_SCALED_FONT_MAP;
00530 
00531        cairo_scaled_font_map->num_holdovers = 0;
00532     }
00533 
00534     return cairo_scaled_font_map;
00535 
00536  CLEANUP_SCALED_FONT_MAP:
00537     free (cairo_scaled_font_map);
00538  CLEANUP_MUTEX_LOCK:
00539     CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
00540     return NULL;
00541 }
00542 
00543 static void
00544 _cairo_scaled_font_map_unlock (void)
00545 {
00546    CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
00547 }
00548 
00549 static void
00550 _cairo_scaled_font_map_destroy (void)
00551 {
00552     int i;
00553     cairo_scaled_font_map_t *font_map = cairo_scaled_font_map;
00554     cairo_scaled_font_t *scaled_font;
00555 
00556     if (font_map == NULL)
00557        return;
00558 
00559     CAIRO_MUTEX_UNLOCK (cairo_scaled_font_map_mutex);
00560 
00561     for (i = 0; i < font_map->num_holdovers; i++) {
00562        scaled_font = font_map->holdovers[i];
00563        /* We should only get here through the reset_static_data path
00564         * and there had better not be any active references at that
00565         * point. */
00566        assert (scaled_font->ref_count == 0);
00567        _cairo_hash_table_remove (font_map->hash_table,
00568                               &scaled_font->hash_entry);
00569        _cairo_scaled_font_fini (scaled_font);
00570        free (scaled_font);
00571     }
00572 
00573     _cairo_hash_table_destroy (font_map->hash_table);
00574 
00575     free (cairo_scaled_font_map);
00576     cairo_scaled_font_map = NULL;
00577 }
00578 
00579 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
00580  * 
00581  * Not necessarily better than a lot of other hashes, but should be OK, and
00582  * well tested with binary data.
00583  */
00584 
00585 #define FNV_32_PRIME ((uint32_t)0x01000193)
00586 #define FNV1_32_INIT ((uint32_t)0x811c9dc5)
00587 
00588 static uint32_t
00589 _hash_bytes_fnv (unsigned char *buffer,
00590                int            len,
00591                uint32_t       hval)
00592 {
00593     while (len--) {
00594        hval *= FNV_32_PRIME;
00595        hval ^= *buffer++;
00596     }
00597 
00598     return hval;
00599 }
00600 
00601 static void
00602 _cairo_scaled_font_init_key (cairo_scaled_font_t        *scaled_font,
00603                           cairo_font_face_t              *font_face,
00604                           const cairo_matrix_t       *font_matrix,
00605                           const cairo_matrix_t       *ctm,
00606                           const cairo_font_options_t *options)
00607 {
00608     uint32_t hash = FNV1_32_INIT;
00609 
00610     scaled_font->status = CAIRO_STATUS_SUCCESS;
00611     scaled_font->font_face = font_face;
00612     scaled_font->font_matrix = *font_matrix;
00613     scaled_font->ctm = *ctm;
00614     scaled_font->options = *options;
00615 
00616     /* We do a bytewise hash on the font matrices, ignoring the
00617      * translation values. */
00618     hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->font_matrix.xx),
00619                          sizeof(double) * 4,
00620                          hash);
00621     hash = _hash_bytes_fnv ((unsigned char *)(&scaled_font->ctm.xx),
00622                          sizeof(double) * 4,
00623                          hash);
00624 
00625     hash ^= (unsigned long) scaled_font->font_face;
00626 
00627     hash ^= cairo_font_options_hash (&scaled_font->options);
00628 
00629     scaled_font->hash_entry.hash = hash;
00630 }
00631 
00632 static cairo_bool_t
00633 _cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b)
00634 {
00635     cairo_scaled_font_t *key_a = abstract_key_a;
00636     cairo_scaled_font_t *key_b = abstract_key_b;
00637 
00638     return (key_a->font_face == key_b->font_face &&
00639            memcmp ((unsigned char *)(&key_a->font_matrix.xx),
00640                   (unsigned char *)(&key_b->font_matrix.xx),
00641                   sizeof(double) * 4) == 0 &&
00642            memcmp ((unsigned char *)(&key_a->ctm.xx),
00643                   (unsigned char *)(&key_b->ctm.xx),
00644                   sizeof(double) * 4) == 0 &&
00645            cairo_font_options_equal (&key_a->options, &key_b->options));
00646 }
00647 
00648 void
00649 _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font, 
00650                       cairo_font_face_t             *font_face,
00651                       const cairo_matrix_t              *font_matrix,
00652                       const cairo_matrix_t              *ctm,
00653                       const cairo_font_options_t    *options,
00654                       const cairo_scaled_font_backend_t *backend)
00655 {
00656     scaled_font->ref_count = 1;
00657 
00658     _cairo_scaled_font_init_key (scaled_font, font_face,
00659                              font_matrix, ctm, options);
00660 
00661     cairo_font_face_reference (font_face);
00662 
00663     cairo_matrix_multiply (&scaled_font->scale,
00664                         &scaled_font->font_matrix,
00665                         &scaled_font->ctm);
00666 
00667     scaled_font->backend = backend;
00668 }
00669 
00670 void
00671 _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
00672 {
00673     if (scaled_font->font_face)
00674        cairo_font_face_destroy (scaled_font->font_face);
00675 
00676     scaled_font->backend->fini (scaled_font);
00677 }
00678 
00699 cairo_scaled_font_t *
00700 cairo_scaled_font_create (cairo_font_face_t          *font_face,
00701                        const cairo_matrix_t       *font_matrix,
00702                        const cairo_matrix_t       *ctm,
00703                        const cairo_font_options_t *options)
00704 {
00705     cairo_status_t status;
00706     cairo_scaled_font_map_t *font_map;
00707     cairo_scaled_font_t key, *scaled_font = NULL;
00708 
00709     font_map = _cairo_scaled_font_map_lock ();
00710     if (font_map == NULL)
00711        goto UNWIND;
00712     
00713     _cairo_scaled_font_init_key (&key, font_face,
00714                              font_matrix, ctm, options);
00715 
00716     /* Return existing scaled_font if it exists in the hash table. */
00717     if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
00718                               (cairo_hash_entry_t**) &scaled_font))
00719     {
00720        _cairo_scaled_font_map_unlock ();
00721        return cairo_scaled_font_reference (scaled_font);
00722     }
00723 
00724     /* Otherwise create it and insert it into the hash table. */
00725     status = font_face->backend->scaled_font_create (font_face, font_matrix,
00726                                                ctm, options, &scaled_font);
00727     if (status)
00728        goto UNWIND_FONT_MAP_LOCK;
00729 
00730     status = _cairo_hash_table_insert (font_map->hash_table,
00731                                    &scaled_font->hash_entry);
00732     if (status)
00733        goto UNWIND_SCALED_FONT_CREATE;
00734 
00735     _cairo_scaled_font_map_unlock ();
00736 
00737     return scaled_font;
00738 
00739 UNWIND_SCALED_FONT_CREATE:
00740     /* We can't call _cairo_scaled_font_destroy here since it expects
00741      * that the font has already been successfully inserted into the
00742      * hash table. */
00743     _cairo_scaled_font_fini (scaled_font);
00744     free (scaled_font);
00745 UNWIND_FONT_MAP_LOCK:
00746     _cairo_scaled_font_map_unlock ();
00747 UNWIND:
00748     return NULL;
00749 }
00750 
00762 cairo_scaled_font_t *
00763 cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
00764 {
00765     cairo_scaled_font_map_t *font_map;
00766 
00767     if (scaled_font == NULL)
00768        return NULL;
00769 
00770     if (scaled_font->ref_count == (unsigned int)-1)
00771        return scaled_font;
00772 
00773     /* We would normally assert (scaled_font->ref_count > 0) here, but
00774      * we are using ref_count == 0 as a legitimate case for the
00775      * holdovers array. See below. */
00776 
00777     /* cairo_scaled_font_t objects are cached and shared between
00778      * threads. This works because these objects are immutable. Except
00779      * that the reference count is mutable, so we have to do locking
00780      * around any modification of the reference count. */
00781     font_map = _cairo_scaled_font_map_lock ();
00782     {
00783        /* If the original reference count is 0, then this font must have
00784         * been found in font_map->holdovers, (which means this caching is
00785         * actually working). So now we remove it from the holdovers
00786         * array. */
00787        if (scaled_font->ref_count == 0) {
00788            int i;
00789 
00790            for (i = 0; i < font_map->num_holdovers; i++)
00791               if (font_map->holdovers[i] == scaled_font)
00792                   break;
00793            assert (i < font_map->num_holdovers);
00794 
00795            font_map->num_holdovers--;
00796            memmove (&font_map->holdovers[i],
00797                    &font_map->holdovers[i+1],
00798                    (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
00799        }
00800 
00801        scaled_font->ref_count++;
00802 
00803     }
00804     _cairo_scaled_font_map_unlock ();
00805 
00806     return scaled_font;
00807 }
00808 
00817 void
00818 cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
00819 {
00820     cairo_scaled_font_map_t *font_map;
00821 
00822     if (scaled_font == NULL)
00823        return;
00824 
00825     if (scaled_font->ref_count == (unsigned int)-1)
00826        return;
00827 
00828     /* cairo_scaled_font_t objects are cached and shared between
00829      * threads. This works because these objects are immutable. Except
00830      * that the reference count is mutable, so we have to do locking
00831      * around any modification of the reference count. */
00832     font_map = _cairo_scaled_font_map_lock ();
00833     {
00834        assert (font_map != NULL);
00835 
00836        assert (scaled_font->ref_count > 0);
00837 
00838        if (--(scaled_font->ref_count) == 0)
00839        {
00840            /* Rather than immediately destroying this object, we put it into
00841             * the font_map->holdovers array in case it will get used again
00842             * soon. To make room for it, we do actually destroy the
00843             * least-recently-used holdover.
00844             */
00845            if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
00846               cairo_scaled_font_t *lru;
00847 
00848               lru = font_map->holdovers[0];
00849               assert (lru->ref_count == 0);
00850        
00851               _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
00852 
00853               _cairo_scaled_font_fini (lru);
00854               free (lru);
00855        
00856               font_map->num_holdovers--;
00857               memmove (&font_map->holdovers[0],
00858                       &font_map->holdovers[1],
00859                       font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
00860            }
00861 
00862            font_map->holdovers[font_map->num_holdovers] = scaled_font;
00863            font_map->num_holdovers++;
00864        }
00865     }
00866     _cairo_scaled_font_map_unlock ();
00867 }
00868 
00869 cairo_status_t
00870 _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
00871                                const char          *utf8, 
00872                                cairo_glyph_t      **glyphs, 
00873                                int                      *num_glyphs)
00874 {
00875     if (scaled_font->status)
00876        return scaled_font->status;
00877 
00878     return scaled_font->backend->text_to_glyphs (scaled_font, utf8, glyphs, num_glyphs);
00879 }
00880 
00881 cairo_status_t
00882 _cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
00883                               cairo_glyph_t      *glyphs,
00884                               int                 num_glyphs,
00885                               cairo_text_extents_t  *extents)
00886 {
00887     if (scaled_font->status)
00888        return scaled_font->status;
00889 
00890     return scaled_font->backend->glyph_extents (scaled_font, glyphs, num_glyphs, extents);
00891 }
00892 
00893 
00894 cairo_status_t
00895 _cairo_scaled_font_glyph_bbox (cairo_scaled_font_t *scaled_font,
00896                             cairo_glyph_t       *glyphs,
00897                             int                  num_glyphs,
00898                             cairo_box_t      *bbox)
00899 {
00900     if (scaled_font->status)
00901        return scaled_font->status;
00902 
00903     return scaled_font->backend->glyph_bbox (scaled_font, glyphs, num_glyphs, bbox);
00904 }
00905 
00906 cairo_status_t
00907 _cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
00908                             cairo_operator_t        operator,
00909                             cairo_pattern_t        *pattern,
00910                             cairo_surface_t        *surface,
00911                             int                     source_x,
00912                             int                     source_y,
00913                             int                  dest_x,
00914                             int                  dest_y,
00915                             unsigned int         width,
00916                             unsigned int         height,
00917                             cairo_glyph_t          *glyphs,
00918                             int                     num_glyphs)
00919 {
00920     cairo_status_t status;
00921 
00922     /* These operators aren't interpreted the same way by the backends;
00923      * they are implemented in terms of other operators in cairo-gstate.c
00924      */
00925     assert (operator != CAIRO_OPERATOR_SOURCE && operator != CAIRO_OPERATOR_CLEAR);
00926     
00927     if (scaled_font->status)
00928        return scaled_font->status;
00929 
00930     status = _cairo_surface_show_glyphs (scaled_font, operator, pattern, 
00931                                     surface,
00932                                     source_x, source_y,
00933                                     dest_x, dest_y,
00934                                     width, height,
00935                                     glyphs, num_glyphs);
00936     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
00937        return status;
00938 
00939     /* Surface display routine either does not exist or failed. */
00940     return scaled_font->backend->show_glyphs (scaled_font, operator, pattern, 
00941                                          surface,
00942                                          source_x, source_y,
00943                                          dest_x, dest_y,
00944                                          width, height,
00945                                          glyphs, num_glyphs);
00946 }
00947 
00948 cairo_status_t
00949 _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
00950                             cairo_glyph_t    *glyphs, 
00951                             int               num_glyphs,
00952                             cairo_path_fixed_t  *path)
00953 {
00954     if (scaled_font->status)
00955        return scaled_font->status;
00956 
00957     return scaled_font->backend->glyph_path (scaled_font, glyphs, num_glyphs, path);
00958 }
00959 
00960 cairo_status_t
00961 _cairo_scaled_font_get_glyph_cache_key (cairo_scaled_font_t     *scaled_font,
00962                                    cairo_glyph_cache_key_t *key)
00963 {
00964     if (scaled_font->status)
00965        return scaled_font->status;
00966 
00967     scaled_font->backend->get_glyph_cache_key (scaled_font, key);
00968 
00969     return CAIRO_STATUS_SUCCESS;
00970 }
00971 
00972 cairo_status_t
00973 _cairo_scaled_font_font_extents (cairo_scaled_font_t  *scaled_font,
00974                              cairo_font_extents_t *extents)
00975 {
00976     if (scaled_font->status)
00977        return scaled_font->status;
00978 
00979     return scaled_font->backend->font_extents (scaled_font, extents);
00980 }
00981 
00982 void
00983 _cairo_unscaled_font_init (cairo_unscaled_font_t               *unscaled_font, 
00984                         const cairo_unscaled_font_backend_t *backend)
00985 {
00986     unscaled_font->ref_count = 1;
00987     unscaled_font->backend = backend;
00988 }
00989 
00990 cairo_unscaled_font_t *
00991 _cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
00992 {
00993     if (unscaled_font == NULL)
00994        return NULL;
00995 
00996     unscaled_font->ref_count++;
00997 
00998     return unscaled_font;
00999 }
01000 
01001 void
01002 _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
01003 {    
01004     if (unscaled_font == NULL)
01005        return;
01006 
01007     if (--(unscaled_font->ref_count) > 0)
01008        return;
01009 
01010     unscaled_font->backend->destroy (unscaled_font);
01011 
01012     free (unscaled_font);
01013 }
01014 
01015 /* Public font API follows. */
01016 
01024 void
01025 cairo_scaled_font_extents (cairo_scaled_font_t  *scaled_font,
01026                         cairo_font_extents_t *extents)
01027 {
01028     cairo_int_status_t status;
01029     double  font_scale_x, font_scale_y;
01030     
01031     if (scaled_font->status)
01032        return;
01033 
01034     status = _cairo_scaled_font_font_extents (scaled_font, extents);
01035     if (status) {
01036        _cairo_scaled_font_set_error (scaled_font, status);
01037        return;
01038     }
01039     
01040     _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
01041                                     &font_scale_x, &font_scale_y,
01042                                     /* XXX */ 1);
01043     
01044     /* 
01045      * The font responded in unscaled units, scale by the font
01046      * matrix scale factors to get to user space
01047      */
01048     
01049     extents->ascent *= font_scale_y;
01050     extents->descent *= font_scale_y;
01051     extents->height *= font_scale_y;
01052     extents->max_x_advance *= font_scale_x;
01053     extents->max_y_advance *= font_scale_y;
01054 }
01055 
01066 void
01067 cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
01068                              cairo_glyph_t         *glyphs, 
01069                              int                    num_glyphs,
01070                              cairo_text_extents_t  *extents)
01071 {
01072     cairo_status_t status = CAIRO_STATUS_SUCCESS;
01073     cairo_glyph_t origin_glyph;
01074     cairo_text_extents_t origin_extents;
01075     int i;
01076     double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
01077     double x_pos = 0.0, y_pos = 0.0;
01078     int set = 0;
01079 
01080     if (scaled_font->status)
01081        return;
01082 
01083     if (!num_glyphs)
01084     {
01085        extents->x_bearing = 0.0;
01086        extents->y_bearing = 0.0;
01087        extents->width = 0.0;
01088        extents->height = 0.0;
01089        extents->x_advance = 0.0;
01090        extents->y_advance = 0.0;
01091        
01092        return;
01093     }
01094 
01095     for (i = 0; i < num_glyphs; i++)
01096     {
01097        double        x, y;
01098        double        wm, hm;
01099        
01100        origin_glyph = glyphs[i];
01101        origin_glyph.x = 0.0;
01102        origin_glyph.y = 0.0;
01103        status = _cairo_scaled_font_glyph_extents (scaled_font,
01104                                              &origin_glyph, 1,
01105                                              &origin_extents);
01106        
01107        /*
01108         * Transform font space metrics into user space metrics
01109         * by running the corners through the font matrix and
01110         * expanding the bounding box as necessary
01111         */
01112        x = origin_extents.x_bearing;
01113        y = origin_extents.y_bearing;
01114        cairo_matrix_transform_point (&scaled_font->font_matrix,
01115                                   &x, &y);
01116 
01117        for (hm = 0.0; hm <= 1.0; hm += 1.0)
01118            for (wm = 0.0; wm <= 1.0; wm += 1.0)
01119            {
01120               x = origin_extents.x_bearing + origin_extents.width * wm;
01121               y = origin_extents.y_bearing + origin_extents.height * hm;
01122               cairo_matrix_transform_point (&scaled_font->font_matrix,
01123                                          &x, &y);
01124               x += glyphs[i].x;
01125               y += glyphs[i].y;
01126               if (!set)
01127               {
01128                   min_x = max_x = x;
01129                   min_y = max_y = y;
01130                   set = 1;
01131               }
01132               else
01133               {
01134                   if (x < min_x) min_x = x;
01135                   if (x > max_x) max_x = x;
01136                   if (y < min_y) min_y = y;
01137                   if (y > max_y) max_y = y;
01138               }
01139            }
01140 
01141        x = origin_extents.x_advance;
01142        y = origin_extents.y_advance;
01143        cairo_matrix_transform_point (&scaled_font->font_matrix,
01144                                   &x, &y);
01145        x_pos = glyphs[i].x + x;
01146        y_pos = glyphs[i].y + y;
01147     }
01148 
01149     extents->x_bearing = min_x - glyphs[0].x;
01150     extents->y_bearing = min_y - glyphs[0].y;
01151     extents->width = max_x - min_x;
01152     extents->height = max_y - min_y;
01153     extents->x_advance = x_pos - glyphs[0].x;
01154     extents->y_advance = y_pos - glyphs[0].y;
01155 }
01156 
01157 /* Now we implement functions to access a default global image & metrics
01158  * cache. 
01159  */
01160 
01161 unsigned long
01162 _cairo_glyph_cache_hash (void *cache, void *key)
01163 {
01164     cairo_glyph_cache_key_t *in;
01165     in = (cairo_glyph_cache_key_t *) key;
01166     return 
01167        ((unsigned long) in->unscaled) 
01168        ^ ((unsigned long) in->scale.xx) 
01169        ^ ((unsigned long) in->scale.yx) 
01170        ^ ((unsigned long) in->scale.xy) 
01171        ^ ((unsigned long) in->scale.yy)
01172         ^ (in->flags * 1451) /* 1451 is just an abitrary prime */
01173        ^ in->index;
01174 }
01175 
01176 int
01177 _cairo_glyph_cache_keys_equal (void *cache,
01178                             void *k1,
01179                             void *k2)
01180 {
01181     cairo_glyph_cache_key_t *a, *b;
01182     a = (cairo_glyph_cache_key_t *) k1;
01183     b = (cairo_glyph_cache_key_t *) k2;
01184     return (a->index == b->index)
01185        && (a->unscaled == b->unscaled)
01186        && (a->flags == b->flags)
01187        && (a->scale.xx == b->scale.xx)
01188        && (a->scale.yx == b->scale.yx)
01189        && (a->scale.xy == b->scale.xy)
01190        && (a->scale.yy == b->scale.yy);
01191 }
01192 
01193 
01194 static cairo_status_t
01195 _image_glyph_cache_create_entry (void *cache,
01196                              void *key,
01197                              void **return_value)
01198 {
01199     cairo_glyph_cache_key_t *k = (cairo_glyph_cache_key_t *) key;
01200     cairo_image_glyph_cache_entry_t *im;
01201     cairo_status_t status;
01202 
01203     im = calloc (1, sizeof (cairo_image_glyph_cache_entry_t));
01204     if (im == NULL)
01205        return CAIRO_STATUS_NO_MEMORY;
01206 
01207     im->key = *k;    
01208     status = im->key.unscaled->backend->create_glyph (im->key.unscaled,
01209                                                 im);
01210 
01211     if (status != CAIRO_STATUS_SUCCESS) {
01212        free (im);
01213        return status;
01214     }
01215 
01216     _cairo_unscaled_font_reference (im->key.unscaled);
01217 
01218     im->key.base.memory = 
01219        sizeof (cairo_image_glyph_cache_entry_t) 
01220        + (im->image ? 
01221           sizeof (cairo_image_surface_t) 
01222           + 28 * sizeof (int) /* rough guess at size of pixman image structure */
01223           + (im->image->height * im->image->stride) : 0);
01224 
01225     *return_value = im;
01226 
01227     return CAIRO_STATUS_SUCCESS;
01228 }
01229 
01230 
01231 static void
01232 _image_glyph_cache_destroy_entry (void *cache,
01233                               void *value)
01234 {
01235     cairo_image_glyph_cache_entry_t *im;
01236 
01237     im = (cairo_image_glyph_cache_entry_t *) value;
01238     _cairo_unscaled_font_destroy (im->key.unscaled);
01239     cairo_surface_destroy (&(im->image->base));
01240     free (im); 
01241 }
01242 
01243 static void 
01244 _image_glyph_cache_destroy_cache (void *cache)
01245 {
01246     free (cache);
01247 }
01248 
01249 static const cairo_cache_backend_t cairo_image_cache_backend = {
01250     _cairo_glyph_cache_hash,
01251     _cairo_glyph_cache_keys_equal,
01252     _image_glyph_cache_create_entry,
01253     _image_glyph_cache_destroy_entry,
01254     _image_glyph_cache_destroy_cache
01255 };
01256 
01257 CAIRO_MUTEX_DECLARE(_global_image_glyph_cache_mutex);
01258 
01259 static cairo_cache_t *
01260 _global_image_glyph_cache = NULL;
01261 
01262 void
01263 _cairo_lock_global_image_glyph_cache (void)
01264 {
01265     CAIRO_MUTEX_LOCK (_global_image_glyph_cache_mutex);
01266 }
01267 
01268 void
01269 _cairo_unlock_global_image_glyph_cache (void)
01270 {
01271     if (_global_image_glyph_cache) {
01272        _cairo_cache_shrink_to (_global_image_glyph_cache, 
01273                             CAIRO_IMAGE_GLYPH_CACHE_MEMORY_DEFAULT);
01274     }
01275     CAIRO_MUTEX_UNLOCK (_global_image_glyph_cache_mutex);
01276 }
01277 
01278 cairo_cache_t *
01279 _cairo_get_global_image_glyph_cache (void)
01280 {
01281     if (_global_image_glyph_cache == NULL) {
01282        _global_image_glyph_cache = malloc (sizeof (cairo_cache_t));
01283        
01284        if (_global_image_glyph_cache == NULL)
01285            goto FAIL;
01286        
01287        if (_cairo_cache_init (_global_image_glyph_cache,
01288                             &cairo_image_cache_backend,
01289                             0))
01290            goto FAIL;
01291     }
01292 
01293     return _global_image_glyph_cache;
01294     
01295  FAIL:
01296     if (_global_image_glyph_cache)
01297        free (_global_image_glyph_cache);
01298     _global_image_glyph_cache = NULL;
01299     return NULL;
01300 }
01301 
01302 void
01303 _cairo_font_reset_static_data (void)
01304 {
01305     _cairo_scaled_font_map_destroy ();
01306 
01307     _cairo_lock_global_image_glyph_cache();
01308     _cairo_cache_destroy (_global_image_glyph_cache);
01309     _global_image_glyph_cache = NULL;
01310     _cairo_unlock_global_image_glyph_cache();
01311 
01312     CAIRO_MUTEX_LOCK (cairo_toy_font_face_hash_table_mutex);
01313     _cairo_hash_table_destroy (cairo_toy_font_face_hash_table);
01314     cairo_toy_font_face_hash_table = NULL;
01315     CAIRO_MUTEX_UNLOCK (cairo_toy_font_face_hash_table_mutex);
01316 }