LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-truetype-subset.c (source / functions) Found Hit Coverage
Test: app.info Lines: 678 0 0.0 %
Date: 2012-06-02 Functions: 30 0 0.0 %

       1                 : /* cairo - a vector graphics library with display and print output
       2                 :  *
       3                 :  * Copyright © 2004 Red Hat, Inc
       4                 :  *
       5                 :  * This library is free software; you can redistribute it and/or
       6                 :  * modify it either under the terms of the GNU Lesser General Public
       7                 :  * License version 2.1 as published by the Free Software Foundation
       8                 :  * (the "LGPL") or, at your option, under the terms of the Mozilla
       9                 :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      10                 :  * notice, a recipient may use your version of this file under either
      11                 :  * the MPL or the LGPL.
      12                 :  *
      13                 :  * You should have received a copy of the LGPL along with this library
      14                 :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      15                 :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      16                 :  * You should have received a copy of the MPL along with this library
      17                 :  * in the file COPYING-MPL-1.1
      18                 :  *
      19                 :  * The contents of this file are subject to the Mozilla Public License
      20                 :  * Version 1.1 (the "License"); you may not use this file except in
      21                 :  * compliance with the License. You may obtain a copy of the License at
      22                 :  * http://www.mozilla.org/MPL/
      23                 :  *
      24                 :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      25                 :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      26                 :  * the specific language governing rights and limitations.
      27                 :  *
      28                 :  * The Original Code is the cairo graphics library.
      29                 :  *
      30                 :  * The Initial Developer of the Original Code is Red Hat, Inc.
      31                 :  *
      32                 :  * Contributor(s):
      33                 :  *      Kristian Høgsberg <krh@redhat.com>
      34                 :  *      Adrian Johnson <ajohnson@redneon.com>
      35                 :  */
      36                 : 
      37                 : /*
      38                 :  * Useful links:
      39                 :  * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html
      40                 :  * http://www.microsoft.com/typography/specs/default.htm
      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-truetype-subset-private.h"
      51                 : 
      52                 : 
      53                 : typedef struct subset_glyph subset_glyph_t;
      54                 : struct subset_glyph {
      55                 :     int parent_index;
      56                 :     unsigned long location;
      57                 : };
      58                 : 
      59                 : typedef struct _cairo_truetype_font cairo_truetype_font_t;
      60                 : 
      61                 : typedef struct table table_t;
      62                 : struct table {
      63                 :     unsigned long tag;
      64                 :     cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag);
      65                 :     int pos; /* position in the font directory */
      66                 : };
      67                 : 
      68                 : struct _cairo_truetype_font {
      69                 : 
      70                 :     cairo_scaled_font_subset_t *scaled_font_subset;
      71                 : 
      72                 :     table_t truetype_tables[10];
      73                 :     int num_tables;
      74                 : 
      75                 :     struct {
      76                 :         char *font_name;
      77                 :         char *ps_name;
      78                 :         unsigned int num_glyphs;
      79                 :         int *widths;
      80                 :         long x_min, y_min, x_max, y_max;
      81                 :         long ascent, descent;
      82                 :         int  units_per_em;
      83                 :     } base;
      84                 : 
      85                 :     subset_glyph_t *glyphs;
      86                 :     const cairo_scaled_font_backend_t *backend;
      87                 :     int num_glyphs_in_face;
      88                 :     int checksum_index;
      89                 :     cairo_array_t output;
      90                 :     cairo_array_t string_offsets;
      91                 :     unsigned long last_offset;
      92                 :     unsigned long last_boundary;
      93                 :     int *parent_to_subset;
      94                 :     cairo_status_t status;
      95                 : 
      96                 : };
      97                 : 
      98                 : /*
      99                 :  * Test that the structs we define for TrueType tables have the
     100                 :  * correct size, ie. they are not padded.
     101                 :  */
     102                 : #define check(T, S) COMPILE_TIME_ASSERT (sizeof (T) == (S))
     103                 : check (tt_head_t,       54);
     104                 : check (tt_hhea_t,       36);
     105                 : check (tt_maxp_t,       32);
     106                 : check (tt_name_record_t, 12);
     107                 : check (tt_name_t,       18);
     108                 : check (tt_name_t,       18);
     109                 : check (tt_composite_glyph_t, 16);
     110                 : check (tt_glyph_data_t, 26);
     111                 : #undef check
     112                 : 
     113                 : static cairo_status_t
     114                 : cairo_truetype_font_use_glyph (cairo_truetype_font_t        *font,
     115                 :                                unsigned short                glyph,
     116                 :                                unsigned short               *out);
     117                 : 
     118                 : #define SFNT_VERSION                    0x00010000
     119                 : #define SFNT_STRING_MAX_LENGTH  65535
     120                 : 
     121                 : static cairo_status_t
     122               0 : _cairo_truetype_font_set_error (cairo_truetype_font_t *font,
     123                 :                                 cairo_status_t status)
     124                 : {
     125               0 :     if (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED)
     126               0 :         return status;
     127                 : 
     128               0 :     _cairo_status_set_error (&font->status, status);
     129                 : 
     130               0 :     return _cairo_error (status);
     131                 : }
     132                 : 
     133                 : static cairo_status_t
     134               0 : _cairo_truetype_font_create (cairo_scaled_font_subset_t  *scaled_font_subset,
     135                 :                              cairo_truetype_font_t      **font_return)
     136                 : {
     137                 :     cairo_status_t status;
     138                 :     cairo_truetype_font_t *font;
     139                 :     const cairo_scaled_font_backend_t *backend;
     140                 :     tt_head_t head;
     141                 :     tt_hhea_t hhea;
     142                 :     tt_maxp_t maxp;
     143                 :     unsigned long size;
     144                 : 
     145               0 :     backend = scaled_font_subset->scaled_font->backend;
     146               0 :     if (!backend->load_truetype_table)
     147               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
     148                 : 
     149                 :     /* FIXME: We should either support subsetting vertical fonts, or fail on
     150                 :      * vertical.  Currently font_options_t doesn't have vertical flag, but
     151                 :      * it should be added in the future.  For now, the freetype backend
     152                 :      * returns UNSUPPORTED in load_truetype_table if the font is vertical.
     153                 :      *
     154                 :      *  if (cairo_font_options_get_vertical_layout (scaled_font_subset->scaled_font))
     155                 :      *   return CAIRO_INT_STATUS_UNSUPPORTED;
     156                 :      */
     157                 : 
     158               0 :     size = sizeof (tt_head_t);
     159               0 :     status = backend->load_truetype_table (scaled_font_subset->scaled_font,
     160                 :                                           TT_TAG_head, 0,
     161                 :                                           (unsigned char *) &head,
     162                 :                                           &size);
     163               0 :     if (unlikely (status))
     164               0 :         return status;
     165                 : 
     166               0 :     size = sizeof (tt_maxp_t);
     167               0 :     status = backend->load_truetype_table (scaled_font_subset->scaled_font,
     168                 :                                            TT_TAG_maxp, 0,
     169                 :                                            (unsigned char *) &maxp,
     170                 :                                            &size);
     171               0 :     if (unlikely (status))
     172               0 :         return status;
     173                 : 
     174               0 :     size = sizeof (tt_hhea_t);
     175               0 :     status = backend->load_truetype_table (scaled_font_subset->scaled_font,
     176                 :                                            TT_TAG_hhea, 0,
     177                 :                                            (unsigned char *) &hhea,
     178                 :                                            &size);
     179               0 :     if (unlikely (status))
     180               0 :         return status;
     181                 : 
     182               0 :     font = malloc (sizeof (cairo_truetype_font_t));
     183               0 :     if (unlikely (font == NULL))
     184               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     185                 : 
     186               0 :     font->backend = backend;
     187               0 :     font->num_glyphs_in_face = be16_to_cpu (maxp.num_glyphs);
     188               0 :     font->scaled_font_subset = scaled_font_subset;
     189                 : 
     190               0 :     font->last_offset = 0;
     191               0 :     font->last_boundary = 0;
     192               0 :     _cairo_array_init (&font->output, sizeof (char));
     193               0 :     status = _cairo_array_grow_by (&font->output, 4096);
     194               0 :     if (unlikely (status))
     195               0 :         goto fail1;
     196                 : 
     197               0 :     font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t));
     198               0 :     if (unlikely (font->glyphs == NULL)) {
     199               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     200               0 :         goto fail1;
     201                 :     }
     202                 : 
     203               0 :     font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int));
     204               0 :     if (unlikely (font->parent_to_subset == NULL)) {
     205               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     206               0 :         goto fail2;
     207                 :     }
     208                 : 
     209               0 :     font->base.num_glyphs = 0;
     210               0 :     font->base.x_min = (int16_t) be16_to_cpu (head.x_min);
     211               0 :     font->base.y_min = (int16_t) be16_to_cpu (head.y_min);
     212               0 :     font->base.x_max = (int16_t) be16_to_cpu (head.x_max);
     213               0 :     font->base.y_max = (int16_t) be16_to_cpu (head.y_max);
     214               0 :     font->base.ascent = (int16_t) be16_to_cpu (hhea.ascender);
     215               0 :     font->base.descent = (int16_t) be16_to_cpu (hhea.descender);
     216               0 :     font->base.units_per_em = (int16_t) be16_to_cpu (head.units_per_em);
     217               0 :     if (font->base.units_per_em == 0)
     218               0 :         font->base.units_per_em = 2048;
     219                 : 
     220               0 :     font->base.ps_name = NULL;
     221               0 :     font->base.font_name = NULL;
     222               0 :     status = _cairo_truetype_read_font_name (scaled_font_subset->scaled_font,
     223                 :                                              &font->base.ps_name,
     224                 :                                              &font->base.font_name);
     225               0 :     if (_cairo_status_is_error (status))
     226               0 :         goto fail3;
     227                 : 
     228                 :     /* If the PS name is not found, create a CairoFont-x-y name. */
     229               0 :     if (font->base.ps_name == NULL) {
     230               0 :         font->base.ps_name = malloc (30);
     231               0 :         if (unlikely (font->base.ps_name == NULL)) {
     232               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     233               0 :             goto fail3;
     234                 :         }
     235                 : 
     236               0 :         snprintf(font->base.ps_name, 30, "CairoFont-%u-%u",
     237                 :                  scaled_font_subset->font_id,
     238                 :                  scaled_font_subset->subset_id);
     239                 :     }
     240                 : 
     241               0 :     font->base.widths = calloc (font->num_glyphs_in_face, sizeof (int));
     242               0 :     if (unlikely (font->base.widths == NULL)) {
     243               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     244               0 :         goto fail4;
     245                 :     }
     246                 : 
     247               0 :     _cairo_array_init (&font->string_offsets, sizeof (unsigned long));
     248               0 :     status = _cairo_array_grow_by (&font->string_offsets, 10);
     249               0 :     if (unlikely (status))
     250               0 :         goto fail5;
     251                 : 
     252               0 :     font->status = CAIRO_STATUS_SUCCESS;
     253                 : 
     254               0 :     *font_return = font;
     255                 : 
     256               0 :     return CAIRO_STATUS_SUCCESS;
     257                 : 
     258                 :  fail5:
     259               0 :     _cairo_array_fini (&font->string_offsets);
     260               0 :     free (font->base.widths);
     261                 :  fail4:
     262               0 :     free (font->base.ps_name);
     263                 :  fail3:
     264               0 :     free (font->parent_to_subset);
     265               0 :     if (font->base.font_name)
     266               0 :         free (font->base.font_name);
     267                 :  fail2:
     268               0 :     free (font->glyphs);
     269                 :  fail1:
     270               0 :     _cairo_array_fini (&font->output);
     271               0 :     free (font);
     272                 : 
     273               0 :     return status;
     274                 : }
     275                 : 
     276                 : static void
     277               0 : cairo_truetype_font_destroy (cairo_truetype_font_t *font)
     278                 : {
     279               0 :     _cairo_array_fini (&font->string_offsets);
     280               0 :     free (font->base.widths);
     281               0 :     free (font->base.ps_name);
     282               0 :     if (font->base.font_name)
     283               0 :         free (font->base.font_name);
     284               0 :     free (font->parent_to_subset);
     285               0 :     free (font->glyphs);
     286               0 :     _cairo_array_fini (&font->output);
     287               0 :     free (font);
     288               0 : }
     289                 : 
     290                 : static cairo_status_t
     291               0 : cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t  *font,
     292                 :                                            size_t                  length,
     293                 :                                            unsigned char         **buffer)
     294                 : {
     295                 :     cairo_status_t status;
     296                 : 
     297               0 :     if (font->status)
     298               0 :         return font->status;
     299                 : 
     300               0 :     status = _cairo_array_allocate (&font->output, length, (void **) buffer);
     301               0 :     if (unlikely (status))
     302               0 :         return _cairo_truetype_font_set_error (font, status);
     303                 : 
     304               0 :     return CAIRO_STATUS_SUCCESS;
     305                 : }
     306                 : 
     307                 : static void
     308               0 : cairo_truetype_font_write (cairo_truetype_font_t *font,
     309                 :                            const void            *data,
     310                 :                            size_t                 length)
     311                 : {
     312                 :     cairo_status_t status;
     313                 : 
     314               0 :     if (font->status)
     315               0 :         return;
     316                 : 
     317               0 :     status = _cairo_array_append_multiple (&font->output, data, length);
     318               0 :     if (unlikely (status))
     319               0 :         status = _cairo_truetype_font_set_error (font, status);
     320                 : }
     321                 : 
     322                 : static void
     323               0 : cairo_truetype_font_write_be16 (cairo_truetype_font_t *font,
     324                 :                                 uint16_t               value)
     325                 : {
     326                 :     uint16_t be16_value;
     327                 : 
     328               0 :     if (font->status)
     329               0 :         return;
     330                 : 
     331               0 :     be16_value = cpu_to_be16 (value);
     332               0 :     cairo_truetype_font_write (font, &be16_value, sizeof be16_value);
     333                 : }
     334                 : 
     335                 : static void
     336               0 : cairo_truetype_font_write_be32 (cairo_truetype_font_t *font,
     337                 :                                 uint32_t               value)
     338                 : {
     339                 :     uint32_t be32_value;
     340                 : 
     341               0 :     if (font->status)
     342               0 :         return;
     343                 : 
     344               0 :     be32_value = cpu_to_be32 (value);
     345               0 :     cairo_truetype_font_write (font, &be32_value, sizeof be32_value);
     346                 : }
     347                 : 
     348                 : static cairo_status_t
     349               0 : cairo_truetype_font_align_output (cairo_truetype_font_t     *font,
     350                 :                                   unsigned long             *aligned)
     351                 : {
     352                 :     int length, pad;
     353                 :     unsigned char *padding;
     354                 : 
     355               0 :     length = _cairo_array_num_elements (&font->output);
     356               0 :     *aligned = (length + 3) & ~3;
     357               0 :     pad = *aligned - length;
     358                 : 
     359               0 :     if (pad) {
     360                 :         cairo_status_t status;
     361                 : 
     362               0 :         status = cairo_truetype_font_allocate_write_buffer (font, pad,
     363                 :                                                             &padding);
     364               0 :         if (unlikely (status))
     365               0 :             return status;
     366                 : 
     367               0 :         memset (padding, 0, pad);
     368                 :     }
     369                 : 
     370               0 :     return CAIRO_STATUS_SUCCESS;
     371                 : }
     372                 : 
     373                 : static cairo_status_t
     374               0 : cairo_truetype_font_check_boundary (cairo_truetype_font_t *font,
     375                 :                                     unsigned long          boundary)
     376                 : {
     377                 :     cairo_status_t status;
     378                 : 
     379               0 :     if (font->status)
     380               0 :         return font->status;
     381                 : 
     382               0 :     if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH)
     383                 :     {
     384               0 :         status = _cairo_array_append (&font->string_offsets,
     385               0 :                                       &font->last_boundary);
     386               0 :         if (unlikely (status))
     387               0 :             return _cairo_truetype_font_set_error (font, status);
     388                 : 
     389               0 :         font->last_offset = font->last_boundary;
     390                 :     }
     391               0 :     font->last_boundary = boundary;
     392                 : 
     393               0 :     return CAIRO_STATUS_SUCCESS;
     394                 : }
     395                 : 
     396                 : static cairo_status_t
     397               0 : cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font,
     398                 :                                       unsigned long          tag)
     399                 : {
     400                 :     unsigned int i;
     401                 : 
     402               0 :     cairo_truetype_font_write_be16 (font, 0);  /* Table version */
     403               0 :     cairo_truetype_font_write_be16 (font, 2);  /* Num tables */
     404                 : 
     405               0 :     cairo_truetype_font_write_be16 (font, 3);  /* Platform */
     406               0 :     cairo_truetype_font_write_be16 (font, 0);  /* Encoding */
     407               0 :     cairo_truetype_font_write_be32 (font, 20); /* Offset to start of table */
     408                 : 
     409               0 :     cairo_truetype_font_write_be16 (font, 1);  /* Platform */
     410               0 :     cairo_truetype_font_write_be16 (font, 0);  /* Encoding */
     411               0 :     cairo_truetype_font_write_be32 (font, 52); /* Offset to start of table */
     412                 : 
     413                 :     /* Output a format 4 encoding table. */
     414                 : 
     415               0 :     cairo_truetype_font_write_be16 (font, 4);  /* Format */
     416               0 :     cairo_truetype_font_write_be16 (font, 32); /* Length */
     417               0 :     cairo_truetype_font_write_be16 (font, 0);  /* Version */
     418               0 :     cairo_truetype_font_write_be16 (font, 4);  /* 2*segcount */
     419               0 :     cairo_truetype_font_write_be16 (font, 4);  /* searchrange */
     420               0 :     cairo_truetype_font_write_be16 (font, 1);  /* entry selector */
     421               0 :     cairo_truetype_font_write_be16 (font, 0);  /* rangeshift */
     422               0 :     cairo_truetype_font_write_be16 (font, 0xf000 + font->base.num_glyphs - 1); /* end count[0] */
     423               0 :     cairo_truetype_font_write_be16 (font, 0xffff);  /* end count[1] */
     424               0 :     cairo_truetype_font_write_be16 (font, 0);       /* reserved */
     425               0 :     cairo_truetype_font_write_be16 (font, 0xf000);  /* startCode[0] */
     426               0 :     cairo_truetype_font_write_be16 (font, 0xffff);  /* startCode[1] */
     427               0 :     cairo_truetype_font_write_be16 (font, 0x1000);  /* delta[0] */
     428               0 :     cairo_truetype_font_write_be16 (font, 1);       /* delta[1] */
     429               0 :     cairo_truetype_font_write_be16 (font, 0);       /* rangeOffset[0] */
     430               0 :     cairo_truetype_font_write_be16 (font, 0);       /* rangeOffset[1] */
     431                 : 
     432                 :     /* Output a format 6 encoding table. */
     433                 : 
     434               0 :     cairo_truetype_font_write_be16 (font, 6);
     435               0 :     cairo_truetype_font_write_be16 (font, 10 + 2 * font->base.num_glyphs);
     436               0 :     cairo_truetype_font_write_be16 (font, 0);
     437               0 :     cairo_truetype_font_write_be16 (font, 0); /* First character */
     438               0 :     cairo_truetype_font_write_be16 (font, font->base.num_glyphs);
     439               0 :     for (i = 0; i < font->base.num_glyphs; i++)
     440               0 :         cairo_truetype_font_write_be16 (font, i);
     441                 : 
     442               0 :     return font->status;
     443                 : }
     444                 : 
     445                 : static cairo_status_t
     446               0 : cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font,
     447                 :                                          unsigned long          tag)
     448                 : {
     449                 :     cairo_status_t status;
     450                 :     unsigned char *buffer;
     451                 :     unsigned long size;
     452                 : 
     453               0 :     if (font->status)
     454               0 :         return font->status;
     455                 : 
     456               0 :     size = 0;
     457               0 :     status = font->backend->load_truetype_table(font->scaled_font_subset->scaled_font,
     458                 :                                                 tag, 0, NULL, &size);
     459               0 :     if (unlikely (status))
     460               0 :         return _cairo_truetype_font_set_error (font, status);
     461                 : 
     462               0 :     status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
     463               0 :     if (unlikely (status))
     464               0 :         return _cairo_truetype_font_set_error (font, status);
     465                 : 
     466               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     467                 :                                                  tag, 0, buffer, &size);
     468               0 :     if (unlikely (status))
     469               0 :         return _cairo_truetype_font_set_error (font, status);
     470                 : 
     471               0 :     return CAIRO_STATUS_SUCCESS;
     472                 : }
     473                 : 
     474                 : static cairo_status_t
     475               0 : cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t        *font,
     476                 :                                            unsigned char                *buffer,
     477                 :                                            unsigned long                 size)
     478                 : {
     479                 :     tt_glyph_data_t *glyph_data;
     480                 :     tt_composite_glyph_t *composite_glyph;
     481                 :     int num_args;
     482                 :     int has_more_components;
     483                 :     unsigned short flags;
     484                 :     unsigned short index;
     485                 :     cairo_status_t status;
     486               0 :     unsigned char *end = buffer + size;
     487                 : 
     488               0 :     if (font->status)
     489               0 :         return font->status;
     490                 : 
     491               0 :     glyph_data = (tt_glyph_data_t *) buffer;
     492               0 :     if ((unsigned char *)(&glyph_data->data) >= end)
     493               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
     494                 : 
     495               0 :     if ((int16_t)be16_to_cpu (glyph_data->num_contours) >= 0)
     496               0 :         return CAIRO_STATUS_SUCCESS;
     497                 : 
     498               0 :     composite_glyph = &glyph_data->glyph;
     499                 :     do {
     500               0 :         if ((unsigned char *)(&composite_glyph->args[1]) > end)
     501               0 :             return CAIRO_INT_STATUS_UNSUPPORTED;
     502                 : 
     503               0 :         flags = be16_to_cpu (composite_glyph->flags);
     504               0 :         has_more_components = flags & TT_MORE_COMPONENTS;
     505               0 :         status = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index), &index);
     506               0 :         if (unlikely (status))
     507               0 :             return status;
     508                 : 
     509               0 :         composite_glyph->index = cpu_to_be16 (index);
     510               0 :         num_args = 1;
     511               0 :         if (flags & TT_ARG_1_AND_2_ARE_WORDS)
     512               0 :             num_args += 1;
     513                 : 
     514               0 :         if (flags & TT_WE_HAVE_A_SCALE)
     515               0 :             num_args += 1;
     516               0 :         else if (flags & TT_WE_HAVE_AN_X_AND_Y_SCALE)
     517               0 :             num_args += 2;
     518               0 :         else if (flags & TT_WE_HAVE_A_TWO_BY_TWO)
     519               0 :             num_args += 4;
     520                 : 
     521               0 :         composite_glyph = (tt_composite_glyph_t *) &(composite_glyph->args[num_args]);
     522               0 :     } while (has_more_components);
     523                 : 
     524               0 :     return CAIRO_STATUS_SUCCESS;
     525                 : }
     526                 : 
     527                 : static cairo_status_t
     528               0 : cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
     529                 :                                       unsigned long          tag)
     530                 : {
     531                 :     unsigned long start_offset, index, size, next;
     532                 :     tt_head_t header;
     533                 :     unsigned long begin, end;
     534                 :     unsigned char *buffer;
     535                 :     unsigned int i;
     536                 :     union {
     537                 :         unsigned char *bytes;
     538                 :         uint16_t      *short_offsets;
     539                 :         uint32_t      *long_offsets;
     540                 :     } u;
     541                 :     cairo_status_t status;
     542                 : 
     543               0 :     if (font->status)
     544               0 :         return font->status;
     545                 : 
     546               0 :     size = sizeof (tt_head_t);
     547               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     548                 :                                                  TT_TAG_head, 0,
     549                 :                                                  (unsigned char*) &header, &size);
     550               0 :     if (unlikely (status))
     551               0 :         return _cairo_truetype_font_set_error (font, status);
     552                 : 
     553               0 :     if (be16_to_cpu (header.index_to_loc_format) == 0)
     554               0 :         size = sizeof (int16_t) * (font->num_glyphs_in_face + 1);
     555                 :     else
     556               0 :         size = sizeof (int32_t) * (font->num_glyphs_in_face + 1);
     557                 : 
     558               0 :     u.bytes = malloc (size);
     559               0 :     if (unlikely (u.bytes == NULL))
     560               0 :         return _cairo_truetype_font_set_error (font, CAIRO_STATUS_NO_MEMORY);
     561                 : 
     562               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     563                 :                                                  TT_TAG_loca, 0, u.bytes, &size);
     564               0 :     if (unlikely (status))
     565               0 :         return _cairo_truetype_font_set_error (font, status);
     566                 : 
     567               0 :     start_offset = _cairo_array_num_elements (&font->output);
     568               0 :     for (i = 0; i < font->base.num_glyphs; i++) {
     569               0 :         index = font->glyphs[i].parent_index;
     570               0 :         if (be16_to_cpu (header.index_to_loc_format) == 0) {
     571               0 :             begin = be16_to_cpu (u.short_offsets[index]) * 2;
     572               0 :             end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
     573                 :         }
     574                 :         else {
     575               0 :             begin = be32_to_cpu (u.long_offsets[index]);
     576               0 :             end = be32_to_cpu (u.long_offsets[index + 1]);
     577                 :         }
     578                 : 
     579                 :         /* quick sanity check... */
     580               0 :         if (end < begin) {
     581               0 :             status = CAIRO_INT_STATUS_UNSUPPORTED;
     582               0 :             goto FAIL;
     583                 :         }
     584                 : 
     585               0 :         size = end - begin;
     586               0 :         status = cairo_truetype_font_align_output (font, &next);
     587               0 :         if (unlikely (status))
     588               0 :             goto FAIL;
     589                 : 
     590               0 :         status = cairo_truetype_font_check_boundary (font, next);
     591               0 :         if (unlikely (status))
     592               0 :             goto FAIL;
     593                 : 
     594               0 :         font->glyphs[i].location = next - start_offset;
     595                 : 
     596               0 :         status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
     597               0 :         if (unlikely (status))
     598               0 :             goto FAIL;
     599                 : 
     600               0 :         if (size != 0) {
     601               0 :             status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     602                 :                                                          TT_TAG_glyf, begin, buffer, &size);
     603               0 :             if (unlikely (status))
     604               0 :                 goto FAIL;
     605                 : 
     606               0 :             status = cairo_truetype_font_remap_composite_glyph (font, buffer, size);
     607               0 :             if (unlikely (status))
     608               0 :                 goto FAIL;
     609                 :         }
     610                 :     }
     611                 : 
     612               0 :     status = cairo_truetype_font_align_output (font, &next);
     613               0 :     if (unlikely (status))
     614               0 :         goto FAIL;
     615                 : 
     616               0 :     font->glyphs[i].location = next - start_offset;
     617                 : 
     618               0 :     status = font->status;
     619                 : FAIL:
     620               0 :     free (u.bytes);
     621                 : 
     622               0 :     return _cairo_truetype_font_set_error (font, status);
     623                 : }
     624                 : 
     625                 : static cairo_status_t
     626               0 : cairo_truetype_font_write_head_table (cairo_truetype_font_t *font,
     627                 :                                       unsigned long          tag)
     628                 : {
     629                 :     unsigned char *buffer;
     630                 :     unsigned long size;
     631                 :     cairo_status_t status;
     632                 : 
     633               0 :     if (font->status)
     634               0 :         return font->status;
     635                 : 
     636               0 :     size = 0;
     637               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     638                 :                                                  tag, 0, NULL, &size);
     639               0 :     if (unlikely (status))
     640               0 :         return _cairo_truetype_font_set_error (font, status);
     641                 : 
     642               0 :     font->checksum_index = _cairo_array_num_elements (&font->output) + 8;
     643               0 :     status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
     644               0 :     if (unlikely (status))
     645               0 :         return _cairo_truetype_font_set_error (font, status);
     646                 : 
     647               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     648                 :                                                  tag, 0, buffer, &size);
     649               0 :     if (unlikely (status))
     650               0 :         return _cairo_truetype_font_set_error (font, status);
     651                 : 
     652                 :     /* set checkSumAdjustment to 0 for table checksum calculation */
     653               0 :     *(uint32_t *)(buffer + 8) = 0;
     654                 : 
     655               0 :     return CAIRO_STATUS_SUCCESS;
     656                 : }
     657                 : 
     658                 : static cairo_status_t
     659               0 : cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long tag)
     660                 : {
     661                 :     tt_hhea_t *hhea;
     662                 :     unsigned long size;
     663                 :     cairo_status_t status;
     664                 : 
     665               0 :     if (font->status)
     666               0 :         return font->status;
     667                 : 
     668               0 :     size = sizeof (tt_hhea_t);
     669               0 :     status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea);
     670               0 :     if (unlikely (status))
     671               0 :         return _cairo_truetype_font_set_error (font, status);
     672                 : 
     673               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     674                 :                                                  tag, 0, (unsigned char *) hhea, &size);
     675               0 :     if (unlikely (status))
     676               0 :         return _cairo_truetype_font_set_error (font, status);
     677                 : 
     678               0 :     hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs));
     679                 : 
     680               0 :     return CAIRO_STATUS_SUCCESS;
     681                 : }
     682                 : 
     683                 : static cairo_status_t
     684               0 : cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
     685                 :                                       unsigned long          tag)
     686                 : {
     687                 :     unsigned long size;
     688                 :     unsigned long long_entry_size;
     689                 :     unsigned long short_entry_size;
     690                 :     short *p;
     691                 :     unsigned int i;
     692                 :     tt_hhea_t hhea;
     693                 :     int num_hmetrics;
     694                 :     cairo_status_t status;
     695                 : 
     696               0 :     if (font->status)
     697               0 :         return font->status;
     698                 : 
     699               0 :     size = sizeof (tt_hhea_t);
     700               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     701                 :                                                  TT_TAG_hhea, 0,
     702                 :                                                  (unsigned char*) &hhea, &size);
     703               0 :     if (unlikely (status))
     704               0 :         return _cairo_truetype_font_set_error (font, status);
     705                 : 
     706               0 :     num_hmetrics = be16_to_cpu(hhea.num_hmetrics);
     707                 : 
     708               0 :     for (i = 0; i < font->base.num_glyphs; i++) {
     709               0 :         long_entry_size = 2 * sizeof (int16_t);
     710               0 :         short_entry_size = sizeof (int16_t);
     711               0 :         status = cairo_truetype_font_allocate_write_buffer (font,
     712                 :                                                             long_entry_size,
     713                 :                                                             (unsigned char **) &p);
     714               0 :         if (unlikely (status))
     715               0 :             return _cairo_truetype_font_set_error (font, status);
     716                 : 
     717               0 :         if (font->glyphs[i].parent_index < num_hmetrics) {
     718               0 :             status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     719                 :                                                          TT_TAG_hmtx,
     720               0 :                                                          font->glyphs[i].parent_index * long_entry_size,
     721                 :                                                          (unsigned char *) p, &long_entry_size);
     722               0 :             if (unlikely (status))
     723               0 :                 return _cairo_truetype_font_set_error (font, status);
     724                 :         }
     725                 :         else
     726                 :         {
     727               0 :             status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     728                 :                                                          TT_TAG_hmtx,
     729               0 :                                                          (num_hmetrics - 1) * long_entry_size,
     730                 :                                                          (unsigned char *) p, &short_entry_size);
     731               0 :             if (unlikely (status))
     732               0 :                 return _cairo_truetype_font_set_error (font, status);
     733                 : 
     734               0 :             status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     735                 :                                                          TT_TAG_hmtx,
     736               0 :                                                          num_hmetrics * long_entry_size +
     737               0 :                                                          (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size,
     738               0 :                                                          (unsigned char *) (p + 1), &short_entry_size);
     739               0 :             if (unlikely (status))
     740               0 :                 return _cairo_truetype_font_set_error (font, status);
     741                 :         }
     742               0 :         font->base.widths[i] = be16_to_cpu (p[0]);
     743                 :     }
     744                 : 
     745               0 :     return CAIRO_STATUS_SUCCESS;
     746                 : }
     747                 : 
     748                 : static cairo_status_t
     749               0 : cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font,
     750                 :                                       unsigned long          tag)
     751                 : {
     752                 :     unsigned int i;
     753                 :     tt_head_t header;
     754                 :     unsigned long size;
     755                 :     cairo_status_t status;
     756                 : 
     757               0 :     if (font->status)
     758               0 :         return font->status;
     759                 : 
     760               0 :     size = sizeof(tt_head_t);
     761               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     762                 :                                                  TT_TAG_head, 0,
     763                 :                                                  (unsigned char*) &header, &size);
     764               0 :     if (unlikely (status))
     765               0 :         return _cairo_truetype_font_set_error (font, status);
     766                 : 
     767               0 :     if (be16_to_cpu (header.index_to_loc_format) == 0)
     768                 :     {
     769               0 :         for (i = 0; i < font->base.num_glyphs + 1; i++)
     770               0 :             cairo_truetype_font_write_be16 (font, font->glyphs[i].location / 2);
     771                 :     } else {
     772               0 :         for (i = 0; i < font->base.num_glyphs + 1; i++)
     773               0 :             cairo_truetype_font_write_be32 (font, font->glyphs[i].location);
     774                 :     }
     775                 : 
     776               0 :     return font->status;
     777                 : }
     778                 : 
     779                 : static cairo_status_t
     780               0 : cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font,
     781                 :                                       unsigned long          tag)
     782                 : {
     783                 :     tt_maxp_t *maxp;
     784                 :     unsigned long size;
     785                 :     cairo_status_t status;
     786                 : 
     787               0 :     if (font->status)
     788               0 :         return font->status;
     789                 : 
     790               0 :     size = sizeof (tt_maxp_t);
     791               0 :     status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp);
     792               0 :     if (unlikely (status))
     793               0 :         return _cairo_truetype_font_set_error (font, status);
     794                 : 
     795               0 :     status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
     796                 :                                                  tag, 0, (unsigned char *) maxp, &size);
     797               0 :     if (unlikely (status))
     798               0 :         return _cairo_truetype_font_set_error (font, status);
     799                 : 
     800               0 :     maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs);
     801                 : 
     802               0 :     return CAIRO_STATUS_SUCCESS;
     803                 : }
     804                 : 
     805                 : static cairo_status_t
     806               0 : cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font)
     807                 : {
     808                 :     cairo_status_t status;
     809                 :     unsigned char *table_buffer;
     810                 :     size_t table_buffer_length;
     811                 :     unsigned short search_range, entry_selector, range_shift;
     812                 : 
     813               0 :     if (font->status)
     814               0 :         return font->status;
     815                 : 
     816               0 :     search_range = 1;
     817               0 :     entry_selector = 0;
     818               0 :     while (search_range * 2 <= font->num_tables) {
     819               0 :         search_range *= 2;
     820               0 :         entry_selector++;
     821                 :     }
     822               0 :     search_range *= 16;
     823               0 :     range_shift = font->num_tables * 16 - search_range;
     824                 : 
     825               0 :     cairo_truetype_font_write_be32 (font, SFNT_VERSION);
     826               0 :     cairo_truetype_font_write_be16 (font, font->num_tables);
     827               0 :     cairo_truetype_font_write_be16 (font, search_range);
     828               0 :     cairo_truetype_font_write_be16 (font, entry_selector);
     829               0 :     cairo_truetype_font_write_be16 (font, range_shift);
     830                 : 
     831                 :     /* Allocate space for the table directory. Each directory entry
     832                 :      * will be filled in by cairo_truetype_font_update_entry() after
     833                 :      * the table is written. */
     834               0 :     table_buffer_length = font->num_tables * 16;
     835               0 :     status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length,
     836                 :                                                       &table_buffer);
     837               0 :     if (unlikely (status))
     838               0 :         return _cairo_truetype_font_set_error (font, status);
     839                 : 
     840               0 :     return CAIRO_STATUS_SUCCESS;
     841                 : }
     842                 : 
     843                 : static uint32_t
     844               0 : cairo_truetype_font_calculate_checksum (cairo_truetype_font_t *font,
     845                 :                                         unsigned long          start,
     846                 :                                         unsigned long          end)
     847                 : {
     848                 :     uint32_t *padded_end;
     849                 :     uint32_t *p;
     850                 :     uint32_t checksum;
     851                 :     char *data;
     852                 : 
     853               0 :     checksum = 0;
     854               0 :     data = _cairo_array_index (&font->output, 0);
     855               0 :     p = (uint32_t *) (data + start);
     856               0 :     padded_end = (uint32_t *) (data + ((end + 3) & ~3));
     857               0 :     while (p < padded_end)
     858               0 :         checksum += be32_to_cpu(*p++);
     859                 : 
     860               0 :     return checksum;
     861                 : }
     862                 : 
     863                 : static void
     864               0 : cairo_truetype_font_update_entry (cairo_truetype_font_t *font,
     865                 :                                   int                    index,
     866                 :                                   unsigned long          tag,
     867                 :                                   unsigned long          start,
     868                 :                                   unsigned long          end)
     869                 : {
     870                 :     uint32_t *entry;
     871                 : 
     872               0 :     entry = _cairo_array_index (&font->output, 12 + 16 * index);
     873               0 :     entry[0] = cpu_to_be32 ((uint32_t)tag);
     874               0 :     entry[1] = cpu_to_be32 (cairo_truetype_font_calculate_checksum (font, start, end));
     875               0 :     entry[2] = cpu_to_be32 ((uint32_t)start);
     876               0 :     entry[3] = cpu_to_be32 ((uint32_t)(end - start));
     877               0 : }
     878                 : 
     879                 : static cairo_status_t
     880               0 : cairo_truetype_font_generate (cairo_truetype_font_t  *font,
     881                 :                               const char            **data,
     882                 :                               unsigned long          *length,
     883                 :                               const unsigned long   **string_offsets,
     884                 :                               unsigned long          *num_strings)
     885                 : {
     886                 :     cairo_status_t status;
     887                 :     unsigned long start, end, next;
     888                 :     uint32_t checksum, *checksum_location;
     889                 :     int i;
     890                 : 
     891               0 :     if (font->status)
     892               0 :         return font->status;
     893                 : 
     894               0 :     status = cairo_truetype_font_write_offset_table (font);
     895               0 :     if (unlikely (status))
     896               0 :         goto FAIL;
     897                 : 
     898               0 :     status = cairo_truetype_font_align_output (font, &start);
     899               0 :     if (unlikely (status))
     900               0 :         goto FAIL;
     901                 : 
     902               0 :     end = 0;
     903               0 :     for (i = 0; i < font->num_tables; i++) {
     904               0 :         status = font->truetype_tables[i].write (font, font->truetype_tables[i].tag);
     905               0 :         if (unlikely (status))
     906               0 :             goto FAIL;
     907                 : 
     908               0 :         end = _cairo_array_num_elements (&font->output);
     909               0 :         status = cairo_truetype_font_align_output (font, &next);
     910               0 :         if (unlikely (status))
     911               0 :             goto FAIL;
     912                 : 
     913               0 :         cairo_truetype_font_update_entry (font, font->truetype_tables[i].pos,
     914                 :                                           font->truetype_tables[i].tag, start, end);
     915               0 :         status = cairo_truetype_font_check_boundary (font, next);
     916               0 :         if (unlikely (status))
     917               0 :             goto FAIL;
     918                 : 
     919               0 :         start = next;
     920                 :     }
     921                 : 
     922               0 :     checksum =
     923               0 :         0xb1b0afba - cairo_truetype_font_calculate_checksum (font, 0, end);
     924               0 :     checksum_location = _cairo_array_index (&font->output, font->checksum_index);
     925               0 :     *checksum_location = cpu_to_be32 (checksum);
     926                 : 
     927               0 :     *data = _cairo_array_index (&font->output, 0);
     928               0 :     *length = _cairo_array_num_elements (&font->output);
     929               0 :     *num_strings = _cairo_array_num_elements (&font->string_offsets);
     930               0 :     if (*num_strings != 0)
     931               0 :         *string_offsets = _cairo_array_index (&font->string_offsets, 0);
     932                 :     else
     933               0 :         *string_offsets = NULL;
     934                 : 
     935                 :  FAIL:
     936               0 :     return _cairo_truetype_font_set_error (font, status);
     937                 : }
     938                 : 
     939                 : static cairo_status_t
     940               0 : cairo_truetype_font_use_glyph (cairo_truetype_font_t        *font,
     941                 :                                unsigned short                glyph,
     942                 :                                unsigned short               *out)
     943                 : {
     944               0 :     if (glyph >= font->num_glyphs_in_face)
     945               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
     946                 : 
     947               0 :     if (font->parent_to_subset[glyph] == 0) {
     948               0 :         font->parent_to_subset[glyph] = font->base.num_glyphs;
     949               0 :         font->glyphs[font->base.num_glyphs].parent_index = glyph;
     950               0 :         font->base.num_glyphs++;
     951                 :     }
     952                 : 
     953               0 :     *out = font->parent_to_subset[glyph];
     954               0 :     return CAIRO_STATUS_SUCCESS;
     955                 : }
     956                 : 
     957                 : static void
     958               0 : cairo_truetype_font_add_truetype_table (cairo_truetype_font_t *font,
     959                 :            unsigned long tag,
     960                 :            cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag),
     961                 :            int pos)
     962                 : {
     963               0 :     font->truetype_tables[font->num_tables].tag = tag;
     964               0 :     font->truetype_tables[font->num_tables].write = write;
     965               0 :     font->truetype_tables[font->num_tables].pos = pos;
     966               0 :     font->num_tables++;
     967               0 : }
     968                 : 
     969                 : /* cairo_truetype_font_create_truetype_table_list() builds the list of
     970                 :  * truetype tables to be embedded in the subsetted font. Each call to
     971                 :  * cairo_truetype_font_add_truetype_table() adds a table, the callback
     972                 :  * for generating the table, and the position in the table directory
     973                 :  * to the truetype_tables array.
     974                 :  *
     975                 :  * As we write out the glyf table we remap composite glyphs.
     976                 :  * Remapping composite glyphs will reference the sub glyphs the
     977                 :  * composite glyph is made up of. The "glyf" table callback needs to
     978                 :  * be called first so we have all the glyphs in the subset before
     979                 :  * going further.
     980                 :  *
     981                 :  * The order in which tables are added to the truetype_table array
     982                 :  * using cairo_truetype_font_add_truetype_table() specifies the order
     983                 :  * in which the callback functions will be called.
     984                 :  *
     985                 :  * The tables in the table directory must be listed in alphabetical
     986                 :  * order.  The "cvt", "fpgm", and "prep" are optional tables. They
     987                 :  * will only be embedded in the subset if they exist in the source
     988                 :  * font. The pos parameter of cairo_truetype_font_add_truetype_table()
     989                 :  * specifies the position of the table in the table directory.
     990                 :  */
     991                 : static void
     992               0 : cairo_truetype_font_create_truetype_table_list (cairo_truetype_font_t *font)
     993                 : {
     994               0 :     cairo_bool_t has_cvt = FALSE;
     995               0 :     cairo_bool_t has_fpgm = FALSE;
     996               0 :     cairo_bool_t has_prep = FALSE;
     997                 :     unsigned long size;
     998                 :     int pos;
     999                 : 
    1000               0 :     size = 0;
    1001               0 :     if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
    1002                 :                                       TT_TAG_cvt, 0, NULL,
    1003                 :                                       &size) == CAIRO_STATUS_SUCCESS)
    1004               0 :         has_cvt = TRUE;
    1005                 : 
    1006               0 :     size = 0;
    1007               0 :     if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
    1008                 :                                       TT_TAG_fpgm, 0, NULL,
    1009                 :                                       &size) == CAIRO_STATUS_SUCCESS)
    1010               0 :         has_fpgm = TRUE;
    1011                 : 
    1012               0 :     size = 0;
    1013               0 :     if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
    1014                 :                                       TT_TAG_prep, 0, NULL,
    1015                 :                                       &size) == CAIRO_STATUS_SUCCESS)
    1016               0 :         has_prep = TRUE;
    1017                 : 
    1018               0 :     font->num_tables = 0;
    1019               0 :     pos = 1;
    1020               0 :     if (has_cvt)
    1021               0 :         pos++;
    1022               0 :     if (has_fpgm)
    1023               0 :         pos++;
    1024               0 :     cairo_truetype_font_add_truetype_table (font, TT_TAG_glyf, cairo_truetype_font_write_glyf_table, pos);
    1025                 : 
    1026               0 :     pos = 0;
    1027               0 :     cairo_truetype_font_add_truetype_table (font, TT_TAG_cmap, cairo_truetype_font_write_cmap_table, pos++);
    1028               0 :     if (has_cvt)
    1029               0 :         cairo_truetype_font_add_truetype_table (font, TT_TAG_cvt, cairo_truetype_font_write_generic_table, pos++);
    1030               0 :     if (has_fpgm)
    1031               0 :         cairo_truetype_font_add_truetype_table (font, TT_TAG_fpgm, cairo_truetype_font_write_generic_table, pos++);
    1032               0 :     pos++;
    1033               0 :     cairo_truetype_font_add_truetype_table (font, TT_TAG_head, cairo_truetype_font_write_head_table, pos++);
    1034               0 :     cairo_truetype_font_add_truetype_table (font, TT_TAG_hhea, cairo_truetype_font_write_hhea_table, pos++);
    1035               0 :     cairo_truetype_font_add_truetype_table (font, TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, pos++);
    1036               0 :     cairo_truetype_font_add_truetype_table (font, TT_TAG_loca, cairo_truetype_font_write_loca_table, pos++);
    1037               0 :     cairo_truetype_font_add_truetype_table (font, TT_TAG_maxp, cairo_truetype_font_write_maxp_table, pos++);
    1038               0 :     if (has_prep)
    1039               0 :         cairo_truetype_font_add_truetype_table (font, TT_TAG_prep, cairo_truetype_font_write_generic_table, pos);
    1040               0 : }
    1041                 : 
    1042                 : cairo_status_t
    1043               0 : _cairo_truetype_subset_init (cairo_truetype_subset_t    *truetype_subset,
    1044                 :                              cairo_scaled_font_subset_t *font_subset)
    1045                 : {
    1046               0 :     cairo_truetype_font_t *font = NULL;
    1047                 :     cairo_status_t status;
    1048               0 :     const char *data = NULL; /* squelch bogus compiler warning */
    1049               0 :     unsigned long length = 0; /* squelch bogus compiler warning */
    1050                 :     unsigned long offsets_length;
    1051                 :     unsigned int i;
    1052               0 :     const unsigned long *string_offsets = NULL;
    1053               0 :     unsigned long num_strings = 0;
    1054                 : 
    1055               0 :     status = _cairo_truetype_font_create (font_subset, &font);
    1056               0 :     if (unlikely (status))
    1057               0 :         return status;
    1058                 : 
    1059               0 :     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
    1060               0 :         unsigned short parent_glyph = font->scaled_font_subset->glyphs[i];
    1061               0 :         status = cairo_truetype_font_use_glyph (font, parent_glyph, &parent_glyph);
    1062               0 :         if (unlikely (status))
    1063               0 :             goto fail1;
    1064                 :     }
    1065                 : 
    1066               0 :     cairo_truetype_font_create_truetype_table_list (font);
    1067               0 :     status = cairo_truetype_font_generate (font, &data, &length,
    1068                 :                                            &string_offsets, &num_strings);
    1069               0 :     if (unlikely (status))
    1070               0 :         goto fail1;
    1071                 : 
    1072               0 :     truetype_subset->ps_name = strdup (font->base.ps_name);
    1073               0 :     if (unlikely (truetype_subset->ps_name == NULL)) {
    1074               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1075               0 :         goto fail1;
    1076                 :     }
    1077                 : 
    1078               0 :     if (font->base.font_name != NULL) {
    1079               0 :         truetype_subset->font_name = strdup (font->base.font_name);
    1080               0 :         if (unlikely (truetype_subset->font_name == NULL)) {
    1081               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1082               0 :             goto fail2;
    1083                 :         }
    1084                 :     } else {
    1085               0 :         truetype_subset->font_name = NULL;
    1086                 :     }
    1087                 : 
    1088                 :     /* The widths array returned must contain only widths for the
    1089                 :      * glyphs in font_subset. Any subglyphs appended after
    1090                 :      * font_subset->num_glyphs are omitted. */
    1091               0 :     truetype_subset->widths = calloc (sizeof (double),
    1092               0 :                                       font->scaled_font_subset->num_glyphs);
    1093               0 :     if (unlikely (truetype_subset->widths == NULL)) {
    1094               0 :         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1095               0 :         goto fail3;
    1096                 :     }
    1097               0 :     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
    1098               0 :         truetype_subset->widths[i] = (double)font->base.widths[i]/font->base.units_per_em;
    1099                 : 
    1100               0 :     truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em;
    1101               0 :     truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em;
    1102               0 :     truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em;
    1103               0 :     truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em;
    1104               0 :     truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em;
    1105               0 :     truetype_subset->descent = (double)font->base.descent/font->base.units_per_em;
    1106                 : 
    1107               0 :     if (length) {
    1108               0 :         truetype_subset->data = malloc (length);
    1109               0 :         if (unlikely (truetype_subset->data == NULL)) {
    1110               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1111               0 :             goto fail4;
    1112                 :         }
    1113                 : 
    1114               0 :         memcpy (truetype_subset->data, data, length);
    1115                 :     } else
    1116               0 :         truetype_subset->data = NULL;
    1117               0 :     truetype_subset->data_length = length;
    1118                 : 
    1119               0 :     if (num_strings) {
    1120               0 :         offsets_length = num_strings * sizeof (unsigned long);
    1121               0 :         truetype_subset->string_offsets = malloc (offsets_length);
    1122               0 :         if (unlikely (truetype_subset->string_offsets == NULL)) {
    1123               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1124               0 :             goto fail5;
    1125                 :         }
    1126                 : 
    1127               0 :         memcpy (truetype_subset->string_offsets, string_offsets, offsets_length);
    1128               0 :         truetype_subset->num_string_offsets = num_strings;
    1129                 :     } else {
    1130               0 :         truetype_subset->string_offsets = NULL;
    1131               0 :         truetype_subset->num_string_offsets = 0;
    1132                 :     }
    1133                 : 
    1134               0 :     cairo_truetype_font_destroy (font);
    1135                 : 
    1136               0 :     return CAIRO_STATUS_SUCCESS;
    1137                 : 
    1138                 :  fail5:
    1139               0 :     free (truetype_subset->data);
    1140                 :  fail4:
    1141               0 :     free (truetype_subset->widths);
    1142                 :  fail3:
    1143               0 :     if (truetype_subset->font_name)
    1144               0 :         free (truetype_subset->font_name);
    1145                 :  fail2:
    1146               0 :     free (truetype_subset->ps_name);
    1147                 :  fail1:
    1148               0 :     cairo_truetype_font_destroy (font);
    1149                 : 
    1150               0 :     return status;
    1151                 : }
    1152                 : 
    1153                 : void
    1154               0 : _cairo_truetype_subset_fini (cairo_truetype_subset_t *subset)
    1155                 : {
    1156               0 :     free (subset->ps_name);
    1157               0 :     if (subset->font_name)
    1158               0 :         free (subset->font_name);
    1159               0 :     free (subset->widths);
    1160               0 :     free (subset->data);
    1161               0 :     free (subset->string_offsets);
    1162               0 : }
    1163                 : 
    1164                 : static cairo_int_status_t
    1165               0 : _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
    1166                 :                               unsigned long        table_offset,
    1167                 :                               unsigned long        index,
    1168                 :                               uint32_t            *ucs4)
    1169                 : {
    1170                 :     cairo_status_t status;
    1171                 :     const cairo_scaled_font_backend_t *backend;
    1172                 :     tt_segment_map_t *map;
    1173                 :     char buf[4];
    1174                 :     unsigned int num_segments, i;
    1175                 :     unsigned long size;
    1176                 :     uint16_t *start_code;
    1177                 :     uint16_t *end_code;
    1178                 :     uint16_t *delta;
    1179                 :     uint16_t *range_offset;
    1180                 :     uint16_t *glyph_array;
    1181                 :     uint16_t  c;
    1182                 : 
    1183               0 :     backend = scaled_font->backend;
    1184               0 :     size = 4;
    1185               0 :     status = backend->load_truetype_table (scaled_font,
    1186                 :                                            TT_TAG_cmap, table_offset,
    1187                 :                                            (unsigned char *) &buf,
    1188                 :                                            &size);
    1189               0 :     if (unlikely (status))
    1190               0 :         return status;
    1191                 : 
    1192                 :     /* All table formats have the same first two words */
    1193               0 :     map = (tt_segment_map_t *) buf;
    1194               0 :     if (be16_to_cpu (map->format) != 4)
    1195               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1196                 : 
    1197               0 :     size = be16_to_cpu (map->length);
    1198               0 :     map = malloc (size);
    1199               0 :     if (unlikely (map == NULL))
    1200               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1201                 : 
    1202               0 :     status = backend->load_truetype_table (scaled_font,
    1203                 :                                            TT_TAG_cmap, table_offset,
    1204                 :                                            (unsigned char *) map,
    1205                 :                                            &size);
    1206               0 :     if (unlikely (status))
    1207               0 :         goto fail;
    1208                 : 
    1209               0 :     num_segments = be16_to_cpu (map->segCountX2)/2;
    1210                 : 
    1211                 :     /* A Format 4 cmap contains 8 uint16_t numbers and 4 arrays of
    1212                 :      * uint16_t each num_segments long. */
    1213               0 :     if (size < (8 + 4*num_segments)*sizeof(uint16_t))
    1214               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1215                 : 
    1216               0 :     end_code = map->endCount;
    1217               0 :     start_code = &(end_code[num_segments + 1]);
    1218               0 :     delta = &(start_code[num_segments]);
    1219               0 :     range_offset = &(delta[num_segments]);
    1220               0 :     glyph_array = &(range_offset[num_segments]);
    1221                 : 
    1222                 :     /* search for glyph in segments with rangeOffset=0 */
    1223               0 :     for (i = 0; i < num_segments; i++) {
    1224               0 :         c = index - be16_to_cpu (delta[i]);
    1225               0 :         if (range_offset[i] == 0 &&
    1226               0 :             c >= be16_to_cpu (start_code[i]) &&
    1227               0 :             c <= be16_to_cpu (end_code[i]))
    1228                 :         {
    1229               0 :             *ucs4 = c;
    1230               0 :             goto found;
    1231                 :         }
    1232                 :     }
    1233                 : 
    1234                 :     /* search for glyph in segments with rangeOffset=1 */
    1235               0 :     for (i = 0; i < num_segments; i++) {
    1236               0 :         if (range_offset[i] != 0) {
    1237               0 :             uint16_t *glyph_ids = &range_offset[i] + be16_to_cpu (range_offset[i])/2;
    1238               0 :             int range_size = be16_to_cpu (end_code[i]) - be16_to_cpu (start_code[i]) + 1;
    1239               0 :             uint16_t g_id_be = cpu_to_be16 (index);
    1240                 :             int j;
    1241                 : 
    1242               0 :             if (range_size > 0) {
    1243               0 :                 if ((char*)glyph_ids + 2*range_size > (char*)map + size)
    1244               0 :                     return CAIRO_INT_STATUS_UNSUPPORTED;
    1245                 : 
    1246               0 :                 for (j = 0; j < range_size; j++) {
    1247               0 :                     if (glyph_ids[j] == g_id_be) {
    1248               0 :                         *ucs4 = be16_to_cpu (start_code[i]) + j;
    1249               0 :                         goto found;
    1250                 :                     }
    1251                 :                 }
    1252                 :             }
    1253                 :         }
    1254                 :     }
    1255                 : 
    1256                 :     /* glyph not found */
    1257               0 :     *ucs4 = -1;
    1258                 : 
    1259                 : found:
    1260               0 :     status = CAIRO_STATUS_SUCCESS;
    1261                 : 
    1262                 : fail:
    1263               0 :     free (map);
    1264                 : 
    1265               0 :     return status;
    1266                 : }
    1267                 : 
    1268                 : cairo_int_status_t
    1269               0 : _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
    1270                 :                                unsigned long        index,
    1271                 :                                uint32_t            *ucs4)
    1272                 : {
    1273               0 :     cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
    1274                 :     const cairo_scaled_font_backend_t *backend;
    1275                 :     tt_cmap_t *cmap;
    1276                 :     char buf[4];
    1277                 :     int num_tables, i;
    1278                 :     unsigned long size;
    1279                 : 
    1280               0 :     backend = scaled_font->backend;
    1281               0 :     if (!backend->load_truetype_table)
    1282               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1283                 : 
    1284               0 :     size = 4;
    1285               0 :     status = backend->load_truetype_table (scaled_font,
    1286                 :                                            TT_TAG_cmap, 0,
    1287                 :                                            (unsigned char *) &buf,
    1288                 :                                            &size);
    1289               0 :     if (unlikely (status))
    1290               0 :         return status;
    1291                 : 
    1292               0 :     cmap = (tt_cmap_t *) buf;
    1293               0 :     num_tables = be16_to_cpu (cmap->num_tables);
    1294               0 :     size = 4 + num_tables*sizeof(tt_cmap_index_t);
    1295               0 :     cmap = _cairo_malloc_ab_plus_c (num_tables, sizeof (tt_cmap_index_t), 4);
    1296               0 :     if (unlikely (cmap == NULL))
    1297               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1298                 : 
    1299               0 :     status = backend->load_truetype_table (scaled_font,
    1300                 :                                            TT_TAG_cmap, 0,
    1301                 :                                            (unsigned char *) cmap,
    1302                 :                                            &size);
    1303               0 :     if (unlikely (status))
    1304               0 :         goto cleanup;
    1305                 : 
    1306                 :     /* Find a table with Unicode mapping */
    1307               0 :     for (i = 0; i < num_tables; i++) {
    1308               0 :         if (be16_to_cpu (cmap->index[i].platform) == 3 &&
    1309               0 :             be16_to_cpu (cmap->index[i].encoding) == 1) {
    1310               0 :             status = _cairo_truetype_reverse_cmap (scaled_font,
    1311               0 :                                                    be32_to_cpu (cmap->index[i].offset),
    1312                 :                                                    index,
    1313                 :                                                    ucs4);
    1314               0 :             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
    1315               0 :                 break;
    1316                 :         }
    1317                 :     }
    1318                 : 
    1319                 : cleanup:
    1320               0 :     free (cmap);
    1321                 : 
    1322               0 :     return status;
    1323                 : }
    1324                 : 
    1325                 : cairo_int_status_t
    1326               0 : _cairo_truetype_read_font_name (cairo_scaled_font_t      *scaled_font,
    1327                 :                                 char                    **ps_name_out,
    1328                 :                                 char                    **font_name_out)
    1329                 : {
    1330                 :     cairo_status_t status;
    1331                 :     const cairo_scaled_font_backend_t *backend;
    1332                 :     tt_name_t *name;
    1333                 :     tt_name_record_t *record;
    1334                 :     unsigned long size;
    1335                 :     int i, j;
    1336               0 :     char *ps_name = NULL;
    1337               0 :     char *font_name = NULL;
    1338                 : 
    1339               0 :     backend = scaled_font->backend;
    1340               0 :     if (!backend->load_truetype_table)
    1341               0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
    1342                 : 
    1343               0 :     size = 0;
    1344               0 :     status = backend->load_truetype_table (scaled_font,
    1345                 :                                            TT_TAG_name, 0,
    1346                 :                                            NULL,
    1347                 :                                            &size);
    1348               0 :     if (status)
    1349               0 :         return status;
    1350                 : 
    1351               0 :     name = malloc (size);
    1352               0 :     if (name == NULL)
    1353               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1354                 : 
    1355               0 :    status = backend->load_truetype_table (scaled_font,
    1356                 :                                            TT_TAG_name, 0,
    1357                 :                                            (unsigned char *) name,
    1358                 :                                            &size);
    1359               0 :     if (status)
    1360               0 :         goto fail;
    1361                 : 
    1362                 :     /* Extract the font name and PS name from the name table. At
    1363                 :      * present this just looks for the Mac platform/Roman encoded font
    1364                 :      * name. It should be extended to use any suitable font name in
    1365                 :      * the name table.
    1366                 :      */
    1367               0 :     for (i = 0; i < be16_to_cpu(name->num_records); i++) {
    1368               0 :         record = &(name->records[i]);
    1369               0 :         if ((be16_to_cpu (record->platform) == 1) &&
    1370               0 :             (be16_to_cpu (record->encoding) == 0)) {
    1371                 : 
    1372               0 :             if (be16_to_cpu (record->name) == 4) {
    1373               0 :                 font_name = malloc (be16_to_cpu(record->length) + 1);
    1374               0 :                 if (font_name == NULL) {
    1375               0 :                     status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1376               0 :                     goto fail;
    1377                 :                 }
    1378               0 :                 strncpy(font_name,
    1379               0 :                         ((char*)name) + be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset),
    1380               0 :                         be16_to_cpu (record->length));
    1381               0 :                 font_name[be16_to_cpu (record->length)] = 0;
    1382                 :             }
    1383                 : 
    1384               0 :             if (be16_to_cpu (record->name) == 6) {
    1385               0 :                 ps_name = malloc (be16_to_cpu(record->length) + 1);
    1386               0 :                 if (ps_name == NULL) {
    1387               0 :                     status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    1388               0 :                     goto fail;
    1389                 :                 }
    1390               0 :                 strncpy(ps_name,
    1391               0 :                         ((char*)name) + be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset),
    1392               0 :                         be16_to_cpu (record->length));
    1393               0 :                 ps_name[be16_to_cpu (record->length)] = 0;
    1394                 :             }
    1395                 : 
    1396               0 :             if (font_name && ps_name)
    1397               0 :                 break;
    1398                 :         }
    1399                 :     }
    1400                 : 
    1401               0 :     free (name);
    1402                 : 
    1403                 :     /* Ensure PS name does not contain any spaces */
    1404               0 :     if (ps_name) {
    1405               0 :         for (i = 0, j = 0; ps_name[j]; j++) {
    1406               0 :             if (ps_name[j] == ' ')
    1407               0 :                 continue;
    1408               0 :             ps_name[i++] = ps_name[j];
    1409                 :         }
    1410               0 :         ps_name[i] = '\0';
    1411                 :     }
    1412                 : 
    1413               0 :     *ps_name_out = ps_name;
    1414               0 :     *font_name_out = font_name;
    1415                 : 
    1416               0 :     return CAIRO_STATUS_SUCCESS;
    1417                 : 
    1418                 : fail:
    1419               0 :     free (name);
    1420                 : 
    1421               0 :     if (ps_name != NULL)
    1422               0 :         free (ps_name);
    1423                 : 
    1424               0 :     if (font_name != NULL)
    1425               0 :         free (font_name);
    1426                 : 
    1427               0 :     *ps_name_out = NULL;
    1428               0 :     *font_name_out = NULL;
    1429                 : 
    1430               0 :     return status;
    1431                 : }
    1432                 : 
    1433                 : #endif /* CAIRO_HAS_FONT_SUBSET */

Generated by: LCOV version 1.7