LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-scaled-font-subsets.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 493 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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.13