/* Font Data */ unsignedchar *data; unsignedlong data_length; unsignedchar *current_ptr; unsignedchar *data_end;
cff_header_t *header; char *font_name; char *ps_name;
cairo_hash_table_t *top_dict;
cairo_hash_table_t *private_dict;
cairo_array_t strings_index;
cairo_array_t charstrings_index;
cairo_array_t global_sub_index;
cairo_array_t local_sub_index; unsignedchar *charset; 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; double default_width; double nominal_width;
/* CID Font Data */ int *fdselect; unsignedint num_fontdicts;
cairo_hash_table_t **fd_dict;
cairo_hash_table_t **fd_private_dict;
cairo_array_t *fd_local_sub_index; int *fd_local_sub_bias; double *fd_default_width; double *fd_nominal_width;
/* Subsetted Font Data */ char *subset_font_name;
cairo_array_t charstrings_subset_index;
cairo_array_t strings_subset_index; int euro_sid; int *fdselect_subset; unsignedint num_subset_fontdicts; int *fd_subset_map; int *private_dict_offset;
cairo_bool_t subset_subroutines;
cairo_bool_t *global_subs_used;
cairo_bool_t *local_subs_used;
cairo_bool_t **fd_local_subs_used;
cairo_array_t output;
/* Subset Metrics */ int *widths; int x_min, y_min, x_max, y_max; int ascent, descent;
/* Type 2 charstring data */ int type2_stack_size; int type2_stack_top_value;
cairo_bool_t type2_stack_top_is_int; 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_bool_t type2_has_path;
} cairo_cff_font_t;
/* Encoded integer using maximum sized encoding. This is required for
* operands that are later modified after encoding. */ staticunsignedchar *
encode_integer_max (unsignedchar *p, int i)
{
*p++ = 29;
*p++ = i >> 24;
*p++ = (i >> 16) & 0xff;
*p++ = (i >> 8) & 0xff;
*p++ = i & 0xff; return p;
}
staticunsignedchar *
encode_integer (unsignedchar *p, int i)
{ if (i >= -107 && i <= 107) {
*p++ = i + 139;
} elseif (i >= 108 && i <= 1131) {
i -= 108;
*p++ = (i >> 8)+ 247;
*p++ = i & 0xff;
} elseif (i >= -1131 && i <= -108) {
i = -i - 108;
*p++ = (i >> 8)+ 251;
*p++ = i & 0xff;
} elseif (i >= -32768 && i <= 32767) {
*p++ = 28;
*p++ = (i >> 8) & 0xff;
*p++ = i & 0xff;
} else {
p = encode_integer_max (p, i);
} return p;
}
p = *ptr; if (p + 2 > end_ptr) return CAIRO_INT_STATUS_UNSUPPORTED;
count = get_unaligned_be16 (p);
p += 2; if (count > 0) {
offset_size = *p++; if (p + (count + 1)*offset_size > end_ptr || offset_size > 4) return CAIRO_INT_STATUS_UNSUPPORTED;
data = p + offset_size*(count + 1) - 1;
start = decode_index_offset (p, offset_size);
p += offset_size; for (i = 0; i < count; i++) {
end = decode_index_offset (p, offset_size);
p += offset_size; if (p > end_ptr || end < start || data + end > end_ptr) return CAIRO_INT_STATUS_UNSUPPORTED;
element.length = end - start;
element.is_copy = FALSE;
element.data = data + start;
status = _cairo_array_append (index, &element); if (unlikely (status)) return status;
start = end;
}
p = data + end;
}
*ptr = p;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
cff_index_write (cairo_array_t *index, cairo_array_t *output)
{ int offset_size; int offset; int num_elem; int i;
cff_index_element_t *element;
uint16_t count; unsignedchar buf[5];
cairo_status_t status;
num_elem = _cairo_array_num_elements (index);
count = cpu_to_be16 ((uint16_t) num_elem);
status = _cairo_array_append_multiple (output, &count, 2); if (unlikely (status)) return status;
if (num_elem == 0) return CAIRO_STATUS_SUCCESS;
/* Find maximum offset to determine offset size */
offset = 1; for (i = 0; i < num_elem; i++) {
element = _cairo_array_index (index, i);
offset += element->length;
} if (offset < 0x100)
offset_size = 1; elseif (offset < 0x10000)
offset_size = 2; elseif (offset < 0x1000000)
offset_size = 3; else
offset_size = 4;
buf[0] = (unsignedchar) offset_size;
status = _cairo_array_append (output, buf); if (unlikely (status)) return status;
offset = 1;
encode_index_offset (buf, offset_size, offset);
status = _cairo_array_append_multiple (output, buf, offset_size); if (unlikely (status)) return status;
for (i = 0; i < num_elem; i++) {
element = _cairo_array_index (index, i);
offset += element->length;
encode_index_offset (buf, offset_size, offset);
status = _cairo_array_append_multiple (output, buf, offset_size); if (unlikely (status)) return status;
}
for (i = 0; i < num_elem; i++) {
element = _cairo_array_index (index, i); if (element->length > 0) {
status = _cairo_array_append_multiple (output,
element->data,
element->length);
} if (unlikely (status)) return status;
} return CAIRO_STATUS_SUCCESS;
}
staticvoid
cff_index_set_object (cairo_array_t *index, int obj_index, unsignedchar *object , int length)
{
cff_index_element_t *element;
element = _cairo_array_index (index, obj_index); if (element->is_copy)
free (element->data);
for (i = 0; i < _cairo_array_num_elements (index); i++) {
element = _cairo_array_index (index, i); if (element->is_copy && element->data)
free (element->data);
}
_cairo_array_fini (index);
}
/* The CFF specification requires that the Top Dict of CID fonts
* begin with the ROS operator. */
_cairo_dict_init_key (&key, ROS_OP);
op = _cairo_hash_table_lookup (dict, &key.base); if (op != NULL)
cairo_dict_write_operator (op, &write_info);
static cairo_int_status_t
cairo_cff_font_read_name (cairo_cff_font_t *font)
{
cairo_array_t index;
cairo_int_status_t status;
cff_index_element_t *element; unsignedchar *p; int i, len;
cff_index_init (&index);
status = cff_index_read (&index, &font->current_ptr, font->data_end); if (status == CAIRO_INT_STATUS_SUCCESS && !font->is_opentype) {
element = _cairo_array_index (&index, 0);
p = element->data;
len = element->length;
/* If font name is prefixed with a subset tag, strip it off. */ if (len > 7 && p[6] == '+') { for (i = 0; i < 6; i++) if (p[i] < 'A' || p[i] > 'Z') break; if (i == 6) {
p += 7;
len -= 7;
}
}
status = _cairo_escape_ps_name (&font->ps_name);
}
cff_index_fini (&index);
return status;
}
static cairo_int_status_t
cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
cairo_hash_table_t *private_dict,
cairo_array_t *local_sub_index, int *local_sub_bias,
cairo_bool_t **local_subs_used, double *default_width, double *nominal_width, unsignedchar *ptr, int size)
{
cairo_int_status_t status; unsignedchar buf[10]; unsignedchar *end_buf; int offset; int i; unsignedchar *operand; unsignedchar *p; int num_subs;
status = cff_dict_read (private_dict, ptr, size); if (unlikely (status)) return status;
operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i); if (operand) {
decode_integer (operand, &offset);
p = ptr + offset;
status = cff_index_read (local_sub_index, &p, font->data_end); if (unlikely (status)) return status;
/* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0);
status = cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf); if (unlikely (status)) return status;
}
/* Set integer operand to max value to use max size encoding to reserve
* space for any value later */
end_buf = encode_integer_max (buf, 0);
end_buf = encode_integer_max (end_buf, 0);
status = cff_dict_set_operands (font->fd_dict[i], PRIVATE_OP, buf, end_buf - buf); if (unlikely (status)) goto fail;
}
x_min = 0.0;
y_min = 0.0;
x_max = 0.0;
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/abs(yy) to get units per EM */
font->units_per_em = _cairo_round(1.0/fabs(yy));
}
/* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0);
status = cff_dict_set_operands (font->top_dict,
CHARSTRINGS_OP, buf, end_buf - buf); if (unlikely (status)) goto fail;
status = cff_dict_set_operands (font->top_dict,
CHARSET_OP, buf, end_buf - buf); if (unlikely (status)) goto fail;
if (font->scaled_font_subset->is_latin) {
status = cff_dict_set_operands (font->top_dict,
ENCODING_OP, buf, end_buf - buf); if (unlikely (status)) goto fail;
/* Private has two operands - size and offset */
end_buf = encode_integer_max (end_buf, 0);
cff_dict_set_operands (font->top_dict, PRIVATE_OP, buf, end_buf - buf); if (unlikely (status)) goto fail;
} else {
status = cff_dict_set_operands (font->top_dict,
FDSELECT_OP, buf, end_buf - buf); if (unlikely (status)) goto fail;
status = cff_dict_set_operands (font->top_dict,
FDARRAY_OP, buf, end_buf - buf); if (unlikely (status)) goto fail;
/* Remove the unique identifier operators as the subsetted font is
* not the same is the original font. */
cff_dict_remove (font->top_dict, UNIQUEID_OP);
cff_dict_remove (font->top_dict, XUID_OP);
sid1 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append_copy (&font->strings_subset_index,
(unsignedchar *)registry,
strlen(registry)); if (unlikely (status)) return status;
sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append_copy (&font->strings_subset_index,
(unsignedchar *)ordering,
strlen(ordering)); if (unlikely (status)) return status;
p = encode_integer (buf, sid1);
p = encode_integer (p, sid2);
p = encode_integer (p, 0);
status = cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf); if (unlikely (status)) return status;
p = encode_integer (buf, font->scaled_font_subset->num_glyphs);
status = cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf); if (unlikely (status)) return status;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
cairo_cff_font_subset_dict_string(cairo_cff_font_t *font,
cairo_hash_table_t *dict, intoperator)
{ int size; unsignedchar *p; int sid; unsignedchar buf[100];
cff_index_element_t *element;
cairo_status_t status;
p = cff_dict_get_operands (dict, operator, &size); if (!p) return CAIRO_STATUS_SUCCESS;
decode_integer (p, &sid); if (sid < NUM_STD_STRINGS) return CAIRO_STATUS_SUCCESS;
element = _cairo_array_index (&font->strings_index, sid - NUM_STD_STRINGS);
sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append (&font->strings_subset_index, element->data, element->length); if (unlikely (status)) return status;
p = encode_integer (buf, sid);
status = cff_dict_set_operands (dict, operator, buf, p - buf); if (unlikely (status)) return status;
for (i = 0; i < ARRAY_LENGTH (dict_strings); i++) {
status = cairo_cff_font_subset_dict_string (font, dict, dict_strings[i]); if (unlikely (status)) return status;
}
/* Type 2 charstring parser for finding calls to local or global * 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 the 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. * * When the first stack clearing operator is encountered * type2_find_width is set to FALSE and type2_found_width is set to * TRUE if an extra argument is found, otherwise FALSE.
*/ static cairo_status_t
cairo_cff_parse_charstring (cairo_cff_font_t *font, unsignedchar *charstring, int length, int glyph_id,
cairo_bool_t need_width)
{ unsignedchar *p = charstring; unsignedchar *end = charstring + length; int integer; int hint_bytes; int sub_num;
cff_index_element_t *element; int fd;
while (p < end) { if (*p == 28 || *p >= 32) { /* Integer value */
p = type2_decode_integer (p, &integer);
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;
}
} elseif (*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++;
} elseif (*p == TYPE2_hintmask || *p == TYPE2_cntrmask) { /* Hintmask operator. These operators are followed by a * variable length mask where the length depends on the * number of hints declared. The first time this is called * it is also an implicit vstem if there are arguments on
* the stack. */ 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;
/* All the 2 byte operators are either not valid before a * stack clearing operator or they are one of the
* arithmetic, storage, or conditional operators. */ if (need_width && font->type2_find_width) return CAIRO_INT_STATUS_UNSUPPORTED;
static cairo_status_t
cairo_cff_find_width_and_subroutines_used (cairo_cff_font_t *font, unsignedchar *charstring, int length, int glyph_id, int subset_id)
{
cairo_status_t status; int width; int fd;
font->subset_subroutines = TRUE; for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { if (font->is_cid && !font->is_opentype) {
cid = font->scaled_font_subset->glyphs[i];
status = cairo_cff_font_get_gid_for_cid (font, cid, &glyph); if (unlikely (status)) return status;
} else {
glyph = font->scaled_font_subset->glyphs[i];
}
element = _cairo_array_index (&font->charstrings_index, glyph);
status = cff_index_append (&font->charstrings_subset_index,
element->data,
element->length); if (unlikely (status)) return status;
if (font->subset_subroutines) {
status = cairo_cff_find_width_and_subroutines_used (font,
element->data, element->length,
glyph, i); if (status == CAIRO_INT_STATUS_UNSUPPORTED) { /* If parsing the charstrings fails we embed all the * subroutines. But if the font is not opentype we * need to successfully parse all charstrings to get
* the widths. */
font->subset_subroutines = FALSE; if (!font->is_opentype) return status;
} elseif (unlikely (status)) { return status;
}
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
cairo_cff_font_subset_fontdict (cairo_cff_font_t *font)
{ unsignedint i; int fd; int *reverse_map; unsignedlong cid, gid;
cairo_int_status_t status;
/* Set integer operand to max value to use max size encoding to reserve
* space for any value later */
end_buf = encode_integer_max (buf, 0);
end_buf = encode_integer_max (end_buf, 0);
status = cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf); if (unlikely (status)) return status;
status = cairo_cff_font_subset_dict_strings (font, font->top_dict); if (unlikely (status)) return status;
if (font->is_cid) { for (i = 0; i < font->num_subset_fontdicts; i++) {
status = cairo_cff_font_subset_dict_strings (font, font->fd_dict[font->fd_subset_map[i]]); if (unlikely (status)) return status;
status = cairo_cff_font_subset_dict_strings (font, font->fd_private_dict[font->fd_subset_map[i]]); if (unlikely (status)) return status;
}
} else {
status = cairo_cff_font_subset_dict_strings (font, font->private_dict);
}
return status;
}
/* The Euro is the only the only character in the winansi encoding * with a glyph name that is not a CFF standard string. As the strings * are written before the charset, we need to check during the * subsetting phase if the Euro glyph is required and add the * glyphname to the list of strings to write out.
*/ static cairo_status_t
cairo_cff_font_add_euro_charset_string (cairo_cff_font_t *font)
{
cairo_status_t status; unsignedint i; int ch; constchar *euro = "Euro";
for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
ch = font->scaled_font_subset->to_latin_char[i]; if (ch == 128) {
font->euro_sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append_copy (&font->strings_subset_index,
(unsignedchar *)euro, strlen(euro)); return status;
}
}
if (!font->scaled_font_subset->is_latin) {
status = cairo_cff_font_set_ros_strings (font); if (unlikely (status)) return status;
}
status = cairo_cff_font_subset_charstrings_and_subroutines (font); if (unlikely (status)) return status;
if (!font->scaled_font_subset->is_latin) { if (font->is_cid)
status = cairo_cff_font_subset_fontdict (font); else
status = cairo_cff_font_create_cid_fontdict (font); if (unlikely (status)) return status;
} else {
font->private_dict_offset = _cairo_malloc (sizeof (int)); if (unlikely (font->private_dict_offset == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
status = cairo_cff_font_subset_strings (font); if (unlikely (status)) return status;
if (font->scaled_font_subset->is_latin)
status = cairo_cff_font_add_euro_charset_string (font);
return status;
}
/* Set the operand of the specified operator in the (already written) * top dict to point to the current position in the output * array. Operands updated with this function must have previously
* been encoded with the 5-byte (max) integer encoding. */ staticvoid
cairo_cff_font_set_topdict_operator_to_cur_pos (cairo_cff_font_t *font, intoperator)
{ int cur_pos; int offset; int size; unsignedchar buf[10]; unsignedchar *buf_end; unsignedchar *op_ptr;
status = cff_index_append_copy (&index,
(unsignedchar *) font->ps_name,
strlen(font->ps_name)); if (unlikely (status)) goto FAIL;
status = cff_index_write (&index, &font->output); if (unlikely (status)) goto FAIL;
FAIL:
cff_index_fini (&index);
return status;
}
static cairo_status_t
cairo_cff_font_write_top_dict (cairo_cff_font_t *font)
{
uint16_t count; unsignedchar buf[10]; unsignedchar *p; int offset_index; int dict_start, dict_size; int offset_size = 4;
cairo_status_t status;
/* Write an index containing the top dict */
count = cpu_to_be16 (1);
status = _cairo_array_append_multiple (&font->output, &count, 2); if (unlikely (status)) return status;
buf[0] = offset_size;
status = _cairo_array_append (&font->output, buf); if (unlikely (status)) return status;
encode_index_offset (buf, offset_size, 1);
status = _cairo_array_append_multiple (&font->output, buf, offset_size); if (unlikely (status)) return status;
/* Reserve space for last element of offset array and update after
* dict is written */
offset_index = _cairo_array_num_elements (&font->output);
status = _cairo_array_append_multiple (&font->output, buf, offset_size); if (unlikely (status)) return status;
dict_start = _cairo_array_num_elements (&font->output);
status = cff_dict_write (font->top_dict, &font->output); if (unlikely (status)) return status;
dict_size = _cairo_array_num_elements (&font->output) - dict_start;
/* poppler and fontforge don't like zero length subroutines so we
* replace unused subroutines with a 'return' instruction. */ if (font->subset_subroutines) { for (i = 0; i < _cairo_array_num_elements (&font->global_sub_index); i++) { if (! font->global_subs_used[i])
cff_index_set_object (&font->global_sub_index, i, &return_op, 1);
}
}
cairo_cff_font_set_topdict_operator_to_cur_pos (font, ENCODING_OP);
buf[0] = 0; /* Format 0 */
buf[1] = font->scaled_font_subset->num_glyphs - 1;
status = _cairo_array_append_multiple (&font->output, buf, 2); if (unlikely (status)) return status;
for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) { unsignedchar ch = font->scaled_font_subset->to_latin_char[i];
status = _cairo_array_append (&font->output, &ch); if (unlikely (status)) return status;
}
if (font->is_cid) {
data = 0;
status = _cairo_array_append (&font->output, &data); if (unlikely (status)) return status;
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
data = font->fdselect_subset[i];
status = _cairo_array_append (&font->output, &data); if (unlikely (status)) return status;
}
} else { unsignedchar byte;
uint16_t word;
status = _cairo_array_grow_by (&font->output, 9); if (unlikely (status)) return status;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.