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

David Maxwell <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
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 <[email protected]>
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

-- 
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.