cairo/src/cairo-type1-fallback.c
Chris Wilson af9fbd176b Introduce a new compositor architecture
Having spent the last dev cycle looking at how we could specialize the
compositors for various backends, we once again look for the
commonalities in order to reduce the duplication. In part this is
motivated by the idea that spans is a good interface for both the
existent GL backend and pixman, and so they deserve a dedicated
compositor. xcb/xlib target an identical rendering system and so they
should be using the same compositor, and it should be possible to run
that same compositor locally against pixman to generate reference tests.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

P.S. This brings massive upheaval (read breakage) I've tried delaying in
order to fix as many things as possible but now this one patch does far,
far, far too much. Apologies in advance for breaking your favourite
backend, but trust me in that the end result will be much better. :)
2011-09-12 08:29:48 +01:00

903 lines
30 KiB
C

/* 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 */