Add support for subsetting bare CFF fonts

This avoids fallback when using poppler cairo for printing PDFs with
CFF fonts.

The current CFF subsetting only works with Opentype/CFF fonts. CFF
fonts inside PDF files are usually embedded as a bare CFF font without
the Opentype wrapper.

Making the CFF subset work with bare CFF fonts requires doing a bit of
extra work to extract the fontname, font bbox, and glyph widths from
the CFF data instead of using the Opentype tables.
This commit is contained in:
Adrian Johnson 2011-07-21 21:17:18 +09:30
parent 6b3e5cd39c
commit f6043b06d6
2 changed files with 481 additions and 114 deletions

View file

@ -57,14 +57,17 @@
#define CHARSET_OP 0x000f
#define CHARSTRINGS_OP 0x0011
#define COPYRIGHT_OP 0x0c00
#define DEFAULTWIDTH_OP 0x0014
#define ENCODING_OP 0x0010
#define FAMILYNAME_OP 0x0003
#define FDARRAY_OP 0x0c24
#define FDSELECT_OP 0x0c25
#define FONTBBOX_OP 0x0005
#define FONTMATRIX_OP 0x0c07
#define FONTNAME_OP 0x0c26
#define FULLNAME_OP 0x0002
#define LOCAL_SUB_OP 0x0013
#define NOMINALWIDTH_OP 0x0015
#define NOTICE_OP 0x0001
#define POSTSCRIPT_OP 0x0c15
#define PRIVATE_OP 0x0012
@ -90,6 +93,11 @@
#define TYPE2_vstemhm 0x0017
#define TYPE2_callgsubr 0x001d
#define TYPE2_rmoveto 0x0015
#define TYPE2_hmoveto 0x0016
#define TYPE2_vmoveto 0x0004
#define MAX_SUBROUTINE_NESTING 10 /* From Type2 Charstring spec */
@ -136,9 +144,12 @@ typedef struct _cairo_cff_font {
cairo_array_t local_sub_index;
int num_glyphs;
cairo_bool_t is_cid;
cairo_bool_t is_opentype;
int units_per_em;
int global_sub_bias;
int local_sub_bias;
int default_width;
int nominal_width;
/* CID Font Data */
int *fdselect;
@ -147,6 +158,8 @@ typedef struct _cairo_cff_font {
cairo_hash_table_t **fd_private_dict;
cairo_array_t *fd_local_sub_index;
int *fd_local_sub_bias;
int *fd_default_width;
int *fd_nominal_width;
/* Subsetted Font Data */
char *subset_font_name;
@ -175,6 +188,10 @@ typedef struct _cairo_cff_font {
int type2_num_hints;
int type2_hintmask_bytes;
int type2_nesting_level;
cairo_bool_t type2_seen_first_int;
cairo_bool_t type2_find_width;
cairo_bool_t type2_found_width;
int type2_width;
} cairo_cff_font_t;
@ -238,6 +255,76 @@ decode_integer (unsigned char *p, int *integer)
return p;
}
static char *
decode_nibble (int n, char *buf)
{
switch (n)
{
case 0xa:
*buf++ = '.';
break;
case 0xb:
*buf++ = 'E';
break;
case 0xc:
*buf++ = 'E';
*buf++ = '-';
break;
case 0xd:
*buf++ = '-';
break;
case 0xe:
*buf++ = '-';
break;
case 0xf:
break;
default:
*buf++ = '0' + n;
break;
}
return buf;
}
static unsigned char *
decode_real (unsigned char *p, double *real)
{
int n;
char buffer[100];
char *buf = buffer;
char *buf_end = buffer + sizeof (buf);
p++;
while (buf + 2 < buf_end) {
n = *p >> 4;
buf = decode_nibble (n, buf);
n = *p & 0x0f;
buf = decode_nibble (n, buf);
if ((*p & 0x0f) == 0x0f)
break;
p++;
};
*buf = 0;
if (sscanf(buffer, "%lf", real) != 1)
*real = 0.0;
return p;
}
static unsigned char *
decode_number (unsigned char *p, double *number)
{
if (*p == 30) {
p = decode_real (p, number);
} else {
int i;
p = decode_integer (p, &i);
*number = i;
}
return p;
}
static unsigned char *
decode_operator (unsigned char *p, unsigned short *operator)
{
@ -742,6 +829,7 @@ cairo_cff_font_read_header (cairo_cff_font_t *font)
if (font->data_length < sizeof (cff_header_t))
return CAIRO_INT_STATUS_UNSUPPORTED;
font->header = (cff_header_t *) font->data;
font->current_ptr = font->data + font->header->header_size;
@ -753,11 +841,19 @@ cairo_cff_font_read_name (cairo_cff_font_t *font)
{
cairo_array_t index;
cairo_int_status_t status;
cff_index_element_t *element;
/* The original font name is not used in the subset. Read the name
* index to skip over it. */
cff_index_init (&index);
status = cff_index_read (&index, &font->current_ptr, font->data_end);
if (!font->is_opentype) {
element = _cairo_array_index (&index, 0);
font->ps_name = malloc (element->length + 1);
if (unlikely (font->ps_name == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (font->ps_name, element->data, element->length);
font->ps_name[element->length] = 0;
}
cff_index_fini (&index);
return status;
@ -769,6 +865,8 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
cairo_array_t *local_sub_index,
int *local_sub_bias,
cairo_bool_t **local_subs_used,
int *default_width,
int *nominal_width,
unsigned char *ptr,
int size)
{
@ -798,9 +896,18 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
status = cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf);
if (unlikely (status))
return status;
}
*default_width = 0;
operand = cff_dict_get_operands (private_dict, DEFAULTWIDTH_OP, &i);
if (operand)
decode_integer (operand, default_width);
*nominal_width = 0;
operand = cff_dict_get_operands (private_dict, NOMINALWIDTH_OP, &i);
if (operand)
decode_integer (operand, nominal_width);
num_subs = _cairo_array_num_elements (local_sub_index);
*local_subs_used = calloc (num_subs, sizeof (cairo_bool_t));
if (unlikely (*local_subs_used == NULL))
@ -899,6 +1006,18 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
goto fail;
}
font->fd_default_width = calloc (sizeof (int), font->num_fontdicts);
if (unlikely (font->fd_default_width == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail;
}
font->fd_nominal_width = calloc (sizeof (int), font->num_fontdicts);
if (unlikely (font->fd_nominal_width == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail;
}
for (i = 0; i < font->num_fontdicts; i++) {
status = cff_dict_init (&font->fd_dict[i]);
if (unlikely (status))
@ -926,6 +1045,8 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
&font->fd_local_sub_index[i],
&font->fd_local_sub_bias[i],
&font->fd_local_subs_used[i],
&font->fd_default_width[i],
&font->fd_nominal_width[i],
font->data + offset,
size);
if (unlikely (status))
@ -948,6 +1069,58 @@ fail:
return status;
}
static void
cairo_cff_font_read_font_metrics (cairo_cff_font_t *font, cairo_hash_table_t *top_dict)
{
unsigned char *p;
unsigned char *end;
int size;
double x_min, y_min, x_max, y_max;
double xx, yx, xy, yy;
font->x_min = 0.0;
font->y_min = 0.0;
font->x_max = 0.0;
font->y_max = 0.0;
p = cff_dict_get_operands (font->top_dict, FONTBBOX_OP, &size);
if (p) {
end = p + size;
if (p < end)
p = decode_number (p, &x_min);
if (p < end)
p = decode_number (p, &y_min);
if (p < end)
p = decode_number (p, &x_max);
if (p < end)
p = decode_number (p, &y_max);
}
font->x_min = floor (x_min);
font->y_min = floor (y_min);
font->x_max = floor (x_max);
font->y_max = floor (y_max);
font->ascent = font->y_max;
font->descent = font->y_min;
xx = 0.001;
yx = 0.0;
xy = 0.0;
yy = 0.001;
p = cff_dict_get_operands (font->top_dict, FONTMATRIX_OP, &size);
if (p) {
end = p + size;
if (p < end)
p = decode_number (p, &xx);
if (p < end)
p = decode_number (p, &yx);
if (p < end)
p = decode_number (p, &xy);
if (p < end)
p = decode_number (p, &yy);
}
/* Freetype uses 1/yy to get units per EM */
font->units_per_em = _cairo_round(1.0/yy);
}
static cairo_int_status_t
cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
{
@ -984,6 +1157,9 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
goto fail;
font->num_glyphs = _cairo_array_num_elements (&font->charstrings_index);
if (!font->is_opentype)
cairo_cff_font_read_font_metrics (font, font->top_dict);
if (font->is_cid) {
operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size);
decode_integer (operand, &offset);
@ -1005,6 +1181,8 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
&font->local_sub_index,
&font->local_sub_bias,
&font->local_subs_used,
&font->default_width,
&font->nominal_width,
font->data + offset,
size);
if (unlikely (status))
@ -1243,21 +1421,30 @@ type2_decode_integer (unsigned char *p, int *integer)
}
/* Type 2 charstring parser for finding calls to local or global
* subroutines. When we find a subroutine operator, the subroutine is
* marked as in use and recursively followed. The subroutine number is
* the value on the top of the stack when the subroutine operator is
* executed. In most fonts the subroutine number is encoded in an
* integer immediately preceding the subroutine operator. However it
* is possible for the subroutine number on the stack to be the result
* of a computation (in which case there will be an operator preceding
* subroutines. For non Opentype CFF fonts it also gets the glyph
* widths.
*
* When we find a subroutine operator, the subroutine is marked as in
* use and recursively followed. The subroutine number is the value on
* the top of the stack when the subroutine operator is executed. In
* most fonts the subroutine number is encoded in an integer
* immediately preceding the subroutine operator. However it is
* possible for the subroutine number on the stack to be the result of
* a computation (in which case there will be an operator preceding
* the subroutine operator). If this occurs, subroutine subsetting is
* disabled since we can't easily determine which subroutines are
* used.
*
* The width, if present, is the first integer in the charstring. The
* only way to confirm if an integer at the start of the charstring is
* the width is when the first stack clearing operator is parsed,
* check if there is an extra integer left over on the stack.
*/
static cairo_status_t
cairo_cff_parse_charstring (cairo_cff_font_t *font,
unsigned char *charstring, int length,
int glyph_id)
int glyph_id,
cairo_bool_t need_width)
{
unsigned char *p = charstring;
unsigned char *end = charstring + length;
@ -1274,13 +1461,21 @@ cairo_cff_parse_charstring (cairo_cff_font_t *font,
font->type2_stack_size++;
font->type2_stack_top_value = integer;
font->type2_stack_top_is_int = TRUE;
if (!font->type2_seen_first_int) {
font->type2_width = integer;
font->type2_seen_first_int = TRUE;
}
} else if (*p == TYPE2_hstem || *p == TYPE2_vstem ||
*p == TYPE2_hstemhm || *p == TYPE2_vstemhm) {
/* Hint operator. The number of hints declared by the
* operator depends on the size of the stack. */
font->type2_stack_top_is_int = FALSE;
font->type2_num_hints += font->type2_stack_size/2;
if (font->type2_find_width && font->type2_stack_size % 2)
font->type2_found_width = TRUE;
font->type2_stack_size = 0;
font->type2_find_width = FALSE;
p++;
} else if (*p == TYPE2_hintmask || *p == TYPE2_cntrmask) {
/* Hintmask operator. These operators are followed by a
@ -1291,13 +1486,36 @@ cairo_cff_parse_charstring (cairo_cff_font_t *font,
if (font->type2_hintmask_bytes == 0) {
font->type2_stack_top_is_int = FALSE;
font->type2_num_hints += font->type2_stack_size/2;
if (font->type2_find_width && font->type2_stack_size % 2)
font->type2_found_width = TRUE;
font->type2_stack_size = 0;
font->type2_find_width = FALSE;
font->type2_hintmask_bytes = (font->type2_num_hints+7)/8;
}
hint_bytes = font->type2_hintmask_bytes;
p++;
p += hint_bytes;
} else if (*p == TYPE2_rmoveto) {
if (font->type2_find_width && font->type2_stack_size > 2)
font->type2_found_width = TRUE;
font->type2_stack_size = 0;
font->type2_find_width = FALSE;
p++;
} else if (*p == TYPE2_hmoveto || *p == TYPE2_vmoveto) {
if (font->type2_find_width && font->type2_stack_size > 1)
font->type2_found_width = TRUE;
font->type2_stack_size = 0;
font->type2_find_width = FALSE;
p++;
} else if (*p == TYPE2_endchar) {
if (font->type2_find_width && font->type2_stack_size > 0)
font->type2_found_width = TRUE;
return CAIRO_STATUS_SUCCESS;
} else if (*p == TYPE2_callsubr) {
/* call to local subroutine */
if (! font->type2_stack_top_is_int)
@ -1309,20 +1527,25 @@ cairo_cff_parse_charstring (cairo_cff_font_t *font,
p++;
font->type2_stack_top_is_int = FALSE;
font->type2_stack_size--;
if (font->type2_find_width && font->type2_stack_size == 0)
font->type2_seen_first_int = FALSE;
if (font->is_cid) {
fd = font->fdselect[glyph_id];
sub_num = font->type2_stack_top_value + font->fd_local_sub_bias[fd];
element = _cairo_array_index (&font->fd_local_sub_index[fd], sub_num);
if (! font->fd_local_subs_used[fd][sub_num]) {
font->fd_local_subs_used[fd][sub_num] = TRUE;
cairo_cff_parse_charstring (font, element->data, element->length, glyph_id);
cairo_cff_parse_charstring (font, element->data, element->length, glyph_id, need_width);
}
} else {
sub_num = font->type2_stack_top_value + font->local_sub_bias;
element = _cairo_array_index (&font->local_sub_index, sub_num);
if (! font->local_subs_used[sub_num]) {
if (! font->local_subs_used[sub_num] ||
(need_width && !font->type2_found_width))
{
font->local_subs_used[sub_num] = TRUE;
cairo_cff_parse_charstring (font, element->data, element->length, glyph_id);
cairo_cff_parse_charstring (font, element->data, element->length, glyph_id, need_width);
}
}
font->type2_nesting_level--;
@ -1337,15 +1560,25 @@ cairo_cff_parse_charstring (cairo_cff_font_t *font,
p++;
font->type2_stack_size--;
font->type2_stack_top_is_int = FALSE;
if (font->type2_find_width && font->type2_stack_size == 0)
font->type2_seen_first_int = FALSE;
sub_num = font->type2_stack_top_value + font->global_sub_bias;
element = _cairo_array_index (&font->global_sub_index, sub_num);
if (! font->global_subs_used[sub_num]) {
if (! font->global_subs_used[sub_num] ||
(need_width && !font->type2_found_width))
{
font->global_subs_used[sub_num] = TRUE;
cairo_cff_parse_charstring (font, element->data, element->length, glyph_id);
cairo_cff_parse_charstring (font, element->data, element->length, glyph_id, need_width);
}
font->type2_nesting_level--;
} else if (*p == 12) {
/* 2 byte instruction */
/* Most of the 2 byte operators */
if (need_width && (p[1] < 0x22 || p[1] > 0x25))
return CAIRO_INT_STATUS_UNSUPPORTED;
p += 2;
font->type2_stack_top_is_int = FALSE;
} else {
@ -1361,16 +1594,42 @@ cairo_cff_parse_charstring (cairo_cff_font_t *font,
static cairo_status_t
cairo_cff_find_subroutines_used (cairo_cff_font_t *font,
unsigned char *charstring, int length,
int glyph_id)
int glyph_id, int subset_id)
{
cairo_status_t status;
int width;
int fd;
font->type2_stack_size = 0;
font->type2_stack_top_value = 0;;
font->type2_stack_top_is_int = FALSE;
font->type2_num_hints = 0;
font->type2_hintmask_bytes = 0;
font->type2_nesting_level = 0;
font->type2_seen_first_int = FALSE;
font->type2_find_width = TRUE;
font->type2_found_width = FALSE;
font->type2_width = 0;
return cairo_cff_parse_charstring (font, charstring, length, glyph_id);
status = cairo_cff_parse_charstring (font, charstring, length, glyph_id, TRUE);
if (!font->is_opentype) {
if (font->is_cid) {
fd = font->fdselect[glyph_id];
if (font->type2_found_width)
width = font->fd_nominal_width[fd] + font->type2_width;
else
width = font->fd_default_width[fd];
} else {
if (font->type2_found_width)
width = font->nominal_width + font->type2_width;
else
width = font->default_width;
}
font->widths[subset_id] = width;
}
return status;
}
static cairo_int_status_t
@ -1392,7 +1651,7 @@ cairo_cff_font_subset_charstrings_and_subroutines (cairo_cff_font_t *font)
return status;
if (font->subset_subroutines) {
status = cairo_cff_find_subroutines_used (font, element->data, element->length, glyph);
status = cairo_cff_find_subroutines_used (font, element->data, element->length, glyph, i);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
font->subset_subroutines = FALSE;
} else if (unlikely (status))
@ -1618,8 +1877,8 @@ cairo_cff_font_write_name (cairo_cff_font_t *font)
cff_index_init (&index);
status = cff_index_append_copy (&index,
(unsigned char *) font->subset_font_name,
strlen(font->subset_font_name));
(unsigned char *) font->ps_name,
strlen(font->ps_name));
if (unlikely (status))
goto FAIL;
@ -2152,6 +2411,17 @@ cairo_cff_font_generate (cairo_cff_font_t *font,
if (unlikely (status))
return status;
/* If the PS name is not found, create a CairoFont-x-y name. */
if (font->ps_name == NULL) {
font->ps_name = malloc (30);
if (unlikely (font->ps_name == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
snprintf(font->ps_name, 30, "CairoFont-%u-%u",
font->scaled_font_subset->font_id,
font->scaled_font_subset->subset_id);
}
status = cairo_cff_font_subset_font (font);
if (unlikely (status))
return status;
@ -2160,6 +2430,7 @@ cairo_cff_font_generate (cairo_cff_font_t *font,
if (unlikely (status))
return status;
*data = _cairo_array_index (&font->output, 0);
*length = _cairo_array_num_elements (&font->output);
@ -2187,7 +2458,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
return status;
num_hmetrics = be16_to_cpu (hhea.num_hmetrics);
for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
glyph_index = font->scaled_font_subset->glyphs[i];
long_entry_size = 2 * sizeof (int16_t);
short_entry_size = sizeof (int16_t);
@ -2214,69 +2485,63 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cairo_cff_font_t **font_return,
const char *subset_name)
static cairo_bool_t
check_fontdata_is_cff (const unsigned char *data, long length)
{
const cairo_scaled_font_backend_t *backend;
cff_header_t *header;
if (length < (long)sizeof (cff_header_t))
return FALSE;
header = (cff_header_t *) data;
if (header->major == 1 &&
header->minor == 0 &&
header->header_size == 4)
{
return TRUE;
}
return FALSE;
}
static cairo_int_status_t
_cairo_cff_font_load_opentype_cff (cairo_cff_font_t *font)
{
const cairo_scaled_font_backend_t *backend = font->backend;
cairo_status_t status;
cairo_cff_font_t *font;
tt_head_t head;
tt_hhea_t hhea;
unsigned long size, data_length;
backend = scaled_font_subset->scaled_font->backend;
if (!backend->load_truetype_table)
return CAIRO_INT_STATUS_UNSUPPORTED;
/* We need to use a fallback font generated from the synthesized outlines. */
if (backend->is_synthetic && backend->is_synthetic (scaled_font_subset->scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
data_length = 0;
status = backend->load_truetype_table( scaled_font_subset->scaled_font,
status = backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_CFF, 0, NULL, &data_length);
if (unlikely (status))
if (status)
return status;
size = sizeof (tt_head_t);
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
status = backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char *) &head, &size);
if (unlikely (status))
return status;
size = sizeof (tt_hhea_t);
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
status = backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hhea, 0,
(unsigned char *) &hhea, &size);
if (unlikely (status))
return status;
size = 0;
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
status = backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hmtx, 0, NULL, &size);
if (unlikely (status))
return status;
font = malloc (sizeof (cairo_cff_font_t));
if (unlikely (font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->backend = backend;
font->scaled_font_subset = scaled_font_subset;
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
if (unlikely (status))
goto fail2;
font->subset_font_name = strdup (subset_name);
if (unlikely (font->subset_font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
font->x_min = (int16_t) be16_to_cpu (head.x_min);
font->y_min = (int16_t) be16_to_cpu (head.y_min);
font->x_max = (int16_t) be16_to_cpu (head.x_max);
@ -2288,56 +2553,123 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->units_per_em = 1000;
font->font_name = NULL;
status = _cairo_truetype_read_font_name (scaled_font_subset->scaled_font,
status = _cairo_truetype_read_font_name (font->scaled_font_subset->scaled_font,
&font->ps_name,
&font->font_name);
if (_cairo_status_is_error (status))
goto fail3;
return status;
/* If the PS name is not found, create a CairoFont-x-y name. */
if (font->ps_name == NULL) {
font->ps_name = malloc (30);
if (unlikely (font->ps_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
font->is_opentype = TRUE;
font->data_length = data_length;
font->data = malloc (data_length);
if (unlikely (font->data == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
snprintf(font->ps_name, 30, "CairoFont-%u-%u",
scaled_font_subset->font_id,
scaled_font_subset->subset_id);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_CFF, 0, font->data,
&font->data_length);
if (unlikely (status))
return status;
if (!check_fontdata_is_cff (font->data, data_length))
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_cff_font_load_cff (cairo_cff_font_t *font)
{
const cairo_scaled_font_backend_t *backend = font->backend;
cairo_status_t status;
unsigned long data_length;
if (!backend->load_type1_data)
return CAIRO_INT_STATUS_UNSUPPORTED;
data_length = 0;
status = backend->load_type1_data (font->scaled_font_subset->scaled_font,
0, NULL, &data_length);
if (unlikely (status))
return status;
font->font_name = NULL;
font->is_opentype = FALSE;
font->data_length = data_length;
font->data = malloc (data_length);
if (unlikely (font->data == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = font->backend->load_type1_data (font->scaled_font_subset->scaled_font,
0, font->data, &font->data_length);
if (unlikely (status))
return status;
if (!check_fontdata_is_cff (font->data, data_length))
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cairo_cff_font_t **font_return,
const char *subset_name)
{
const cairo_scaled_font_backend_t *backend;
cairo_int_status_t status;
cairo_cff_font_t *font;
backend = scaled_font_subset->scaled_font->backend;
/* We need to use a fallback font generated from the synthesized outlines. */
if (backend->is_synthetic && backend->is_synthetic (scaled_font_subset->scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
font = malloc (sizeof (cairo_cff_font_t));
if (unlikely (font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->backend = backend;
font->scaled_font_subset = scaled_font_subset;
status = _cairo_cff_font_load_opentype_cff (font);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_cff_font_load_cff (font);
if (status)
goto fail1;
font->data_end = font->data + font->data_length;
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
if (unlikely (status))
goto fail2;
font->subset_font_name = strdup (subset_name);
if (unlikely (font->subset_font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int));
if (unlikely (font->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
goto fail3;
}
status = cairo_cff_font_create_set_widths (font);
if (unlikely (status))
goto fail5;
font->data_length = data_length;
font->data = malloc (data_length);
if (unlikely (font->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail5;
if (font->is_opentype) {
status = cairo_cff_font_create_set_widths (font);
if (unlikely (status))
goto fail4;
}
status = font->backend->load_truetype_table ( font->scaled_font_subset->scaled_font,
TT_TAG_CFF, 0, font->data,
&font->data_length);
if (unlikely (status))
goto fail6;
font->data_end = font->data + font->data_length;
status = cff_dict_init (&font->top_dict);
if (unlikely (status))
goto fail6;
goto fail4;
status = cff_dict_init (&font->private_dict);
if (unlikely (status))
goto fail7;
goto fail5;
cff_index_init (&font->strings_index);
cff_index_init (&font->charstrings_index);
@ -2362,19 +2694,20 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
return CAIRO_STATUS_SUCCESS;
fail7:
_cairo_hash_table_destroy (font->top_dict);
fail6:
free (font->data);
fail5:
free (font->widths);
_cairo_hash_table_destroy (font->top_dict);
fail4:
if (font->font_name)
free (font->font_name);
free (font->widths);
fail3:
free (font->subset_font_name);
fail2:
free (font->data);
if (font->font_name)
free (font->font_name);
if (font->ps_name)
free (font->ps_name);
_cairo_array_fini (&font->output);
fail1:
free (font);
return status;
@ -2444,7 +2777,10 @@ cairo_cff_font_destroy (cairo_cff_font_t *font)
}
free (font->fd_local_subs_used);
}
if (font->fd_default_width)
free (font->fd_default_width);
if (font->fd_nominal_width)
free (font->fd_nominal_width);
}
if (font->data)
@ -2556,27 +2892,47 @@ _cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font)
cairo_bool_t is_cid = FALSE;
backend = scaled_font->backend;
if (!backend->load_truetype_table)
return FALSE;
/* check for CFF font */
data = NULL;
data_length = 0;
status = backend->load_truetype_table(scaled_font,
TT_TAG_CFF, 0, NULL, &data_length);
if (status)
return FALSE;
status = CAIRO_INT_STATUS_UNSUPPORTED;
/* Try to load an OpenType/CFF font */
if (backend->load_truetype_table &&
(status = backend->load_truetype_table (scaled_font, TT_TAG_CFF,
0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS)
{
data = malloc (data_length);
if (unlikely (data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
/* load CFF data */
data = malloc (data_length);
if (unlikely (data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
status = backend->load_truetype_table (scaled_font, TT_TAG_CFF,
status = backend->load_truetype_table (scaled_font, TT_TAG_CFF,
0, data, &data_length);
if (unlikely (status))
goto fail1;
if (unlikely (status))
goto fail1;
}
/* Try to load a CFF font */
if (status == CAIRO_INT_STATUS_UNSUPPORTED &&
backend->load_type1_data &&
(status = backend->load_type1_data (scaled_font,
0, NULL, &data_length)) == CAIRO_STATUS_SUCCESS)
{
data = malloc (data_length);
if (unlikely (data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
status = backend->load_type1_data (scaled_font, 0, data, &data_length);
if (unlikely (status))
goto fail1;
}
if (status)
goto fail1;
/* Check if it looks like a CFF font */
if (!check_fontdata_is_cff (data, data_length))
goto fail1;
data_end = data + data_length;
@ -2621,7 +2977,8 @@ fail2:
cff_index_fini (&index);
fail1:
free (data);
if (data)
free (data);
return is_cid;
}

View file

@ -2521,8 +2521,18 @@ _cairo_ft_load_type1_data (void *abstract_font,
if (!face)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
#if HAVE_FT_LOAD_SFNT_TABLE
if (FT_IS_SFNT (face)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto unlock;
}
#endif
font_format = FT_Get_X11_Font_Format (face);
if (!(font_format && strcmp (font_format, "Type 1") == 0)) {
if (!font_format ||
!(strcmp (font_format, "Type 1") == 0 ||
strcmp (font_format, "CFF") == 0))
{
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto unlock;
}