0,0 → 1,887 |
/* 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-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; |
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; |
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, |
CAIRO_DIRECTION_FORWARD, |
_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"); |
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_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 */ |