diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2007-04-20 22:30:55 +0930 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2007-04-20 22:30:55 +0930 |
commit | 0c2a653033e0b631a1cb6591263cbd6125ccc00c (patch) | |
tree | 0568fe5c4f1f53468a91698dcc299041eea436a3 | |
parent | c68a2389f51880b0fa9df6750abdd840258666fc (diff) |
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.
-rw-r--r-- | src/cairo-cff-subset.c | 212 | ||||
-rw-r--r-- | src/cairo-scaled-font-subsets-private.h | 68 | ||||
-rw-r--r-- | src/cairo-type1-fallback.c | 211 |
3 files changed, 432 insertions, 59 deletions
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c index e4c8cfce..a448e372 100644 --- a/src/cairo-cff-subset.c +++ b/src/cairo-cff-subset.c @@ -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); +} diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h index 4c8221e1..03076c86 100644 --- a/src/cairo-scaled-font-subsets-private.h +++ b/src/cairo-scaled-font-subsets-private.h @@ -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 diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c index dcf55f44..3a0bd124 100644 --- a/src/cairo-type1-fallback.c +++ b/src/cairo-type1-fallback.c @@ -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", - name, + "/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n", 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); +} |