Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2003 University of Southern California
  4.  * Copyright © 2005 Red Hat, Inc
  5.  * Copyright © 2006 Keith Packard
  6.  * Copyright © 2006 Red Hat, Inc
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it either under the terms of the GNU Lesser General Public
  10.  * License version 2.1 as published by the Free Software Foundation
  11.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  12.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  13.  * notice, a recipient may use your version of this file under either
  14.  * the MPL or the LGPL.
  15.  *
  16.  * You should have received a copy of the LGPL along with this library
  17.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  19.  * You should have received a copy of the MPL along with this library
  20.  * in the file COPYING-MPL-1.1
  21.  *
  22.  * The contents of this file are subject to the Mozilla Public License
  23.  * Version 1.1 (the "License"); you may not use this file except in
  24.  * compliance with the License. You may obtain a copy of the License at
  25.  * http://www.mozilla.org/MPL/
  26.  *
  27.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  28.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  29.  * the specific language governing rights and limitations.
  30.  *
  31.  * The Original Code is the cairo graphics library.
  32.  *
  33.  * The Initial Developer of the Original Code is University of Southern
  34.  * California.
  35.  *
  36.  * Contributor(s):
  37.  *      Carl D. Worth <cworth@cworth.org>
  38.  *      Kristian Høgsberg <krh@redhat.com>
  39.  *      Keith Packard <keithp@keithp.com>
  40.  *      Adrian Johnson <ajohnson@redneon.com>
  41.  */
  42.  
  43. #define _BSD_SOURCE /* for snprintf(), strdup() */
  44. #include "cairoint.h"
  45. #include "cairo-error-private.h"
  46.  
  47. #if CAIRO_HAS_FONT_SUBSET
  48.  
  49. #include "cairo-scaled-font-subsets-private.h"
  50. #include "cairo-user-font-private.h"
  51.  
  52. #define MAX_GLYPHS_PER_SIMPLE_FONT 256
  53. #define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
  54.  
  55. typedef enum {
  56.     CAIRO_SUBSETS_SCALED,
  57.     CAIRO_SUBSETS_SIMPLE,
  58.     CAIRO_SUBSETS_COMPOSITE
  59. } cairo_subsets_type_t;
  60.  
  61. typedef enum {
  62.     CAIRO_SUBSETS_FOREACH_UNSCALED,
  63.     CAIRO_SUBSETS_FOREACH_SCALED,
  64.     CAIRO_SUBSETS_FOREACH_USER
  65. } cairo_subsets_foreach_type_t;
  66.  
  67. typedef struct _cairo_sub_font {
  68.     cairo_hash_entry_t base;
  69.  
  70.     cairo_bool_t is_scaled;
  71.     cairo_bool_t is_composite;
  72.     cairo_bool_t is_user;
  73.     cairo_bool_t use_latin_subset;
  74.     cairo_scaled_font_subsets_t *parent;
  75.     cairo_scaled_font_t *scaled_font;
  76.     unsigned int font_id;
  77.  
  78.     int current_subset;
  79.     int num_glyphs_in_current_subset;
  80.     int num_glyphs_in_latin_subset;
  81.     int max_glyphs_per_subset;
  82.     char latin_char_map[256];
  83.  
  84.     cairo_hash_table_t *sub_font_glyphs;
  85.     struct _cairo_sub_font *next;
  86. } cairo_sub_font_t;
  87.  
  88. struct _cairo_scaled_font_subsets {
  89.     cairo_subsets_type_t type;
  90.     cairo_bool_t use_latin_subset;
  91.  
  92.     int max_glyphs_per_unscaled_subset_used;
  93.     cairo_hash_table_t *unscaled_sub_fonts;
  94.     cairo_sub_font_t *unscaled_sub_fonts_list;
  95.     cairo_sub_font_t *unscaled_sub_fonts_list_end;
  96.  
  97.     int max_glyphs_per_scaled_subset_used;
  98.     cairo_hash_table_t *scaled_sub_fonts;
  99.     cairo_sub_font_t *scaled_sub_fonts_list;
  100.     cairo_sub_font_t *scaled_sub_fonts_list_end;
  101.  
  102.     int num_sub_fonts;
  103. };
  104.  
  105. typedef struct _cairo_sub_font_glyph {
  106.     cairo_hash_entry_t base;
  107.  
  108.     unsigned int subset_id;
  109.     unsigned int subset_glyph_index;
  110.     double       x_advance;
  111.     double       y_advance;
  112.  
  113.     cairo_bool_t is_latin;
  114.     int          latin_character;
  115.     cairo_bool_t is_mapped;
  116.     uint32_t     unicode;
  117.     char        *utf8;
  118.     int          utf8_len;
  119. } cairo_sub_font_glyph_t;
  120.  
  121. typedef struct _cairo_sub_font_collection {
  122.     unsigned long *glyphs; /* scaled_font_glyph_index */
  123.     char       **utf8;
  124.     unsigned int glyphs_size;
  125.     int           *to_latin_char;
  126.     unsigned long *latin_to_subset_glyph_index;
  127.     unsigned int max_glyph;
  128.     unsigned int num_glyphs;
  129.  
  130.     unsigned int subset_id;
  131.  
  132.     cairo_status_t status;
  133.     cairo_scaled_font_subset_callback_func_t font_subset_callback;
  134.     void *font_subset_callback_closure;
  135. } cairo_sub_font_collection_t;
  136.  
  137. typedef struct _cairo_string_entry {
  138.     cairo_hash_entry_t base;
  139.     char *string;
  140. } cairo_string_entry_t;
  141.  
  142. static cairo_status_t
  143. _cairo_sub_font_map_glyph (cairo_sub_font_t     *sub_font,
  144.                            unsigned long         scaled_font_glyph_index,
  145.                            const char *          utf8,
  146.                            int                   utf8_len,
  147.                            cairo_scaled_font_subsets_glyph_t *subset_glyph);
  148.  
  149. static void
  150. _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t  *sub_font_glyph,
  151.                                 unsigned long            scaled_font_glyph_index)
  152. {
  153.     sub_font_glyph->base.hash = scaled_font_glyph_index;
  154. }
  155.  
  156. static cairo_sub_font_glyph_t *
  157. _cairo_sub_font_glyph_create (unsigned long     scaled_font_glyph_index,
  158.                               unsigned int      subset_id,
  159.                               unsigned int      subset_glyph_index,
  160.                               double            x_advance,
  161.                               double            y_advance,
  162.                               int               latin_character,
  163.                               uint32_t          unicode,
  164.                               char             *utf8,
  165.                               int               utf8_len)
  166. {
  167.     cairo_sub_font_glyph_t *sub_font_glyph;
  168.  
  169.     sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
  170.     if (unlikely (sub_font_glyph == NULL)) {
  171.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  172.         return NULL;
  173.     }
  174.  
  175.     _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
  176.     sub_font_glyph->subset_id = subset_id;
  177.     sub_font_glyph->subset_glyph_index = subset_glyph_index;
  178.     sub_font_glyph->x_advance = x_advance;
  179.     sub_font_glyph->y_advance = y_advance;
  180.     sub_font_glyph->is_latin = (latin_character >= 0);
  181.     sub_font_glyph->latin_character = latin_character;
  182.     sub_font_glyph->is_mapped = FALSE;
  183.     sub_font_glyph->unicode = unicode;
  184.     sub_font_glyph->utf8 = utf8;
  185.     sub_font_glyph->utf8_len = utf8_len;
  186.  
  187.     return sub_font_glyph;
  188. }
  189.  
  190. static void
  191. _cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
  192. {
  193.     free (sub_font_glyph->utf8);
  194.  
  195.     free (sub_font_glyph);
  196. }
  197.  
  198. static void
  199. _cairo_sub_font_glyph_pluck (void *entry, void *closure)
  200. {
  201.     cairo_sub_font_glyph_t *sub_font_glyph = entry;
  202.     cairo_hash_table_t *sub_font_glyphs = closure;
  203.  
  204.     _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
  205.     _cairo_sub_font_glyph_destroy (sub_font_glyph);
  206. }
  207.  
  208. static void
  209. _cairo_sub_font_glyph_collect (void *entry, void *closure)
  210. {
  211.     cairo_sub_font_glyph_t *sub_font_glyph = entry;
  212.     cairo_sub_font_collection_t *collection = closure;
  213.     unsigned long scaled_font_glyph_index;
  214.     unsigned int subset_glyph_index;
  215.  
  216.     if (sub_font_glyph->subset_id != collection->subset_id)
  217.         return;
  218.  
  219.     scaled_font_glyph_index = sub_font_glyph->base.hash;
  220.     subset_glyph_index = sub_font_glyph->subset_glyph_index;
  221.  
  222.     /* Ensure we don't exceed the allocated bounds. */
  223.     assert (subset_glyph_index < collection->glyphs_size);
  224.  
  225.     collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
  226.     collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
  227.     collection->to_latin_char[subset_glyph_index] = sub_font_glyph->latin_character;
  228.     if (sub_font_glyph->is_latin)
  229.         collection->latin_to_subset_glyph_index[sub_font_glyph->latin_character] = subset_glyph_index;
  230.  
  231.     if (subset_glyph_index > collection->max_glyph)
  232.         collection->max_glyph = subset_glyph_index;
  233.  
  234.     collection->num_glyphs++;
  235. }
  236.  
  237. static cairo_bool_t
  238. _cairo_sub_fonts_equal (const void *key_a, const void *key_b)
  239. {
  240.     const cairo_sub_font_t *sub_font_a = key_a;
  241.     const cairo_sub_font_t *sub_font_b = key_b;
  242.     cairo_scaled_font_t *a = sub_font_a->scaled_font;
  243.     cairo_scaled_font_t *b = sub_font_b->scaled_font;
  244.  
  245.     if (sub_font_a->is_scaled)
  246.         return a == b;
  247.     else
  248.         return a->font_face == b->font_face || a->original_font_face == b->original_font_face;
  249. }
  250.  
  251. static void
  252. _cairo_sub_font_init_key (cairo_sub_font_t      *sub_font,
  253.                           cairo_scaled_font_t   *scaled_font)
  254. {
  255.     if (sub_font->is_scaled)
  256.     {
  257.         sub_font->base.hash = (unsigned long) scaled_font;
  258.         sub_font->scaled_font = scaled_font;
  259.     }
  260.     else
  261.     {
  262.         sub_font->base.hash = (unsigned long) scaled_font->font_face;
  263.         sub_font->scaled_font = scaled_font;
  264.     }
  265. }
  266.  
  267. static cairo_status_t
  268. _cairo_sub_font_create (cairo_scaled_font_subsets_t     *parent,
  269.                         cairo_scaled_font_t             *scaled_font,
  270.                         unsigned int                     font_id,
  271.                         int                              max_glyphs_per_subset,
  272.                         cairo_bool_t                     is_scaled,
  273.                         cairo_bool_t                     is_composite,
  274.                         cairo_sub_font_t               **sub_font_out)
  275. {
  276.     cairo_sub_font_t *sub_font;
  277.     int i;
  278.  
  279.     sub_font = malloc (sizeof (cairo_sub_font_t));
  280.     if (unlikely (sub_font == NULL))
  281.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  282.  
  283.     sub_font->is_scaled = is_scaled;
  284.     sub_font->is_composite = is_composite;
  285.     sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
  286.     _cairo_sub_font_init_key (sub_font, scaled_font);
  287.  
  288.     sub_font->parent = parent;
  289.     sub_font->scaled_font = scaled_font;
  290.     sub_font->font_id = font_id;
  291.  
  292.     sub_font->use_latin_subset = parent->use_latin_subset;
  293.  
  294.     /* latin subsets of Type 3 and CID CFF fonts are not supported */
  295.     if (sub_font->is_user || sub_font->is_scaled ||
  296.         _cairo_cff_scaled_font_is_cid_cff (scaled_font) )
  297.     {
  298.         sub_font->use_latin_subset = FALSE;
  299.     }
  300.  
  301.     if (sub_font->use_latin_subset)
  302.         sub_font->current_subset = 1; /* reserve subset 0 for latin glyphs */
  303.     else
  304.         sub_font->current_subset = 0;
  305.  
  306.     sub_font->num_glyphs_in_current_subset = 0;
  307.     sub_font->num_glyphs_in_latin_subset = 0;
  308.     sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
  309.     for (i = 0; i < 256; i++)
  310.         sub_font->latin_char_map[i] = FALSE;
  311.  
  312.     sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL);
  313.     if (unlikely (sub_font->sub_font_glyphs == NULL)) {
  314.         free (sub_font);
  315.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  316.     }
  317.     sub_font->next = NULL;
  318.     *sub_font_out = sub_font;
  319.     return CAIRO_STATUS_SUCCESS;
  320. }
  321.  
  322. static void
  323. _cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
  324. {
  325.     _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
  326.                                _cairo_sub_font_glyph_pluck,
  327.                                sub_font->sub_font_glyphs);
  328.     _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
  329.     cairo_scaled_font_destroy (sub_font->scaled_font);
  330.     free (sub_font);
  331. }
  332.  
  333. static void
  334. _cairo_sub_font_pluck (void *entry, void *closure)
  335. {
  336.     cairo_sub_font_t *sub_font = entry;
  337.     cairo_hash_table_t *sub_fonts = closure;
  338.  
  339.     _cairo_hash_table_remove (sub_fonts, &sub_font->base);
  340.     _cairo_sub_font_destroy (sub_font);
  341. }
  342.  
  343. /* Characters 0x80 to 0x9f in the winansi encoding.
  344.  * All other characters in the range 0x00 to 0xff map 1:1 to unicode */
  345. static unsigned int _winansi_0x80_to_0x9f[] = {
  346.     0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
  347.     0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000,
  348.     0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
  349.     0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178
  350. };
  351.  
  352. int
  353. _cairo_unicode_to_winansi (unsigned long uni)
  354. {
  355.     int i;
  356.  
  357.     /* exclude the extra "hyphen" at 0xad to avoid duplicate glyphnames */
  358.     if ((uni >= 0x20 && uni <= 0x7e) ||
  359.         (uni >= 0xa1 && uni <= 0xff && uni != 0xad) ||
  360.         uni == 0)
  361.         return uni;
  362.  
  363.     for (i = 0; i < 32; i++)
  364.         if (_winansi_0x80_to_0x9f[i] == uni)
  365.             return i + 0x80;
  366.  
  367.     return -1;
  368. }
  369.  
  370. static cairo_status_t
  371. _cairo_sub_font_glyph_lookup_unicode (cairo_scaled_font_t    *scaled_font,
  372.                                       unsigned long           scaled_font_glyph_index,
  373.                                       uint32_t               *unicode_out,
  374.                                       char                  **utf8_out,
  375.                                       int                    *utf8_len_out)
  376. {
  377.     uint32_t unicode;
  378.     char buf[8];
  379.     int len;
  380.     cairo_status_t status;
  381.  
  382.     /* Do a reverse lookup on the glyph index. unicode is -1 if the
  383.      * index could not be mapped to a unicode character. */
  384.     unicode = -1;
  385.     status = _cairo_truetype_index_to_ucs4 (scaled_font,
  386.                                             scaled_font_glyph_index,
  387.                                             &unicode);
  388.     if (_cairo_status_is_error (status))
  389.         return status;
  390.  
  391.     if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) {
  392.         status = scaled_font->backend->index_to_ucs4 (scaled_font,
  393.                                                       scaled_font_glyph_index,
  394.                                                       &unicode);
  395.         if (unlikely (status))
  396.             return status;
  397.     }
  398.  
  399.     *unicode_out = unicode;
  400.     *utf8_out = NULL;
  401.     *utf8_len_out = 0;
  402.     if (unicode != (uint32_t) -1) {
  403.         len = _cairo_ucs4_to_utf8 (unicode, buf);
  404.         if (len > 0) {
  405.             *utf8_out = malloc (len + 1);
  406.             if (unlikely (*utf8_out == NULL))
  407.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  408.  
  409.             memcpy (*utf8_out, buf, len);
  410.             (*utf8_out)[len] = 0;
  411.             *utf8_len_out = len;
  412.         }
  413.     }
  414.  
  415.     return CAIRO_STATUS_SUCCESS;
  416. }
  417.  
  418. static cairo_status_t
  419. _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
  420.                                       const char             *utf8,
  421.                                       int                     utf8_len,
  422.                                       cairo_bool_t           *is_mapped)
  423. {
  424.     *is_mapped = FALSE;
  425.  
  426.     if (utf8_len < 0)
  427.         return CAIRO_STATUS_SUCCESS;
  428.  
  429.     if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
  430.         utf8_len--;
  431.  
  432.     if (utf8 != NULL && utf8_len != 0) {
  433.         if (sub_font_glyph->utf8 != NULL) {
  434.             if (utf8_len == sub_font_glyph->utf8_len &&
  435.                 memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
  436.             {
  437.                 /* Requested utf8 mapping matches the existing mapping */
  438.                 *is_mapped = TRUE;
  439.             }
  440.         } else {
  441.             /* No existing mapping. Use the requested mapping */
  442.             sub_font_glyph->utf8 = malloc (utf8_len + 1);
  443.             if (unlikely (sub_font_glyph->utf8 == NULL))
  444.                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  445.  
  446.             memcpy (sub_font_glyph->utf8, utf8, utf8_len);
  447.             sub_font_glyph->utf8[utf8_len] = 0;
  448.             sub_font_glyph->utf8_len = utf8_len;
  449.             *is_mapped = TRUE;
  450.         }
  451.     }
  452.  
  453.     return CAIRO_STATUS_SUCCESS;
  454. }
  455.  
  456. static cairo_int_status_t
  457. _cairo_sub_font_lookup_glyph (cairo_sub_font_t                  *sub_font,
  458.                               unsigned long                      scaled_font_glyph_index,
  459.                               const char                        *utf8,
  460.                               int                                utf8_len,
  461.                               cairo_scaled_font_subsets_glyph_t *subset_glyph)
  462. {
  463.     cairo_sub_font_glyph_t key, *sub_font_glyph;
  464.     cairo_int_status_t status;
  465.  
  466.     _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
  467.     sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
  468.                                               &key.base);
  469.     if (sub_font_glyph != NULL) {
  470.         subset_glyph->font_id = sub_font->font_id;
  471.         subset_glyph->subset_id = sub_font_glyph->subset_id;
  472.         if (sub_font_glyph->is_latin)
  473.             subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
  474.         else
  475.             subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
  476.  
  477.         subset_glyph->is_scaled = sub_font->is_scaled;
  478.         subset_glyph->is_composite = sub_font->is_composite;
  479.         subset_glyph->is_latin = sub_font_glyph->is_latin;
  480.         subset_glyph->x_advance = sub_font_glyph->x_advance;
  481.         subset_glyph->y_advance = sub_font_glyph->y_advance;
  482.         status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
  483.                                                        utf8, utf8_len,
  484.                                                        &subset_glyph->utf8_is_mapped);
  485.         subset_glyph->unicode = sub_font_glyph->unicode;
  486.  
  487.         return status;
  488.     }
  489.  
  490.     return CAIRO_INT_STATUS_UNSUPPORTED;
  491. }
  492.  
  493. static cairo_status_t
  494. _cairo_sub_font_add_glyph (cairo_sub_font_t        *sub_font,
  495.                            unsigned long            scaled_font_glyph_index,
  496.                            cairo_bool_t             is_latin,
  497.                            int                      latin_character,
  498.                            uint32_t                 unicode,
  499.                            char                    *utf8,
  500.                            int                      utf8_len,
  501.                            cairo_sub_font_glyph_t **sub_font_glyph_out)
  502. {
  503.     cairo_scaled_glyph_t *scaled_glyph;
  504.     cairo_sub_font_glyph_t *sub_font_glyph;
  505.     int *num_glyphs_in_subset_ptr;
  506.     double x_advance;
  507.     double y_advance;
  508.     cairo_int_status_t status;
  509.  
  510.     _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
  511.     status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
  512.                                          scaled_font_glyph_index,
  513.                                          CAIRO_SCALED_GLYPH_INFO_METRICS,
  514.                                          &scaled_glyph);
  515.     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
  516.     if (unlikely (status)) {
  517.         _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
  518.         return status;
  519.     }
  520.  
  521.     x_advance = scaled_glyph->metrics.x_advance;
  522.     y_advance = scaled_glyph->metrics.y_advance;
  523.     _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
  524.  
  525.     if (!is_latin && sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
  526.     {
  527.         sub_font->current_subset++;
  528.         sub_font->num_glyphs_in_current_subset = 0;
  529.     }
  530.  
  531.     if (is_latin)
  532.         num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset;
  533.     else
  534.         num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset;
  535.  
  536.     /* Reserve first glyph in subset for the .notdef glyph except for
  537.      * Type 3 fonts */
  538.     if (*num_glyphs_in_subset_ptr == 0 &&
  539.         scaled_font_glyph_index != 0 &&
  540.         ! _cairo_font_face_is_user (sub_font->scaled_font->font_face))
  541.     {
  542.         status = _cairo_sub_font_add_glyph (sub_font,
  543.                                             0,
  544.                                             is_latin,
  545.                                             0,
  546.                                             0,
  547.                                             NULL,
  548.                                             -1,
  549.                                             &sub_font_glyph);
  550.         if (unlikely (status))
  551.             return status;
  552.     }
  553.  
  554.     sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
  555.                                                    is_latin ? 0 : sub_font->current_subset,
  556.                                                    *num_glyphs_in_subset_ptr,
  557.                                                    x_advance,
  558.                                                    y_advance,
  559.                                                    is_latin ? latin_character : -1,
  560.                                                    unicode,
  561.                                                    utf8,
  562.                                                    utf8_len);
  563.  
  564.     if (unlikely (sub_font_glyph == NULL))
  565.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  566.  
  567.     status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
  568.     if (unlikely (status)) {
  569.         _cairo_sub_font_glyph_destroy (sub_font_glyph);
  570.         return status;
  571.     }
  572.  
  573.     (*num_glyphs_in_subset_ptr)++;
  574.     if (sub_font->is_scaled) {
  575.         if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used)
  576.             sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr;
  577.     } else {
  578.         if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used)
  579.             sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr;
  580.     }
  581.  
  582.     *sub_font_glyph_out = sub_font_glyph;
  583.  
  584.     return CAIRO_STATUS_SUCCESS;
  585. }
  586.  
  587. static cairo_status_t
  588. _cairo_sub_font_map_glyph (cairo_sub_font_t     *sub_font,
  589.                            unsigned long         scaled_font_glyph_index,
  590.                            const char           *text_utf8,
  591.                            int                   text_utf8_len,
  592.                            cairo_scaled_font_subsets_glyph_t *subset_glyph)
  593. {
  594.     cairo_sub_font_glyph_t key, *sub_font_glyph;
  595.     cairo_status_t status;
  596.  
  597.     _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
  598.     sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
  599.                                                &key.base);
  600.     if (sub_font_glyph == NULL) {
  601.         uint32_t font_unicode;
  602.         char *font_utf8;
  603.         int font_utf8_len;
  604.         cairo_bool_t is_latin;
  605.         int latin_character;
  606.  
  607.         status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font,
  608.                                                            scaled_font_glyph_index,
  609.                                                            &font_unicode,
  610.                                                            &font_utf8,
  611.                                                            &font_utf8_len);
  612.         if (unlikely(status))
  613.             return status;
  614.  
  615.         /* If the supplied utf8 is a valid single character, use it
  616.          * instead of the font lookup */
  617.         if (text_utf8 != NULL && text_utf8_len > 0) {
  618.             uint32_t  *ucs4;
  619.             int ucs4_len;
  620.  
  621.             status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len,
  622.                                           &ucs4, &ucs4_len);
  623.             if (status == CAIRO_STATUS_SUCCESS) {
  624.                 if (ucs4_len == 1) {
  625.                     font_unicode = ucs4[0];
  626.                     free (font_utf8);
  627.                     font_utf8 = malloc (text_utf8_len + 1);
  628.                     if (font_utf8 == NULL) {
  629.                         free (ucs4);
  630.                         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  631.                     }
  632.                     memcpy (font_utf8, text_utf8, text_utf8_len);
  633.                     font_utf8[text_utf8_len] = 0;
  634.                     font_utf8_len = text_utf8_len;
  635.                 }
  636.                 free (ucs4);
  637.             }
  638.         }
  639.  
  640.         /* If glyph is in the winansi encoding and font is not a user
  641.          * font, put glyph in the latin subset. If glyph is .notdef
  642.          * the latin subset is preferred but only if the latin subset
  643.          * already contains at least one glyph. We don't want to
  644.          * create a separate subset just for the .notdef glyph.
  645.          */
  646.         is_latin = FALSE;
  647.         latin_character = -1;
  648.         if (sub_font->use_latin_subset &&
  649.             (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)))
  650.         {
  651.             latin_character = _cairo_unicode_to_winansi (font_unicode);
  652.             if (latin_character > 0 ||
  653.                 (latin_character == 0 && sub_font->num_glyphs_in_latin_subset > 0))
  654.             {
  655.                 if (!sub_font->latin_char_map[latin_character]) {
  656.                     sub_font->latin_char_map[latin_character] = TRUE;
  657.                     is_latin = TRUE;
  658.                 }
  659.             }
  660.         }
  661.  
  662.         status = _cairo_sub_font_add_glyph (sub_font,
  663.                                             scaled_font_glyph_index,
  664.                                             is_latin,
  665.                                             latin_character,
  666.                                             font_unicode,
  667.                                             font_utf8,
  668.                                             font_utf8_len,
  669.                                             &sub_font_glyph);
  670.         if (unlikely(status))
  671.             return status;
  672.     }
  673.  
  674.     subset_glyph->font_id = sub_font->font_id;
  675.     subset_glyph->subset_id = sub_font_glyph->subset_id;
  676.     if (sub_font_glyph->is_latin)
  677.         subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
  678.     else
  679.         subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
  680.  
  681.     subset_glyph->is_scaled = sub_font->is_scaled;
  682.     subset_glyph->is_composite = sub_font->is_composite;
  683.     subset_glyph->is_latin = sub_font_glyph->is_latin;
  684.     subset_glyph->x_advance = sub_font_glyph->x_advance;
  685.     subset_glyph->y_advance = sub_font_glyph->y_advance;
  686.     status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
  687.                                                    text_utf8, text_utf8_len,
  688.                                                    &subset_glyph->utf8_is_mapped);
  689.     subset_glyph->unicode = sub_font_glyph->unicode;
  690.  
  691.     return status;
  692. }
  693.  
  694. static void
  695. _cairo_sub_font_collect (void *entry, void *closure)
  696. {
  697.     cairo_sub_font_t *sub_font = entry;
  698.     cairo_sub_font_collection_t *collection = closure;
  699.     cairo_scaled_font_subset_t subset;
  700.     int i;
  701.     unsigned int j;
  702.  
  703.     if (collection->status)
  704.         return;
  705.  
  706.     collection->status = sub_font->scaled_font->status;
  707.     if (collection->status)
  708.         return;
  709.  
  710.     for (i = 0; i <= sub_font->current_subset; i++) {
  711.         collection->subset_id = i;
  712.         collection->num_glyphs = 0;
  713.         collection->max_glyph = 0;
  714.         memset (collection->latin_to_subset_glyph_index, 0, 256*sizeof(unsigned long));
  715.  
  716.         _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
  717.                                    _cairo_sub_font_glyph_collect, collection);
  718.         if (collection->status)
  719.             break;
  720.         if (collection->num_glyphs == 0)
  721.             continue;
  722.  
  723.         /* Ensure the resulting array has no uninitialized holes */
  724.         assert (collection->num_glyphs == collection->max_glyph + 1);
  725.  
  726.         subset.scaled_font = sub_font->scaled_font;
  727.         subset.is_composite = sub_font->is_composite;
  728.         subset.is_scaled = sub_font->is_scaled;
  729.         subset.font_id = sub_font->font_id;
  730.         subset.subset_id = i;
  731.         subset.glyphs = collection->glyphs;
  732.         subset.utf8 = collection->utf8;
  733.         subset.num_glyphs = collection->num_glyphs;
  734.         subset.glyph_names = NULL;
  735.  
  736.         subset.is_latin = FALSE;
  737.         if (sub_font->use_latin_subset && i == 0) {
  738.             subset.is_latin = TRUE;
  739.             subset.to_latin_char = collection->to_latin_char;
  740.             subset.latin_to_subset_glyph_index = collection->latin_to_subset_glyph_index;
  741.         } else {
  742.             subset.to_latin_char = NULL;
  743.             subset.latin_to_subset_glyph_index = NULL;
  744.         }
  745.  
  746.         collection->status = (collection->font_subset_callback) (&subset,
  747.                                             collection->font_subset_callback_closure);
  748.  
  749.         if (subset.glyph_names != NULL) {
  750.             for (j = 0; j < collection->num_glyphs; j++)
  751.                 free (subset.glyph_names[j]);
  752.             free (subset.glyph_names);
  753.         }
  754.  
  755.         if (collection->status)
  756.             break;
  757.     }
  758. }
  759.  
  760. static cairo_scaled_font_subsets_t *
  761. _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
  762. {
  763.     cairo_scaled_font_subsets_t *subsets;
  764.  
  765.     subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
  766.     if (unlikely (subsets == NULL)) {
  767.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  768.         return NULL;
  769.     }
  770.  
  771.     subsets->type = type;
  772.     subsets->use_latin_subset = FALSE;
  773.     subsets->max_glyphs_per_unscaled_subset_used = 0;
  774.     subsets->max_glyphs_per_scaled_subset_used = 0;
  775.     subsets->num_sub_fonts = 0;
  776.  
  777.     subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
  778.     if (! subsets->unscaled_sub_fonts) {
  779.         free (subsets);
  780.         return NULL;
  781.     }
  782.     subsets->unscaled_sub_fonts_list = NULL;
  783.     subsets->unscaled_sub_fonts_list_end = NULL;
  784.  
  785.     subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
  786.     if (! subsets->scaled_sub_fonts) {
  787.         _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
  788.         free (subsets);
  789.         return NULL;
  790.     }
  791.     subsets->scaled_sub_fonts_list = NULL;
  792.     subsets->scaled_sub_fonts_list_end = NULL;
  793.  
  794.     return subsets;
  795. }
  796.  
  797. cairo_scaled_font_subsets_t *
  798. _cairo_scaled_font_subsets_create_scaled (void)
  799. {
  800.     return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
  801. }
  802.  
  803. cairo_scaled_font_subsets_t *
  804. _cairo_scaled_font_subsets_create_simple (void)
  805. {
  806.     return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
  807. }
  808.  
  809. cairo_scaled_font_subsets_t *
  810. _cairo_scaled_font_subsets_create_composite (void)
  811. {
  812.     return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
  813. }
  814.  
  815. void
  816. _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
  817. {
  818.     _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
  819.     _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
  820.  
  821.     _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
  822.     _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
  823.  
  824.     free (subsets);
  825. }
  826.  
  827. void
  828. _cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t *font_subsets,
  829.                                                 cairo_bool_t                 use_latin)
  830. {
  831.     font_subsets->use_latin_subset = use_latin;
  832. }
  833.  
  834. cairo_status_t
  835. _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t       *subsets,
  836.                                       cairo_scaled_font_t               *scaled_font,
  837.                                       unsigned long                      scaled_font_glyph_index,
  838.                                       const char *                       utf8,
  839.                                       int                                utf8_len,
  840.                                       cairo_scaled_font_subsets_glyph_t *subset_glyph)
  841. {
  842.     cairo_sub_font_t key, *sub_font;
  843.     cairo_scaled_glyph_t *scaled_glyph;
  844.     cairo_font_face_t *font_face;
  845.     cairo_matrix_t identity;
  846.     cairo_font_options_t font_options;
  847.     cairo_scaled_font_t *unscaled_font;
  848.     cairo_int_status_t status;
  849.     int max_glyphs;
  850.     cairo_bool_t type1_font;
  851.  
  852.     /* Lookup glyph in unscaled subsets */
  853.     if (subsets->type != CAIRO_SUBSETS_SCALED) {
  854.         key.is_scaled = FALSE;
  855.         _cairo_sub_font_init_key (&key, scaled_font);
  856.         sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
  857.                                              &key.base);
  858.         if (sub_font != NULL) {
  859.             status = _cairo_sub_font_lookup_glyph (sub_font,
  860.                                                    scaled_font_glyph_index,
  861.                                                    utf8, utf8_len,
  862.                                                    subset_glyph);
  863.             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  864.                 return status;
  865.         }
  866.     }
  867.  
  868.     /* Lookup glyph in scaled subsets */
  869.     key.is_scaled = TRUE;
  870.     _cairo_sub_font_init_key (&key, scaled_font);
  871.     sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
  872.                                          &key.base);
  873.     if (sub_font != NULL) {
  874.         status = _cairo_sub_font_lookup_glyph (sub_font,
  875.                                                scaled_font_glyph_index,
  876.                                                utf8, utf8_len,
  877.                                                subset_glyph);
  878.         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
  879.             return status;
  880.     }
  881.  
  882.     /* Glyph not found. Determine whether the glyph is outline or
  883.      * bitmap and add to the appropriate subset.
  884.      *
  885.      * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
  886.      * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
  887.      * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
  888.      * empty glyphs in this case so we can put the glyph in a unscaled
  889.      * subset. */
  890.     if (scaled_font_glyph_index == 0 ||
  891.         _cairo_font_face_is_user (scaled_font->font_face)) {
  892.         status = CAIRO_STATUS_SUCCESS;
  893.     } else {
  894.         _cairo_scaled_font_freeze_cache (scaled_font);
  895.         status = _cairo_scaled_glyph_lookup (scaled_font,
  896.                                              scaled_font_glyph_index,
  897.                                              CAIRO_SCALED_GLYPH_INFO_PATH,
  898.                                              &scaled_glyph);
  899.         _cairo_scaled_font_thaw_cache (scaled_font);
  900.     }
  901.     if (_cairo_int_status_is_error (status))
  902.         return status;
  903.  
  904.     if (status == CAIRO_INT_STATUS_SUCCESS &&
  905.         subsets->type != CAIRO_SUBSETS_SCALED &&
  906.         ! _cairo_font_face_is_user (scaled_font->font_face))
  907.     {
  908.         /* Path available. Add to unscaled subset. */
  909.         key.is_scaled = FALSE;
  910.         _cairo_sub_font_init_key (&key, scaled_font);
  911.         sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
  912.                                              &key.base);
  913.         if (sub_font == NULL) {
  914.             font_face = cairo_scaled_font_get_font_face (scaled_font);
  915.             cairo_matrix_init_identity (&identity);
  916.             _cairo_font_options_init_default (&font_options);
  917.             cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
  918.             cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
  919.             unscaled_font = cairo_scaled_font_create (font_face,
  920.                                                       &identity,
  921.                                                       &identity,
  922.                                                       &font_options);
  923.             if (unlikely (unscaled_font->status))
  924.                 return unscaled_font->status;
  925.  
  926.             subset_glyph->is_scaled = FALSE;
  927.             type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
  928.             if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
  929.                 max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
  930.                 subset_glyph->is_composite = TRUE;
  931.             } else {
  932.                 max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
  933.                 subset_glyph->is_composite = FALSE;
  934.             }
  935.  
  936.             status = _cairo_sub_font_create (subsets,
  937.                                              unscaled_font,
  938.                                              subsets->num_sub_fonts,
  939.                                              max_glyphs,
  940.                                              subset_glyph->is_scaled,
  941.                                              subset_glyph->is_composite,
  942.                                              &sub_font);
  943.  
  944.             if (unlikely (status)) {
  945.                 cairo_scaled_font_destroy (unscaled_font);
  946.                 return status;
  947.             }
  948.  
  949.             status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
  950.                                                &sub_font->base);
  951.  
  952.             if (unlikely (status)) {
  953.                 _cairo_sub_font_destroy (sub_font);
  954.                 return status;
  955.             }
  956.             if (!subsets->unscaled_sub_fonts_list)
  957.                 subsets->unscaled_sub_fonts_list = sub_font;
  958.             else
  959.                 subsets->unscaled_sub_fonts_list_end->next = sub_font;
  960.             subsets->unscaled_sub_fonts_list_end = sub_font;
  961.             subsets->num_sub_fonts++;
  962.         }
  963.     } else {
  964.         /* No path available. Add to scaled subset. */
  965.         key.is_scaled = TRUE;
  966.         _cairo_sub_font_init_key (&key, scaled_font);
  967.         sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
  968.                                              &key.base);
  969.         if (sub_font == NULL) {
  970.             subset_glyph->is_scaled = TRUE;
  971.             subset_glyph->is_composite = FALSE;
  972.             if (subsets->type == CAIRO_SUBSETS_SCALED)
  973.                 max_glyphs = INT_MAX;
  974.             else
  975.                 max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
  976.  
  977.             status = _cairo_sub_font_create (subsets,
  978.                                              cairo_scaled_font_reference (scaled_font),
  979.                                              subsets->num_sub_fonts,
  980.                                              max_glyphs,
  981.                                              subset_glyph->is_scaled,
  982.                                              subset_glyph->is_composite,
  983.                                              &sub_font);
  984.             if (unlikely (status)) {
  985.                 cairo_scaled_font_destroy (scaled_font);
  986.                 return status;
  987.             }
  988.  
  989.             status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
  990.                                                &sub_font->base);
  991.             if (unlikely (status)) {
  992.                 _cairo_sub_font_destroy (sub_font);
  993.                 return status;
  994.             }
  995.             if (!subsets->scaled_sub_fonts_list)
  996.                 subsets->scaled_sub_fonts_list = sub_font;
  997.             else
  998.                 subsets->scaled_sub_fonts_list_end->next = sub_font;
  999.             subsets->scaled_sub_fonts_list_end = sub_font;
  1000.             subsets->num_sub_fonts++;
  1001.         }
  1002.     }
  1003.  
  1004.     return _cairo_sub_font_map_glyph (sub_font,
  1005.                                       scaled_font_glyph_index,
  1006.                                       utf8, utf8_len,
  1007.                                       subset_glyph);
  1008. }
  1009.  
  1010. static cairo_status_t
  1011. _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t              *font_subsets,
  1012.                                              cairo_scaled_font_subset_callback_func_t  font_subset_callback,
  1013.                                              void                                     *closure,
  1014.                                              cairo_subsets_foreach_type_t              type)
  1015. {
  1016.     cairo_sub_font_collection_t collection;
  1017.     cairo_sub_font_t *sub_font;
  1018.     cairo_bool_t is_scaled, is_user;
  1019.  
  1020.     is_scaled = FALSE;
  1021.     is_user = FALSE;
  1022.  
  1023.     if (type == CAIRO_SUBSETS_FOREACH_USER)
  1024.         is_user = TRUE;
  1025.  
  1026.     if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
  1027.         type == CAIRO_SUBSETS_FOREACH_USER)
  1028.     {
  1029.         is_scaled = TRUE;
  1030.     }
  1031.  
  1032.     if (is_scaled)
  1033.         collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
  1034.     else
  1035.         collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
  1036.  
  1037.     if (! collection.glyphs_size)
  1038.         return CAIRO_STATUS_SUCCESS;
  1039.  
  1040.     collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
  1041.     collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
  1042.     collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int));
  1043.     collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long));
  1044.     if (unlikely (collection.glyphs == NULL ||
  1045.                   collection.utf8 == NULL ||
  1046.                   collection.to_latin_char == NULL ||
  1047.                   collection.latin_to_subset_glyph_index == NULL)) {
  1048.         free (collection.glyphs);
  1049.         free (collection.utf8);
  1050.         free (collection.to_latin_char);
  1051.         free (collection.latin_to_subset_glyph_index);
  1052.  
  1053.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1054.     }
  1055.  
  1056.     collection.font_subset_callback = font_subset_callback;
  1057.     collection.font_subset_callback_closure = closure;
  1058.     collection.status = CAIRO_STATUS_SUCCESS;
  1059.  
  1060.     if (is_scaled)
  1061.         sub_font = font_subsets->scaled_sub_fonts_list;
  1062.     else
  1063.         sub_font = font_subsets->unscaled_sub_fonts_list;
  1064.  
  1065.     while (sub_font) {
  1066.         if (sub_font->is_user == is_user)
  1067.             _cairo_sub_font_collect (sub_font, &collection);
  1068.  
  1069.         sub_font = sub_font->next;
  1070.     }
  1071.     free (collection.utf8);
  1072.     free (collection.glyphs);
  1073.     free (collection.to_latin_char);
  1074.     free (collection.latin_to_subset_glyph_index);
  1075.  
  1076.     return collection.status;
  1077. }
  1078.  
  1079. cairo_status_t
  1080. _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t              *font_subsets,
  1081.                                            cairo_scaled_font_subset_callback_func_t  font_subset_callback,
  1082.                                            void                                     *closure)
  1083. {
  1084.     return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
  1085.                                                         font_subset_callback,
  1086.                                                         closure,
  1087.                                                         CAIRO_SUBSETS_FOREACH_SCALED);
  1088. }
  1089.  
  1090. cairo_status_t
  1091. _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t            *font_subsets,
  1092.                                            cairo_scaled_font_subset_callback_func_t  font_subset_callback,
  1093.                                            void                                     *closure)
  1094. {
  1095.     return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
  1096.                                                         font_subset_callback,
  1097.                                                         closure,
  1098.                                                         CAIRO_SUBSETS_FOREACH_UNSCALED);
  1099. }
  1100.  
  1101. cairo_status_t
  1102. _cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t              *font_subsets,
  1103.                                          cairo_scaled_font_subset_callback_func_t  font_subset_callback,
  1104.                                          void                                     *closure)
  1105. {
  1106.     return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
  1107.                                                         font_subset_callback,
  1108.                                                         closure,
  1109.                                                         CAIRO_SUBSETS_FOREACH_USER);
  1110. }
  1111.  
  1112. static cairo_bool_t
  1113. _cairo_string_equal (const void *key_a, const void *key_b)
  1114. {
  1115.     const cairo_string_entry_t *a = key_a;
  1116.     const cairo_string_entry_t *b = key_b;
  1117.  
  1118.     if (strcmp (a->string, b->string) == 0)
  1119.         return TRUE;
  1120.     else
  1121.         return FALSE;
  1122. }
  1123.  
  1124. static void
  1125. _cairo_string_init_key (cairo_string_entry_t *key, char *s)
  1126. {
  1127.     unsigned long sum = 0;
  1128.     unsigned int i;
  1129.  
  1130.     for (i = 0; i < strlen(s); i++)
  1131.         sum += s[i];
  1132.     key->base.hash = sum;
  1133.     key->string = s;
  1134. }
  1135.  
  1136. static cairo_status_t
  1137. create_string_entry (char *s, cairo_string_entry_t **entry)
  1138. {
  1139.     *entry = malloc (sizeof (cairo_string_entry_t));
  1140.     if (unlikely (*entry == NULL))
  1141.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1142.  
  1143.     _cairo_string_init_key (*entry, s);
  1144.  
  1145.     return CAIRO_STATUS_SUCCESS;
  1146. }
  1147.  
  1148. static void
  1149. _pluck_entry (void *entry, void *closure)
  1150. {
  1151.     _cairo_hash_table_remove (closure, entry);
  1152.     free (entry);
  1153. }
  1154.  
  1155. cairo_int_status_t
  1156. _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
  1157. {
  1158.     unsigned int i;
  1159.     cairo_hash_table_t *names;
  1160.     cairo_string_entry_t key, *entry;
  1161.     char buf[30];
  1162.     char *utf8;
  1163.     uint16_t *utf16;
  1164.     int utf16_len;
  1165.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  1166.  
  1167.     names = _cairo_hash_table_create (_cairo_string_equal);
  1168.     if (unlikely (names == NULL))
  1169.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1170.  
  1171.     subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
  1172.     if (unlikely (subset->glyph_names == NULL)) {
  1173.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1174.         goto CLEANUP_HASH;
  1175.     }
  1176.  
  1177.     i = 0;
  1178.     if (! subset->is_scaled) {
  1179.         subset->glyph_names[0] = strdup (".notdef");
  1180.         if (unlikely (subset->glyph_names[0] == NULL)) {
  1181.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1182.             goto CLEANUP_HASH;
  1183.         }
  1184.  
  1185.         status = create_string_entry (subset->glyph_names[0], &entry);
  1186.         if (unlikely (status))
  1187.             goto CLEANUP_HASH;
  1188.  
  1189.         status = _cairo_hash_table_insert (names, &entry->base);
  1190.         if (unlikely (status)) {
  1191.             free (entry);
  1192.             goto CLEANUP_HASH;
  1193.         }
  1194.         i++;
  1195.     }
  1196.  
  1197.     for (; i < subset->num_glyphs; i++) {
  1198.         utf8 = subset->utf8[i];
  1199.         utf16 = NULL;
  1200.         utf16_len = 0;
  1201.         if (utf8 && *utf8) {
  1202.             status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
  1203.             if (unlikely (status))
  1204.                 goto CLEANUP_HASH;
  1205.         }
  1206.  
  1207.         if (utf16_len == 1) {
  1208.             int ch = _cairo_unicode_to_winansi (utf16[0]);
  1209.             if (ch > 0 && _cairo_winansi_to_glyphname (ch))
  1210.                 strncpy (buf, _cairo_winansi_to_glyphname (ch), sizeof (buf));
  1211.             else
  1212.                 snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
  1213.  
  1214.             _cairo_string_init_key (&key, buf);
  1215.             entry = _cairo_hash_table_lookup (names, &key.base);
  1216.             if (entry != NULL)
  1217.                 snprintf (buf, sizeof (buf), "g%d", i);
  1218.         } else {
  1219.             snprintf (buf, sizeof (buf), "g%d", i);
  1220.         }
  1221.         free (utf16);
  1222.  
  1223.         subset->glyph_names[i] = strdup (buf);
  1224.         if (unlikely (subset->glyph_names[i] == NULL)) {
  1225.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1226.             goto CLEANUP_HASH;
  1227.         }
  1228.  
  1229.         status = create_string_entry (subset->glyph_names[i], &entry);
  1230.         if (unlikely (status))
  1231.             goto CLEANUP_HASH;
  1232.  
  1233.         status = _cairo_hash_table_insert (names, &entry->base);
  1234.         if (unlikely (status)) {
  1235.             free (entry);
  1236.             goto CLEANUP_HASH;
  1237.         }
  1238.     }
  1239.  
  1240. CLEANUP_HASH:
  1241.     _cairo_hash_table_foreach (names, _pluck_entry, names);
  1242.     _cairo_hash_table_destroy (names);
  1243.  
  1244.     if (likely (status == CAIRO_STATUS_SUCCESS))
  1245.         return CAIRO_STATUS_SUCCESS;
  1246.  
  1247.     if (subset->glyph_names != NULL) {
  1248.         for (i = 0; i < subset->num_glyphs; i++) {
  1249.             free (subset->glyph_names[i]);
  1250.         }
  1251.  
  1252.         free (subset->glyph_names);
  1253.         subset->glyph_names = NULL;
  1254.     }
  1255.  
  1256.     return status;
  1257. }
  1258.  
  1259. #endif /* CAIRO_HAS_FONT_SUBSET */
  1260.