mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-15 19:00:25 +01:00
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. :)
903 lines
30 KiB
C
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 */
|