mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-30 09:40:13 +01:00
892 lines
29 KiB
C
892 lines
29 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>
|
|
*/
|
|
|
|
#include "cairoint.h"
|
|
#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;
|
|
|
|
font = calloc (1, sizeof (cairo_type1_font_t));
|
|
if (font == NULL)
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
|
|
font->widths = calloc (scaled_font_subset->num_glyphs,
|
|
sizeof (int));
|
|
if (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);
|
|
if (font->type1_scaled_font->status)
|
|
goto fail;
|
|
|
|
_cairo_array_init (&font->contents, sizeof (unsigned char));
|
|
|
|
*subset_return = font;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
fail:
|
|
free (font->widths);
|
|
free (font);
|
|
|
|
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
}
|
|
|
|
/* 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,
|
|
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 (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,
|
|
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 (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,
|
|
cairo_point_t *point1,
|
|
cairo_point_t *point2,
|
|
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 (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 (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
|
|
create_notdef_charstring (cairo_array_t *data, cairo_charstring_type_t type)
|
|
{
|
|
cairo_status_t status;
|
|
|
|
/* We're passing constants below, so we know the 0 values will
|
|
* only use 1 byte each, and the 500 values will use 2 bytes
|
|
* each. Then 2 more for each of the commands is 10 total. */
|
|
status = _cairo_array_grow_by (data, 10);
|
|
if (status)
|
|
return status;
|
|
|
|
if (type == CAIRO_CHARSTRING_TYPE1) {
|
|
charstring_encode_integer (data, 0, type);
|
|
charstring_encode_integer (data, 0, type);
|
|
|
|
/* The width and height is arbitrary. */
|
|
charstring_encode_integer (data, 500, type);
|
|
charstring_encode_integer (data, 500, type);
|
|
charstring_encode_command (data, CHARSTRING_sbw);
|
|
}
|
|
|
|
charstring_encode_command (data, CHARSTRING_endchar);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
|
|
/* 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);
|
|
if (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 (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.width, type);
|
|
charstring_encode_integer (data, (int) scaled_glyph->metrics.height, 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.width, type);
|
|
|
|
path_info.current_x = 0;
|
|
path_info.current_y = 0;
|
|
}
|
|
path_info.data = data;
|
|
path_info.type = type;
|
|
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 (status)
|
|
return status;
|
|
|
|
status = _cairo_array_grow_by (data, 1);
|
|
if (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 (status)
|
|
goto fail;
|
|
|
|
_cairo_output_stream_printf (encrypted_output,
|
|
"2 index /CharStrings %d dict dup begin\n",
|
|
font->scaled_font_subset->num_glyphs + 1);
|
|
|
|
for (i = 1; 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 (status)
|
|
goto fail;
|
|
status = cairo_type1_font_create_charstring (font, i,
|
|
font->scaled_font_subset->glyphs[i],
|
|
CAIRO_CHARSTRING_TYPE1,
|
|
&data);
|
|
if (status)
|
|
goto fail;
|
|
charstring_encrypt (&data);
|
|
length = _cairo_array_num_elements (&data);
|
|
_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");
|
|
}
|
|
|
|
/* All type 1 fonts must have a /.notdef charstring */
|
|
|
|
_cairo_array_truncate (&data, 0);
|
|
/* four "random" bytes required by encryption algorithm */
|
|
status = _cairo_array_append_multiple (&data, zeros, 4);
|
|
if (status)
|
|
goto fail;
|
|
status = create_notdef_charstring (&data, CAIRO_CHARSTRING_TYPE1);
|
|
if (status)
|
|
goto fail;
|
|
charstring_encrypt (&data);
|
|
length = _cairo_array_num_elements (&data);
|
|
_cairo_output_stream_printf (encrypted_output, "/.notdef %d RD ", length);
|
|
_cairo_output_stream_write (encrypted_output,
|
|
_cairo_array_index (&data, 0),
|
|
length);
|
|
_cairo_output_stream_printf (encrypted_output, " ND\n");
|
|
|
|
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 = 0; i < font->scaled_font_subset->num_glyphs; i++)
|
|
_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 (encrypted_output == NULL) {
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
goto fail;
|
|
}
|
|
|
|
/* 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}"
|
|
" 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 (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 (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 (status)
|
|
return status;
|
|
|
|
font->output = _cairo_output_stream_create (cairo_type1_write_stream, NULL, font);
|
|
|
|
status = cairo_type1_font_write (font, name);
|
|
if (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;
|
|
|
|
free (font->widths);
|
|
cairo_scaled_font_destroy (font->type1_scaled_font);
|
|
_cairo_array_fini (&font->contents);
|
|
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 (status)
|
|
return status;
|
|
|
|
status = cairo_type1_font_generate (font, name);
|
|
if (status)
|
|
goto fail1;
|
|
|
|
type1_subset->base_font = strdup (name);
|
|
if (type1_subset->base_font == NULL) {
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
goto fail1;
|
|
}
|
|
|
|
type1_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
|
|
if (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] = font->widths[i];
|
|
|
|
type1_subset->x_min = (int) font->x_min;
|
|
type1_subset->y_min = (int) font->y_min;
|
|
type1_subset->x_max = (int) font->x_max;
|
|
type1_subset->y_max = (int) font->y_max;
|
|
type1_subset->ascent = (int) font->y_max;
|
|
type1_subset->descent = (int) font->y_min;
|
|
|
|
length = font->header_size + font->data_size +
|
|
font->trailer_size;
|
|
type1_subset->data = malloc (length);
|
|
if (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)type1_subset->x_min,
|
|
(int)type1_subset->y_min,
|
|
(int)type1_subset->x_max,
|
|
(int)type1_subset->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 _cairo_error (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 (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 (type2_subset->widths == NULL) {
|
|
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
|
goto fail1;
|
|
}
|
|
|
|
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 (status)
|
|
goto fail2;
|
|
|
|
if (i == 0) {
|
|
status = create_notdef_charstring (&charstring, CAIRO_CHARSTRING_TYPE2);
|
|
} else {
|
|
status = cairo_type1_font_create_charstring (font, i,
|
|
font->scaled_font_subset->glyphs[i],
|
|
CAIRO_CHARSTRING_TYPE2,
|
|
&charstring);
|
|
}
|
|
if (status)
|
|
goto fail2;
|
|
|
|
status = _cairo_array_append (&type2_subset->charstrings, &charstring);
|
|
if (status)
|
|
goto fail2;
|
|
}
|
|
|
|
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_array_fini (&charstring);
|
|
_cairo_type2_charstrings_fini (type2_subset);
|
|
fail1:
|
|
cairo_type1_font_destroy (font);
|
|
return _cairo_error (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);
|
|
}
|