LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-truetype-subset.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 678 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 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 © 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.13