diff options
Diffstat (limited to 'Build/source/libs/cairo/cairo-1.14.0/src/cairo-type1-fallback.c')
-rw-r--r-- | Build/source/libs/cairo/cairo-1.14.0/src/cairo-type1-fallback.c | 903 |
1 files changed, 903 insertions, 0 deletions
diff --git a/Build/source/libs/cairo/cairo-1.14.0/src/cairo-type1-fallback.c b/Build/source/libs/cairo/cairo-1.14.0/src/cairo-type1-fallback.c new file mode 100644 index 00000000000..4a657413e48 --- /dev/null +++ b/Build/source/libs/cairo/cairo-1.14.0/src/cairo-type1-fallback.c @@ -0,0 +1,903 @@ +/* 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): + * Adrian Johnson <ajohnson@redneon.com> + */ + +#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-path-fixed-private.h" +#include "cairo-output-stream-private.h" + +typedef enum { + CAIRO_CHARSTRING_TYPE1, + CAIRO_CHARSTRING_TYPE2 +} cairo_charstring_type_t; + +typedef struct _cairo_type1_font { + int *widths; + + cairo_scaled_font_subset_t *scaled_font_subset; + cairo_scaled_font_t *type1_scaled_font; + + cairo_array_t contents; + + double x_min, y_min, x_max, y_max; + + const char *data; + unsigned long header_size; + unsigned long data_size; + unsigned long trailer_size; + int bbox_position; + int bbox_max_chars; + + cairo_output_stream_t *output; + + unsigned short eexec_key; + cairo_bool_t hex_encode; + int hex_column; +} cairo_type1_font_t; + +static cairo_status_t +cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset, + cairo_type1_font_t **subset_return, + cairo_bool_t hex_encode) +{ + cairo_type1_font_t *font; + cairo_font_face_t *font_face; + cairo_matrix_t font_matrix; + cairo_matrix_t ctm; + cairo_font_options_t font_options; + cairo_status_t status; + + font = calloc (1, sizeof (cairo_type1_font_t)); + if (unlikely (font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + font->widths = calloc (scaled_font_subset->num_glyphs, sizeof (int)); + if (unlikely (font->widths == NULL)) { + free (font); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + font->scaled_font_subset = scaled_font_subset; + font->hex_encode = hex_encode; + + font_face = cairo_scaled_font_get_font_face (scaled_font_subset->scaled_font); + + cairo_matrix_init_scale (&font_matrix, 1000, -1000); + cairo_matrix_init_identity (&ctm); + + _cairo_font_options_init_default (&font_options); + cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); + + font->type1_scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + &font_options); + status = font->type1_scaled_font->status; + if (unlikely (status)) + goto fail; + + _cairo_array_init (&font->contents, sizeof (unsigned char)); + font->output = NULL; + + *subset_return = font; + + return CAIRO_STATUS_SUCCESS; + +fail: + free (font->widths); + free (font); + + return status; +} + +/* Charstring commands. If the high byte is 0 the command is encoded + * with a single byte. */ +#define CHARSTRING_sbw 0x0c07 +#define CHARSTRING_rmoveto 0x0015 +#define CHARSTRING_rlineto 0x0005 +#define CHARSTRING_rcurveto 0x0008 +#define CHARSTRING_closepath 0x0009 +#define CHARSTRING_endchar 0x000e + +/* Before calling this function, the caller must allocate sufficient + * space in data (see _cairo_array_grow_by). The maximum number of + * bytes that will be used is 2. + */ +static void +charstring_encode_command (cairo_array_t *data, int command) +{ + cairo_status_t status; + unsigned int orig_size; + unsigned char buf[5]; + unsigned char *p = buf; + + if (command & 0xff00) + *p++ = command >> 8; + *p++ = command & 0x00ff; + + /* Ensure the array doesn't grow, which allows this function to + * have no possibility of failure. */ + orig_size = _cairo_array_size (data); + status = _cairo_array_append_multiple (data, buf, p - buf); + + assert (status == CAIRO_STATUS_SUCCESS); + assert (_cairo_array_size (data) == orig_size); +} + +/* Before calling this function, the caller must allocate sufficient + * space in data (see _cairo_array_grow_by). The maximum number of + * bytes that will be used is 5. + */ +static void +charstring_encode_integer (cairo_array_t *data, + int i, + cairo_charstring_type_t type) +{ + cairo_status_t status; + unsigned int orig_size; + unsigned char buf[10]; + unsigned char *p = buf; + + if (i >= -107 && i <= 107) { + *p++ = i + 139; + } else if (i >= 108 && i <= 1131) { + i -= 108; + *p++ = (i >> 8)+ 247; + *p++ = i & 0xff; + } else if (i >= -1131 && i <= -108) { + i = -i - 108; + *p++ = (i >> 8)+ 251; + *p++ = i & 0xff; + } else { + if (type == CAIRO_CHARSTRING_TYPE1) { + *p++ = 0xff; + *p++ = i >> 24; + *p++ = (i >> 16) & 0xff; + *p++ = (i >> 8) & 0xff; + *p++ = i & 0xff; + } else { + *p++ = 0xff; + *p++ = (i >> 8) & 0xff; + *p++ = i & 0xff; + *p++ = 0; + *p++ = 0; + } + } + + /* Ensure the array doesn't grow, which allows this function to + * have no possibility of failure. */ + orig_size = _cairo_array_size (data); + status = _cairo_array_append_multiple (data, buf, p - buf); + + assert (status == CAIRO_STATUS_SUCCESS); + assert (_cairo_array_size (data) == orig_size); +} + +typedef struct _ps_path_info { + cairo_array_t *data; + int current_x, current_y; + cairo_charstring_type_t type; +} t1_path_info_t; + +static cairo_status_t +_charstring_move_to (void *closure, + const cairo_point_t *point) +{ + t1_path_info_t *path_info = (t1_path_info_t *) closure; + int dx, dy; + cairo_status_t status; + + status = _cairo_array_grow_by (path_info->data, 12); + if (unlikely (status)) + return status; + + dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; + dy = _cairo_fixed_integer_part (point->y) - path_info->current_y; + charstring_encode_integer (path_info->data, dx, path_info->type); + charstring_encode_integer (path_info->data, dy, path_info->type); + path_info->current_x += dx; + path_info->current_y += dy; + + charstring_encode_command (path_info->data, CHARSTRING_rmoveto); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_charstring_line_to (void *closure, + const cairo_point_t *point) +{ + t1_path_info_t *path_info = (t1_path_info_t *) closure; + int dx, dy; + cairo_status_t status; + + status = _cairo_array_grow_by (path_info->data, 12); + if (unlikely (status)) + return status; + + dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; + dy = _cairo_fixed_integer_part (point->y) - path_info->current_y; + charstring_encode_integer (path_info->data, dx, path_info->type); + charstring_encode_integer (path_info->data, dy, path_info->type); + path_info->current_x += dx; + path_info->current_y += dy; + + charstring_encode_command (path_info->data, CHARSTRING_rlineto); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_charstring_curve_to (void *closure, + const cairo_point_t *point1, + const cairo_point_t *point2, + const cairo_point_t *point3) +{ + t1_path_info_t *path_info = (t1_path_info_t *) closure; + int dx1, dy1, dx2, dy2, dx3, dy3; + cairo_status_t status; + + status = _cairo_array_grow_by (path_info->data, 32); + if (unlikely (status)) + return status; + + dx1 = _cairo_fixed_integer_part (point1->x) - path_info->current_x; + dy1 = _cairo_fixed_integer_part (point1->y) - path_info->current_y; + dx2 = _cairo_fixed_integer_part (point2->x) - path_info->current_x - dx1; + dy2 = _cairo_fixed_integer_part (point2->y) - path_info->current_y - dy1; + dx3 = _cairo_fixed_integer_part (point3->x) - path_info->current_x - dx1 - dx2; + dy3 = _cairo_fixed_integer_part (point3->y) - path_info->current_y - dy1 - dy2; + charstring_encode_integer (path_info->data, dx1, path_info->type); + charstring_encode_integer (path_info->data, dy1, path_info->type); + charstring_encode_integer (path_info->data, dx2, path_info->type); + charstring_encode_integer (path_info->data, dy2, path_info->type); + charstring_encode_integer (path_info->data, dx3, path_info->type); + charstring_encode_integer (path_info->data, dy3, path_info->type); + path_info->current_x += dx1 + dx2 + dx3; + path_info->current_y += dy1 + dy2 + dy3; + charstring_encode_command (path_info->data, CHARSTRING_rcurveto); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_charstring_close_path (void *closure) +{ + cairo_status_t status; + t1_path_info_t *path_info = (t1_path_info_t *) closure; + + if (path_info->type == CAIRO_CHARSTRING_TYPE2) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_array_grow_by (path_info->data, 2); + if (unlikely (status)) + return status; + + charstring_encode_command (path_info->data, CHARSTRING_closepath); + + return CAIRO_STATUS_SUCCESS; +} + +static void +charstring_encrypt (cairo_array_t *data) +{ + unsigned char *d, *end; + uint16_t c, p, r; + + r = CAIRO_TYPE1_CHARSTRING_KEY; + d = (unsigned char *) _cairo_array_index (data, 0); + end = d + _cairo_array_num_elements (data); + while (d < end) { + p = *d; + c = p ^ (r >> 8); + r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; + *d++ = c; + } +} + +static cairo_int_status_t +cairo_type1_font_create_charstring (cairo_type1_font_t *font, + int subset_index, + int glyph_index, + cairo_charstring_type_t type, + cairo_array_t *data) +{ + cairo_int_status_t status; + cairo_scaled_glyph_t *scaled_glyph; + t1_path_info_t path_info; + cairo_text_extents_t *metrics; + cairo_bool_t emit_path = TRUE; + + /* This call may return CAIRO_INT_STATUS_UNSUPPORTED for bitmap fonts. */ + status = _cairo_scaled_glyph_lookup (font->type1_scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS| + CAIRO_SCALED_GLYPH_INFO_PATH, + &scaled_glyph); + + /* It is ok for the .notdef glyph to not have a path available. We + * just need the metrics to emit an empty glyph. */ + if (glyph_index == 0 && status == CAIRO_INT_STATUS_UNSUPPORTED) { + emit_path = FALSE; + status = _cairo_scaled_glyph_lookup (font->type1_scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + &scaled_glyph); + } + if (unlikely (status)) + return status; + + metrics = &scaled_glyph->metrics; + if (subset_index == 0) { + font->x_min = metrics->x_bearing; + font->y_min = metrics->y_bearing; + font->x_max = metrics->x_bearing + metrics->width; + font->y_max = metrics->y_bearing + metrics->height; + } else { + if (metrics->x_bearing < font->x_min) + font->x_min = metrics->x_bearing; + if (metrics->y_bearing < font->y_min) + font->y_min = metrics->y_bearing; + if (metrics->x_bearing + metrics->width > font->x_max) + font->x_max = metrics->x_bearing + metrics->width; + if (metrics->y_bearing + metrics->height > font->y_max) + font->y_max = metrics->y_bearing + metrics->height; + } + font->widths[subset_index] = metrics->x_advance; + + status = _cairo_array_grow_by (data, 30); + if (unlikely (status)) + return status; + + if (type == CAIRO_CHARSTRING_TYPE1) { + charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.x_advance, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.y_advance, type); + charstring_encode_command (data, CHARSTRING_sbw); + + path_info.current_x = (int) scaled_glyph->metrics.x_bearing; + path_info.current_y = (int) scaled_glyph->metrics.y_bearing; + } else { + charstring_encode_integer (data, (int) scaled_glyph->metrics.x_advance, type); + + path_info.current_x = 0; + path_info.current_y = 0; + } + path_info.data = data; + path_info.type = type; + if (emit_path) { + status = _cairo_path_fixed_interpret (scaled_glyph->path, + _charstring_move_to, + _charstring_line_to, + _charstring_curve_to, + _charstring_close_path, + &path_info); + if (unlikely (status)) + return status; + } + + status = _cairo_array_grow_by (data, 1); + if (unlikely (status)) + return status; + charstring_encode_command (path_info.data, CHARSTRING_endchar); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_type1_font_write_charstrings (cairo_type1_font_t *font, + cairo_output_stream_t *encrypted_output) +{ + cairo_status_t status; + unsigned char zeros[] = { 0, 0, 0, 0 }; + cairo_array_t data; + unsigned int i; + int length; + + _cairo_array_init (&data, sizeof (unsigned char)); + status = _cairo_array_grow_by (&data, 1024); + if (unlikely (status)) + goto fail; + + _cairo_output_stream_printf (encrypted_output, + "2 index /CharStrings %d dict dup begin\n", + font->scaled_font_subset->num_glyphs + 1); + + _cairo_scaled_font_freeze_cache (font->type1_scaled_font); + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + _cairo_array_truncate (&data, 0); + /* four "random" bytes required by encryption algorithm */ + status = _cairo_array_append_multiple (&data, zeros, 4); + if (unlikely (status)) + break; + + status = cairo_type1_font_create_charstring (font, i, + font->scaled_font_subset->glyphs[i], + CAIRO_CHARSTRING_TYPE1, + &data); + if (unlikely (status)) + break; + + charstring_encrypt (&data); + length = _cairo_array_num_elements (&data); + if (font->scaled_font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (encrypted_output, "/%s %d RD ", + font->scaled_font_subset->glyph_names[i], + length); + } else if (i == 0) { + _cairo_output_stream_printf (encrypted_output, "/.notdef %d RD ", length); + } else { + _cairo_output_stream_printf (encrypted_output, "/g%d %d RD ", i, length); + } + _cairo_output_stream_write (encrypted_output, + _cairo_array_index (&data, 0), + length); + _cairo_output_stream_printf (encrypted_output, " ND\n"); + } + _cairo_scaled_font_thaw_cache (font->type1_scaled_font); + +fail: + _cairo_array_fini (&data); + return status; +} + +static void +cairo_type1_font_write_header (cairo_type1_font_t *font, + const char *name) +{ + unsigned int i; + const char spaces[50] = " "; + + _cairo_output_stream_printf (font->output, + "%%!FontType1-1.1 %s 1.0\n" + "11 dict begin\n" + "/FontName /%s def\n" + "/PaintType 0 def\n" + "/FontType 1 def\n" + "/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n", + name, + name); + + /* We don't know the bbox values until after the charstrings have + * been generated. Reserve some space and fill in the bbox + * later. */ + + /* Worst case for four signed ints with spaces between each number */ + font->bbox_max_chars = 50; + + _cairo_output_stream_printf (font->output, "/FontBBox {"); + font->bbox_position = _cairo_output_stream_get_position (font->output); + _cairo_output_stream_write (font->output, spaces, font->bbox_max_chars); + + _cairo_output_stream_printf (font->output, + "} readonly def\n" + "/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) { + if (font->scaled_font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (font->output, "dup %d /%s put\n", + i, font->scaled_font_subset->glyph_names[subset_glyph]); + } else { + _cairo_output_stream_printf (font->output, "dup %d /g%d put\n", i, subset_glyph); + } + } + } + } else { + for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) { + if (font->scaled_font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (font->output, "dup %d /%s put\n", + i, font->scaled_font_subset->glyph_names[i]); + } else { + _cairo_output_stream_printf (font->output, "dup %d /g%d put\n", i, i); + } + } + } + _cairo_output_stream_printf (font->output, + "readonly def\n" + "currentdict end\n" + "currentfile eexec\n"); +} + +static cairo_status_t +cairo_type1_write_stream_encrypted (void *closure, + const unsigned char *data, + unsigned int length) +{ + const unsigned char *in, *end; + uint16_t c, p; + static const char hex_digits[16] = "0123456789abcdef"; + char digits[3]; + cairo_type1_font_t *font = closure; + + 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 CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_type1_font_write_private_dict (cairo_type1_font_t *font, + const char *name) +{ + cairo_int_status_t status; + cairo_status_t status2; + cairo_output_stream_t *encrypted_output; + + font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; + font->hex_column = 0; + encrypted_output = _cairo_output_stream_create ( + cairo_type1_write_stream_encrypted, + NULL, + font); + if (_cairo_output_stream_get_status (encrypted_output)) + return _cairo_output_stream_destroy (encrypted_output); + + /* Note: the first four spaces at the start of this private dict + * are the four "random" bytes of plaintext required by the + * encryption algorithm */ + _cairo_output_stream_printf (encrypted_output, + " dup /Private 9 dict dup begin\n" + "/RD {string currentfile exch readstring pop}" + " bind executeonly def\n" + "/ND {noaccess def} executeonly def\n" + "/NP {noaccess put} executeonly def\n" + "/BlueValues [] def\n" + "/MinFeature {16 16} def\n" + "/lenIV 4 def\n" + "/password 5839 def\n"); + + status = cairo_type1_font_write_charstrings (font, encrypted_output); + if (unlikely (status)) + goto fail; + + _cairo_output_stream_printf (encrypted_output, + "end\n" + "end\n" + "readonly put\n" + "noaccess put\n" + "dup /FontName get exch definefont pop\n" + "mark currentfile closefile\n"); + + fail: + status2 = _cairo_output_stream_destroy (encrypted_output); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + + return status; +} + +static void +cairo_type1_font_write_trailer(cairo_type1_font_t *font) +{ + int i; + static const char zeros[65] = + "0000000000000000000000000000000000000000000000000000000000000000\n"; + + for (i = 0; i < 8; i++) + _cairo_output_stream_write (font->output, zeros, sizeof zeros); + + _cairo_output_stream_printf (font->output, "cleartomark\n"); +} + +static cairo_status_t +cairo_type1_write_stream (void *closure, + const unsigned char *data, + unsigned int length) +{ + cairo_type1_font_t *font = closure; + + return _cairo_array_append_multiple (&font->contents, data, length); +} + +static cairo_int_status_t +cairo_type1_font_write (cairo_type1_font_t *font, + const char *name) +{ + cairo_int_status_t status; + + cairo_type1_font_write_header (font, name); + font->header_size = _cairo_output_stream_get_position (font->output); + + status = cairo_type1_font_write_private_dict (font, name); + if (unlikely (status)) + return status; + + font->data_size = _cairo_output_stream_get_position (font->output) - + font->header_size; + + cairo_type1_font_write_trailer (font); + font->trailer_size = + _cairo_output_stream_get_position (font->output) - + font->header_size - font->data_size; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_type1_font_generate (cairo_type1_font_t *font, const char *name) +{ + cairo_int_status_t status; + + status = _cairo_array_grow_by (&font->contents, 4096); + if (unlikely (status)) + return status; + + font->output = _cairo_output_stream_create (cairo_type1_write_stream, NULL, font); + if (_cairo_output_stream_get_status (font->output)) + return _cairo_output_stream_destroy (font->output); + + status = cairo_type1_font_write (font, name); + if (unlikely (status)) + return status; + + font->data = _cairo_array_index (&font->contents, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_type1_font_destroy (cairo_type1_font_t *font) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + free (font->widths); + cairo_scaled_font_destroy (font->type1_scaled_font); + _cairo_array_fini (&font->contents); + if (font->output) + status = _cairo_output_stream_destroy (font->output); + free (font); + + return status; +} + +static cairo_status_t +_cairo_type1_fallback_init_internal (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_t *font; + cairo_status_t status; + unsigned long length; + unsigned int i, len; + + status = cairo_type1_font_create (scaled_font_subset, &font, hex_encode); + if (unlikely (status)) + return status; + + status = cairo_type1_font_generate (font, name); + if (unlikely (status)) + goto fail1; + + type1_subset->base_font = strdup (name); + if (unlikely (type1_subset->base_font == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + type1_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs); + if (unlikely (type1_subset->widths == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail2; + } + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + type1_subset->widths[i] = (double)font->widths[i]/1000; + + type1_subset->x_min = (double)font->x_min/1000; + type1_subset->y_min = (double)font->y_min/1000; + type1_subset->x_max = (double)font->x_max/1000; + type1_subset->y_max = (double)font->y_max/1000; + type1_subset->ascent = (double)font->y_max/1000; + type1_subset->descent = (double)font->y_min/1000; + + length = font->header_size + font->data_size + + font->trailer_size; + type1_subset->data = malloc (length); + if (unlikely (type1_subset->data == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail3; + } + memcpy (type1_subset->data, + _cairo_array_index (&font->contents, 0), length); + + len = snprintf(type1_subset->data + font->bbox_position, + font->bbox_max_chars, + "%d %d %d %d", + (int)font->x_min, + (int)font->y_min, + (int)font->x_max, + (int)font->y_max); + type1_subset->data[font->bbox_position + len] = ' '; + + type1_subset->header_length = font->header_size; + type1_subset->data_length = font->data_size; + type1_subset->trailer_length = font->trailer_size; + + return cairo_type1_font_destroy (font); + + fail3: + free (type1_subset->widths); + fail2: + free (type1_subset->base_font); + fail1: + /* status is already set, ignore further errors */ + cairo_type1_font_destroy (font); + + return status; +} + +cairo_status_t +_cairo_type1_fallback_init_binary (cairo_type1_subset_t *type1_subset, + const char *name, + cairo_scaled_font_subset_t *scaled_font_subset) +{ + return _cairo_type1_fallback_init_internal (type1_subset, + name, + scaled_font_subset, FALSE); +} + +cairo_status_t +_cairo_type1_fallback_init_hex (cairo_type1_subset_t *type1_subset, + const char *name, + cairo_scaled_font_subset_t *scaled_font_subset) +{ + return _cairo_type1_fallback_init_internal (type1_subset, + name, + scaled_font_subset, TRUE); +} + +void +_cairo_type1_fallback_fini (cairo_type1_subset_t *subset) +{ + free (subset->base_font); + free (subset->widths); + free (subset->data); +} + +cairo_status_t +_cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset, + cairo_scaled_font_subset_t *scaled_font_subset) +{ + cairo_type1_font_t *font; + cairo_status_t status; + unsigned int i; + cairo_array_t charstring; + + status = cairo_type1_font_create (scaled_font_subset, &font, FALSE); + if (unlikely (status)) + return status; + + _cairo_array_init (&type2_subset->charstrings, sizeof (cairo_array_t)); + + type2_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); + if (unlikely (type2_subset->widths == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + _cairo_scaled_font_freeze_cache (font->type1_scaled_font); + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + _cairo_array_init (&charstring, sizeof (unsigned char)); + status = _cairo_array_grow_by (&charstring, 32); + if (unlikely (status)) + goto fail2; + + status = cairo_type1_font_create_charstring (font, i, + font->scaled_font_subset->glyphs[i], + CAIRO_CHARSTRING_TYPE2, + &charstring); + if (unlikely (status)) + goto fail2; + + status = _cairo_array_append (&type2_subset->charstrings, &charstring); + if (unlikely (status)) + goto fail2; + } + _cairo_scaled_font_thaw_cache (font->type1_scaled_font); + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + type2_subset->widths[i] = font->widths[i]; + + type2_subset->x_min = (int) font->x_min; + type2_subset->y_min = (int) font->y_min; + type2_subset->x_max = (int) font->x_max; + type2_subset->y_max = (int) font->y_max; + type2_subset->ascent = (int) font->y_max; + type2_subset->descent = (int) font->y_min; + + return cairo_type1_font_destroy (font); + +fail2: + _cairo_scaled_font_thaw_cache (font->type1_scaled_font); + _cairo_array_fini (&charstring); + _cairo_type2_charstrings_fini (type2_subset); +fail1: + cairo_type1_font_destroy (font); + return status; +} + +void +_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *type2_subset) +{ + unsigned int i, num_charstrings; + cairo_array_t *charstring; + + num_charstrings = _cairo_array_num_elements (&type2_subset->charstrings); + for (i = 0; i < num_charstrings; i++) { + charstring = _cairo_array_index (&type2_subset->charstrings, i); + _cairo_array_fini (charstring); + } + _cairo_array_fini (&type2_subset->charstrings); + + free (type2_subset->widths); +} + +#endif /* CAIRO_HAS_FONT_SUBSET */ |