| /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ |
| /* cairo - a vector graphics library with display and print output |
| * |
| * Copyright © 2006 Red Hat, Inc |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it either under the terms of the GNU Lesser General Public |
| * License version 2.1 as published by the Free Software Foundation |
| * (the "LGPL") or, at your option, under the terms of the Mozilla |
| * Public License Version 1.1 (the "MPL"). If you do not alter this |
| * notice, a recipient may use your version of this file under either |
| * the MPL or the LGPL. |
| * |
| * You should have received a copy of the LGPL along with this library |
| * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
| * You should have received a copy of the MPL along with this library |
| * in the file COPYING-MPL-1.1 |
| * |
| * The contents of this file are subject to the Mozilla Public License |
| * Version 1.1 (the "License"); you may not use this file except in |
| * compliance with the License. You may obtain a copy of the License at |
| * http://www.mozilla.org/MPL/ |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
| * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
| * the specific language governing rights and limitations. |
| * |
| * The Original Code is the cairo graphics library. |
| * |
| * The Initial Developer of the Original Code is Red Hat, Inc. |
| * |
| * Contributor(s): |
| * Kristian Høgsberg <krh@redhat.com> |
| */ |
| |
| /* |
| * Useful links: |
| * http://partners.adobe.com/public/developer/en/font/T1_SPEC.PDF |
| */ |
| |
| |
| #define _BSD_SOURCE /* for snprintf(), strdup() */ |
| #include "cairoint.h" |
| |
| #include "cairo-array-private.h" |
| #include "cairo-error-private.h" |
| |
| #if CAIRO_HAS_FONT_SUBSET |
| |
| #include "cairo-type1-private.h" |
| #include "cairo-scaled-font-subsets-private.h" |
| #include "cairo-output-stream-private.h" |
| |
| #include <ctype.h> |
| |
| #define TYPE1_STACKSIZE 24 /* Defined in Type 1 Font Format */ |
| |
| |
| typedef struct { |
| int subset_index; |
| double width; |
| const char *encrypted_charstring; |
| int encrypted_charstring_length; |
| } glyph_data_t; |
| |
| typedef struct _cairo_type1_font_subset { |
| cairo_scaled_font_subset_t *scaled_font_subset; |
| |
| struct { |
| unsigned int font_id; |
| char *base_font; |
| unsigned int num_glyphs; |
| double x_min, y_min, x_max, y_max; |
| double ascent, descent; |
| double units_per_em; |
| |
| const char *data; |
| unsigned long header_size; |
| unsigned long data_size; |
| unsigned long trailer_size; |
| } base; |
| |
| int num_glyphs; |
| |
| /* The glyphs and glyph_names arrays are indexed by the order of |
| * the Charstrings in the font. This is not necessarily the same |
| * order as the glyph index. The index_to_glyph_name() font backend |
| * function is used to map the glyph index to the glyph order in |
| * the Charstrings. */ |
| |
| glyph_data_t *glyphs; |
| char **glyph_names; |
| cairo_array_t glyphs_array; |
| cairo_array_t glyph_names_array; |
| |
| int num_subrs; |
| cairo_bool_t subset_subrs; |
| struct { |
| const char *subr_string; |
| int subr_length; |
| const char *np; |
| int np_length; |
| cairo_bool_t used; |
| } *subrs; |
| |
| /* Indexed by subset_index this maps to the glyph order in the |
| * glyph_names and glyphs arrays. Has font->num_golyphs |
| * elements. */ |
| int *subset_index_to_glyphs; |
| |
| cairo_output_stream_t *output; |
| cairo_array_t contents; |
| |
| const char *rd, *nd, *np; |
| |
| int lenIV; |
| |
| char *type1_data; |
| unsigned int type1_length; |
| char *type1_end; |
| |
| char *header_segment; |
| int header_segment_size; |
| char *eexec_segment; |
| int eexec_segment_size; |
| cairo_bool_t eexec_segment_is_ascii; |
| |
| char *cleartext; |
| char *cleartext_end; |
| |
| int header_size; |
| |
| unsigned short eexec_key; |
| cairo_bool_t hex_encode; |
| int hex_column; |
| |
| struct { |
| double stack[TYPE1_STACKSIZE]; |
| int sp; |
| } build_stack; |
| |
| struct { |
| int stack[TYPE1_STACKSIZE]; |
| int sp; |
| } ps_stack; |
| |
| |
| } cairo_type1_font_subset_t; |
| |
| |
| static cairo_status_t |
| _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font, |
| cairo_scaled_font_subset_t *scaled_font_subset, |
| cairo_bool_t hex_encode) |
| { |
| memset (font, 0, sizeof (*font)); |
| font->scaled_font_subset = scaled_font_subset; |
| |
| _cairo_array_init (&font->glyphs_array, sizeof (glyph_data_t)); |
| _cairo_array_init (&font->glyph_names_array, sizeof (char *)); |
| font->subset_index_to_glyphs = NULL; |
| font->base.num_glyphs = 0; |
| font->num_subrs = 0; |
| font->subset_subrs = TRUE; |
| font->subrs = NULL; |
| |
| font->hex_encode = hex_encode; |
| font->num_glyphs = 0; |
| |
| _cairo_array_init (&font->contents, sizeof (char)); |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static void |
| cairo_type1_font_subset_use_glyph (cairo_type1_font_subset_t *font, int glyph) |
| { |
| if (font->glyphs[glyph].subset_index >= 0) |
| return; |
| |
| font->glyphs[glyph].subset_index = font->num_glyphs; |
| font->subset_index_to_glyphs[font->num_glyphs] = glyph; |
| font->num_glyphs++; |
| } |
| |
| static cairo_bool_t |
| is_ps_delimiter(int c) |
| { |
| static const char delimiters[] = "()[]{}<>/% \t\r\n"; |
| |
| return strchr (delimiters, c) != NULL; |
| } |
| |
| static const char * |
| find_token (const char *buffer, const char *end, const char *token) |
| { |
| int i, length; |
| /* FIXME: find substring really must be find_token */ |
| |
| if (buffer == NULL) |
| return NULL; |
| |
| length = strlen (token); |
| for (i = 0; buffer + i < end - length + 1; i++) |
| if (memcmp (buffer + i, token, length) == 0) |
| if ((i == 0 || token[0] == '/' || is_ps_delimiter(buffer[i - 1])) && |
| (buffer + i == end - length || is_ps_delimiter(buffer[i + length]))) |
| return buffer + i; |
| |
| return NULL; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font) |
| { |
| unsigned char *p; |
| const char *eexec_token; |
| int size, i; |
| |
| p = (unsigned char *) font->type1_data; |
| font->type1_end = font->type1_data + font->type1_length; |
| if (p[0] == 0x80 && p[1] == 0x01) { |
| font->header_segment_size = |
| p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24); |
| font->header_segment = (char *) p + 6; |
| |
| p += 6 + font->header_segment_size; |
| font->eexec_segment_size = |
| p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24); |
| font->eexec_segment = (char *) p + 6; |
| font->eexec_segment_is_ascii = (p[1] == 1); |
| |
| p += 6 + font->eexec_segment_size; |
| while (p < (unsigned char *) (font->type1_end) && p[1] != 0x03) { |
| size = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24); |
| p += 6 + size; |
| } |
| font->type1_end = (char *) p; |
| } else { |
| eexec_token = find_token ((char *) p, font->type1_end, "eexec"); |
| if (eexec_token == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| font->header_segment_size = eexec_token - (char *) p + strlen ("eexec\n"); |
| font->header_segment = (char *) p; |
| font->eexec_segment_size = font->type1_length - font->header_segment_size; |
| font->eexec_segment = (char *) p + font->header_segment_size; |
| font->eexec_segment_is_ascii = TRUE; |
| for (i = 0; i < 4; i++) { |
| if (!isxdigit(font->eexec_segment[i])) |
| font->eexec_segment_is_ascii = FALSE; |
| } |
| } |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| /* Search for the definition of key and erase it by overwriting with spaces. |
| * This function is looks for definitions of the form: |
| * |
| * /key1 1234 def |
| * /key2 [12 34 56] def |
| * |
| * ie a key defined as an integer or array of integers. |
| * |
| */ |
| static void |
| cairo_type1_font_erase_dict_key (cairo_type1_font_subset_t *font, |
| const char *key) |
| { |
| const char *start, *p, *segment_end; |
| |
| segment_end = font->header_segment + font->header_segment_size; |
| |
| start = font->header_segment; |
| do { |
| start = find_token (start, segment_end, key); |
| if (start) { |
| p = start + strlen(key); |
| /* skip integers or array of integers */ |
| while (p < segment_end && |
| (_cairo_isspace(*p) || |
| _cairo_isdigit(*p) || |
| *p == '[' || |
| *p == ']')) |
| { |
| p++; |
| } |
| |
| if (p + 3 < segment_end && memcmp(p, "def", 3) == 0) { |
| /* erase definition of the key */ |
| memset((char *) start, ' ', p + 3 - start); |
| } |
| start += strlen(key); |
| } |
| } while (start); |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_get_matrix (cairo_type1_font_subset_t *font, |
| const char *name, |
| double *a, |
| double *b, |
| double *c, |
| double *d) |
| { |
| const char *start, *end, *segment_end; |
| int ret, s_max, i, j; |
| char *s; |
| const char *decimal_point; |
| int decimal_point_len; |
| |
| decimal_point = cairo_get_locale_decimal_point (); |
| decimal_point_len = strlen (decimal_point); |
| |
| assert (decimal_point_len != 0); |
| |
| segment_end = font->header_segment + font->header_segment_size; |
| start = find_token (font->header_segment, segment_end, name); |
| if (start == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| end = find_token (start, segment_end, "def"); |
| if (end == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| s_max = end - start + 5*decimal_point_len + 1; |
| s = malloc (s_max); |
| if (unlikely (s == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| i = 0; |
| j = 0; |
| while (i < end - start && j < s_max - decimal_point_len) { |
| if (start[i] == '.') { |
| strncpy(s + j, decimal_point, decimal_point_len); |
| i++; |
| j += decimal_point_len; |
| } else { |
| s[j++] = start[i++]; |
| } |
| } |
| s[j] = 0; |
| |
| start = strpbrk (s, "{["); |
| if (!start) { |
| free (s); |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| } |
| |
| start++; |
| ret = 0; |
| if (*start) |
| ret = sscanf(start, "%lf %lf %lf %lf", a, b, c, d); |
| |
| free (s); |
| |
| if (ret != 4) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_get_bbox (cairo_type1_font_subset_t *font) |
| { |
| cairo_status_t status; |
| double x_min, y_min, x_max, y_max; |
| double xx, yx, xy, yy; |
| |
| status = cairo_type1_font_subset_get_matrix (font, "/FontBBox", |
| &x_min, |
| &y_min, |
| &x_max, |
| &y_max); |
| if (unlikely (status)) |
| return status; |
| |
| status = cairo_type1_font_subset_get_matrix (font, "/FontMatrix", |
| &xx, &yx, &xy, &yy); |
| if (unlikely (status)) |
| return status; |
| |
| if (yy == 0.0) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Freetype uses 1/yy to get units per EM */ |
| font->base.units_per_em = 1.0/yy; |
| |
| font->base.x_min = x_min / font->base.units_per_em; |
| font->base.y_min = y_min / font->base.units_per_em; |
| font->base.x_max = x_max / font->base.units_per_em; |
| font->base.y_max = y_max / font->base.units_per_em; |
| font->base.ascent = font->base.y_max; |
| font->base.descent = font->base.y_min; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_get_fontname (cairo_type1_font_subset_t *font) |
| { |
| const char *start, *end, *segment_end; |
| char *s; |
| int i; |
| cairo_status_t status; |
| |
| segment_end = font->header_segment + font->header_segment_size; |
| start = find_token (font->header_segment, segment_end, "/FontName"); |
| if (start == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| start += strlen ("/FontName"); |
| |
| end = find_token (start, segment_end, "def"); |
| if (end == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| while (end > start && _cairo_isspace(end[-1])) |
| end--; |
| |
| s = malloc (end - start + 1); |
| if (unlikely (s == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| strncpy (s, start, end - start); |
| s[end - start] = 0; |
| |
| start = strchr (s, '/'); |
| if (!start++ || !start) { |
| free (s); |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| } |
| |
| /* If font name is prefixed with a subset tag, strip it off. */ |
| if (strlen(start) > 7 && start[6] == '+') { |
| for (i = 0; i < 6; i++) { |
| if (start[i] < 'A' || start[i] > 'Z') |
| break; |
| } |
| if (i == 6) |
| start += 7; |
| } |
| |
| font->base.base_font = strdup (start); |
| free (s); |
| if (unlikely (font->base.base_font == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| status = _cairo_escape_ps_name (&font->base.base_font); |
| |
| return status; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font, |
| const char *name) |
| { |
| const char *start, *end, *segment_end; |
| unsigned int i; |
| |
| /* FIXME: |
| * This function assumes that /FontName always appears |
| * before /Encoding. This appears to always be the case with Type1 |
| * fonts. |
| * |
| * The more recently added code for removing the UniqueID and XUID |
| * keys can not make any assumptions about the position of the |
| * keys in the dictionary so it is implemented by overwriting the |
| * key definition with spaces before we start copying the font to |
| * the output. |
| * |
| * This code should be rewritten to not make any assumptions about |
| * the order of dictionary keys. This will allow UniqueID to be |
| * stripped out instead of leaving a bunch of spaces in the |
| * output. |
| */ |
| cairo_type1_font_erase_dict_key (font, "/UniqueID"); |
| cairo_type1_font_erase_dict_key (font, "/XUID"); |
| |
| segment_end = font->header_segment + font->header_segment_size; |
| |
| /* Type 1 fonts created by Fontforge have some PostScript code at |
| * the start of the font that skips the font if the printer has a |
| * cached copy of the font with the same unique id. This breaks |
| * our subsetted font so we disable it by searching for the |
| * PostScript operator "known" when used to check for the |
| * "/UniqueID" dictionary key. We append " pop false " after it to |
| * pop the result of this check off the stack and replace it with |
| * "false" to make the PostScript code think "/UniqueID" does not |
| * exist. |
| */ |
| end = font->header_segment; |
| start = find_token (font->header_segment, segment_end, "/UniqueID"); |
| if (start) { |
| start += 9; |
| while (start < segment_end && _cairo_isspace (*start)) |
| start++; |
| if (start + 5 < segment_end && memcmp(start, "known", 5) == 0) { |
| _cairo_output_stream_write (font->output, font->header_segment, |
| start + 5 - font->header_segment); |
| _cairo_output_stream_printf (font->output, " pop false "); |
| end = start + 5; |
| } |
| } |
| |
| start = find_token (end, segment_end, "/FontName"); |
| if (start == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| _cairo_output_stream_write (font->output, end, |
| start - end); |
| |
| _cairo_output_stream_printf (font->output, "/FontName /%s def", name); |
| |
| end = find_token (start, segment_end, "def"); |
| if (end == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| end += 3; |
| |
| start = find_token (end, segment_end, "/Encoding"); |
| if (start == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| _cairo_output_stream_write (font->output, end, start - end); |
| |
| _cairo_output_stream_printf (font->output, |
| "/Encoding 256 array\n" |
| "0 1 255 {1 index exch /.notdef put} for\n"); |
| if (font->scaled_font_subset->is_latin) { |
| for (i = 1; i < 256; i++) { |
| int subset_glyph = font->scaled_font_subset->latin_to_subset_glyph_index[i]; |
| |
| if (subset_glyph > 0) { |
| _cairo_output_stream_printf (font->output, |
| "dup %d /%s put\n", |
| i, |
| _cairo_winansi_to_glyphname (i)); |
| } |
| } |
| } else { |
| for (i = 0; i < font->base.num_glyphs; i++) { |
| if (font->glyphs[i].subset_index <= 0) |
| continue; |
| _cairo_output_stream_printf (font->output, |
| "dup %d /%s put\n", |
| font->glyphs[i].subset_index, |
| font->glyph_names[i]); |
| } |
| } |
| _cairo_output_stream_printf (font->output, "readonly def"); |
| |
| end = find_token (start, segment_end, "def"); |
| if (end == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| end += 3; |
| |
| /* There are some buggy fonts that contain more than one /Encoding */ |
| if (find_token (end, segment_end, "/Encoding")) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| _cairo_output_stream_write (font->output, end, segment_end - end); |
| |
| return font->output->status; |
| } |
| |
| static int |
| hex_to_int (int ch) |
| { |
| if (ch <= '9') |
| return ch - '0'; |
| else if (ch <= 'F') |
| return ch - 'A' + 10; |
| else |
| return ch - 'a' + 10; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font, |
| const char *data, unsigned int length) |
| { |
| const unsigned char *in, *end; |
| int c, p; |
| static const char hex_digits[16] = "0123456789abcdef"; |
| char digits[3]; |
| |
| in = (const unsigned char *) data; |
| end = (const unsigned char *) data + length; |
| while (in < end) { |
| p = *in++; |
| c = p ^ (font->eexec_key >> 8); |
| font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; |
| |
| if (font->hex_encode) { |
| digits[0] = hex_digits[c >> 4]; |
| digits[1] = hex_digits[c & 0x0f]; |
| digits[2] = '\n'; |
| font->hex_column += 2; |
| |
| if (font->hex_column == 78) { |
| _cairo_output_stream_write (font->output, digits, 3); |
| font->hex_column = 0; |
| } else { |
| _cairo_output_stream_write (font->output, digits, 2); |
| } |
| } else { |
| digits[0] = c; |
| _cairo_output_stream_write (font->output, digits, 1); |
| } |
| } |
| |
| return font->output->status; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font) |
| { |
| unsigned short r = CAIRO_TYPE1_PRIVATE_DICT_KEY; |
| unsigned char *in, *end; |
| char *out; |
| int c, p; |
| int i; |
| |
| in = (unsigned char *) font->eexec_segment; |
| end = (unsigned char *) in + font->eexec_segment_size; |
| |
| font->cleartext = malloc (font->eexec_segment_size + 1); |
| if (unlikely (font->cleartext == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| out = font->cleartext; |
| while (in < end) { |
| if (font->eexec_segment_is_ascii) { |
| c = *in++; |
| if (_cairo_isspace (c)) |
| continue; |
| c = (hex_to_int (c) << 4) | hex_to_int (*in++); |
| } else { |
| c = *in++; |
| } |
| p = c ^ (r >> 8); |
| r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; |
| |
| *out++ = p; |
| } |
| font->cleartext_end = out; |
| |
| /* Overwrite random bytes with spaces. |
| * |
| * The first 4 bytes of the cleartext are the random bytes |
| * required by the encryption algorithm. When encrypting the |
| * cleartext, the first ciphertext byte must not be a white space |
| * character and the first 4 bytes must not be an ASCII Hex |
| * character. Some fonts do not check that their randomly chosen |
| * bytes results in ciphertext that complies with this |
| * restriction. This may cause problems for some PDF consumers. By |
| * replacing the random bytes with spaces, the first four bytes of |
| * ciphertext will always be 0xf9, 0x83, 0xef, 0x00 which complies |
| * with this restriction. Using spaces also means we don't have to |
| * skip over the random bytes when parsing the cleartext. |
| */ |
| for (i = 0; i < 4 && i < font->eexec_segment_size; i++) |
| font->cleartext[i] = ' '; |
| |
| /* Ensure strtol() can not scan past the end of the cleartext */ |
| font->cleartext[font->eexec_segment_size] = 0; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static const char * |
| skip_token (const char *p, const char *end) |
| { |
| while (p < end && _cairo_isspace(*p)) |
| p++; |
| |
| while (p < end && !_cairo_isspace(*p)) |
| p++; |
| |
| if (p == end) |
| return NULL; |
| |
| return p; |
| } |
| |
| static void |
| cairo_type1_font_subset_decrypt_charstring (const unsigned char *in, int size, unsigned char *out) |
| { |
| unsigned short r = CAIRO_TYPE1_CHARSTRING_KEY; |
| int c, p, i; |
| |
| for (i = 0; i < size; i++) { |
| c = *in++; |
| p = c ^ (r >> 8); |
| r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; |
| *out++ = p; |
| } |
| } |
| |
| static const unsigned char * |
| cairo_type1_font_subset_decode_integer (const unsigned char *p, int *integer) |
| { |
| if (*p <= 246) { |
| *integer = *p++ - 139; |
| } else if (*p <= 250) { |
| *integer = (p[0] - 247) * 256 + p[1] + 108; |
| p += 2; |
| } else if (*p <= 254) { |
| *integer = -(p[0] - 251) * 256 - p[1] - 108; |
| p += 2; |
| } else { |
| *integer = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]; |
| p += 5; |
| } |
| |
| return p; |
| } |
| |
| static cairo_status_t |
| use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index) |
| { |
| const char *glyph_name; |
| unsigned int i; |
| |
| if (index < 0 || index > 255) |
| return CAIRO_STATUS_SUCCESS; |
| |
| glyph_name = _cairo_ps_standard_encoding_to_glyphname (index); |
| if (glyph_name == NULL) |
| return CAIRO_STATUS_SUCCESS; |
| |
| for (i = 0; i < font->base.num_glyphs; i++) { |
| if (font->glyph_names[i] && strcmp (font->glyph_names[i], glyph_name) == 0) { |
| cairo_type1_font_subset_use_glyph (font, i); |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| } |
| |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| } |
| |
| |
| #define TYPE1_CHARSTRING_COMMAND_HSTEM 0x01 |
| #define TYPE1_CHARSTRING_COMMAND_VSTEM 0x03 |
| #define TYPE1_CHARSTRING_COMMAND_VMOVETO 0x04 |
| #define TYPE1_CHARSTRING_COMMAND_RLINETO 0x05 |
| #define TYPE1_CHARSTRING_COMMAND_HLINETO 0x06 |
| #define TYPE1_CHARSTRING_COMMAND_VLINETO 0x07 |
| #define TYPE1_CHARSTRING_COMMAND_RRCURVETO 0x08 |
| #define TYPE1_CHARSTRING_COMMAND_CLOSEPATH 0x09 |
| #define TYPE1_CHARSTRING_COMMAND_CALLSUBR 0x0a |
| #define TYPE1_CHARSTRING_COMMAND_RETURN 0x0b |
| #define TYPE1_CHARSTRING_COMMAND_ESCAPE 0x0c |
| #define TYPE1_CHARSTRING_COMMAND_HSBW 0x0d |
| #define TYPE1_CHARSTRING_COMMAND_ENDCHAR 0x0e |
| #define TYPE1_CHARSTRING_COMMAND_RMOVETO 0x15 |
| #define TYPE1_CHARSTRING_COMMAND_HMOVETO 0x16 |
| #define TYPE1_CHARSTRING_COMMAND_VHCURVETO 0x1e |
| #define TYPE1_CHARSTRING_COMMAND_HVCURVETO 0x1f |
| #define TYPE1_CHARSTRING_COMMAND_DOTSECTION 0x0c00 |
| #define TYPE1_CHARSTRING_COMMAND_VSTEM3 0x0c01 |
| #define TYPE1_CHARSTRING_COMMAND_HSTEM3 0x0c02 |
| #define TYPE1_CHARSTRING_COMMAND_SEAC 0x0c06 |
| #define TYPE1_CHARSTRING_COMMAND_SBW 0x0c07 |
| #define TYPE1_CHARSTRING_COMMAND_DIV 0x0c0c |
| #define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR 0x0c10 |
| #define TYPE1_CHARSTRING_COMMAND_POP 0x0c11 |
| #define TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT 0x0c21 |
| |
| /* Parse the charstring, including recursing into subroutines. Find |
| * the glyph width, subroutines called, and glyphs required by the |
| * SEAC operator. */ |
| static cairo_status_t |
| cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font, |
| int glyph, |
| const char *encrypted_charstring, |
| int encrypted_charstring_length) |
| { |
| cairo_status_t status; |
| unsigned char *charstring; |
| const unsigned char *end; |
| const unsigned char *p; |
| int command; |
| |
| charstring = malloc (encrypted_charstring_length); |
| if (unlikely (charstring == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| cairo_type1_font_subset_decrypt_charstring ((const unsigned char *) |
| encrypted_charstring, |
| encrypted_charstring_length, |
| charstring); |
| end = charstring + encrypted_charstring_length; |
| p = charstring + font->lenIV; |
| status = CAIRO_STATUS_SUCCESS; |
| while (p < end) { |
| if (*p < 32) { |
| command = *p++; |
| switch (command) { |
| case TYPE1_CHARSTRING_COMMAND_HSTEM: |
| case TYPE1_CHARSTRING_COMMAND_VSTEM: |
| case TYPE1_CHARSTRING_COMMAND_VMOVETO: |
| case TYPE1_CHARSTRING_COMMAND_RLINETO: |
| case TYPE1_CHARSTRING_COMMAND_HLINETO: |
| case TYPE1_CHARSTRING_COMMAND_VLINETO: |
| case TYPE1_CHARSTRING_COMMAND_RRCURVETO: |
| case TYPE1_CHARSTRING_COMMAND_CLOSEPATH: |
| case TYPE1_CHARSTRING_COMMAND_RMOVETO: |
| case TYPE1_CHARSTRING_COMMAND_HMOVETO: |
| case TYPE1_CHARSTRING_COMMAND_VHCURVETO: |
| case TYPE1_CHARSTRING_COMMAND_HVCURVETO: |
| case TYPE1_CHARSTRING_COMMAND_RETURN: |
| case TYPE1_CHARSTRING_COMMAND_ENDCHAR: |
| default: |
| /* stack clearing operator */ |
| font->build_stack.sp = 0; |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_CALLSUBR: |
| if (font->subset_subrs && font->build_stack.sp > 0) { |
| double int_val; |
| if (modf(font->build_stack.stack[--font->build_stack.sp], &int_val) == 0.0) { |
| int subr_num = int_val; |
| if (subr_num >= 0 && subr_num < font->num_subrs) { |
| font->subrs[subr_num].used = TRUE; |
| status = cairo_type1_font_subset_parse_charstring ( |
| font, |
| glyph, |
| font->subrs[subr_num].subr_string, |
| font->subrs[subr_num].subr_length); |
| break; |
| } |
| } |
| } |
| font->subset_subrs = FALSE; |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_HSBW: |
| if (font->build_stack.sp < 2) { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } |
| |
| font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em; |
| font->build_stack.sp = 0; |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_ESCAPE: |
| command = command << 8 | *p++; |
| switch (command) { |
| case TYPE1_CHARSTRING_COMMAND_DOTSECTION: |
| case TYPE1_CHARSTRING_COMMAND_VSTEM3: |
| case TYPE1_CHARSTRING_COMMAND_HSTEM3: |
| case TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT: |
| default: |
| /* stack clearing operator */ |
| font->build_stack.sp = 0; |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_SEAC: |
| /* The seac command takes five integer arguments. The |
| * last two are glyph indices into the PS standard |
| * encoding give the names of the glyphs that this |
| * glyph is composed from. All we need to do is to |
| * make sure those glyphs are present in the subset |
| * under their standard names. */ |
| if (font->build_stack.sp < 5) { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } |
| |
| status = use_standard_encoding_glyph (font, font->build_stack.stack[3]); |
| if (unlikely (status)) |
| goto cleanup; |
| |
| status = use_standard_encoding_glyph (font, font->build_stack.stack[4]); |
| if (unlikely (status)) |
| goto cleanup; |
| |
| font->build_stack.sp = 0; |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_SBW: |
| if (font->build_stack.sp < 4) { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } |
| |
| font->glyphs[glyph].width = font->build_stack.stack[2]/font->base.units_per_em; |
| font->build_stack.sp = 0; |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_DIV: |
| if (font->build_stack.sp < 2) { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } else { |
| double num1 = font->build_stack.stack[font->build_stack.sp - 2]; |
| double num2 = font->build_stack.stack[font->build_stack.sp - 1]; |
| font->build_stack.sp--; |
| if (num2 == 0.0) { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } |
| font->build_stack.stack[font->build_stack.sp - 1] = num1/num2; |
| } |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR: |
| if (font->build_stack.sp < 1) { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } |
| |
| font->build_stack.sp--; |
| font->ps_stack.sp = 0; |
| while (font->build_stack.sp) |
| font->ps_stack.stack[font->ps_stack.sp++] = font->build_stack.stack[--font->build_stack.sp]; |
| |
| break; |
| |
| case TYPE1_CHARSTRING_COMMAND_POP: |
| if (font->ps_stack.sp < 1) { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } |
| |
| /* T1 spec states that if the interpreter does not |
| * support executing the callothersub, the results |
| * must be taken from the callothersub arguments. */ |
| font->build_stack.stack[font->build_stack.sp++] = font->ps_stack.stack[--font->ps_stack.sp]; |
| break; |
| } |
| break; |
| } |
| } else { |
| /* integer argument */ |
| if (font->build_stack.sp < TYPE1_STACKSIZE) { |
| int val; |
| p = cairo_type1_font_subset_decode_integer (p, &val); |
| font->build_stack.stack[font->build_stack.sp++] = val; |
| } else { |
| status = CAIRO_INT_STATUS_UNSUPPORTED; |
| goto cleanup; |
| } |
| } |
| } |
| |
| cleanup: |
| free (charstring); |
| |
| return status; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_build_subr_list (cairo_type1_font_subset_t *font, |
| int subr_number, |
| const char *encrypted_charstring, int encrypted_charstring_length, |
| const char *np, int np_length) |
| { |
| |
| font->subrs[subr_number].subr_string = encrypted_charstring; |
| font->subrs[subr_number].subr_length = encrypted_charstring_length; |
| font->subrs[subr_number].np = np; |
| font->subrs[subr_number].np_length = np_length; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static cairo_status_t |
| write_used_subrs (cairo_type1_font_subset_t *font, |
| int subr_number, |
| const char *subr_string, int subr_string_length, |
| const char *np, int np_length) |
| { |
| cairo_status_t status; |
| char buffer[256]; |
| int length; |
| |
| if (!font->subrs[subr_number].used) |
| return CAIRO_STATUS_SUCCESS; |
| |
| length = snprintf (buffer, sizeof buffer, |
| "dup %d %d %s ", |
| subr_number, subr_string_length, font->rd); |
| status = cairo_type1_font_subset_write_encrypted (font, buffer, length); |
| if (unlikely (status)) |
| return status; |
| |
| status = cairo_type1_font_subset_write_encrypted (font, |
| subr_string, |
| subr_string_length); |
| if (unlikely (status)) |
| return status; |
| |
| if (np) { |
| status = cairo_type1_font_subset_write_encrypted (font, np, np_length); |
| } else { |
| length = snprintf (buffer, sizeof buffer, "%s\n", font->np); |
| status = cairo_type1_font_subset_write_encrypted (font, buffer, length); |
| } |
| if (unlikely (status)) |
| return status; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| typedef cairo_status_t (*subr_func_t) (cairo_type1_font_subset_t *font, |
| int subr_number, |
| const char *subr_string, int subr_string_length, |
| const char *np, int np_length); |
| |
| static cairo_status_t |
| cairo_type1_font_for_each_subr (cairo_type1_font_subset_t *font, |
| const char *array_start, |
| const char *cleartext_end, |
| subr_func_t func, |
| const char **array_end) |
| { |
| const char *p, *subr_string; |
| char *end; |
| int subr_num, subr_length; |
| const char *np; |
| int np_length; |
| cairo_status_t status; |
| |
| /* We're looking at "dup" at the start of the first subroutine. The subroutines |
| * definitions are on the form: |
| * |
| * dup 5 23 RD <23 binary bytes> NP |
| * |
| * or alternatively using -| and |- instead of RD and ND. |
| * The first number is the subroutine number. |
| */ |
| |
| p = array_start; |
| while (p + 3 < cleartext_end && strncmp (p, "dup", 3) == 0) { |
| p = skip_token (p, cleartext_end); |
| |
| /* get subr number */ |
| subr_num = strtol (p, &end, 10); |
| if (p == end) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| if (subr_num < 0 || subr_num >= font->num_subrs) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* get subr length */ |
| p = end; |
| subr_length = strtol (p, &end, 10); |
| if (p == end) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Skip past -| or RD to binary data. There is exactly one space |
| * between the -| or RD token and the encrypted data, thus '+ 1'. */ |
| subr_string = skip_token (end, cleartext_end) + 1; |
| |
| np = NULL; |
| np_length = 0; |
| |
| /* Skip binary data and | or NP token. */ |
| p = skip_token (subr_string + subr_length, cleartext_end); |
| while (p < cleartext_end && _cairo_isspace(*p)) |
| p++; |
| |
| /* Some fonts have "noaccess put" instead of "NP" */ |
| if (p + 3 < cleartext_end && strncmp (p, "put", 3) == 0) { |
| p = skip_token (p, cleartext_end); |
| while (p < cleartext_end && _cairo_isspace(*p)) |
| p++; |
| |
| np = subr_string + subr_length; |
| np_length = p - np; |
| } |
| |
| status = func (font, subr_num, |
| subr_string, subr_length, np, np_length); |
| if (unlikely (status)) |
| return status; |
| |
| } |
| |
| *array_end = (char *) p; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_build_glyph_list (cairo_type1_font_subset_t *font, |
| int glyph_number, |
| const char *name, int name_length, |
| const char *encrypted_charstring, int encrypted_charstring_length) |
| { |
| char *s; |
| glyph_data_t glyph; |
| cairo_status_t status; |
| |
| s = malloc (name_length + 1); |
| if (unlikely (s == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| strncpy (s, name, name_length); |
| s[name_length] = 0; |
| |
| status = _cairo_array_append (&font->glyph_names_array, &s); |
| if (unlikely (status)) |
| return status; |
| |
| glyph.subset_index = -1; |
| glyph.width = 0; |
| glyph.encrypted_charstring = encrypted_charstring; |
| glyph.encrypted_charstring_length = encrypted_charstring_length; |
| status = _cairo_array_append (&font->glyphs_array, &glyph); |
| |
| return status; |
| } |
| |
| static cairo_status_t |
| write_used_glyphs (cairo_type1_font_subset_t *font, |
| int glyph_number, |
| const char *name, int name_length, |
| const char *charstring, int charstring_length) |
| { |
| cairo_status_t status; |
| char buffer[256]; |
| int length; |
| unsigned int subset_id; |
| int ch; |
| const char *wa_name; |
| |
| if (font->glyphs[glyph_number].subset_index < 0) |
| return CAIRO_STATUS_SUCCESS; |
| |
| if (font->scaled_font_subset->is_latin) { |
| /* When using the WinAnsi encoding in PDF, the /Encoding array |
| * is ignored and instead glyphs are keyed by glyph names. To |
| * ensure correct rendering we replace the glyph name in the |
| * font with the standard name. |
| **/ |
| subset_id = font->glyphs[glyph_number].subset_index; |
| /* Any additional glyph included for use by the seac operator |
| * will either have subset_id >= font->scaled_font_subset->num_glyphs |
| * or will not map to a winansi name (wa_name = NULL). In this |
| * case the original name is used. |
| */ |
| if (subset_id > 0 && subset_id < font->scaled_font_subset->num_glyphs) { |
| ch = font->scaled_font_subset->to_latin_char[subset_id]; |
| wa_name = _cairo_winansi_to_glyphname (ch); |
| if (wa_name) { |
| name = wa_name; |
| name_length = strlen(name); |
| } |
| } |
| } |
| |
| length = snprintf (buffer, sizeof buffer, |
| "/%.*s %d %s ", |
| name_length, name, charstring_length, font->rd); |
| status = cairo_type1_font_subset_write_encrypted (font, buffer, length); |
| if (unlikely (status)) |
| return status; |
| |
| status = cairo_type1_font_subset_write_encrypted (font, |
| charstring, |
| charstring_length); |
| if (unlikely (status)) |
| return status; |
| |
| length = snprintf (buffer, sizeof buffer, "%s\n", font->nd); |
| status = cairo_type1_font_subset_write_encrypted (font, buffer, length); |
| if (unlikely (status)) |
| return status; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| typedef cairo_status_t (*glyph_func_t) (cairo_type1_font_subset_t *font, |
| int glyph_number, |
| const char *name, int name_length, |
| const char *charstring, int charstring_length); |
| |
| static cairo_status_t |
| cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font, |
| const char *dict_start, |
| const char *dict_end, |
| glyph_func_t func, |
| const char **dict_out) |
| { |
| int charstring_length, name_length; |
| const char *p, *charstring, *name; |
| char *end; |
| cairo_status_t status; |
| int glyph_count; |
| |
| /* We're looking at '/' in the name of the first glyph. The glyph |
| * definitions are on the form: |
| * |
| * /name 23 RD <23 binary bytes> ND |
| * |
| * or alternatively using -| and |- instead of RD and ND. |
| * |
| * We parse the glyph name and see if it is in the subset. If it |
| * is, we call the specified callback with the glyph name and |
| * glyph data, otherwise we just skip it. We need to parse |
| * through a glyph definition; we can't just find the next '/', |
| * since the binary data could contain a '/'. |
| */ |
| |
| p = dict_start; |
| glyph_count = 0; |
| while (*p == '/') { |
| name = p + 1; |
| p = skip_token (p, dict_end); |
| name_length = p - name; |
| |
| charstring_length = strtol (p, &end, 10); |
| if (p == end) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Skip past -| or RD to binary data. There is exactly one space |
| * between the -| or RD token and the encrypted data, thus '+ 1'. */ |
| charstring = skip_token (end, dict_end) + 1; |
| |
| /* Skip binary data and |- or ND token. */ |
| p = skip_token (charstring + charstring_length, dict_end); |
| while (p < dict_end && _cairo_isspace(*p)) |
| p++; |
| |
| /* In case any of the skip_token() calls above reached EOF, p will |
| * be equal to dict_end. */ |
| if (p == dict_end) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| status = func (font, glyph_count++, |
| name, name_length, |
| charstring, charstring_length); |
| if (unlikely (status)) |
| return status; |
| } |
| |
| *dict_out = p; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| |
| static cairo_status_t |
| cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, |
| const char *name) |
| { |
| cairo_status_t status; |
| const char *p, *subrs, *charstrings, *array_start, *array_end, *dict_start, *dict_end; |
| const char *lenIV_start, *lenIV_end, *closefile_token; |
| char buffer[32], *lenIV_str, *subr_count_end, *glyph_count_end; |
| int ret, lenIV, length; |
| const cairo_scaled_font_backend_t *backend; |
| unsigned int i; |
| int glyph, j; |
| |
| /* The private dict holds hint information, common subroutines and |
| * the actual glyph definitions (charstrings). |
| * |
| * What we do here is scan directly to the /Subrs token, which |
| * marks the beginning of the subroutines. We read in all the |
| * subroutines, then move on to the /CharString token, which marks |
| * the beginning of the glyph definitions, and read in the charstrings. |
| * |
| * The charstrings are parsed to extract glyph widths, work out |
| * which subroutines are called, and to see if any extra glyphs |
| * need to be included due to the use of the seac glyph combining |
| * operator. |
| * |
| * Finally, the private dict is copied to the subset font minus the |
| * subroutines and charstrings not required. |
| */ |
| |
| /* Determine lenIV, the number of random characters at the start of |
| each encrypted charstring. The default is 4, but this can be |
| overridden in the private dict. */ |
| font->lenIV = 4; |
| if ((lenIV_start = find_token (font->cleartext, font->cleartext_end, "/lenIV")) != NULL) { |
| lenIV_start += 6; |
| lenIV_end = find_token (lenIV_start, font->cleartext_end, "def"); |
| if (lenIV_end == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| lenIV_str = malloc (lenIV_end - lenIV_start + 1); |
| if (unlikely (lenIV_str == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| strncpy (lenIV_str, lenIV_start, lenIV_end - lenIV_start); |
| lenIV_str[lenIV_end - lenIV_start] = 0; |
| |
| ret = sscanf(lenIV_str, "%d", &lenIV); |
| free(lenIV_str); |
| |
| if (unlikely (ret <= 0)) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Apparently some fonts signal unencrypted charstrings with a negative lenIV, |
| though this is not part of the Type 1 Font Format specification. See, e.g. |
| http://lists.gnu.org/archive/html/freetype-devel/2000-06/msg00064.html. */ |
| if (unlikely (lenIV < 0)) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| font->lenIV = lenIV; |
| } |
| |
| /* Find start of Subrs */ |
| subrs = find_token (font->cleartext, font->cleartext_end, "/Subrs"); |
| if (subrs == NULL) { |
| font->subset_subrs = FALSE; |
| p = font->cleartext; |
| array_start = NULL; |
| goto skip_subrs; |
| } |
| |
| /* Scan past /Subrs and get the array size. */ |
| p = subrs + strlen ("/Subrs"); |
| font->num_subrs = strtol (p, &subr_count_end, 10); |
| if (subr_count_end == p) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| if (font->num_subrs <= 0) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| font->subrs = calloc (font->num_subrs, sizeof (font->subrs[0])); |
| if (unlikely (font->subrs == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| /* look for "dup" which marks the beginning of the first subr */ |
| array_start = find_token (subr_count_end, font->cleartext_end, "dup"); |
| if (subrs == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Read in the subroutines */ |
| status = cairo_type1_font_for_each_subr (font, |
| array_start, |
| font->cleartext_end, |
| cairo_type1_font_subset_build_subr_list, |
| &array_end); |
| if (unlikely(status)) |
| return status; |
| |
| p = array_end; |
| skip_subrs: |
| |
| /* Find start of CharStrings */ |
| charstrings = find_token (p, font->cleartext_end, "/CharStrings"); |
| if (charstrings == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Scan past /CharStrings and the integer following it. */ |
| p = charstrings + strlen ("/CharStrings"); |
| strtol (p, &glyph_count_end, 10); |
| if (p == glyph_count_end) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Look for a '/' which marks the beginning of the first glyph |
| * definition. */ |
| for (p = glyph_count_end; p < font->cleartext_end; p++) |
| if (*p == '/') |
| break; |
| if (p == font->cleartext_end) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| dict_start = p; |
| |
| /* Now that we have the private dictionary broken down in |
| * sections, do the first pass through the glyph definitions to |
| * build a list of glyph names and charstrings. */ |
| status = cairo_type1_font_subset_for_each_glyph (font, |
| dict_start, |
| font->cleartext_end, |
| cairo_type1_font_subset_build_glyph_list, |
| &dict_end); |
| if (unlikely(status)) |
| return status; |
| |
| font->glyphs = _cairo_array_index (&font->glyphs_array, 0); |
| font->glyph_names = _cairo_array_index (&font->glyph_names_array, 0); |
| font->base.num_glyphs = _cairo_array_num_elements (&font->glyphs_array); |
| font->subset_index_to_glyphs = calloc (font->base.num_glyphs, sizeof font->subset_index_to_glyphs[0]); |
| if (unlikely (font->subset_index_to_glyphs == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| backend = font->scaled_font_subset->scaled_font->backend; |
| if (!backend->index_to_glyph_name) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* Find the glyph number corresponding to each glyph in the subset |
| * and mark it as in use */ |
| |
| for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { |
| unsigned long index; |
| |
| status = backend->index_to_glyph_name (font->scaled_font_subset->scaled_font, |
| font->glyph_names, |
| font->base.num_glyphs, |
| font->scaled_font_subset->glyphs[i], |
| &index); |
| if (unlikely(status)) |
| return status; |
| |
| cairo_type1_font_subset_use_glyph (font, index); |
| } |
| |
| /* Go through the charstring of each glyph in use, get the glyph |
| * width and figure out which extra glyphs may be required by the |
| * seac operator (which may cause font->num_glyphs to increase |
| * while this loop is executing). Also subset the Subrs. */ |
| for (j = 0; j < font->num_glyphs; j++) { |
| glyph = font->subset_index_to_glyphs[j]; |
| font->build_stack.sp = 0; |
| font->ps_stack.sp = 0; |
| status = cairo_type1_font_subset_parse_charstring (font, |
| glyph, |
| font->glyphs[glyph].encrypted_charstring, |
| font->glyphs[glyph].encrypted_charstring_length); |
| if (unlikely (status)) |
| return status; |
| } |
| |
| /* Always include the first five subroutines in case the Flex/hint mechanism is |
| * being used. */ |
| for (j = 0; j < MIN (font->num_subrs, 5); j++) { |
| font->subrs[j].used = TRUE; |
| } |
| |
| closefile_token = find_token (dict_end, font->cleartext_end, "closefile"); |
| if (closefile_token == NULL) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| /* We're ready to start outputting. First write the header, |
| * i.e. the public part of the font dict.*/ |
| status = cairo_type1_font_subset_write_header (font, name); |
| if (unlikely (status)) |
| return status; |
| |
| font->base.header_size = _cairo_output_stream_get_position (font->output); |
| |
| /* Start outputting the private dict */ |
| if (font->subset_subrs) { |
| /* First output everything up to the start of the Subrs array. */ |
| status = cairo_type1_font_subset_write_encrypted (font, font->cleartext, |
| array_start - font->cleartext); |
| if (unlikely (status)) |
| return status; |
| |
| /* Write out the subr definitions for each of the glyphs in |
| * the subset. */ |
| status = cairo_type1_font_for_each_subr (font, |
| array_start, |
| font->cleartext_end, |
| write_used_subrs, |
| &p); |
| if (unlikely (status)) |
| return status; |
| } else { |
| p = font->cleartext; |
| } |
| |
| /* If subr subsetting, output everything from end of subrs to |
| * start of /CharStrings token. If not subr subsetting, output |
| * everything start of private dict to start of /CharStrings |
| * token. */ |
| status = cairo_type1_font_subset_write_encrypted (font, p, charstrings - p); |
| if (unlikely (status)) |
| return status; |
| |
| /* Write out new charstring count */ |
| length = snprintf (buffer, sizeof buffer, |
| "/CharStrings %d", font->num_glyphs); |
| status = cairo_type1_font_subset_write_encrypted (font, buffer, length); |
| if (unlikely (status)) |
| return status; |
| |
| /* Write out text between the charstring count and the first |
| * charstring definition */ |
| status = cairo_type1_font_subset_write_encrypted (font, glyph_count_end, |
| dict_start - glyph_count_end); |
| if (unlikely (status)) |
| return status; |
| |
| /* Write out the charstring definitions for each of the glyphs in |
| * the subset. */ |
| status = cairo_type1_font_subset_for_each_glyph (font, |
| dict_start, |
| font->cleartext_end, |
| write_used_glyphs, |
| &p); |
| if (unlikely (status)) |
| return status; |
| |
| /* Output what's left between the end of the glyph definitions and |
| * the end of the private dict to the output. */ |
| status = cairo_type1_font_subset_write_encrypted (font, p, |
| closefile_token - p + strlen ("closefile") + 1); |
| if (unlikely (status)) |
| return status; |
| |
| if (font->hex_encode) |
| _cairo_output_stream_write (font->output, "\n", 1); |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_write_trailer(cairo_type1_font_subset_t *font) |
| { |
| const char *cleartomark_token; |
| int i; |
| static const char zeros[65] = |
| "0000000000000000000000000000000000000000000000000000000000000000\n"; |
| |
| |
| for (i = 0; i < 8; i++) |
| _cairo_output_stream_write (font->output, zeros, sizeof zeros); |
| |
| cleartomark_token = find_token (font->type1_data, font->type1_end, "cleartomark"); |
| if (cleartomark_token) { |
| /* Some fonts have conditional save/restore around the entire |
| * font dict, so we need to retain whatever postscript code |
| * that may come after 'cleartomark'. */ |
| |
| _cairo_output_stream_write (font->output, cleartomark_token, |
| font->type1_end - cleartomark_token); |
| if (*(font->type1_end - 1) != '\n') |
| _cairo_output_stream_printf (font->output, "\n"); |
| |
| } else if (!font->eexec_segment_is_ascii) { |
| /* Fonts embedded in PDF may omit the fixed-content portion |
| * that includes the 'cleartomark' operator. Type 1 in PDF is |
| * always binary. */ |
| |
| _cairo_output_stream_printf (font->output, "cleartomark\n"); |
| } else { |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| } |
| |
| /* some fonts do not have a newline at the end of the last line */ |
| _cairo_output_stream_printf (font->output, "\n"); |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static cairo_status_t |
| type1_font_write (void *closure, const unsigned char *data, unsigned int length) |
| { |
| cairo_type1_font_subset_t *font = closure; |
| |
| return _cairo_array_append_multiple (&font->contents, data, length); |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_write (cairo_type1_font_subset_t *font, |
| const char *name) |
| { |
| cairo_status_t status; |
| |
| status = cairo_type1_font_subset_find_segments (font); |
| if (unlikely (status)) |
| return status; |
| |
| status = cairo_type1_font_subset_decrypt_eexec_segment (font); |
| if (unlikely (status)) |
| return status; |
| |
| /* Determine which glyph definition delimiters to use. */ |
| if (find_token (font->cleartext, font->cleartext_end, "/-|") != NULL) { |
| font->rd = "-|"; |
| font->nd = "|-"; |
| font->np = "|"; |
| } else if (find_token (font->cleartext, font->cleartext_end, "/RD") != NULL) { |
| font->rd = "RD"; |
| font->nd = "ND"; |
| font->np = "NP"; |
| } else { |
| /* Don't know *what* kind of font this is... */ |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| } |
| |
| font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; |
| font->hex_column = 0; |
| |
| status = cairo_type1_font_subset_get_bbox (font); |
| if (unlikely (status)) |
| return status; |
| |
| status = cairo_type1_font_subset_get_fontname (font); |
| if (unlikely (status)) |
| return status; |
| |
| status = cairo_type1_font_subset_write_private_dict (font, name); |
| if (unlikely (status)) |
| return status; |
| |
| font->base.data_size = _cairo_output_stream_get_position (font->output) - |
| font->base.header_size; |
| |
| status = cairo_type1_font_subset_write_trailer (font); |
| if (unlikely (status)) |
| return status; |
| |
| font->base.trailer_size = |
| _cairo_output_stream_get_position (font->output) - |
| font->base.header_size - font->base.data_size; |
| |
| return CAIRO_STATUS_SUCCESS; |
| } |
| |
| static cairo_bool_t |
| check_fontdata_is_type1 (const unsigned char *data, long length) |
| { |
| /* Test for Type 1 Binary (PFB) */ |
| if (length > 2 && data[0] == 0x80 && data[1] == 0x01) |
| return TRUE; |
| |
| /* Test for Type 1 1 ASCII (PFA) */ |
| if (length > 2 && data[0] == '%' && data[1] == '!') |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| static cairo_status_t |
| cairo_type1_font_subset_generate (void *abstract_font, |
| const char *name) |
| |
| { |
| cairo_type1_font_subset_t *font = abstract_font; |
| cairo_scaled_font_t *scaled_font; |
| cairo_status_t status; |
| unsigned long data_length; |
| |
| scaled_font = font->scaled_font_subset->scaled_font; |
| if (!scaled_font->backend->load_type1_data) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| status = scaled_font->backend->load_type1_data (scaled_font, 0, NULL, &data_length); |
| if (status) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| font->type1_length = data_length; |
| font->type1_data = malloc (font->type1_length); |
| if (unlikely (font->type1_data == NULL)) |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| |
| status = scaled_font->backend->load_type1_data (scaled_font, 0, |
| (unsigned char *) font->type1_data, |
| &data_length); |
| if (unlikely (status)) |
| return status; |
| |
| if (!check_fontdata_is_type1 ((unsigned char *)font->type1_data, data_length)) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| status = _cairo_array_grow_by (&font->contents, 4096); |
| if (unlikely (status)) |
| return status; |
| |
| font->output = _cairo_output_stream_create (type1_font_write, NULL, font); |
| if (unlikely ((status = font->output->status))) |
| return status; |
| |
| status = cairo_type1_font_subset_write (font, name); |
| if (unlikely (status)) |
| return status; |
| |
| font->base.data = _cairo_array_index (&font->contents, 0); |
| |
| return status; |
| } |
| |
| static cairo_status_t |
| _cairo_type1_font_subset_fini (cairo_type1_font_subset_t *font) |
| { |
| cairo_status_t status = CAIRO_STATUS_SUCCESS; |
| unsigned int i; |
| |
| /* If the subset generation failed, some of the pointers below may |
| * be NULL depending on at which point the error occurred. */ |
| |
| _cairo_array_fini (&font->contents); |
| |
| free (font->type1_data); |
| for (i = 0; i < _cairo_array_num_elements (&font->glyph_names_array); i++) { |
| char **s; |
| |
| s = _cairo_array_index (&font->glyph_names_array, i); |
| free (*s); |
| } |
| _cairo_array_fini (&font->glyph_names_array); |
| _cairo_array_fini (&font->glyphs_array); |
| |
| free (font->subrs); |
| |
| if (font->output != NULL) |
| status = _cairo_output_stream_destroy (font->output); |
| |
| free (font->base.base_font); |
| |
| free (font->subset_index_to_glyphs); |
| |
| free (font->cleartext); |
| |
| return status; |
| } |
| |
| cairo_status_t |
| _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, |
| const char *name, |
| cairo_scaled_font_subset_t *scaled_font_subset, |
| cairo_bool_t hex_encode) |
| { |
| cairo_type1_font_subset_t font; |
| cairo_status_t status; |
| unsigned long length; |
| unsigned int i; |
| char buf[30]; |
| |
| /* We need to use a fallback font generated from the synthesized outlines. */ |
| if (scaled_font_subset->scaled_font->backend->is_synthetic && |
| scaled_font_subset->scaled_font->backend->is_synthetic (scaled_font_subset->scaled_font)) |
| return CAIRO_INT_STATUS_UNSUPPORTED; |
| |
| status = _cairo_type1_font_subset_init (&font, scaled_font_subset, hex_encode); |
| if (unlikely (status)) |
| return status; |
| |
| status = cairo_type1_font_subset_generate (&font, name); |
| if (unlikely (status)) |
| goto fail1; |
| |
| if (font.base.base_font) { |
| type1_subset->base_font = strdup (font.base.base_font); |
| } else { |
| snprintf(buf, sizeof (buf), "CairoFont-%u-%u", |
| scaled_font_subset->font_id, scaled_font_subset->subset_id); |
| type1_subset->base_font = strdup (buf); |
| } |
| if (unlikely (type1_subset->base_font == NULL)) |
| goto fail1; |
| |
| type1_subset->widths = calloc (sizeof (double), font.num_glyphs); |
| if (unlikely (type1_subset->widths == NULL)) |
| goto fail2; |
| for (i = 0; i < font.base.num_glyphs; i++) { |
| if (font.glyphs[i].subset_index < 0) |
| continue; |
| type1_subset->widths[font.glyphs[i].subset_index] = |
| font.glyphs[i].width; |
| } |
| |
| type1_subset->x_min = font.base.x_min; |
| type1_subset->y_min = font.base.y_min; |
| type1_subset->x_max = font.base.x_max; |
| type1_subset->y_max = font.base.y_max; |
| type1_subset->ascent = font.base.ascent; |
| type1_subset->descent = font.base.descent; |
| |
| length = font.base.header_size + |
| font.base.data_size + |
| font.base.trailer_size; |
| type1_subset->data = malloc (length); |
| if (unlikely (type1_subset->data == NULL)) |
| goto fail3; |
| |
| memcpy (type1_subset->data, |
| _cairo_array_index (&font.contents, 0), length); |
| |
| type1_subset->header_length = font.base.header_size; |
| type1_subset->data_length = font.base.data_size; |
| type1_subset->trailer_length = font.base.trailer_size; |
| |
| return _cairo_type1_font_subset_fini (&font); |
| |
| fail3: |
| free (type1_subset->widths); |
| fail2: |
| free (type1_subset->base_font); |
| fail1: |
| _cairo_type1_font_subset_fini (&font); |
| |
| return status; |
| } |
| |
| void |
| _cairo_type1_subset_fini (cairo_type1_subset_t *subset) |
| { |
| free (subset->base_font); |
| free (subset->widths); |
| free (subset->data); |
| } |
| |
| cairo_bool_t |
| _cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font) |
| { |
| cairo_status_t status; |
| unsigned long length; |
| unsigned char buf[64]; |
| |
| if (!scaled_font->backend->load_type1_data) |
| return FALSE; |
| |
| status = scaled_font->backend->load_type1_data (scaled_font, 0, NULL, &length); |
| if (status) |
| return FALSE; |
| |
| /* We only need a few bytes to test for Type 1 */ |
| if (length > sizeof (buf)) |
| length = sizeof (buf); |
| |
| status = scaled_font->backend->load_type1_data (scaled_font, 0, buf, &length); |
| if (status) |
| return FALSE; |
| |
| return check_fontdata_is_type1 (buf, length); |
| } |
| |
| #endif /* CAIRO_HAS_FONT_SUBSET */ |