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. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright © 2002 University of Southern California
  5.  * Copyright © 2005,2008 Red Hat Inc.
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it either under the terms of the GNU Lesser General Public
  9.  * License version 2.1 as published by the Free Software Foundation
  10.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  11.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  12.  * notice, a recipient may use your version of this file under either
  13.  * the MPL or the LGPL.
  14.  *
  15.  * You should have received a copy of the LGPL along with this library
  16.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  18.  * You should have received a copy of the MPL along with this library
  19.  * in the file COPYING-MPL-1.1
  20.  *
  21.  * The contents of this file are subject to the Mozilla Public License
  22.  * Version 1.1 (the "License"); you may not use this file except in
  23.  * compliance with the License. You may obtain a copy of the License at
  24.  * http://www.mozilla.org/MPL/
  25.  *
  26.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  27.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  28.  * the specific language governing rights and limitations.
  29.  *
  30.  * The Original Code is the cairo graphics library.
  31.  *
  32.  * The Initial Developer of the Original Code is University of Southern
  33.  * California.
  34.  *
  35.  * Contributor(s):
  36.  *      Carl D. Worth <cworth@cworth.org>
  37.  *      Graydon Hoare <graydon@redhat.com>
  38.  *      Owen Taylor <otaylor@redhat.com>
  39.  *      Behdad Esfahbod <behdad@behdad.org>
  40.  */
  41.  
  42. #define _BSD_SOURCE /* for strdup() */
  43. #include "cairoint.h"
  44. #include "cairo-error-private.h"
  45.  
  46.  
  47. static const cairo_font_face_t _cairo_font_face_null_pointer = {
  48.     { 0 },                              /* hash_entry */
  49.     CAIRO_STATUS_NULL_POINTER,          /* status */
  50.     CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
  51.     { 0, 0, 0, NULL },                  /* user_data */
  52.     NULL
  53. };
  54.  
  55. static const cairo_font_face_t _cairo_font_face_invalid_string = {
  56.     { 0 },                              /* hash_entry */
  57.     CAIRO_STATUS_INVALID_STRING,        /* status */
  58.     CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
  59.     { 0, 0, 0, NULL },                  /* user_data */
  60.     NULL
  61. };
  62.  
  63. static const cairo_font_face_t _cairo_font_face_invalid_slant = {
  64.     { 0 },                              /* hash_entry */
  65.     CAIRO_STATUS_INVALID_SLANT,         /* status */
  66.     CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
  67.     { 0, 0, 0, NULL },                  /* user_data */
  68.     NULL
  69. };
  70.  
  71. static const cairo_font_face_t _cairo_font_face_invalid_weight = {
  72.     { 0 },                              /* hash_entry */
  73.     CAIRO_STATUS_INVALID_WEIGHT,        /* status */
  74.     CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
  75.     { 0, 0, 0, NULL },                  /* user_data */
  76.     NULL
  77. };
  78.  
  79.  
  80. static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
  81.  
  82. static int
  83. _cairo_toy_font_face_keys_equal (const void *key_a,
  84.                                  const void *key_b);
  85.  
  86. /* We maintain a hash table from family/weight/slant =>
  87.  * #cairo_font_face_t for #cairo_toy_font_t. The primary purpose of
  88.  * this mapping is to provide unique #cairo_font_face_t values so that
  89.  * our cache and mapping from #cairo_font_face_t => #cairo_scaled_font_t
  90.  * works. Once the corresponding #cairo_font_face_t objects fall out of
  91.  * downstream caches, we don't need them in this hash table anymore.
  92.  *
  93.  * Modifications to this hash table are protected by
  94.  * _cairo_toy_font_face_mutex.
  95.  */
  96. static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL;
  97.  
  98. static cairo_hash_table_t *
  99. _cairo_toy_font_face_hash_table_lock (void)
  100. {
  101.     CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex);
  102.  
  103.     if (cairo_toy_font_face_hash_table == NULL)
  104.     {
  105.         cairo_toy_font_face_hash_table =
  106.             _cairo_hash_table_create (_cairo_toy_font_face_keys_equal);
  107.  
  108.         if (cairo_toy_font_face_hash_table == NULL) {
  109.             CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
  110.             return NULL;
  111.         }
  112.     }
  113.  
  114.     return cairo_toy_font_face_hash_table;
  115. }
  116.  
  117. static void
  118. _cairo_toy_font_face_hash_table_unlock (void)
  119. {
  120.     CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
  121. }
  122.  
  123. /**
  124.  * _cairo_toy_font_face_init_key:
  125.  *
  126.  * Initialize those portions of #cairo_toy_font_face_t needed to use
  127.  * it as a hash table key, including the hash code buried away in
  128.  * font_face->base.hash_entry. No memory allocation is performed here
  129.  * so that no fini call is needed. We do this to make it easier to use
  130.  * an automatic #cairo_toy_font_face_t variable as a key.
  131.  **/
  132. static void
  133. _cairo_toy_font_face_init_key (cairo_toy_font_face_t *key,
  134.                                const char            *family,
  135.                                cairo_font_slant_t     slant,
  136.                                cairo_font_weight_t    weight)
  137. {
  138.     unsigned long hash;
  139.  
  140.     key->family = family;
  141.     key->owns_family = FALSE;
  142.  
  143.     key->slant = slant;
  144.     key->weight = weight;
  145.  
  146.     /* 1607 and 1451 are just a couple of arbitrary primes. */
  147.     hash = _cairo_hash_string (family);
  148.     hash += ((unsigned long) slant) * 1607;
  149.     hash += ((unsigned long) weight) * 1451;
  150.  
  151.     key->base.hash_entry.hash = hash;
  152. }
  153.  
  154. static cairo_status_t
  155. _cairo_toy_font_face_create_impl_face (cairo_toy_font_face_t *font_face,
  156.                                        cairo_font_face_t **impl_font_face)
  157. {
  158.     const cairo_font_face_backend_t * backend = CAIRO_FONT_FACE_BACKEND_DEFAULT;
  159.     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
  160.  
  161.     if (unlikely (font_face->base.status))
  162.         return font_face->base.status;
  163.  
  164.     if (backend->create_for_toy != NULL &&
  165.         0 != strncmp (font_face->family, CAIRO_USER_FONT_FAMILY_DEFAULT,
  166.                       strlen (CAIRO_USER_FONT_FAMILY_DEFAULT)))
  167.     {
  168.         status = backend->create_for_toy (font_face, impl_font_face);
  169.     }
  170.  
  171.     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
  172.         backend = &_cairo_user_font_face_backend;
  173.         status = backend->create_for_toy (font_face, impl_font_face);
  174.     }
  175.  
  176.     return status;
  177. }
  178.  
  179. static cairo_status_t
  180. _cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
  181.                            const char            *family,
  182.                            cairo_font_slant_t     slant,
  183.                            cairo_font_weight_t    weight)
  184. {
  185.     char *family_copy;
  186.     cairo_status_t status;
  187.  
  188.     family_copy = strdup (family);
  189.     if (unlikely (family_copy == NULL))
  190.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  191.  
  192.     _cairo_toy_font_face_init_key (font_face, family_copy, slant, weight);
  193.     font_face->owns_family = TRUE;
  194.  
  195.     _cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend);
  196.  
  197.     status = _cairo_toy_font_face_create_impl_face (font_face,
  198.                                                     &font_face->impl_face);
  199.     if (unlikely (status)) {
  200.         free (family_copy);
  201.         return status;
  202.     }
  203.  
  204.     return CAIRO_STATUS_SUCCESS;
  205. }
  206.  
  207. static void
  208. _cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face)
  209. {
  210.     /* We assert here that we own font_face->family before casting
  211.      * away the const qualifer. */
  212.     assert (font_face->owns_family);
  213.     free ((char*) font_face->family);
  214.  
  215.     if (font_face->impl_face)
  216.         cairo_font_face_destroy (font_face->impl_face);
  217. }
  218.  
  219. static int
  220. _cairo_toy_font_face_keys_equal (const void *key_a,
  221.                                  const void *key_b)
  222. {
  223.     const cairo_toy_font_face_t *face_a = key_a;
  224.     const cairo_toy_font_face_t *face_b = key_b;
  225.  
  226.     return (strcmp (face_a->family, face_b->family) == 0 &&
  227.             face_a->slant == face_b->slant &&
  228.             face_a->weight == face_b->weight);
  229. }
  230.  
  231. /**
  232.  * cairo_toy_font_face_create:
  233.  * @family: a font family name, encoded in UTF-8
  234.  * @slant: the slant for the font
  235.  * @weight: the weight for the font
  236.  *
  237.  * Creates a font face from a triplet of family, slant, and weight.
  238.  * These font faces are used in implementation of the the #cairo_t "toy"
  239.  * font API.
  240.  *
  241.  * If @family is the zero-length string "", the platform-specific default
  242.  * family is assumed.  The default family then can be queried using
  243.  * cairo_toy_font_face_get_family().
  244.  *
  245.  * The cairo_select_font_face() function uses this to create font faces.
  246.  * See that function for limitations and other details of toy font faces.
  247.  *
  248.  * Return value: a newly created #cairo_font_face_t. Free with
  249.  *  cairo_font_face_destroy() when you are done using it.
  250.  *
  251.  * Since: 1.8
  252.  **/
  253. cairo_font_face_t *
  254. cairo_toy_font_face_create (const char          *family,
  255.                             cairo_font_slant_t   slant,
  256.                             cairo_font_weight_t  weight)
  257. {
  258.     cairo_status_t status;
  259.     cairo_toy_font_face_t key, *font_face;
  260.     cairo_hash_table_t *hash_table;
  261.  
  262.     if (family == NULL)
  263.         return (cairo_font_face_t*) &_cairo_font_face_null_pointer;
  264.  
  265.     /* Make sure we've got valid UTF-8 for the family */
  266.     status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
  267.     if (unlikely (status)) {
  268.         if (status == CAIRO_STATUS_INVALID_STRING)
  269.             return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
  270.  
  271.         return (cairo_font_face_t*) &_cairo_font_face_nil;
  272.     }
  273.  
  274.     switch (slant) {
  275.         case CAIRO_FONT_SLANT_NORMAL:
  276.         case CAIRO_FONT_SLANT_ITALIC:
  277.         case CAIRO_FONT_SLANT_OBLIQUE:
  278.             break;
  279.         default:
  280.             return (cairo_font_face_t*) &_cairo_font_face_invalid_slant;
  281.     }
  282.  
  283.     switch (weight) {
  284.         case CAIRO_FONT_WEIGHT_NORMAL:
  285.         case CAIRO_FONT_WEIGHT_BOLD:
  286.             break;
  287.         default:
  288.             return (cairo_font_face_t*) &_cairo_font_face_invalid_weight;
  289.     }
  290.  
  291.     if (*family == '\0')
  292.         family = CAIRO_FONT_FAMILY_DEFAULT;
  293.  
  294.     hash_table = _cairo_toy_font_face_hash_table_lock ();
  295.     if (unlikely (hash_table == NULL))
  296.         goto UNWIND;
  297.  
  298.     _cairo_toy_font_face_init_key (&key, family, slant, weight);
  299.  
  300.     /* Return existing font_face if it exists in the hash table. */
  301.     font_face = _cairo_hash_table_lookup (hash_table,
  302.                                           &key.base.hash_entry);
  303.     if (font_face != NULL) {
  304.         if (font_face->base.status == CAIRO_STATUS_SUCCESS) {
  305.             cairo_font_face_reference (&font_face->base);
  306.             _cairo_toy_font_face_hash_table_unlock ();
  307.             return &font_face->base;
  308.         }
  309.  
  310.         /* remove the bad font from the hash table */
  311.         _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
  312.     }
  313.  
  314.     /* Otherwise create it and insert into hash table. */
  315.     font_face = malloc (sizeof (cairo_toy_font_face_t));
  316.     if (unlikely (font_face == NULL)) {
  317.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  318.         goto UNWIND_HASH_TABLE_LOCK;
  319.     }
  320.  
  321.     status = _cairo_toy_font_face_init (font_face, family, slant, weight);
  322.     if (unlikely (status))
  323.         goto UNWIND_FONT_FACE_MALLOC;
  324.  
  325.     assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash);
  326.     status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
  327.     if (unlikely (status))
  328.         goto UNWIND_FONT_FACE_INIT;
  329.  
  330.     _cairo_toy_font_face_hash_table_unlock ();
  331.  
  332.     return &font_face->base;
  333.  
  334.  UNWIND_FONT_FACE_INIT:
  335.     _cairo_toy_font_face_fini (font_face);
  336.  UNWIND_FONT_FACE_MALLOC:
  337.     free (font_face);
  338.  UNWIND_HASH_TABLE_LOCK:
  339.     _cairo_toy_font_face_hash_table_unlock ();
  340.  UNWIND:
  341.     return (cairo_font_face_t*) &_cairo_font_face_nil;
  342. }
  343. slim_hidden_def (cairo_toy_font_face_create);
  344.  
  345. static void
  346. _cairo_toy_font_face_destroy (void *abstract_face)
  347. {
  348.     cairo_toy_font_face_t *font_face = abstract_face;
  349.     cairo_hash_table_t *hash_table;
  350.  
  351.     hash_table = _cairo_toy_font_face_hash_table_lock ();
  352.     /* All created objects must have been mapped in the hash table. */
  353.     assert (hash_table != NULL);
  354.  
  355.     if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->base.ref_count)) {
  356.         /* somebody recreated the font whilst we waited for the lock */
  357.         _cairo_toy_font_face_hash_table_unlock ();
  358.         return;
  359.     }
  360.  
  361.     /* Font faces in SUCCESS status are guaranteed to be in the
  362.      * hashtable. Font faces in an error status are removed from the
  363.      * hashtable if they are found during a lookup, thus they should
  364.      * only be removed if they are in the hashtable. */
  365.     if (likely (font_face->base.status == CAIRO_STATUS_SUCCESS) ||
  366.         _cairo_hash_table_lookup (hash_table, &font_face->base.hash_entry) == font_face)
  367.         _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
  368.  
  369.     _cairo_toy_font_face_hash_table_unlock ();
  370.  
  371.     _cairo_toy_font_face_fini (font_face);
  372. }
  373.  
  374. static cairo_status_t
  375. _cairo_toy_font_face_scaled_font_create (void                *abstract_font_face,
  376.                                          const cairo_matrix_t       *font_matrix,
  377.                                          const cairo_matrix_t       *ctm,
  378.                                          const cairo_font_options_t *options,
  379.                                          cairo_scaled_font_t       **scaled_font)
  380. {
  381.     cairo_toy_font_face_t *font_face = (cairo_toy_font_face_t *) abstract_font_face;
  382.  
  383.     ASSERT_NOT_REACHED;
  384.  
  385.     return _cairo_font_face_set_error (&font_face->base, CAIRO_STATUS_FONT_TYPE_MISMATCH);
  386. }
  387.  
  388. static cairo_font_face_t *
  389. _cairo_toy_font_face_get_implementation (void                *abstract_font_face,
  390.                                          const cairo_matrix_t       *font_matrix,
  391.                                          const cairo_matrix_t       *ctm,
  392.                                          const cairo_font_options_t *options)
  393. {
  394.     cairo_toy_font_face_t *font_face = abstract_font_face;
  395.  
  396.     if (font_face->impl_face) {
  397.         cairo_font_face_t *impl = font_face->impl_face;
  398.  
  399.         if (impl->backend->get_implementation != NULL) {
  400.             return impl->backend->get_implementation (impl,
  401.                                                       font_matrix,
  402.                                                       ctm,
  403.                                                       options);
  404.         }
  405.  
  406.         return cairo_font_face_reference (impl);
  407.     }
  408.  
  409.     return abstract_font_face;
  410. }
  411.  
  412. static cairo_bool_t
  413. _cairo_font_face_is_toy (cairo_font_face_t *font_face)
  414. {
  415.     return font_face->backend == &_cairo_toy_font_face_backend;
  416. }
  417.  
  418. /**
  419.  * cairo_toy_font_face_get_family:
  420.  * @font_face: A toy font face
  421.  *
  422.  * Gets the familly name of a toy font.
  423.  *
  424.  * Return value: The family name.  This string is owned by the font face
  425.  * and remains valid as long as the font face is alive (referenced).
  426.  *
  427.  * Since: 1.8
  428.  **/
  429. const char *
  430. cairo_toy_font_face_get_family (cairo_font_face_t *font_face)
  431. {
  432.     cairo_toy_font_face_t *toy_font_face;
  433.  
  434.     if (font_face->status)
  435.         return CAIRO_FONT_FAMILY_DEFAULT;
  436.  
  437.     toy_font_face = (cairo_toy_font_face_t *) font_face;
  438.     if (! _cairo_font_face_is_toy (font_face)) {
  439.         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
  440.             return CAIRO_FONT_FAMILY_DEFAULT;
  441.     }
  442.     assert (toy_font_face->owns_family);
  443.     return toy_font_face->family;
  444. }
  445.  
  446. /**
  447.  * cairo_toy_font_face_get_slant:
  448.  * @font_face: A toy font face
  449.  *
  450.  * Gets the slant a toy font.
  451.  *
  452.  * Return value: The slant value
  453.  *
  454.  * Since: 1.8
  455.  **/
  456. cairo_font_slant_t
  457. cairo_toy_font_face_get_slant (cairo_font_face_t *font_face)
  458. {
  459.     cairo_toy_font_face_t *toy_font_face;
  460.  
  461.     if (font_face->status)
  462.         return CAIRO_FONT_SLANT_DEFAULT;
  463.  
  464.     toy_font_face = (cairo_toy_font_face_t *) font_face;
  465.     if (! _cairo_font_face_is_toy (font_face)) {
  466.         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
  467.             return CAIRO_FONT_SLANT_DEFAULT;
  468.     }
  469.     return toy_font_face->slant;
  470. }
  471. slim_hidden_def (cairo_toy_font_face_get_slant);
  472.  
  473. /**
  474.  * cairo_toy_font_face_get_weight:
  475.  * @font_face: A toy font face
  476.  *
  477.  * Gets the weight a toy font.
  478.  *
  479.  * Return value: The weight value
  480.  *
  481.  * Since: 1.8
  482.  **/
  483. cairo_font_weight_t
  484. cairo_toy_font_face_get_weight (cairo_font_face_t *font_face)
  485. {
  486.     cairo_toy_font_face_t *toy_font_face;
  487.  
  488.     if (font_face->status)
  489.         return CAIRO_FONT_WEIGHT_DEFAULT;
  490.  
  491.     toy_font_face = (cairo_toy_font_face_t *) font_face;
  492.     if (! _cairo_font_face_is_toy (font_face)) {
  493.         if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
  494.             return CAIRO_FONT_WEIGHT_DEFAULT;
  495.     }
  496.     return toy_font_face->weight;
  497. }
  498. slim_hidden_def (cairo_toy_font_face_get_weight);
  499.  
  500. static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
  501.     CAIRO_FONT_TYPE_TOY,
  502.     NULL,                                       /* create_for_toy */
  503.     _cairo_toy_font_face_destroy,
  504.     _cairo_toy_font_face_scaled_font_create,
  505.     _cairo_toy_font_face_get_implementation
  506. };
  507.  
  508. void
  509. _cairo_toy_font_face_reset_static_data (void)
  510. {
  511.     cairo_hash_table_t *hash_table;
  512.  
  513.     /* We manually acquire the lock rather than calling
  514.      * cairo_toy_font_face_hash_table_lock simply to avoid
  515.      * creating the table only to destroy it again. */
  516.     CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex);
  517.     hash_table = cairo_toy_font_face_hash_table;
  518.     cairo_toy_font_face_hash_table = NULL;
  519.     CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex);
  520.  
  521.     if (hash_table != NULL)
  522.         _cairo_hash_table_destroy (hash_table);
  523. }
  524.