LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-scaled-font-subsets.c (source / functions) Found Hit Coverage
Test: app.info Lines: 493 0 0.0 %
Date: 2012-06-02 Functions: 31 0 0.0 %

       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_scaled_font_subsets_t *parent;
      74                 :     cairo_scaled_font_t *scaled_font;
      75                 :     unsigned int font_id;
      76                 : 
      77                 :     int current_subset;
      78                 :     int num_glyphs_in_current_subset;
      79                 :     int max_glyphs_per_subset;
      80                 : 
      81                 :     cairo_hash_table_t *sub_font_glyphs;
      82                 :     struct _cairo_sub_font *next;
      83                 : } cairo_sub_font_t;
      84                 : 
      85                 : struct _cairo_scaled_font_subsets {
      86                 :     cairo_subsets_type_t type;
      87                 : 
      88                 :     int max_glyphs_per_unscaled_subset_used;
      89                 :     cairo_hash_table_t *unscaled_sub_fonts;
      90                 :     cairo_sub_font_t *unscaled_sub_fonts_list;
      91                 :     cairo_sub_font_t *unscaled_sub_fonts_list_end;
      92                 : 
      93                 :     int max_glyphs_per_scaled_subset_used;
      94                 :     cairo_hash_table_t *scaled_sub_fonts;
      95                 :     cairo_sub_font_t *scaled_sub_fonts_list;
      96                 :     cairo_sub_font_t *scaled_sub_fonts_list_end;
      97                 : 
      98                 :     int num_sub_fonts;
      99                 : };
     100                 : 
     101                 : typedef struct _cairo_sub_font_glyph {
     102                 :     cairo_hash_entry_t base;
     103                 : 
     104                 :     unsigned int subset_id;
     105                 :     unsigned int subset_glyph_index;
     106                 :     double       x_advance;
     107                 :     double       y_advance;
     108                 : 
     109                 :     cairo_bool_t is_mapped;
     110                 :     uint32_t     unicode;
     111                 :     char        *utf8;
     112                 :     int          utf8_len;
     113                 : } cairo_sub_font_glyph_t;
     114                 : 
     115                 : typedef struct _cairo_sub_font_collection {
     116                 :     unsigned long *glyphs; /* scaled_font_glyph_index */
     117                 :     char       **utf8;
     118                 :     unsigned int glyphs_size;
     119                 :     unsigned int max_glyph;
     120                 :     unsigned int num_glyphs;
     121                 : 
     122                 :     unsigned int subset_id;
     123                 : 
     124                 :     cairo_status_t status;
     125                 :     cairo_scaled_font_subset_callback_func_t font_subset_callback;
     126                 :     void *font_subset_callback_closure;
     127                 : } cairo_sub_font_collection_t;
     128                 : 
     129                 : typedef struct _cairo_string_entry {
     130                 :     cairo_hash_entry_t base;
     131                 :     char *string;
     132                 : } cairo_string_entry_t;
     133                 : 
     134                 : static cairo_status_t
     135                 : _cairo_sub_font_map_glyph (cairo_sub_font_t     *sub_font,
     136                 :                            unsigned long         scaled_font_glyph_index,
     137                 :                            const char *          utf8,
     138                 :                            int                   utf8_len,
     139                 :                            cairo_scaled_font_subsets_glyph_t *subset_glyph);
     140                 : 
     141                 : static void
     142               0 : _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t  *sub_font_glyph,
     143                 :                                 unsigned long            scaled_font_glyph_index)
     144                 : {
     145               0 :     sub_font_glyph->base.hash = scaled_font_glyph_index;
     146               0 : }
     147                 : 
     148                 : static cairo_bool_t
     149               0 : _cairo_sub_font_glyphs_equal (const void *key_a, const void *key_b)
     150                 : {
     151               0 :     const cairo_sub_font_glyph_t *sub_font_glyph_a = key_a;
     152               0 :     const cairo_sub_font_glyph_t *sub_font_glyph_b = key_b;
     153                 : 
     154               0 :     return sub_font_glyph_a->base.hash == sub_font_glyph_b->base.hash;
     155                 : }
     156                 : 
     157                 : static cairo_sub_font_glyph_t *
     158               0 : _cairo_sub_font_glyph_create (unsigned long     scaled_font_glyph_index,
     159                 :                               unsigned int      subset_id,
     160                 :                               unsigned int      subset_glyph_index,
     161                 :                               double            x_advance,
     162                 :                               double            y_advance)
     163                 : {
     164                 :     cairo_sub_font_glyph_t *sub_font_glyph;
     165                 : 
     166               0 :     sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
     167               0 :     if (unlikely (sub_font_glyph == NULL)) {
     168               0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     169               0 :         return NULL;
     170                 :     }
     171                 : 
     172               0 :     _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
     173               0 :     sub_font_glyph->subset_id = subset_id;
     174               0 :     sub_font_glyph->subset_glyph_index = subset_glyph_index;
     175               0 :     sub_font_glyph->x_advance = x_advance;
     176               0 :     sub_font_glyph->y_advance = y_advance;
     177               0 :     sub_font_glyph->is_mapped = FALSE;
     178               0 :     sub_font_glyph->unicode = -1;
     179               0 :     sub_font_glyph->utf8 = NULL;
     180               0 :     sub_font_glyph->utf8_len = 0;
     181                 : 
     182               0 :     return sub_font_glyph;
     183                 : }
     184                 : 
     185                 : static void
     186               0 : _cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
     187                 : {
     188               0 :     if (sub_font_glyph->utf8 != NULL)
     189               0 :         free (sub_font_glyph->utf8);
     190                 : 
     191               0 :     free (sub_font_glyph);
     192               0 : }
     193                 : 
     194                 : static void
     195               0 : _cairo_sub_font_glyph_pluck (void *entry, void *closure)
     196                 : {
     197               0 :     cairo_sub_font_glyph_t *sub_font_glyph = entry;
     198               0 :     cairo_hash_table_t *sub_font_glyphs = closure;
     199                 : 
     200               0 :     _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
     201               0 :     _cairo_sub_font_glyph_destroy (sub_font_glyph);
     202               0 : }
     203                 : 
     204                 : static void
     205               0 : _cairo_sub_font_glyph_collect (void *entry, void *closure)
     206                 : {
     207               0 :     cairo_sub_font_glyph_t *sub_font_glyph = entry;
     208               0 :     cairo_sub_font_collection_t *collection = closure;
     209                 :     unsigned long scaled_font_glyph_index;
     210                 :     unsigned int subset_glyph_index;
     211                 : 
     212               0 :     if (sub_font_glyph->subset_id != collection->subset_id)
     213               0 :         return;
     214                 : 
     215               0 :     scaled_font_glyph_index = sub_font_glyph->base.hash;
     216               0 :     subset_glyph_index = sub_font_glyph->subset_glyph_index;
     217                 : 
     218                 :     /* Ensure we don't exceed the allocated bounds. */
     219               0 :     assert (subset_glyph_index < collection->glyphs_size);
     220                 : 
     221               0 :     collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
     222               0 :     collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
     223               0 :     if (subset_glyph_index > collection->max_glyph)
     224               0 :         collection->max_glyph = subset_glyph_index;
     225                 : 
     226               0 :     collection->num_glyphs++;
     227                 : }
     228                 : 
     229                 : static cairo_bool_t
     230               0 : _cairo_sub_fonts_equal (const void *key_a, const void *key_b)
     231                 : {
     232               0 :     const cairo_sub_font_t *sub_font_a = key_a;
     233               0 :     const cairo_sub_font_t *sub_font_b = key_b;
     234               0 :     cairo_scaled_font_t *a = sub_font_a->scaled_font;
     235               0 :     cairo_scaled_font_t *b = sub_font_b->scaled_font;
     236                 : 
     237               0 :     if (sub_font_a->is_scaled)
     238               0 :         return a == b;
     239                 :     else
     240               0 :         return a->font_face == b->font_face || a->original_font_face == b->original_font_face;
     241                 : }
     242                 : 
     243                 : static void
     244               0 : _cairo_sub_font_init_key (cairo_sub_font_t      *sub_font,
     245                 :                           cairo_scaled_font_t   *scaled_font)
     246                 : {
     247               0 :     if (sub_font->is_scaled)
     248                 :     {
     249               0 :         sub_font->base.hash = (unsigned long) scaled_font;
     250               0 :         sub_font->scaled_font = scaled_font;
     251                 :     }
     252                 :     else
     253                 :     {
     254               0 :         sub_font->base.hash = (unsigned long) scaled_font->font_face;
     255               0 :         sub_font->scaled_font = scaled_font;
     256                 :     }
     257               0 : }
     258                 : 
     259                 : static cairo_status_t
     260               0 : _cairo_sub_font_create (cairo_scaled_font_subsets_t     *parent,
     261                 :                         cairo_scaled_font_t             *scaled_font,
     262                 :                         unsigned int                     font_id,
     263                 :                         int                              max_glyphs_per_subset,
     264                 :                         cairo_bool_t                     is_scaled,
     265                 :                         cairo_bool_t                     is_composite,
     266                 :                         cairo_sub_font_t               **sub_font_out)
     267                 : {
     268                 :     cairo_sub_font_t *sub_font;
     269                 :     cairo_status_t status;
     270                 :     cairo_scaled_font_subsets_glyph_t subset_glyph;
     271                 : 
     272               0 :     sub_font = malloc (sizeof (cairo_sub_font_t));
     273               0 :     if (unlikely (sub_font == NULL))
     274               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     275                 : 
     276               0 :     sub_font->is_scaled = is_scaled;
     277               0 :     sub_font->is_composite = is_composite;
     278               0 :     sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
     279               0 :     _cairo_sub_font_init_key (sub_font, scaled_font);
     280                 : 
     281               0 :     sub_font->parent = parent;
     282               0 :     sub_font->scaled_font = scaled_font;
     283               0 :     sub_font->font_id = font_id;
     284                 : 
     285               0 :     sub_font->current_subset = 0;
     286               0 :     sub_font->num_glyphs_in_current_subset = 0;
     287               0 :     sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
     288                 : 
     289               0 :     sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
     290               0 :     if (unlikely (sub_font->sub_font_glyphs == NULL)) {
     291               0 :         free (sub_font);
     292               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     293                 :     }
     294               0 :     sub_font->next = NULL;
     295                 : 
     296                 :     /* Reserve first glyph in subset for the .notdef glyph except for
     297                 :      * Type 3 fonts */
     298               0 :     if (! is_scaled) {
     299               0 :         status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
     300               0 :         if (unlikely (status)) {
     301               0 :             _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
     302               0 :             free (sub_font);
     303               0 :             return status;
     304                 :         }
     305                 :     }
     306                 : 
     307               0 :     *sub_font_out = sub_font;
     308               0 :     return CAIRO_STATUS_SUCCESS;
     309                 : }
     310                 : 
     311                 : static void
     312               0 : _cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
     313                 : {
     314               0 :     _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
     315                 :                                _cairo_sub_font_glyph_pluck,
     316               0 :                                sub_font->sub_font_glyphs);
     317               0 :     _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
     318               0 :     cairo_scaled_font_destroy (sub_font->scaled_font);
     319               0 :     free (sub_font);
     320               0 : }
     321                 : 
     322                 : static void
     323               0 : _cairo_sub_font_pluck (void *entry, void *closure)
     324                 : {
     325               0 :     cairo_sub_font_t *sub_font = entry;
     326               0 :     cairo_hash_table_t *sub_fonts = closure;
     327                 : 
     328               0 :     _cairo_hash_table_remove (sub_fonts, &sub_font->base);
     329               0 :     _cairo_sub_font_destroy (sub_font);
     330               0 : }
     331                 : 
     332                 : static cairo_status_t
     333               0 : _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
     334                 :                                       cairo_scaled_font_t    *scaled_font,
     335                 :                                       unsigned long           scaled_font_glyph_index)
     336                 : {
     337                 :     uint32_t unicode;
     338                 :     char buf[8];
     339                 :     int len;
     340                 :     cairo_status_t status;
     341                 : 
     342                 :     /* Do a reverse lookup on the glyph index. unicode is -1 if the
     343                 :      * index could not be mapped to a unicode character. */
     344               0 :     unicode = -1;
     345               0 :     status = _cairo_truetype_index_to_ucs4 (scaled_font,
     346                 :                                             scaled_font_glyph_index,
     347                 :                                             &unicode);
     348               0 :     if (_cairo_status_is_error (status))
     349               0 :         return status;
     350                 : 
     351               0 :     if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) {
     352               0 :         status = scaled_font->backend->index_to_ucs4 (scaled_font,
     353                 :                                                       scaled_font_glyph_index,
     354                 :                                                       &unicode);
     355               0 :         if (unlikely (status))
     356               0 :             return status;
     357                 :     }
     358                 : 
     359               0 :     sub_font_glyph->unicode = unicode;
     360               0 :     sub_font_glyph->utf8 = NULL;
     361               0 :     sub_font_glyph->utf8_len = 0;
     362               0 :     if (unicode != (uint32_t) -1) {
     363               0 :         len = _cairo_ucs4_to_utf8 (unicode, buf);
     364               0 :         if (len > 0) {
     365               0 :             sub_font_glyph->utf8 = malloc (len + 1);
     366               0 :             if (unlikely (sub_font_glyph->utf8 == NULL))
     367               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     368                 : 
     369               0 :             memcpy (sub_font_glyph->utf8, buf, len);
     370               0 :             sub_font_glyph->utf8[len] = 0;
     371               0 :             sub_font_glyph->utf8_len = len;
     372                 :         }
     373                 :     }
     374                 : 
     375               0 :     return CAIRO_STATUS_SUCCESS;
     376                 : }
     377                 : 
     378                 : static cairo_status_t
     379               0 : _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
     380                 :                                       const char             *utf8,
     381                 :                                       int                     utf8_len,
     382                 :                                       cairo_bool_t           *is_mapped)
     383                 : {
     384               0 :     *is_mapped = FALSE;
     385                 : 
     386               0 :     if (utf8_len < 0)
     387               0 :         return CAIRO_STATUS_SUCCESS;
     388                 : 
     389               0 :     if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
     390               0 :         utf8_len--;
     391                 : 
     392               0 :     if (utf8 != NULL && utf8_len != 0) {
     393               0 :         if (sub_font_glyph->utf8 != NULL) {
     394               0 :             if (utf8_len == sub_font_glyph->utf8_len &&
     395               0 :                 memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
     396                 :             {
     397                 :                 /* Requested utf8 mapping matches the existing mapping */
     398               0 :                 *is_mapped = TRUE;
     399                 :             }
     400                 :         } else {
     401                 :             /* No existing mapping. Use the requested mapping */
     402               0 :             sub_font_glyph->utf8 = malloc (utf8_len + 1);
     403               0 :             if (unlikely (sub_font_glyph->utf8 == NULL))
     404               0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     405                 : 
     406               0 :             memcpy (sub_font_glyph->utf8, utf8, utf8_len);
     407               0 :             sub_font_glyph->utf8[utf8_len] = 0;
     408               0 :             sub_font_glyph->utf8_len = utf8_len;
     409               0 :             *is_mapped = TRUE;
     410                 :         }
     411                 :     }
     412                 : 
     413               0 :     return CAIRO_STATUS_SUCCESS;
     414                 : }
     415                 : 
     416                 : static cairo_int_status_t
     417               0 : _cairo_sub_font_lookup_glyph (cairo_sub_font_t                  *sub_font,
     418                 :                               unsigned long                      scaled_font_glyph_index,
     419                 :                               const char                        *utf8,
     420                 :                               int                                utf8_len,
     421                 :                               cairo_scaled_font_subsets_glyph_t *subset_glyph)
     422                 : {
     423                 :     cairo_sub_font_glyph_t key, *sub_font_glyph;
     424                 :     cairo_int_status_t status;
     425                 : 
     426               0 :     _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
     427               0 :     sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
     428                 :                                               &key.base);
     429               0 :     if (sub_font_glyph != NULL) {
     430               0 :         subset_glyph->font_id = sub_font->font_id;
     431               0 :         subset_glyph->subset_id = sub_font_glyph->subset_id;
     432               0 :         subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
     433               0 :         subset_glyph->is_scaled = sub_font->is_scaled;
     434               0 :         subset_glyph->is_composite = sub_font->is_composite;
     435               0 :         subset_glyph->x_advance = sub_font_glyph->x_advance;
     436               0 :         subset_glyph->y_advance = sub_font_glyph->y_advance;
     437               0 :         status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
     438                 :                                                        utf8, utf8_len,
     439                 :                                                        &subset_glyph->utf8_is_mapped);
     440               0 :         subset_glyph->unicode = sub_font_glyph->unicode;
     441                 : 
     442               0 :         return status;
     443                 :     }
     444                 : 
     445               0 :     return CAIRO_INT_STATUS_UNSUPPORTED;
     446                 : }
     447                 : 
     448                 : static cairo_status_t
     449               0 : _cairo_sub_font_map_glyph (cairo_sub_font_t     *sub_font,
     450                 :                            unsigned long         scaled_font_glyph_index,
     451                 :                            const char           *utf8,
     452                 :                            int                   utf8_len,
     453                 :                            cairo_scaled_font_subsets_glyph_t *subset_glyph)
     454                 : {
     455                 :     cairo_sub_font_glyph_t key, *sub_font_glyph;
     456                 :     cairo_status_t status;
     457                 : 
     458               0 :     _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
     459               0 :     sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
     460                 :                                                &key.base);
     461               0 :     if (sub_font_glyph == NULL) {
     462                 :         cairo_scaled_glyph_t *scaled_glyph;
     463                 : 
     464               0 :         if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
     465                 :         {
     466                 :             cairo_scaled_font_subsets_glyph_t tmp_subset_glyph;
     467                 : 
     468               0 :             sub_font->current_subset++;
     469               0 :             sub_font->num_glyphs_in_current_subset = 0;
     470                 : 
     471                 :             /* Reserve first glyph in subset for the .notdef glyph
     472                 :              * except for Type 3 fonts */
     473               0 :             if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) {
     474               0 :                 status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph);
     475               0 :                 if (unlikely (status))
     476               0 :                     return status;
     477                 :             }
     478                 :         }
     479                 : 
     480               0 :         _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
     481               0 :         status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
     482                 :                                              scaled_font_glyph_index,
     483                 :                                              CAIRO_SCALED_GLYPH_INFO_METRICS,
     484                 :                                              &scaled_glyph);
     485               0 :         assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
     486               0 :         if (unlikely (status)) {
     487               0 :             _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
     488               0 :             return status;
     489                 :         }
     490                 : 
     491               0 :         sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
     492               0 :                                                        sub_font->current_subset,
     493               0 :                                                        sub_font->num_glyphs_in_current_subset,
     494               0 :                                                        scaled_glyph->metrics.x_advance,
     495               0 :                                                        scaled_glyph->metrics.y_advance);
     496               0 :         _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
     497                 : 
     498               0 :         if (unlikely (sub_font_glyph == NULL))
     499               0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     500                 : 
     501               0 :         status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
     502                 :                                                        sub_font->scaled_font,
     503                 :                                                        scaled_font_glyph_index);
     504               0 :         if (unlikely (status)) {
     505               0 :             _cairo_sub_font_glyph_destroy (sub_font_glyph);
     506               0 :             return status;
     507                 :         }
     508                 : 
     509               0 :         status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
     510               0 :         if (unlikely (status)) {
     511               0 :             _cairo_sub_font_glyph_destroy (sub_font_glyph);
     512               0 :             return status;
     513                 :         }
     514                 : 
     515               0 :         sub_font->num_glyphs_in_current_subset++;
     516                 : 
     517               0 :         if (sub_font->is_scaled) {
     518               0 :             if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used)
     519               0 :                 sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset;
     520                 :         } else {
     521               0 :             if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used)
     522               0 :                 sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset;
     523                 :         }
     524                 :     }
     525                 : 
     526               0 :     subset_glyph->font_id = sub_font->font_id;
     527               0 :     subset_glyph->subset_id = sub_font_glyph->subset_id;
     528               0 :     subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
     529               0 :     subset_glyph->is_scaled = sub_font->is_scaled;
     530               0 :     subset_glyph->is_composite = sub_font->is_composite;
     531               0 :     subset_glyph->x_advance = sub_font_glyph->x_advance;
     532               0 :     subset_glyph->y_advance = sub_font_glyph->y_advance;
     533               0 :     status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
     534                 :                                                    utf8, utf8_len,
     535                 :                                                    &subset_glyph->utf8_is_mapped);
     536               0 :     subset_glyph->unicode = sub_font_glyph->unicode;
     537                 : 
     538               0 :     return status;
     539                 : }
     540                 : 
     541                 : static void
     542               0 : _cairo_sub_font_collect (void *entry, void *closure)
     543                 : {
     544               0 :     cairo_sub_font_t *sub_font = entry;
     545               0 :     cairo_sub_font_collection_t *collection = closure;
     546                 :     cairo_scaled_font_subset_t subset;
     547                 :     int i;
     548                 :     unsigned int j;
     549                 : 
     550               0 :     if (collection->status)
     551               0 :         return;
     552                 : 
     553               0 :     collection->status = sub_font->scaled_font->status;
     554               0 :     if (collection->status)
     555               0 :         return;
     556                 : 
     557               0 :     for (i = 0; i <= sub_font->current_subset; i++) {
     558               0 :         collection->subset_id = i;
     559               0 :         collection->num_glyphs = 0;
     560               0 :         collection->max_glyph = 0;
     561                 : 
     562               0 :         _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
     563                 :                                    _cairo_sub_font_glyph_collect, collection);
     564               0 :         if (collection->status)
     565               0 :             break;
     566               0 :         if (collection->num_glyphs == 0)
     567               0 :             continue;
     568                 : 
     569                 :         /* Ensure the resulting array has no uninitialized holes */
     570               0 :         assert (collection->num_glyphs == collection->max_glyph + 1);
     571                 : 
     572               0 :         subset.scaled_font = sub_font->scaled_font;
     573               0 :         subset.is_composite = sub_font->is_composite;
     574               0 :         subset.is_scaled = sub_font->is_scaled;
     575               0 :         subset.font_id = sub_font->font_id;
     576               0 :         subset.subset_id = i;
     577               0 :         subset.glyphs = collection->glyphs;
     578               0 :         subset.utf8 = collection->utf8;
     579               0 :         subset.num_glyphs = collection->num_glyphs;
     580               0 :         subset.glyph_names = NULL;
     581                 :         /* No need to check for out of memory here. If to_unicode is NULL, the PDF
     582                 :          * surface does not emit an ToUnicode stream */
     583               0 :         subset.to_unicode = _cairo_malloc_ab (collection->num_glyphs, sizeof (unsigned long));
     584               0 :         if (subset.to_unicode) {
     585               0 :             for (j = 0; j < collection->num_glyphs; j++) {
     586                 :                 /* default unicode character required when mapping fails */
     587               0 :                 subset.to_unicode[j] = 0xfffd;
     588                 :             }
     589                 :         }
     590               0 :         collection->status = (collection->font_subset_callback) (&subset,
     591                 :                                             collection->font_subset_callback_closure);
     592                 : 
     593               0 :         if (subset.to_unicode != NULL)
     594               0 :             free (subset.to_unicode);
     595                 : 
     596               0 :         if (subset.glyph_names != NULL) {
     597               0 :             for (j = 0; j < collection->num_glyphs; j++)
     598               0 :                 free (subset.glyph_names[j]);
     599               0 :             free (subset.glyph_names);
     600                 :         }
     601                 : 
     602               0 :         if (collection->status)
     603               0 :             break;
     604                 :     }
     605                 : }
     606                 : 
     607                 : static cairo_scaled_font_subsets_t *
     608               0 : _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
     609                 : {
     610                 :     cairo_scaled_font_subsets_t *subsets;
     611                 : 
     612               0 :     subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
     613               0 :     if (unlikely (subsets == NULL)) {
     614               0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     615               0 :         return NULL;
     616                 :     }
     617                 : 
     618               0 :     subsets->type = type;
     619               0 :     subsets->max_glyphs_per_unscaled_subset_used = 0;
     620               0 :     subsets->max_glyphs_per_scaled_subset_used = 0;
     621               0 :     subsets->num_sub_fonts = 0;
     622                 : 
     623               0 :     subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
     624               0 :     if (! subsets->unscaled_sub_fonts) {
     625               0 :         free (subsets);
     626               0 :         return NULL;
     627                 :     }
     628               0 :     subsets->unscaled_sub_fonts_list = NULL;
     629               0 :     subsets->unscaled_sub_fonts_list_end = NULL;
     630                 : 
     631               0 :     subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
     632               0 :     if (! subsets->scaled_sub_fonts) {
     633               0 :         _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
     634               0 :         free (subsets);
     635               0 :         return NULL;
     636                 :     }
     637               0 :     subsets->scaled_sub_fonts_list = NULL;
     638               0 :     subsets->scaled_sub_fonts_list_end = NULL;
     639                 : 
     640               0 :     return subsets;
     641                 : }
     642                 : 
     643                 : cairo_scaled_font_subsets_t *
     644               0 : _cairo_scaled_font_subsets_create_scaled (void)
     645                 : {
     646               0 :     return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
     647                 : }
     648                 : 
     649                 : cairo_scaled_font_subsets_t *
     650               0 : _cairo_scaled_font_subsets_create_simple (void)
     651                 : {
     652               0 :     return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
     653                 : }
     654                 : 
     655                 : cairo_scaled_font_subsets_t *
     656               0 : _cairo_scaled_font_subsets_create_composite (void)
     657                 : {
     658               0 :     return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
     659                 : }
     660                 : 
     661                 : void
     662               0 : _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
     663                 : {
     664               0 :     _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
     665               0 :     _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
     666                 : 
     667               0 :     _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
     668               0 :     _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
     669                 : 
     670               0 :     free (subsets);
     671               0 : }
     672                 : 
     673                 : cairo_status_t
     674               0 : _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t       *subsets,
     675                 :                                       cairo_scaled_font_t               *scaled_font,
     676                 :                                       unsigned long                      scaled_font_glyph_index,
     677                 :                                       const char *                       utf8,
     678                 :                                       int                                utf8_len,
     679                 :                                       cairo_scaled_font_subsets_glyph_t *subset_glyph)
     680                 : {
     681                 :     cairo_sub_font_t key, *sub_font;
     682                 :     cairo_scaled_glyph_t *scaled_glyph;
     683                 :     cairo_font_face_t *font_face;
     684                 :     cairo_matrix_t identity;
     685                 :     cairo_font_options_t font_options;
     686                 :     cairo_scaled_font_t *unscaled_font;
     687                 :     cairo_status_t status;
     688                 :     int max_glyphs;
     689                 :     cairo_bool_t type1_font;
     690                 : 
     691                 :     /* Lookup glyph in unscaled subsets */
     692               0 :     if (subsets->type != CAIRO_SUBSETS_SCALED) {
     693               0 :         key.is_scaled = FALSE;
     694               0 :         _cairo_sub_font_init_key (&key, scaled_font);
     695               0 :         sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
     696                 :                                              &key.base);
     697               0 :         if (sub_font != NULL) {
     698               0 :             status = _cairo_sub_font_lookup_glyph (sub_font,
     699                 :                                                    scaled_font_glyph_index,
     700                 :                                                    utf8, utf8_len,
     701                 :                                                    subset_glyph);
     702               0 :             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
     703               0 :                 return status;
     704                 :         }
     705                 :     }
     706                 : 
     707                 :     /* Lookup glyph in scaled subsets */
     708               0 :     key.is_scaled = TRUE;
     709               0 :     _cairo_sub_font_init_key (&key, scaled_font);
     710               0 :     sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
     711                 :                                          &key.base);
     712               0 :     if (sub_font != NULL) {
     713               0 :         status = _cairo_sub_font_lookup_glyph (sub_font,
     714                 :                                                scaled_font_glyph_index,
     715                 :                                                utf8, utf8_len,
     716                 :                                                subset_glyph);
     717               0 :         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
     718               0 :             return status;
     719                 :     }
     720                 : 
     721                 :     /* Glyph not found. Determine whether the glyph is outline or
     722                 :      * bitmap and add to the appropriate subset.
     723                 :      *
     724                 :      * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
     725                 :      * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
     726                 :      * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
     727                 :      * empty glyphs in this case so we can put the glyph in a unscaled
     728                 :      * subset. */
     729               0 :     if (scaled_font_glyph_index == 0 ||
     730               0 :         _cairo_font_face_is_user (scaled_font->font_face)) {
     731               0 :         status = CAIRO_STATUS_SUCCESS;
     732                 :     } else {
     733               0 :         _cairo_scaled_font_freeze_cache (scaled_font);
     734               0 :         status = _cairo_scaled_glyph_lookup (scaled_font,
     735                 :                                              scaled_font_glyph_index,
     736                 :                                              CAIRO_SCALED_GLYPH_INFO_PATH,
     737                 :                                              &scaled_glyph);
     738               0 :         _cairo_scaled_font_thaw_cache (scaled_font);
     739                 :     }
     740               0 :     if (_cairo_status_is_error (status))
     741               0 :         return status;
     742                 : 
     743               0 :     if (status == CAIRO_STATUS_SUCCESS &&
     744               0 :         subsets->type != CAIRO_SUBSETS_SCALED &&
     745               0 :         ! _cairo_font_face_is_user (scaled_font->font_face))
     746                 :     {
     747                 :         /* Path available. Add to unscaled subset. */
     748               0 :         key.is_scaled = FALSE;
     749               0 :         _cairo_sub_font_init_key (&key, scaled_font);
     750               0 :         sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
     751                 :                                              &key.base);
     752               0 :         if (sub_font == NULL) {
     753               0 :             font_face = cairo_scaled_font_get_font_face (scaled_font);
     754               0 :             cairo_matrix_init_identity (&identity);
     755               0 :             _cairo_font_options_init_default (&font_options);
     756               0 :             cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
     757               0 :             cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
     758               0 :             unscaled_font = cairo_scaled_font_create (font_face,
     759                 :                                                       &identity,
     760                 :                                                       &identity,
     761                 :                                                       &font_options);
     762               0 :             if (unlikely (unscaled_font->status))
     763               0 :                 return unscaled_font->status;
     764                 : 
     765               0 :             subset_glyph->is_scaled = FALSE;
     766               0 :             type1_font = FALSE;
     767                 : #if CAIRO_HAS_FT_FONT
     768               0 :             type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
     769                 : #endif
     770               0 :             if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
     771               0 :                 max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
     772               0 :                 subset_glyph->is_composite = TRUE;
     773                 :             } else {
     774               0 :                 max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
     775               0 :                 subset_glyph->is_composite = FALSE;
     776                 :             }
     777                 : 
     778               0 :             status = _cairo_sub_font_create (subsets,
     779                 :                                              unscaled_font,
     780               0 :                                              subsets->num_sub_fonts,
     781                 :                                              max_glyphs,
     782                 :                                              subset_glyph->is_scaled,
     783                 :                                              subset_glyph->is_composite,
     784                 :                                              &sub_font);
     785                 : 
     786               0 :             if (unlikely (status)) {
     787               0 :                 cairo_scaled_font_destroy (unscaled_font);
     788               0 :                 return status;
     789                 :             }
     790                 : 
     791               0 :             status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
     792               0 :                                                &sub_font->base);
     793                 : 
     794               0 :             if (unlikely (status)) {
     795               0 :                 _cairo_sub_font_destroy (sub_font);
     796               0 :                 return status;
     797                 :             }
     798               0 :             if (!subsets->unscaled_sub_fonts_list)
     799               0 :                 subsets->unscaled_sub_fonts_list = sub_font;
     800                 :             else
     801               0 :                 subsets->unscaled_sub_fonts_list_end->next = sub_font;
     802               0 :             subsets->unscaled_sub_fonts_list_end = sub_font;
     803               0 :             subsets->num_sub_fonts++;
     804                 :         }
     805                 :     } else {
     806                 :         /* No path available. Add to scaled subset. */
     807               0 :         key.is_scaled = TRUE;
     808               0 :         _cairo_sub_font_init_key (&key, scaled_font);
     809               0 :         sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
     810                 :                                              &key.base);
     811               0 :         if (sub_font == NULL) {
     812               0 :             subset_glyph->is_scaled = TRUE;
     813               0 :             subset_glyph->is_composite = FALSE;
     814               0 :             if (subsets->type == CAIRO_SUBSETS_SCALED)
     815               0 :                 max_glyphs = INT_MAX;
     816                 :             else
     817               0 :                 max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
     818                 : 
     819               0 :             status = _cairo_sub_font_create (subsets,
     820                 :                                              cairo_scaled_font_reference (scaled_font),
     821               0 :                                              subsets->num_sub_fonts,
     822                 :                                              max_glyphs,
     823                 :                                              subset_glyph->is_scaled,
     824                 :                                              subset_glyph->is_composite,
     825                 :                                              &sub_font);
     826               0 :             if (unlikely (status)) {
     827               0 :                 cairo_scaled_font_destroy (scaled_font);
     828               0 :                 return status;
     829                 :             }
     830                 : 
     831               0 :             status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
     832               0 :                                                &sub_font->base);
     833               0 :             if (unlikely (status)) {
     834               0 :                 _cairo_sub_font_destroy (sub_font);
     835               0 :                 return status;
     836                 :             }
     837               0 :             if (!subsets->scaled_sub_fonts_list)
     838               0 :                 subsets->scaled_sub_fonts_list = sub_font;
     839                 :             else
     840               0 :                 subsets->scaled_sub_fonts_list_end->next = sub_font;
     841               0 :             subsets->scaled_sub_fonts_list_end = sub_font;
     842               0 :             subsets->num_sub_fonts++;
     843                 :         }
     844                 :     }
     845                 : 
     846               0 :     return _cairo_sub_font_map_glyph (sub_font,
     847                 :                                       scaled_font_glyph_index,
     848                 :                                       utf8, utf8_len,
     849                 :                                       subset_glyph);
     850                 : }
     851                 : 
     852                 : static cairo_status_t
     853               0 : _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t              *font_subsets,
     854                 :                                              cairo_scaled_font_subset_callback_func_t  font_subset_callback,
     855                 :                                              void                                     *closure,
     856                 :                                              cairo_subsets_foreach_type_t              type)
     857                 : {
     858                 :     cairo_sub_font_collection_t collection;
     859                 :     cairo_sub_font_t *sub_font;
     860                 :     cairo_bool_t is_scaled, is_user;
     861                 : 
     862               0 :     is_scaled = FALSE;
     863               0 :     is_user = FALSE;
     864                 : 
     865               0 :     if (type == CAIRO_SUBSETS_FOREACH_USER)
     866               0 :         is_user = TRUE;
     867                 : 
     868               0 :     if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
     869                 :         type == CAIRO_SUBSETS_FOREACH_USER)
     870                 :     {
     871               0 :         is_scaled = TRUE;
     872                 :     }
     873                 : 
     874               0 :     if (is_scaled)
     875               0 :         collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
     876                 :     else
     877               0 :         collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
     878                 : 
     879               0 :     if (! collection.glyphs_size)
     880               0 :         return CAIRO_STATUS_SUCCESS;
     881                 : 
     882               0 :     collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
     883               0 :     collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
     884               0 :     if (unlikely (collection.glyphs == NULL || collection.utf8 == NULL)) {
     885               0 :         if (collection.glyphs != NULL)
     886               0 :             free (collection.glyphs);
     887               0 :         if (collection.utf8 != NULL)
     888               0 :             free (collection.utf8);
     889                 : 
     890               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     891                 :     }
     892                 : 
     893               0 :     collection.font_subset_callback = font_subset_callback;
     894               0 :     collection.font_subset_callback_closure = closure;
     895               0 :     collection.status = CAIRO_STATUS_SUCCESS;
     896                 : 
     897               0 :     if (is_scaled)
     898               0 :         sub_font = font_subsets->scaled_sub_fonts_list;
     899                 :     else
     900               0 :         sub_font = font_subsets->unscaled_sub_fonts_list;
     901                 : 
     902               0 :     while (sub_font) {
     903               0 :         if (sub_font->is_user == is_user)
     904               0 :             _cairo_sub_font_collect (sub_font, &collection);
     905                 : 
     906               0 :         sub_font = sub_font->next;
     907                 :     }
     908               0 :     free (collection.utf8);
     909               0 :     free (collection.glyphs);
     910                 : 
     911               0 :     return collection.status;
     912                 : }
     913                 : 
     914                 : cairo_status_t
     915               0 : _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t              *font_subsets,
     916                 :                                            cairo_scaled_font_subset_callback_func_t  font_subset_callback,
     917                 :                                            void                                     *closure)
     918                 : {
     919               0 :     return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
     920                 :                                                         font_subset_callback,
     921                 :                                                         closure,
     922                 :                                                         CAIRO_SUBSETS_FOREACH_SCALED);
     923                 : }
     924                 : 
     925                 : cairo_status_t
     926               0 : _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t            *font_subsets,
     927                 :                                            cairo_scaled_font_subset_callback_func_t  font_subset_callback,
     928                 :                                            void                                     *closure)
     929                 : {
     930               0 :     return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
     931                 :                                                         font_subset_callback,
     932                 :                                                         closure,
     933                 :                                                         CAIRO_SUBSETS_FOREACH_UNSCALED);
     934                 : }
     935                 : 
     936                 : cairo_status_t
     937               0 : _cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t              *font_subsets,
     938                 :                                          cairo_scaled_font_subset_callback_func_t  font_subset_callback,
     939                 :                                          void                                     *closure)
     940                 : {
     941               0 :     return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
     942                 :                                                         font_subset_callback,
     943                 :                                                         closure,
     944                 :                                                         CAIRO_SUBSETS_FOREACH_USER);
     945                 : }
     946                 : 
     947                 : static cairo_bool_t
     948               0 : _cairo_string_equal (const void *key_a, const void *key_b)
     949                 : {
     950               0 :     const cairo_string_entry_t *a = key_a;
     951               0 :     const cairo_string_entry_t *b = key_b;
     952                 : 
     953               0 :     if (strcmp (a->string, b->string) == 0)
     954               0 :         return TRUE;
     955                 :     else
     956               0 :         return FALSE;
     957                 : }
     958                 : 
     959                 : static void
     960               0 : _cairo_string_init_key (cairo_string_entry_t *key, char *s)
     961                 : {
     962               0 :     unsigned long sum = 0;
     963                 :     unsigned int i;
     964                 : 
     965               0 :     for (i = 0; i < strlen(s); i++)
     966               0 :         sum += s[i];
     967               0 :     key->base.hash = sum;
     968               0 :     key->string = s;
     969               0 : }
     970                 : 
     971                 : static cairo_status_t
     972               0 : create_string_entry (char *s, cairo_string_entry_t **entry)
     973                 : {
     974               0 :     *entry = malloc (sizeof (cairo_string_entry_t));
     975               0 :     if (unlikely (*entry == NULL))
     976               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     977                 : 
     978               0 :     _cairo_string_init_key (*entry, s);
     979                 : 
     980               0 :     return CAIRO_STATUS_SUCCESS;
     981                 : }
     982                 : 
     983                 : static void
     984               0 : _pluck_entry (void *entry, void *closure)
     985                 : {
     986               0 :     _cairo_hash_table_remove (closure, entry);
     987               0 :     free (entry);
     988               0 : }
     989                 : 
     990                 : cairo_int_status_t
     991               0 : _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
     992                 : {
     993                 :     unsigned int i;
     994                 :     cairo_hash_table_t *names;
     995                 :     cairo_string_entry_t key, *entry;
     996                 :     char buf[30];
     997                 :     char *utf8;
     998                 :     uint16_t *utf16;
     999                 :     int utf16_len;
    1000               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
    1001                 : 
    1002               0 :     names = _cairo_hash_table_create (_cairo_string_equal);
    1003               0 :     if (unlikely (names == NULL))
    1004               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1005                 : 
    1006               0 :     subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
    1007               0 :     if (unlikely (subset->glyph_names == NULL)) {
    1008               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1009               0 :         goto CLEANUP_HASH;
    1010                 :     }
    1011                 : 
    1012               0 :     i = 0;
    1013               0 :     if (! subset->is_scaled) {
    1014               0 :         subset->glyph_names[0] = strdup (".notdef");
    1015               0 :         if (unlikely (subset->glyph_names[0] == NULL)) {
    1016               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1017               0 :             goto CLEANUP_HASH;
    1018                 :         }
    1019                 : 
    1020               0 :         status = create_string_entry (subset->glyph_names[0], &entry);
    1021               0 :         if (unlikely (status))
    1022               0 :             goto CLEANUP_HASH;
    1023                 : 
    1024               0 :         status = _cairo_hash_table_insert (names, &entry->base);
    1025               0 :         if (unlikely (status)) {
    1026               0 :             free (entry);
    1027               0 :             goto CLEANUP_HASH;
    1028                 :         }
    1029               0 :         i++;
    1030                 :     }
    1031                 : 
    1032               0 :     for (; i < subset->num_glyphs; i++) {
    1033               0 :         utf8 = subset->utf8[i];
    1034               0 :         utf16 = NULL;
    1035               0 :         utf16_len = 0;
    1036               0 :         if (utf8 && *utf8) {
    1037               0 :             status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
    1038               0 :             if (unlikely (status))
    1039               0 :                 goto CLEANUP_HASH;
    1040                 :         }
    1041                 : 
    1042               0 :         if (utf16_len == 1) {
    1043               0 :             snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
    1044               0 :             _cairo_string_init_key (&key, buf);
    1045               0 :             entry = _cairo_hash_table_lookup (names, &key.base);
    1046               0 :             if (entry != NULL)
    1047               0 :                 snprintf (buf, sizeof (buf), "g%d", i);
    1048                 :         } else {
    1049               0 :             snprintf (buf, sizeof (buf), "g%d", i);
    1050                 :         }
    1051               0 :         if (utf16)
    1052               0 :             free (utf16);
    1053                 : 
    1054               0 :         subset->glyph_names[i] = strdup (buf);
    1055               0 :         if (unlikely (subset->glyph_names[i] == NULL)) {
    1056               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1057               0 :             goto CLEANUP_HASH;
    1058                 :         }
    1059                 : 
    1060               0 :         status = create_string_entry (subset->glyph_names[i], &entry);
    1061               0 :         if (unlikely (status))
    1062               0 :             goto CLEANUP_HASH;
    1063                 : 
    1064               0 :         status = _cairo_hash_table_insert (names, &entry->base);
    1065               0 :         if (unlikely (status)) {
    1066               0 :             free (entry);
    1067               0 :             goto CLEANUP_HASH;
    1068                 :         }
    1069                 :     }
    1070                 : 
    1071                 : CLEANUP_HASH:
    1072               0 :     _cairo_hash_table_foreach (names, _pluck_entry, names);
    1073               0 :     _cairo_hash_table_destroy (names);
    1074                 : 
    1075               0 :     if (likely (status == CAIRO_STATUS_SUCCESS))
    1076               0 :         return CAIRO_STATUS_SUCCESS;
    1077                 : 
    1078               0 :     if (subset->glyph_names != NULL) {
    1079               0 :         for (i = 0; i < subset->num_glyphs; i++) {
    1080               0 :             if (subset->glyph_names[i] != NULL)
    1081               0 :                 free (subset->glyph_names[i]);
    1082                 :         }
    1083                 : 
    1084               0 :         free (subset->glyph_names);
    1085               0 :         subset->glyph_names = NULL;
    1086                 :     }
    1087                 : 
    1088               0 :     return status;
    1089                 : }
    1090                 : 
    1091                 : #endif /* CAIRO_HAS_FONT_SUBSET */

Generated by: LCOV version 1.7