[cairo] [patch] type1 fonts support lenIV; type1 parse_charstring stack management fix

David Maxwell damaxwell at alaska.edu
Tue Oct 2 18:09:17 PDT 2012


cairo_type1_font_subset_write_private_dict  assumed that the font's lenIV (which defines the number of random characters at the start of each charstring) is 4.  But it need not be: MinionPro uses 0.  Failure to use the correct lenIV prevents detection of glyph widths, which leads to an incorrect /Widths array for the font in PDF output, which leads to incorrect spacing at final rendering.

cairo_type1_font_subset_parse_charstring did not handle the stack correctly when calling a subroutine.  Consider (from MinionPro-Regular)

At the start of /B's charstring:
2010 callsubr

At the start of subroutine 2010:
0 588 hsbx

Since hsbx is defined to take its arguments from the bottom of the stack, the stack must read "0 588" at the call to hsbx to get a width of 588.  Previously, cairo had a stack of  "2010 0 588", which leads to an incorrect  glyph width of 0.  Subroutine numbers must be popped off the stack before starting the subroutine.

David Maxwell
Associate Professor
Department of Mathematics and Statistics
University of Alaska Fairbanks

From bf85cc7a91769b8b8dbb43ef256c29e40b338037 Mon Sep 17 00:00:00 2001
From: David Maxwell <damaxwell at alaska.edu>
Date: Tue, 2 Oct 2012 16:16:28 -0800
Subject: [PATCH] type1: lenIV supported, buildchar stack fix

---
 src/cairo-type1-subset.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 44 insertions(+), 4 deletions(-)

diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index c19773d..fb11f54 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -114,6 +114,8 @@ typedef struct _cairo_type1_font_subset {
 
     const char *rd, *nd, *np;
 
+    int lenIV;
+
     char *type1_data;
     unsigned int type1_length;
     char *type1_end;
@@ -754,7 +756,7 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
 						charstring);
     end = charstring + encrypted_charstring_length;
 
-    p = charstring + 4;
+    p = charstring + font->lenIV;
 
     last_op_was_integer = FALSE;
 
@@ -778,6 +780,12 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
 		    font->build_stack.top_value < font->num_subrs)
 		{
 		    subr_num = font->build_stack.top_value;
+            
+            font->build_stack.sp--;
+            if(font->build_stack.sp>0) {
+              font->build_stack.top_value = font->build_stack.stack[font->build_stack.sp-1];
+            }
+
 		    font->subrs[subr_num].used = TRUE;
 		    last_op_was_integer = FALSE;
 		    status = cairo_type1_font_subset_parse_charstring (font,
@@ -1137,9 +1145,9 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
 {
     cairo_status_t status;
     const char *p, *subrs, *charstrings, *array_start, *array_end, *dict_start, *dict_end;
-    const char *closefile_token;
-    char buffer[32], *subr_count_end, *glyph_count_end;
-    int length;
+    const char *lenIV_start, *lenIV_end, *closefile_token;
+    char buffer[32], *lenIV_str, *subr_count_end, *glyph_count_end;
+    int ret, lenIV, length;
     const cairo_scaled_font_backend_t *backend;
     unsigned int i;
     int glyph, j;
@@ -1161,6 +1169,38 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
      * subroutines and charstrings not required.
      */
 
+    /* Determine lenIV, the number of random characters at the start of 
+       each encrypted charstring. The defaults is 4, but this can be 
+       overridden in the private dict. */
+    font->lenIV = 4;
+    if( (lenIV_start = find_token (font->cleartext, font->cleartext_end, "/lenIV")) != NULL) {
+        lenIV_start += 6;
+        lenIV_end = find_token (lenIV_start, font->cleartext_end, "def");
+        if (lenIV_end == NULL)
+            return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        lenIV_str = malloc (lenIV_end - lenIV_start + 1);
+        if (unlikely (lenIV_str == NULL))
+            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+        strncpy (lenIV_str, lenIV_start, lenIV_end - lenIV_start);
+        lenIV_str[lenIV_end - lenIV_start] = 0;
+
+        ret = sscanf(lenIV_str,"%d",&lenIV);
+        free(lenIV_str);
+
+        if( unlikely (ret<=0) )
+            return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        /* Apparently some fonts signal unencrypted charstrings with a negative lenIV, 
+           though this is not part of the Type 1 Font Format specification.  See, e.g.
+           http://lists.gnu.org/archive/html/freetype-devel/2000-06/msg00064.html. */
+        if( unlikely( lenIV<0 ))
+            return CAIRO_INT_STATUS_UNSUPPORTED;
+
+        font->lenIV = lenIV;
+    }
+
     /* Find start of Subrs */
     subrs = find_token (font->cleartext, font->cleartext_end, "/Subrs");
     if (subrs == NULL) {
-- 
1.7.11.1



More information about the cairo mailing list