[cairo-commit] src/cairo-cff-subset.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Sun Jan 28 00:34:01 PST 2007


 src/cairo-cff-subset.c |  253 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 252 insertions(+), 1 deletion(-)

New commits:
diff-tree 7abfb39709342fc3d95269ad2d76a5e1e8f8d38f (from a63ceef06c2c015c8e5f0ad7b756ff6801996096)
Author: Eugeniy Meshcheryakov <eugen at debian.org>
Date:   Sun Jan 28 19:01:38 2007 +1030

    CFF Subsetting: Add charset data to embedded font
    
    Current code for subsetting CFF fonts does not write charset information
    into it. According to spec this means that font have ISOAdobe charset.
    This charset contains only 228 names (excluding .notdef). This is not
    enough for subfonts with 256 glyphs and causes bugs when viewing
    generated PDFs.

diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index d26ee87..c65328e 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -31,6 +31,7 @@
  *
  * Contributor(s):
  *	Adrian Johnson <ajohnson at redneon.com>
+ *      Eugeniy Meshcheryakov <eugen at debian.org>
  */
 
 #include "cairoint.h"
@@ -81,6 +82,12 @@ typedef struct _cff_dict_operator {
     int            operand_offset;
 } cff_dict_operator_t;
 
+typedef struct _cff_charset {
+    cairo_bool_t   is_builtin;
+    const unsigned char *data;
+    int            length;
+} cff_charset_t;
+
 typedef struct _cairo_cff_font {
 
     cairo_scaled_font_subset_t *scaled_font_subset;
@@ -100,11 +107,14 @@ typedef struct _cairo_cff_font {
     cairo_array_t        global_sub_index;
     cairo_array_t        local_sub_index;
     int                  num_glyphs;
+    cff_charset_t        charset;
+    int                  charset_offset;
 
     /* Subsetted Font Data */
     char                *subset_font_name;
     cairo_array_t        charstrings_subset_index;
     cairo_array_t        strings_subset_index;
+    cairo_array_t        charset_subset;
     cairo_array_t        output;
 
     /* Subset Metrics */
@@ -742,12 +752,19 @@ cairo_cff_font_read_top_dict (cairo_cff_
     decode_integer (operand, &offset);
     cairo_cff_font_read_private_dict (font, font->data + offset, size);
 
-    cff_dict_remove (font->top_dict, CHARSET_OP);
+    operand = cff_dict_get_operands (font->top_dict, CHARSET_OP, &size);
+    if (!operand)
+      font->charset_offset = 0;
+    else {
+      decode_integer (operand, &offset);
+      font->charset_offset = offset;
+    }
 
     /* Use maximum sized encoding to reserve space for later modification. */
     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, ENCODING_OP, buf, end_buf - buf);
+    cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf);
     /* 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);
@@ -770,6 +787,134 @@ cairo_cff_font_read_global_subroutines (
     return cff_index_read (&font->global_sub_index, &font->current_ptr, font->data_end);
 }
 
+static cairo_int_status_t
+cff_charset_read_data (cff_charset_t *charset, const unsigned char *data,
+	const unsigned char *data_end, int num_glyphs)
+{
+    const unsigned char *p = data;
+
+    num_glyphs -= 1; /* do not count .notdef */
+
+    if (p + 1 > data_end)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    switch (*p++) {
+    case 0:
+	if (p + num_glyphs*2 > data_end)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	charset->is_builtin = FALSE;
+	charset->data = data;
+	charset->length = num_glyphs * 2 + 1;
+	break;
+    case 1:
+	while (num_glyphs > 0) {
+	    if (p + 3 > data_end)
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	    num_glyphs -= p[2] + 1;
+	    p += 3;
+	}
+	if (num_glyphs < 0)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	charset->is_builtin = FALSE;
+	charset->data = data;
+	charset->length = p - data;
+	break;
+    case 2:
+	while (num_glyphs > 0) {
+	    if (p + 4 > data_end)
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	    num_glyphs -= be16_to_cpu(*(uint16_t *)(p + 2)) + 1;
+	    p += 4;
+	}
+	if (num_glyphs < 0)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	charset->is_builtin = FALSE;
+	charset->data = data;
+	charset->length = p - data;
+	break;
+    default:
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const uint16_t ISOAdobe_charset[] = {
+    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+    31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+    45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+    59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+    73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+    101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+    112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+    123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
+    134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+    145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
+    156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+    167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+    178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+    189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+    200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
+    211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+    222, 223, 224, 225, 226, 227, 228,
+};
+
+static const uint16_t Expert_charset[] = {
+    1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13,
+    14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247,
+    248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257,
+    258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110,
+    267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277,
+    278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
+    289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
+    300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310,
+    311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163,
+    319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169,
+    327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337,
+    338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348,
+    349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
+    360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370,
+    371, 372, 373, 374, 375, 376, 377, 378,
+};
+
+static const uint16_t ExpertSubset_charset[] = {
+    1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240,
+    241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
+    251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
+    263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272,
+    300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321,
+    322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
+    330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
+    341, 342, 343, 344, 345, 346,
+};
+
+#define BUILTIN_CHARSET(name) ((cff_charset_t){TRUE, (const unsigned char *)&(name), sizeof(name)})
+
+static cairo_int_status_t
+cairo_cff_font_read_charset (cairo_cff_font_t *font)
+{
+    switch (font->charset_offset) {
+    case 0:
+	/* ISOAdobe charset */
+	font->charset = BUILTIN_CHARSET(ISOAdobe_charset);
+	return CAIRO_STATUS_SUCCESS;
+    case 1:
+	/* Expert charset */
+	font->charset = BUILTIN_CHARSET(Expert_charset);
+	return CAIRO_STATUS_SUCCESS;
+    case 2:
+	/* ExpertSubset charset */;
+	font->charset = BUILTIN_CHARSET(ExpertSubset_charset);
+	return CAIRO_STATUS_SUCCESS;
+    default:
+	break;
+    }
+    return cff_charset_read_data (&font->charset, font->data + (unsigned)font->charset_offset,
+	    font->data_end, font->num_glyphs);
+}
+
 typedef cairo_int_status_t
 (*font_read_t) (cairo_cff_font_t *font);
 
@@ -779,6 +924,8 @@ static const font_read_t font_read_funcs
     cairo_cff_font_read_top_dict,
     cairo_cff_font_read_strings,
     cairo_cff_font_read_global_subroutines,
+    /* non-contiguous */
+    cairo_cff_font_read_charset,
 };
 
 static cairo_int_status_t
@@ -898,6 +1045,82 @@ cairo_cff_font_subset_charstrings (cairo
     return CAIRO_STATUS_SUCCESS;
 }
 
+static uint16_t
+cff_sid_from_gid (const cff_charset_t *charset, int gid)
+{
+    const uint16_t *sids;
+    const unsigned char *p;
+    int prev_glyph;
+
+    if (charset->is_builtin) {
+	sids = (const uint16_t *)charset->data;
+
+	if (gid - 1 < charset->length / 2)
+	    return sids[gid - 1];
+    }
+    else {
+	/* no need to check sizes here, this was done during reading */
+	switch (charset->data[0]) {
+	case 0:
+	    sids = (const uint16_t *)(charset->data + 1);
+	    return be16_to_cpu(sids[gid - 1]);
+	case 1:
+	    prev_glyph = 1;
+	    for (p = charset->data + 1; p < charset->data + charset->length; p += 3) {
+		if (gid <= prev_glyph + p[2]) {
+		    uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
+		    return sid + gid - prev_glyph;
+		}
+		prev_glyph += p[2] + 1;
+	    }
+	    break;
+	case 2:
+	    prev_glyph = 1;
+	    for (p = charset->data + 1; p < charset->data + charset->length; p += 4) {
+		uint16_t nLeft = be16_to_cpu(*(const uint16_t *)(p + 2));
+		if (gid <= prev_glyph + nLeft) {
+		    uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
+		    return sid + gid - prev_glyph;
+		}
+		prev_glyph += nLeft + 1;
+	    }
+	    break;
+	default:
+	    break;
+	}
+    }
+    return 0;
+}
+
+static cairo_status_t
+cairo_cff_font_subset_charset (cairo_cff_font_t  *font)
+{
+    unsigned int i;
+
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+	int gid = font->scaled_font_subset->glyphs[i];
+	uint16_t original_sid = cff_sid_from_gid(&font->charset, gid);
+	uint16_t new_sid;
+	cff_index_element_t *element;
+	cairo_status_t status;
+
+	if (original_sid >= NUM_STD_STRINGS) {
+	    element = _cairo_array_index (&font->strings_index, original_sid - NUM_STD_STRINGS);
+	    new_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 (status)
+		return status;
+	}
+	else
+	    new_sid = original_sid;
+
+	status = _cairo_array_append(&font->charset_subset, &new_sid);
+	if (status)
+	    return status;
+    }
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_status_t
 cairo_cff_font_subset_font (cairo_cff_font_t  *font)
 {
@@ -910,6 +1133,10 @@ cairo_cff_font_subset_font (cairo_cff_fo
         return status;
 
     status = cairo_cff_font_subset_charstrings (font);
+    if (status)
+	return status;
+
+    status = cairo_cff_font_subset_charset (font);
 
     return status;
 }
@@ -1039,6 +1266,27 @@ cairo_cff_font_write_encoding (cairo_cff
 }
 
 static cairo_status_t
+cairo_cff_font_write_charset (cairo_cff_font_t  *font)
+{
+    unsigned char format = 0;
+    unsigned int i;
+    cairo_status_t status;
+
+    cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP);
+    status = _cairo_array_append (&font->output, &format);
+    if (status)
+	return status;
+
+    for (i = 0; i < (unsigned)_cairo_array_num_elements(&font->charset_subset); i++) {
+	uint16_t sid = cpu_to_be16(*(uint16_t *)_cairo_array_index(&font->charset_subset, i));
+	status = _cairo_array_append_multiple (&font->output, &sid, sizeof(sid));
+	if (status)
+	    return status;
+    }
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
 cairo_cff_font_write_charstrings (cairo_cff_font_t  *font)
 {
     cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSTRINGS_OP);
@@ -1098,6 +1346,7 @@ static const font_write_t font_write_fun
     cairo_cff_font_write_strings,
     cairo_cff_font_write_global_subrs,
     cairo_cff_font_write_encoding,
+    cairo_cff_font_write_charset,
     cairo_cff_font_write_charstrings,
     cairo_cff_font_write_private_dict_and_local_sub,
 };
@@ -1345,6 +1594,7 @@ _cairo_cff_font_create (cairo_scaled_fon
     cff_index_init (&font->local_sub_index);
     cff_index_init (&font->charstrings_subset_index);
     cff_index_init (&font->strings_subset_index);
+    _cairo_array_init (&font->charset_subset, sizeof(uint16_t));
 
     free (name);
     *font_return = font;
@@ -1383,6 +1633,7 @@ cairo_cff_font_destroy (cairo_cff_font_t
     cff_index_fini (&font->local_sub_index);
     cff_index_fini (&font->charstrings_subset_index);
     cff_index_fini (&font->strings_subset_index);
+    _cairo_array_fini (&font->charset_subset);
     free (font);
 }
 


More information about the cairo-commit mailing list