Add CFF CID Fallback

Switching to CID font embedding requires a fallback font for
the case where CFF CID or TrueType CID subsetting fails.

The new function _cairo_type2_charstrings_init() added to
cairo-type1-fallback.c creates Type2 charstrings from glyph
paths. _cairo_cff_fallback_init() in cairo-cff-subset.c
wraps these charstrings in a CFF CID font.
This commit is contained in:
Adrian Johnson 2007-04-20 22:30:55 +09:30
parent c68a2389f5
commit 0c2a653033
3 changed files with 432 additions and 59 deletions

View file

@ -1915,3 +1915,215 @@ _cairo_cff_subset_fini (cairo_cff_subset_t *subset)
free (subset->widths);
free (subset->data);
}
static cairo_int_status_t
_cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset,
cairo_cff_font_t **font_return,
const char *subset_name)
{
cairo_status_t status;
cairo_cff_font_t *font;
font = malloc (sizeof (cairo_cff_font_t));
if (font == NULL)
return CAIRO_STATUS_NO_MEMORY;
font->backend = NULL;
font->scaled_font_subset = scaled_font_subset;
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
if (status)
goto fail1;
font->subset_font_name = strdup (subset_name);
if (font->subset_font_name == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto fail2;
}
font->font_name = strdup (subset_name);
if (font->subset_font_name == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto fail3;
}
font->x_min = 0;
font->y_min = 0;
font->x_max = 0;
font->y_max = 0;
font->ascent = 0;
font->descent = 0;
font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int));
if (font->widths == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto fail4;
}
font->data_length = 0;
font->data = NULL;
font->data_end = 0;
cff_dict_init (&font->top_dict);
cff_dict_init (&font->private_dict);
cff_index_init (&font->strings_index);
cff_index_init (&font->charstrings_index);
cff_index_init (&font->global_sub_index);
cff_index_init (&font->local_sub_index);
cff_index_init (&font->charstrings_subset_index);
cff_index_init (&font->strings_subset_index);
font->fdselect = NULL;
font->fd_dict = NULL;
font->fd_private_dict = NULL;
font->fd_local_sub_index = NULL;
font->fdselect_subset = NULL;
font->fd_subset_map = NULL;
font->private_dict_offset = NULL;
*font_return = font;
return CAIRO_STATUS_SUCCESS;
fail4:
free (font->font_name);
fail3:
free (font->subset_font_name);
fail2:
_cairo_array_fini (&font->output);
fail1:
free (font);
return status;
}
static cairo_int_status_t
cairo_cff_font_fallback_generate (cairo_cff_font_t *font,
cairo_type2_charstrings_t *type2_subset,
const char **data,
unsigned long *length)
{
cairo_int_status_t status;
cff_header_t header;
cairo_array_t *charstring;
unsigned char buf[40];
unsigned char *end_buf;
unsigned int i;
/* Create header */
header.major = 1;
header.minor = 0;
header.header_size = 4;
header.offset_size = 4;
font->header = &header;
/* Create Top Dict */
font->is_cid = FALSE;
end_buf = encode_integer (buf, type2_subset->x_min);
end_buf = encode_integer (end_buf, type2_subset->y_min);
end_buf = encode_integer (end_buf, type2_subset->x_max);
end_buf = encode_integer (end_buf, type2_subset->y_max);
cff_dict_set_operands (font->top_dict, FONTBBOX_OP, buf, end_buf - buf);
end_buf = encode_integer_max (buf, 0);
cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf);
cairo_cff_font_set_ros_strings (font);
/* Create CID FD dictionary */
cairo_cff_font_create_cid_fontdict (font);
/* Create charstrings */
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
charstring = _cairo_array_index(&type2_subset->charstrings, i);
status = cff_index_append (&font->charstrings_subset_index,
_cairo_array_index (charstring, 0),
_cairo_array_num_elements (charstring));
if (status)
return status;
}
status = cairo_cff_font_write_subset (font);
if (status)
return status;
*data = _cairo_array_index (&font->output, 0);
*length = _cairo_array_num_elements (&font->output);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
const char *subset_name,
cairo_scaled_font_subset_t *font_subset)
{
cairo_cff_font_t *font = NULL; /* squelch bogus compiler warning */
cairo_status_t status;
const char *data = NULL; /* squelch bogus compiler warning */
unsigned long length = 0; /* squelch bogus compiler warning */
unsigned int i;
cairo_type2_charstrings_t type2_subset;
status = _cairo_cff_font_fallback_create (font_subset, &font, subset_name);
if (status)
return status;
status = _cairo_type2_charstrings_init (&type2_subset, font_subset);
if (status)
goto fail1;
status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length);
if (status)
goto fail1;
cff_subset->base_font = strdup (font->font_name);
if (cff_subset->base_font == NULL)
goto fail1;
cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
if (cff_subset->widths == NULL)
goto fail2;
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
cff_subset->widths[i] = type2_subset.widths[i];
cff_subset->x_min = type2_subset.x_min;
cff_subset->y_min = type2_subset.y_min;
cff_subset->x_max = type2_subset.x_max;
cff_subset->y_max = type2_subset.y_max;
cff_subset->ascent = type2_subset.y_max;
cff_subset->descent = type2_subset.y_min;
_cairo_type2_charstrings_fini (&type2_subset);
cff_subset->data = malloc (length);
if (cff_subset->data == NULL)
goto fail3;
memcpy (cff_subset->data, data, length);
cff_subset->data_length = length;
cff_subset->data_length = length;
cairo_cff_font_destroy (font);
return CAIRO_STATUS_SUCCESS;
fail3:
free (cff_subset->widths);
fail2:
free (cff_subset->base_font);
fail1:
cairo_cff_font_destroy (font);
return status;
}
void
_cairo_cff_fallback_fini (cairo_cff_subset_t *subset)
{
free (subset->base_font);
free (subset->widths);
free (subset->data);
}

View file

@ -305,6 +305,37 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
cairo_private void
_cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset);
/**
* _cairo_cff_fallback_init:
* @cff_subset: a #cairo_cff_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* cairo_scaled_font_t and the font backend in use) generate a cff
* file corresponding to @font_subset and initialize @cff_subset
* with information about the subset and the cff data.
*
* Return value: CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* cff file, or an non-zero value indicating an error. Possible
* errors include CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
const char *name,
cairo_scaled_font_subset_t *font_subset);
/**
* _cairo_cff_fallback_fini:
* @cff_subset: a #cairo_cff_subset_t
*
* Free all resources associated with @cff_subset. After this
* call, @cff_subset should not be used again without a
* subsequent call to _cairo_cff_subset_init() again first.
**/
cairo_private void
_cairo_cff_fallback_fini (cairo_cff_subset_t *cff_subset);
typedef struct _cairo_truetype_subset {
char *base_font;
double *widths;
@ -446,6 +477,43 @@ _cairo_type1_fallback_init_hex (cairo_type1_subset_t *type_subset,
cairo_private void
_cairo_type1_fallback_fini (cairo_type1_subset_t *subset);
typedef struct _cairo_type2_charstrings {
int *widths;
long x_min, y_min, x_max, y_max;
long ascent, descent;
cairo_array_t charstrings;
} cairo_type2_charstrings_t;
/**
* _cairo_type2_charstrings_init:
* @type2_subset: a #cairo_type2_subset_t to initialize
* @font_subset: the #cairo_scaled_font_subset_t to initialize from
*
* If possible (depending on the format of the underlying
* cairo_scaled_font_t and the font backend in use) generate type2
* charstrings to @font_subset and initialize @type2_subset
* with information about the subset.
*
* Return value: CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2
* charstrings, or an non-zero value indicating an error. Possible errors
* include CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_type2_charstrings_init (cairo_type2_charstrings_t *charstrings,
cairo_scaled_font_subset_t *font_subset);
/**
* _cairo_type2_charstrings_fini:
* @subset: a #cairo_type2_charstrings_t
*
* Free all resources associated with @type2_charstring. After this call,
* @type2_charstring should not be used again without a subsequent call to
* _cairo_type2_charstring_init() again first.
**/
cairo_private void
_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings);
/**
* _cairo_truetype_create_glyph_to_unicode_map:
* @font_subset: the #cairo_scaled_font_subset_t to initialize from

View file

@ -39,6 +39,11 @@
#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;
@ -90,7 +95,7 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font_face = cairo_scaled_font_get_font_face (scaled_font_subset->scaled_font);
cairo_matrix_init_scale (&font_matrix, 1000, 1000);
cairo_matrix_init_scale (&font_matrix, 1000, -1000);
cairo_matrix_init_identity (&ctm);
_cairo_font_options_init_default (&font_options);
@ -156,7 +161,9 @@ charstring_encode_command (cairo_array_t *data, int command)
* bytes that will be used is 5.
*/
static void
charstring_encode_integer (cairo_array_t *data, int i)
charstring_encode_integer (cairo_array_t *data,
int i,
cairo_charstring_type_t type)
{
cairo_status_t status;
int orig_size;
@ -174,11 +181,19 @@ charstring_encode_integer (cairo_array_t *data, int i)
*p++ = (i >> 8)+ 251;
*p++ = i & 0xff;
} else {
*p++ = 0xff;
*p++ = i >> 24;
*p++ = (i >> 16) & 0xff;
*p++ = (i >> 8) & 0xff;
*p++ = i & 0xff;
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
@ -193,6 +208,7 @@ charstring_encode_integer (cairo_array_t *data, int i)
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
@ -209,8 +225,8 @@ _charstring_move_to (void *closure,
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);
charstring_encode_integer (path_info->data, dy);
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;
@ -233,8 +249,8 @@ _charstring_line_to (void *closure,
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);
charstring_encode_integer (path_info->data, dy);
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;
@ -263,12 +279,12 @@ _charstring_curve_to (void *closure,
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);
charstring_encode_integer (path_info->data, dy1);
charstring_encode_integer (path_info->data, dx2);
charstring_encode_integer (path_info->data, dy2);
charstring_encode_integer (path_info->data, dx3);
charstring_encode_integer (path_info->data, dy3);
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);
@ -282,6 +298,9 @@ _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;
@ -309,7 +328,7 @@ charstring_encrypt (cairo_array_t *data)
}
static cairo_int_status_t
create_notdef_charstring (cairo_array_t *data)
create_notdef_charstring (cairo_array_t *data, cairo_charstring_type_t type)
{
cairo_status_t status;
@ -320,13 +339,15 @@ create_notdef_charstring (cairo_array_t *data)
if (status)
return status;
charstring_encode_integer (data, 0);
charstring_encode_integer (data, 0);
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);
charstring_encode_integer (data, 500);
charstring_encode_command (data, CHARSTRING_sbw);
/* 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);
@ -334,10 +355,11 @@ create_notdef_charstring (cairo_array_t *data)
}
static cairo_int_status_t
cairo_type1_font_create_charstring (cairo_type1_font_t *font,
int subset_index,
int glyph_index,
cairo_array_t *data)
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;
@ -369,21 +391,29 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font,
if (metrics->y_bearing + metrics->height > font->y_max)
font->y_max = metrics->y_bearing + metrics->height;
}
font->widths[subset_index] = metrics->width;
font->widths[subset_index] = metrics->x_advance;
status = _cairo_array_grow_by (data, 30);
if (status)
return status;
charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing);
charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing);
charstring_encode_integer (data, (int) scaled_glyph->metrics.width);
charstring_encode_integer (data, (int) scaled_glyph->metrics.height);
charstring_encode_command (data, CHARSTRING_sbw);
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.current_x = (int) scaled_glyph->metrics.x_bearing;
path_info.current_y = (int) scaled_glyph->metrics.y_bearing;
path_info.type = type;
status = _cairo_path_fixed_interpret (scaled_glyph->path,
CAIRO_DIRECTION_FORWARD,
_charstring_move_to,
@ -429,6 +459,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font,
goto fail;
status = cairo_type1_font_create_charstring (font, i,
font->scaled_font_subset->glyphs[i],
CAIRO_CHARSTRING_TYPE1,
&data);
if (status)
goto fail;
@ -448,7 +479,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font,
status = _cairo_array_append_multiple (&data, zeros, 4);
if (status)
goto fail;
status = create_notdef_charstring (&data);
status = create_notdef_charstring (&data, CAIRO_CHARSTRING_TYPE1);
if (status)
goto fail;
charstring_encrypt (&data);
@ -464,35 +495,22 @@ fail:
return status;
}
static cairo_status_t
static void
cairo_type1_font_write_header (cairo_type1_font_t *font,
const char *name)
{
cairo_matrix_t matrix;
cairo_status_t status;
unsigned int i;
const char spaces[50] = " ";
matrix = font->type1_scaled_font->scale;
matrix.xy = -matrix.xy;
matrix.yy = -matrix.yy;
status = cairo_matrix_invert (&matrix);
if (status)
return status;
_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 [%f %f %f %f 0 0] readonly def\n",
"/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n",
name,
name,
matrix.xx,
matrix.yx,
matrix.xy,
matrix.yy);
name);
/* We don't know the bbox values until after the charstrings have
* been generated. Reserve some space and fill in the bbox
@ -515,8 +533,6 @@ cairo_type1_font_write_header (cairo_type1_font_t *font,
"readonly def\n"
"currentdict end\n"
"currentfile eexec\n");
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@ -640,10 +656,7 @@ cairo_type1_font_write (cairo_type1_font_t *font,
{
cairo_int_status_t status;
status = cairo_type1_font_write_header (font, name);
if (status)
return 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);
@ -798,3 +811,83 @@ _cairo_type1_fallback_fini (cairo_type1_subset_t *subset)
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_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;
cairo_type1_font_destroy (font);
return CAIRO_STATUS_SUCCESS;
fail2:
_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);
}