LCOV - app.info - gfx/cairo/cairo/src/cairo-scaled-font-subsets.c

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-07-07 | 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