[cairo-commit] 5 commits - src/cairo-scaled-font-subsets.c src/cairo-type1-subset.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Tue Jun 3 05:55:09 PDT 2008


 src/cairo-scaled-font-subsets.c |   58 ++++++++++++++-------
 src/cairo-type1-subset.c        |  108 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 145 insertions(+), 21 deletions(-)

New commits:
commit e1bc97a7e506c16467d97a525b35722ea30027c3
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Thu May 1 23:29:20 2008 +0930

    Disable UniqueID font check in Type 1 subset font
    
    Some Type 1 fonts have some PostScript code at the start of the font
    that checks if the font is already cached in the printer (based on the
    font UniqueID key). This breaks our subsetted font as it is not the
    same as the original font.
    
    Checking for and removing a random blob of PostScript is difficult so
    this patch takes the simpler approach of searching for the PS code
    that checks if the UniqueID dictionary entry exists
    
    ie
    
      /UniqueID known
    
    this code leaves the value "true" or "false" on the PS interpreter
    stack depending on whether the "UniqueID" key exists.
    
    Then the patch inserts the PS code " pop false " after the above code
    to remove the old result and place "false" on the stack to make it
    appear that UniqueID does not exist.
    
    This approach should be able to handle any type of PostScript code
    that attempts to do something with the UniqueID value in the font
    dictionary.

diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index f51e564..b514181 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -345,12 +345,36 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
 
     segment_end = font->header_segment + font->header_segment_size;
 
-    start = find_token (font->header_segment, segment_end, "/FontName");
+    /* Type 1 fonts created by Fontforge have some PostScript code at
+     * the start of the font that skips the font if the printer has a
+     * cached copy of the font with the same unique id. This breaks
+     * our subsetted font so we disable it by searching for the
+     * PostScript operator "known" when used to check for the
+     * "/UniqueID" dictionary key. We append " pop false " after it to
+     * pop the result of this check off the stack and replace it with
+     * "false" to make the PostScript code think "/UniqueID" does not
+     * exist.
+     */
+    end = font->header_segment;
+    start = find_token (font->header_segment, segment_end, "/UniqueID");
+    if (start) {
+	start += 9;
+	while (start < segment_end && isspace (*start))
+	    start++;
+	if (start + 5 < segment_end && memcmp(start, "known", 5) == 0) {
+	    _cairo_output_stream_write (font->output, font->header_segment,
+					start + 5 - font->header_segment);
+	    _cairo_output_stream_printf (font->output, " pop false ");
+	    end = start + 5;
+	}
+    }
+
+    start = find_token (end, segment_end, "/FontName");
     if (start == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    _cairo_output_stream_write (font->output, font->header_segment,
-				start - font->header_segment);
+    _cairo_output_stream_write (font->output, end,
+				start - end);
 
     _cairo_output_stream_printf (font->output, "/FontName /%s def", name);
 
commit 34c42202f0575be10a2e409fe66f1da95886353f
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Thu May 1 22:55:07 2008 +0930

    Remove XUID key from subsetted Type 1 fonts
    
    Subsetted fonts must not share the same XUID as the original font.

diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index 4f26e7b..f51e564 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -329,11 +329,11 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
      * before /Encoding. This appears to always be the case with Type1
      * fonts.
      *
-     * The more recently added code for removing the UniqueID key can
-     * not make any assumptions about the position of the UniqueID key
-     * in the dictionary so it is implemented by overwriting the key
-     * definition with spaces before we start copying the font to the
-     * output.
+     * The more recently added code for removing the UniqueID and XUID
+     * keys can not make any assumptions about the position of the
+     * keys in the dictionary so it is implemented by overwriting the
+     * key definition with spaces before we start copying the font to
+     * the output.
      *
      * This code should be rewritten to not make any assumptions about
      * the order of dictionary keys. This will allow UniqueID to be
@@ -341,6 +341,7 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
      * output.
      */
     cairo_type1_font_erase_dict_key (font, "/UniqueID");
+    cairo_type1_font_erase_dict_key (font, "/XUID");
 
     segment_end = font->header_segment + font->header_segment_size;
 
commit 6ae1061508d6b14b128a8fbf7558d3a64f9551fa
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Thu May 1 23:24:57 2008 +0930

    Remove UniqueID key from subsetted Type 1 fonts
    
    Subsetted fonts must not share the same UniqueID as the original
    font.

diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index ffb5424..4f26e7b 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -276,6 +276,47 @@ cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font)
     return CAIRO_STATUS_SUCCESS;
 }
 
+/* Search for the definition of key and erase it by overwriting with spaces.
+ * This function is looks for definitions of the form:
+ *
+ * /key1 1234 def
+ * /key2 [12 34 56] def
+ *
+ * ie a key defined as an integer or array of integers.
+ *
+ */
+static void
+cairo_type1_font_erase_dict_key (cairo_type1_font_subset_t *font,
+				 const char *key)
+{
+    const char *start, *p, *segment_end;
+
+    segment_end = font->header_segment + font->header_segment_size;
+
+    start = font->header_segment;
+    do {
+	start = find_token (start, segment_end, key);
+	if (start) {
+	    p = start + strlen(key);
+	    /* skip integers or array of integers */
+	    while (p < segment_end &&
+		   (isspace(*p) ||
+		    isdigit(*p) ||
+		    *p == '[' ||
+		    *p == ']'))
+	    {
+		p++;
+	    }
+
+	    if (p + 3 < segment_end && memcmp(p, "def", 3) == 0) {
+		/* erase definition of the key */
+		memset((char *) start, ' ', p + 3 - start);
+	    }
+	    start += strlen(key);
+	}
+    } while (start);
+}
+
 static cairo_status_t
 cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
 					 const char *name)
@@ -283,6 +324,24 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
     const char *start, *end, *segment_end;
     unsigned int i;
 
+    /* FIXME:
+     * This function assumes that /FontName always appears
+     * before /Encoding. This appears to always be the case with Type1
+     * fonts.
+     *
+     * The more recently added code for removing the UniqueID key can
+     * not make any assumptions about the position of the UniqueID key
+     * in the dictionary so it is implemented by overwriting the key
+     * definition with spaces before we start copying the font to the
+     * output.
+     *
+     * This code should be rewritten to not make any assumptions about
+     * the order of dictionary keys. This will allow UniqueID to be
+     * stripped out instead of leaving a bunch of spaces in the
+     * output.
+     */
+    cairo_type1_font_erase_dict_key (font, "/UniqueID");
+
     segment_end = font->header_segment + font->header_segment_size;
 
     start = find_token (font->header_segment, segment_end, "/FontName");
commit e30cd617c89fa7511d2002a155d4ccdfa2ec9aa9
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue May 13 21:41:56 2008 +0930

    Make font subsetting output fonts in order of the font subset id
    
    This ensures that PS/PDF output is always the same for the same cairo
    input. Previously the order of the embedded fonts depended on the hash
    key of the fonts which depended on the memory location of fonts.

diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index ee29f89..79bc097 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -53,18 +53,6 @@ typedef enum {
     CAIRO_SUBSETS_COMPOSITE
 } cairo_subsets_type_t;
 
-struct _cairo_scaled_font_subsets {
-    cairo_subsets_type_t type;
-
-    int max_glyphs_per_unscaled_subset_used;
-    cairo_hash_table_t *unscaled_sub_fonts;
-
-    int max_glyphs_per_scaled_subset_used;
-    cairo_hash_table_t *scaled_sub_fonts;
-
-    int num_sub_fonts;
-};
-
 typedef struct _cairo_sub_font {
     cairo_hash_entry_t base;
 
@@ -79,8 +67,25 @@ typedef struct _cairo_sub_font {
     int max_glyphs_per_subset;
 
     cairo_hash_table_t *sub_font_glyphs;
+    struct _cairo_sub_font *next;
 } cairo_sub_font_t;
 
+struct _cairo_scaled_font_subsets {
+    cairo_subsets_type_t type;
+
+    int max_glyphs_per_unscaled_subset_used;
+    cairo_hash_table_t *unscaled_sub_fonts;
+    cairo_sub_font_t *unscaled_sub_fonts_list;
+    cairo_sub_font_t *unscaled_sub_fonts_list_end;
+
+    int max_glyphs_per_scaled_subset_used;
+    cairo_hash_table_t *scaled_sub_fonts;
+    cairo_sub_font_t *scaled_sub_fonts_list;
+    cairo_sub_font_t *scaled_sub_fonts_list_end;
+
+    int num_sub_fonts;
+};
+
 typedef struct _cairo_sub_font_glyph {
     cairo_hash_entry_t base;
 
@@ -252,6 +257,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t	*parent,
 	free (sub_font);
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
+    sub_font->next = NULL;
 
     /* Reserve first glyph in subset for the .notdef glyph */
     status = _cairo_sub_font_map_glyph (sub_font, 0, &subset_glyph);
@@ -461,6 +467,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
 	free (subsets);
 	return NULL;
     }
+    subsets->unscaled_sub_fonts_list = NULL;
+    subsets->unscaled_sub_fonts_list_end = NULL;
 
     subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
     if (! subsets->scaled_sub_fonts) {
@@ -468,6 +476,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
 	free (subsets);
 	return NULL;
     }
+    subsets->scaled_sub_fonts_list = NULL;
+    subsets->scaled_sub_fonts_list_end = NULL;
 
     return subsets;
 }
@@ -611,11 +621,16 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
 
             status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
                                                &sub_font->base);
+
             if (status) {
 		_cairo_sub_font_destroy (sub_font);
                 return status;
 	    }
-
+	    if (!subsets->unscaled_sub_fonts_list)
+		subsets->unscaled_sub_fonts_list = sub_font;
+	    else
+		subsets->unscaled_sub_fonts_list_end->next = sub_font;
+	    subsets->unscaled_sub_fonts_list_end = sub_font;
 	    subsets->num_sub_fonts++;
         }
     } else {
@@ -650,7 +665,11 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
 		_cairo_sub_font_destroy (sub_font);
                 return status;
 	    }
-
+	    if (!subsets->scaled_sub_fonts_list)
+		subsets->scaled_sub_fonts_list = sub_font;
+	    else
+		subsets->scaled_sub_fonts_list_end->next = sub_font;
+	    subsets->scaled_sub_fonts_list_end = sub_font;
 	    subsets->num_sub_fonts++;
         }
     }
@@ -667,6 +686,7 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
                                              cairo_bool_t                              is_scaled)
 {
     cairo_sub_font_collection_t collection;
+    cairo_sub_font_t *sub_font;
 
     if (is_scaled)
         collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
@@ -685,12 +705,14 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
     collection.status = CAIRO_STATUS_SUCCESS;
 
     if (is_scaled)
-        _cairo_hash_table_foreach (font_subsets->scaled_sub_fonts,
-                                   _cairo_sub_font_collect, &collection);
+	sub_font = font_subsets->scaled_sub_fonts_list;
     else
-        _cairo_hash_table_foreach (font_subsets->unscaled_sub_fonts,
-                                   _cairo_sub_font_collect, &collection);
+	sub_font = font_subsets->unscaled_sub_fonts_list;
 
+    while (sub_font) {
+	_cairo_sub_font_collect (sub_font, &collection);
+	sub_font = sub_font->next;
+    }
     free (collection.glyphs);
 
     return collection.status;
commit 0dbb5c9f6222660b1083420419d0eaa71c809ac5
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat May 31 20:15:04 2008 +0930

    Ensure eexec encryption in subsetted Type 1 font is compliant (#13679)
    
    In the eexec encryption used in Type 1 fonts, the first four bytes of
    ciphertext must not start with a white space character or contain an
    ASCII Hex character. Some fonts do not comply with this
    restriction. This may cause problems for some PDF consumers.
    
    Fix this by overwriting the four random bytes at the start of the
    decrypted cleartext with spaces. When re-encrypted the first four
    bytes of ciphertext will always be 0xf0, 0x83, 0xef, 0x00 which
    complies with the restrictions.

diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index 4d6c8df..ffb5424 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -382,6 +382,7 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
     unsigned char *in, *end;
     char *out;
     int c, p;
+    int i;
 
     in = (unsigned char *) font->eexec_segment;
     end = (unsigned char *) in + font->eexec_segment_size;
@@ -407,6 +408,23 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
     }
     font->cleartext_end = out;
 
+    /* Overwrite random bytes with spaces.
+     *
+     * The first 4 bytes of the cleartext are the random bytes
+     * required by the encryption algorithm. When encrypting the
+     * cleartext, the first ciphertext byte must not be a white space
+     * character and the first 4 bytes must not be an ASCII Hex
+     * character. Some fonts do not check that their randomly chosen
+     * bytes results in ciphertext that complies with this
+     * restriction. This may cause problems for some PDF consumers. By
+     * replacing the random bytes with spaces, the first four bytes of
+     * ciphertext will always be 0xf9, 0x83, 0xef, 0x00 which complies
+     * with this restriction. Using spaces also means we don't have to
+     * skip over the random bytes when parsing the cleartext.
+     */
+    for (i = 0; i < 4 && i < font->eexec_segment_size; i++)
+	font->cleartext[i] = ' ';
+
     return CAIRO_STATUS_SUCCESS;
 }
 


More information about the cairo-commit mailing list