[cairo] [PATCH] Generate Type 1 fonts from glyph outlines

Adrian Johnson ajohnson at redneon.com
Sun Aug 27 05:28:42 PDT 2006


This patch generates Type 1 fonts for the PS/PDF backends when TrueType
or Type 1 subsetting fails. This has the advantage over the current
Type 3 fallback of reduced font size and better quality rendering
in some PDF viewers. xpdf shows a large improvement in text display
quality with this patch.

-------------- next part --------------
---
 src/Makefile.am                         |    1 
 src/cairo-pdf-surface.c                 |   95 +++-
 src/cairo-ps-surface.c                  |   32 +
 src/cairo-scaled-font-subsets-private.h |   31 +
 src/cairo-type1-fallback.c              |  682 +++++++++++++++++++++++++++++++
 5 files changed, 810 insertions(+), 31 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 80e7ee3..a22bf9b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,6 @@
 font_subset_sources =				\
 	cairo-truetype-subset.c			\
+	cairo-type1-fallback.c			\
 	cairo-truetype-subset-private.h		\
 	cairo-scaled-font-subsets.c		\
 	cairo-scaled-font-subsets-private.h
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 91a1968..6842874 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1578,35 +1578,25 @@ _cairo_pdf_surface_write_pages (cairo_pd
 				 "endobj\r\n");
 }
 
-#if CAIRO_HAS_FT_FONT
 static cairo_status_t
-_cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t		*surface,
-					   cairo_scaled_font_subset_t	*font_subset)
+_cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t		*surface,
+                                    cairo_scaled_font_subset_t	*font_subset,
+                                    cairo_type1_subset_t        *subset)
 {
     cairo_pdf_resource_t stream, descriptor, subset_resource;
-    cairo_status_t status;
     cairo_pdf_font_t font;
-    cairo_type1_subset_t subset;
     unsigned long length, compressed_length;
     char *compressed;
     unsigned int i;
-    char name[64];
-
-    snprintf (name, sizeof name, "CairoFont-%d-%d",
-	      font_subset->font_id, font_subset->subset_id);
-    status = _cairo_type1_subset_init (&subset, name, font_subset);
-    if (status)
-	return status;
 
     /* We ignore the zero-trailer and set Length3 to 0. */
-    length = subset.header_length + subset.data_length;
-    compressed = compress_dup (subset.data, length, &compressed_length);
-    if (compressed == NULL) {
-	_cairo_type1_subset_fini (&subset);
+    length = subset->header_length + subset->data_length;
+    compressed = compress_dup (subset->data, length, &compressed_length);
+    if (compressed == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
-    }
 
     stream = _cairo_pdf_surface_new_object (surface);
+
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Filter /FlateDecode\r\n"
@@ -1618,8 +1608,8 @@ _cairo_pdf_surface_emit_type1_font_subse
 				 "stream\r\n",
 				 stream.id,
 				 compressed_length,
-				 subset.header_length,
-				 subset.data_length);
+				 subset->header_length,
+				 subset->data_length);
     _cairo_output_stream_write (surface->output, compressed, compressed_length);
     _cairo_output_stream_printf (surface->output,
 				 "\r\n"
@@ -1644,13 +1634,13 @@ _cairo_pdf_surface_emit_type1_font_subse
 				 ">>\r\n"
 				 "endobj\r\n",
 				 descriptor.id,
-				 subset.base_font,
-				 subset.x_min,
-				 subset.y_min,
-				 subset.x_max,
-				 subset.y_max,
-				 subset.ascent,
-				 subset.descent,
+				 subset->base_font,
+				 subset->x_min,
+				 subset->y_min,
+				 subset->x_max,
+				 subset->y_max,
+				 subset->ascent,
+				 subset->descent,
 				 stream.id);
 
     subset_resource = _cairo_pdf_surface_new_object (surface);
@@ -1664,14 +1654,14 @@ _cairo_pdf_surface_emit_type1_font_subse
 				 "   /FontDescriptor %d 0 R\r\n"
 				 "   /Widths [",
 				 subset_resource.id,
-				 subset.base_font,
-				 font_subset->num_glyphs,
+				 subset->base_font,
+				 font_subset->num_glyphs - 1,
 				 descriptor.id);
 
     for (i = 0; i < font_subset->num_glyphs; i++)
 	_cairo_output_stream_printf (surface->output,
 				     " %d",
-				     subset.widths[i]);
+				     subset->widths[i]);
 
     _cairo_output_stream_printf (surface->output,
 				 " ]\r\n"
@@ -1683,13 +1673,52 @@ _cairo_pdf_surface_emit_type1_font_subse
     font.subset_resource = subset_resource;
     _cairo_array_append (&surface->fonts, &font);
 
-    _cairo_type1_subset_fini (&subset);
-
     return CAIRO_STATUS_SUCCESS;
 }
+
+#if CAIRO_HAS_FT_FONT
+static cairo_status_t
+_cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t		*surface,
+					   cairo_scaled_font_subset_t	*font_subset)
+{
+    cairo_status_t status;
+    cairo_type1_subset_t subset;
+    char name[64];
+
+    snprintf (name, sizeof name, "CairoFont-%d-%d",
+	      font_subset->font_id, font_subset->subset_id);
+    status = _cairo_type1_subset_init (&subset, name, font_subset);
+    if (status)
+	return status;
+
+    status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
+
+    _cairo_type1_subset_fini (&subset);
+    return status;
+}
 #endif
 
 static cairo_status_t
+_cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t	*surface,
+                                             cairo_scaled_font_subset_t	*font_subset)
+{
+    cairo_status_t status;
+    cairo_type1_subset_t subset;
+    char name[64];
+
+    snprintf (name, sizeof name, "CairoFont-%d-%d",
+	      font_subset->font_id, font_subset->subset_id);
+    status = _cairo_type1_fallback_init (&subset, name, font_subset);
+    if (status)
+	return status;
+
+    status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
+
+    _cairo_type1_fallback_fini (&subset);
+    return status;
+}
+
+static cairo_status_t
 _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t		*surface,
 					      cairo_scaled_font_subset_t	*font_subset)
 {
@@ -2039,6 +2068,10 @@ #endif
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
 
+    status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return;
+
     status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 6ae3a38..6be89bb 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -418,6 +418,34 @@ _cairo_ps_surface_emit_type1_font_subset
 #endif
 
 static cairo_status_t
+_cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t		*surface,
+                                            cairo_scaled_font_subset_t	*font_subset)
+{
+    cairo_type1_subset_t subset;
+    cairo_status_t status;
+    int length;
+    char name[64];
+
+    snprintf (name, sizeof name, "CairoFont-%d-%d",
+	      font_subset->font_id, font_subset->subset_id);
+    status = _cairo_type1_fallback_init (&subset, name, font_subset);
+    if (status)
+	return status;
+
+    /* FIXME: Figure out document structure convention for fonts */
+
+    _cairo_output_stream_printf (surface->final_stream,
+				 "%% _cairo_ps_surface_emit_type1_font_subset\n");
+
+    length = subset.header_length + subset.data_length + subset.trailer_length;
+    _cairo_output_stream_write (surface->final_stream, subset.data, length);
+
+    _cairo_type1_fallback_fini (&subset);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
 _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t		*surface,
 					     cairo_scaled_font_subset_t	*font_subset)
 
@@ -692,6 +720,10 @@ #endif
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
 
+    status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return;
+
     status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index c41e477..8669528 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -266,4 +266,35 @@ _cairo_type1_subset_init (cairo_type1_su
 cairo_private void
 _cairo_type1_subset_fini (cairo_type1_subset_t *subset);
 
+/**
+ * _cairo_type1_fallback_init:
+ * @type1_subset: a #cairo_type1_subset_t to initialize
+ * @font_subset: the #cairo_scaled_font_subset_t to initialize from
+ *
+ * If possible (depending on the format of the underlying
+ * cairo_scaled_font_t and the font backend in use) generate a type1
+ * file corresponding to @font_subset and initialize @type1_subset
+ * with information about the subset and the type1 data.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if successful,
+ * CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
+ * file, or an non-zero value indicating an error.  Possible errors
+ * include CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_private cairo_status_t
+_cairo_type1_fallback_init (cairo_type1_subset_t		*type_subset,
+			  const char			*name,
+			  cairo_scaled_font_subset_t	*font_subset);
+
+/**
+ * _cairo_type1_fallback_fini:
+ * @type1_subset: a #cairo_type1_subset_t
+ *
+ * Free all resources associated with @type1_subset.  After this call,
+ * @type1_subset should not be used again without a subsequent call to
+ * _cairo_truetype_type1_init() again first.
+ **/
+cairo_private void
+_cairo_type1_fallback_fini (cairo_type1_subset_t *subset);
+
 #endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */
diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c
new file mode 100755
index 0000000..04337e3
--- /dev/null
+++ b/src/cairo-type1-fallback.c
@@ -0,0 +1,682 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2006 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ *	Adrian Johnson <ajohnson at redneon.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-output-stream-private.h"
+
+typedef struct _cairo_type1_font {
+    cairo_scaled_font_subset_t *scaled_font_subset;
+    cairo_scaled_font_t        *type1_scaled_font;
+
+    double x_min, y_min, x_max, y_max;
+    int *widths;
+
+    const char    *data;
+    unsigned long  header_size;
+    unsigned long  data_size;
+    unsigned long  trailer_size;
+    int            bbox_position;
+    int            bbox_max_chars;
+
+    cairo_output_stream_t *output;
+    cairo_array_t contents;
+
+    unsigned short eexec_key;
+    cairo_bool_t hex_encode;
+    int hex_column;
+
+    cairo_status_t status;
+} cairo_type1_font_t;
+
+
+static cairo_status_t
+cairo_type1_font_create (cairo_scaled_font_subset_t  *scaled_font_subset,
+                         cairo_type1_font_t         **subset_return)
+{
+    cairo_type1_font_t *font;
+    cairo_matrix_t font_matrix;
+    cairo_matrix_t ctm;
+    cairo_font_options_t *font_options;
+
+    font = calloc (1, sizeof (cairo_type1_font_t));
+    if (font == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    cairo_matrix_init_scale (&font_matrix, 1000, 1000);
+    cairo_matrix_init_identity (&ctm);
+    font_options = cairo_font_options_create ();
+    cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
+    cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
+    font->type1_scaled_font = cairo_scaled_font_create (
+        cairo_scaled_font_get_font_face (scaled_font_subset->scaled_font),
+        &font_matrix,
+        &ctm,
+        font_options);
+    cairo_font_options_destroy (font_options);
+
+    font->scaled_font_subset = scaled_font_subset;
+    font->widths = calloc (font->scaled_font_subset->num_glyphs,
+                           sizeof (int));
+
+    _cairo_array_init (&font->contents, sizeof (unsigned char));
+    *subset_return = font;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+
+/* Magic constants for the type1 eexec encryption */
+static const unsigned short encrypt_c1 = 52845, encrypt_c2 = 22719;
+static const unsigned short private_dict_key = 55665;
+static const unsigned short charstring_key = 4330;
+
+/* Charstring commands. If the high byte is 0 the command is encoded
+ * with a single byte. */
+#define CHARSTRING_sbw        0x0c07
+#define CHARSTRING_rmoveto    0x0015
+#define CHARSTRING_rlineto    0x0005
+#define CHARSTRING_rcurveto   0x0008
+#define CHARSTRING_closepath  0x0009
+#define CHARSTRING_endchar    0x000e
+
+
+static cairo_status_t
+charstring_encode_command (cairo_array_t *data, int command)
+{
+    unsigned char buf[5];
+    unsigned char *p = buf;
+
+    if (command & 0xff00)
+        *p++ = command >> 8;
+    *p++ = command & 0x00ff;
+    return _cairo_array_append_multiple (data, buf, p - buf);
+}
+
+static cairo_status_t
+charstring_encode_integer (cairo_array_t *data, int i)
+{
+    unsigned char buf[10];
+    unsigned char *p = buf;
+
+    if (i >= -107 && i <= 107) {
+        *p++ = i + 139;
+    } else if (i >= 108 && i <= 1131) {
+        i -= 108;
+        *p++ = (i >> 8)+ 247;
+        *p++ = i & 0xff;
+    } else if (i >= -1131 && i <= -108) {
+        i = -i - 108;
+        *p++ = (i >> 8)+ 251;
+        *p++ = i & 0xff;
+    } else {
+        *p++ = 0xff;
+        *p++ = i >> 24;
+        *p++ = (i >> 16) & 0xff;
+        *p++ = (i >> 8)  & 0xff;
+        *p++ = i & 0xff;
+    }
+    return _cairo_array_append_multiple (data, buf, p - buf);
+}
+
+
+typedef struct _ps_path_info {
+    cairo_array_t *data;
+    int current_x, current_y;
+} t1_path_info_t;
+
+static cairo_status_t
+_charstring_move_to (void          *closure,
+                     cairo_point_t *point)
+{
+    t1_path_info_t *path_info = (t1_path_info_t *) closure;
+    int dx, dy;
+    cairo_status_t status;
+
+    status = _cairo_array_grow_by (path_info->data, 12);
+    if (status)
+        return status;
+
+    dx = _cairo_fixed_integer_part (point->x) - path_info->current_x;
+    dy = _cairo_fixed_integer_part (point->y) - path_info->current_y;
+    charstring_encode_integer (path_info->data, dx);
+    charstring_encode_integer (path_info->data, dy);
+    path_info->current_x += dx;
+    path_info->current_y += dy;
+
+    charstring_encode_command (path_info->data, CHARSTRING_rmoveto);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_charstring_line_to (void          *closure,
+                     cairo_point_t *point)
+{
+    t1_path_info_t *path_info = (t1_path_info_t *) closure;
+    int dx, dy;
+    cairo_status_t status;
+
+    status = _cairo_array_grow_by (path_info->data, 12);
+    if (status)
+        return status;
+
+    dx = _cairo_fixed_integer_part (point->x) - path_info->current_x;
+    dy = _cairo_fixed_integer_part (point->y) - path_info->current_y;
+    charstring_encode_integer (path_info->data, dx);
+    charstring_encode_integer (path_info->data, dy);
+    path_info->current_x += dx;
+    path_info->current_y += dy;
+
+    charstring_encode_command (path_info->data, CHARSTRING_rlineto);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_charstring_curve_to (void	    *closure,
+                      cairo_point_t *point1,
+                      cairo_point_t *point2,
+                      cairo_point_t *point3)
+{
+    t1_path_info_t *path_info = (t1_path_info_t *) closure;
+    int dx1, dy1, dx2, dy2, dx3, dy3;
+    cairo_status_t status;
+
+    status = _cairo_array_grow_by (path_info->data, 32);
+    if (status)
+        return status;
+
+    dx1 = _cairo_fixed_integer_part (point1->x) - path_info->current_x;
+    dy1 = _cairo_fixed_integer_part (point1->y) - path_info->current_y;
+    dx2 = _cairo_fixed_integer_part (point2->x) - path_info->current_x - dx1;
+    dy2 = _cairo_fixed_integer_part (point2->y) - path_info->current_y - dy1;
+    dx3 = _cairo_fixed_integer_part (point3->x) - path_info->current_x - dx1 - dx2;
+    dy3 = _cairo_fixed_integer_part (point3->y) - path_info->current_y - dy1 - dy2;
+    charstring_encode_integer (path_info->data, dx1);
+    charstring_encode_integer (path_info->data, dy1);
+    charstring_encode_integer (path_info->data, dx2);
+    charstring_encode_integer (path_info->data, dy2);
+    charstring_encode_integer (path_info->data, dx3);
+    charstring_encode_integer (path_info->data, dy3);
+    path_info->current_x += dx1 + dx2 + dx3;
+    path_info->current_y += dy1 + dy2 + dy3;
+    charstring_encode_command (path_info->data, CHARSTRING_rcurveto);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_charstring_close_path (void *closure)
+{
+    t1_path_info_t *path_info = (t1_path_info_t *) closure;
+
+    return charstring_encode_command (path_info->data, CHARSTRING_closepath);
+}
+
+static void
+charstring_encrypt (cairo_array_t *data)
+{
+    unsigned char *d, *end;
+    uint16_t c, p, r;
+
+    r = charstring_key;
+    d = (unsigned char *) _cairo_array_index (data, 0);
+    end = d + _cairo_array_num_elements (data);
+    while (d < end) {
+	p = *d;
+	c = p ^ (r >> 8);
+	r = (c + r) * encrypt_c1 + encrypt_c2;
+        *d++ = c;
+    }
+}
+
+static cairo_int_status_t
+create_notdef_charstring (cairo_array_t *data)
+{
+    cairo_status_t status;
+
+    status = _cairo_array_grow_by (data, 10);
+    if (status)
+        return status;
+
+    charstring_encode_integer (data, 0);
+    charstring_encode_integer (data, 0);
+
+    /* The width and height is arbitrary. */
+    charstring_encode_integer (data, 500);
+    charstring_encode_integer (data, 500);
+    charstring_encode_command (data, CHARSTRING_sbw);
+
+    charstring_encode_command (data, CHARSTRING_endchar);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_type1_font_create_charstring (cairo_type1_font_t *font,
+                                    int                 subset_index,
+                                    int                 glyph_index,
+                                    cairo_array_t      *data)
+{
+    cairo_scaled_glyph_t *scaled_glyph;
+    t1_path_info_t path_info;
+    cairo_text_extents_t *metrics;
+
+    font->status = _cairo_scaled_glyph_lookup (font->type1_scaled_font,
+                                               glyph_index,
+                                               CAIRO_SCALED_GLYPH_INFO_METRICS|
+                                               CAIRO_SCALED_GLYPH_INFO_PATH,
+                                               &scaled_glyph);
+    if (font->status)
+        return font->status;
+
+    metrics = &scaled_glyph->metrics;
+    if (subset_index == 0) {
+        font->x_min = metrics->x_bearing;
+        font->y_min = metrics->y_bearing;
+        font->x_max = metrics->x_bearing + metrics->width;
+        font->y_max = metrics->y_bearing + metrics->height;
+    } else {
+        if (metrics->x_bearing < font->x_min)
+            font->x_min = metrics->x_bearing;
+        if (metrics->y_bearing < font->y_min)
+            font->y_min = metrics->y_bearing;
+        if (metrics->x_bearing + metrics->width > font->x_max)
+            font->x_max = metrics->x_bearing + metrics->width;
+        if (metrics->y_bearing + metrics->height > font->y_max)
+            font->y_max = metrics->y_bearing + metrics->height;
+    }
+    font->widths[subset_index] = metrics->width;
+
+    font->status = _cairo_array_grow_by (data, 30);
+    if (font->status)
+        return font->status;
+    charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing);
+    charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing);
+    charstring_encode_integer (data, (int) scaled_glyph->metrics.width);
+    charstring_encode_integer (data, (int) scaled_glyph->metrics.height);
+    charstring_encode_command (data, CHARSTRING_sbw);
+
+    path_info.data = data;
+    path_info.current_x = (int) scaled_glyph->metrics.x_bearing;
+    path_info.current_y = (int) scaled_glyph->metrics.y_bearing;
+    _cairo_path_fixed_interpret (scaled_glyph->path,
+                                 CAIRO_DIRECTION_FORWARD,
+                                 _charstring_move_to,
+                                 _charstring_line_to,
+                                 _charstring_curve_to,
+                                 _charstring_close_path,
+                                 &path_info);
+
+    font->status = charstring_encode_command (path_info.data, CHARSTRING_endchar);
+
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_font_write_charstrings (cairo_type1_font_t    *font,
+                                    cairo_output_stream_t *encrypted_output)
+{
+    unsigned char zeros[] = { 0, 0, 0, 0 };
+    cairo_array_t data;
+    unsigned int i;
+    int length;
+
+    _cairo_array_init (&data, sizeof (unsigned char));
+    font->status = _cairo_array_grow_by (&data, 1024);
+    if (font->status)
+        goto fail;
+
+    _cairo_output_stream_printf (encrypted_output,
+                                 "2 index /CharStrings %d dict dup begin\n",
+                                 font->scaled_font_subset->num_glyphs + 1);
+
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+        _cairo_array_truncate (&data, 0);
+        /* four "random" bytes required by encryption algorithm */
+        _cairo_array_append_multiple (&data, zeros, 4);
+        font->status = cairo_type1_font_create_charstring (font, i,
+                                                           font->scaled_font_subset->glyphs[i],
+                                                           &data);
+        if (font->status)
+            goto fail;
+        charstring_encrypt (&data);
+        length = _cairo_array_num_elements (&data);
+        _cairo_output_stream_printf (encrypted_output, "/g%d %d RD ", i, length);
+        _cairo_output_stream_write (encrypted_output,
+                                    _cairo_array_index (&data, 0),
+                                    length);
+        _cairo_output_stream_printf (encrypted_output, " ND\n");
+    }
+
+    /* All type 1 fonts must have a /.notdef charstring */
+
+    _cairo_array_truncate (&data, 0);
+    /* four "random" bytes required by encryption algorithm */
+    _cairo_array_append_multiple (&data, zeros, 4);
+    create_notdef_charstring (&data);
+    charstring_encrypt (&data);
+    length = _cairo_array_num_elements (&data);
+    _cairo_output_stream_printf (encrypted_output, "/.notdef %d RD ", length);
+    _cairo_output_stream_write (encrypted_output,
+                                _cairo_array_index (&data, 0),
+                                length);
+    _cairo_output_stream_printf (encrypted_output, " ND\n");
+
+fail:
+    _cairo_array_fini (&data);
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_font_write_header (cairo_type1_font_t *font,
+                               const char         *name)
+{
+    cairo_matrix_t matrix;
+    unsigned int i;
+    const char spaces[50] = "                                                  ";
+
+    matrix = font->type1_scaled_font->scale;
+    matrix.xy = -matrix.xy;
+    matrix.yy = -matrix.yy;
+    cairo_matrix_invert (&matrix);
+
+    _cairo_output_stream_printf (font->output,
+                                 "%%!FontType1-1.1 %s 1.0\n"
+                                 "11 dict begin\n"
+                                 "/FontName /%s def\n"
+                                 "/PaintType 0 def\n"
+                                 "/FontType 1 def\n"
+                                 "/FontMatrix [%f %f %f %f 0 0] readonly def\n",
+                                 name,
+                                 name,
+                                 matrix.xx,
+				 matrix.yx,
+				 matrix.xy,
+				 matrix.yy);
+
+    /* We don't know the bbox values until after the charstrings have
+     * been generated.  Reserve some space and fill in the bbox
+     * later. */
+
+    /* Worst case for four signed ints with spaces between each number */
+    font->bbox_max_chars = 50;
+
+    _cairo_output_stream_printf (font->output, "/FontBBox {");
+    font->bbox_position = _cairo_output_stream_get_position (font->output);
+    _cairo_output_stream_write (font->output, spaces, font->bbox_max_chars);
+
+    _cairo_output_stream_printf (font->output,
+                                 "} readonly def\n"
+                                 "/Encoding 256 array\n"
+				 "0 1 255 {1 index exch /.notdef put} for\n");
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
+        _cairo_output_stream_printf (font->output, "dup %d /g%d put\n", i, i);
+    _cairo_output_stream_printf (font->output,
+                                 "readonly def\n"
+                                 "currentdict end\n"
+                                 "currentfile eexec\n");
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_write_stream_encrypted (void                *closure,
+                                    const unsigned char *data,
+                                    unsigned int         length)
+{
+    const unsigned char *in, *end;
+    uint16_t c, p;
+    static const char hex_digits[16] = "0123456789abcdef";
+    char digits[3];
+    cairo_type1_font_t *font = closure;
+
+    in = (const unsigned char *) data;
+    end = (const unsigned char *) data + length;
+    while (in < end) {
+	p = *in++;
+	c = p ^ (font->eexec_key >> 8);
+	font->eexec_key = (c + font->eexec_key) * encrypt_c1 + encrypt_c2;
+
+	if (font->hex_encode) {
+	    digits[0] = hex_digits[c >> 4];
+	    digits[1] = hex_digits[c & 0x0f];
+	    digits[2] = '\n';
+	    font->hex_column += 2;
+
+	    if (font->hex_column == 78) {
+		_cairo_output_stream_write (font->output, digits, 3);
+		font->hex_column = 0;
+	    } else {
+		_cairo_output_stream_write (font->output, digits, 2);
+	    }
+	} else {
+	    digits[0] = c;
+	    _cairo_output_stream_write (font->output, digits, 1);
+	}
+    }
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_font_write_private_dict (cairo_type1_font_t *font,
+                                     const char         *name)
+{
+    cairo_output_stream_t *encrypted_output;
+
+    font->eexec_key = private_dict_key;
+    font->hex_encode = TRUE;
+    font->hex_column = 0;
+    encrypted_output = _cairo_output_stream_create (
+        cairo_type1_write_stream_encrypted,
+        NULL,
+        font);
+    if (encrypted_output == NULL)
+	goto fail;
+
+    /* Note: the first four spaces at the start of this private dict
+     * are the four "random" bytes of plaintext required by the
+     * encryption algorithm */
+    _cairo_output_stream_printf (encrypted_output,
+                                 "    dup /Private 9 dict dup begin\n"
+                                 "/RD {string currentfile exch readstring pop}"
+                                 " executeonly def\n"
+                                 "/ND {noaccess def} executeonly def\n"
+                                 "/NP {noaccess put} executeonly def\n"
+                                 "/BlueValues [] def\n"
+                                 "/MinFeature {16 16} def\n"
+                                 "/lenIV 4 def\n"
+                                 "/password 5839 def\n");
+
+    cairo_type1_font_write_charstrings (font, encrypted_output);
+
+    _cairo_output_stream_printf (encrypted_output,
+                                 "end\n"
+                                 "end\n"
+                                 "readonly put\n"
+                                 "noaccess put\n"
+                                 "dup /FontName get exch definefont pop\n"
+                                 "mark currentfile closefile\n");
+
+fail:
+    _cairo_output_stream_destroy (encrypted_output);
+
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_font_write_trailer(cairo_type1_font_t *font)
+{
+    int i;
+    static const char zeros[65] =
+	"0000000000000000000000000000000000000000000000000000000000000000\n";
+
+    for (i = 0; i < 8; i++)
+	_cairo_output_stream_write (font->output, zeros, sizeof zeros);
+
+    _cairo_output_stream_printf (font->output, "cleartomark\n");
+
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_write_stream (void *closure,
+                         const unsigned char *data,
+                         unsigned int length)
+{
+    cairo_type1_font_t *font = closure;
+
+    font->status =
+	_cairo_array_append_multiple (&font->contents, data, length);
+
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_font_write (cairo_type1_font_t *font,
+                        const char *name)
+{
+    cairo_type1_font_write_header (font, name);
+    font->header_size = _cairo_output_stream_get_position (font->output);
+
+    cairo_type1_font_write_private_dict (font, name);
+    font->data_size = _cairo_output_stream_get_position (font->output) -
+	font->header_size;
+
+    cairo_type1_font_write_trailer (font);
+    font->trailer_size =
+	_cairo_output_stream_get_position (font->output) -
+	font->header_size - font->data_size;
+
+    return font->status;
+}
+
+static cairo_status_t
+cairo_type1_font_generate (cairo_type1_font_t *font, const char *name)
+{
+    font->status = _cairo_array_grow_by (&font->contents, 4096);
+    if (font->status)
+        goto fail;
+
+    font->output = _cairo_output_stream_create (cairo_type1_write_stream, NULL, font);
+    cairo_type1_font_write (font, name);
+    font->data = _cairo_array_index (&font->contents, 0);
+
+ fail:
+    return font->status;
+}
+
+static void
+cairo_type1_font_destroy (cairo_type1_font_t *font)
+{
+    free (font->widths);
+    _cairo_array_fini (&font->contents);
+    cairo_scaled_font_destroy (font->type1_scaled_font);
+    free (font);
+}
+
+cairo_status_t
+_cairo_type1_fallback_init (cairo_type1_subset_t	*type1_subset,
+                            const char			*name,
+                            cairo_scaled_font_subset_t	*scaled_font_subset)
+{
+    cairo_type1_font_t *font;
+    cairo_status_t status;
+    unsigned long length;
+    unsigned int i, len;
+
+    status = cairo_type1_font_create (scaled_font_subset, &font);
+    if (status)
+	return status;
+
+    status = cairo_type1_font_generate (font, name);
+    if (status)
+	goto fail1;
+
+    type1_subset->base_font = strdup (name);
+    if (type1_subset->base_font == NULL)
+        goto fail1;
+
+    type1_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
+    if (type1_subset->widths == NULL)
+        goto fail2;
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
+	type1_subset->widths[i] = font->widths[i];
+
+    type1_subset->x_min   = (int) font->x_min;
+    type1_subset->y_min   = (int) font->y_min;
+    type1_subset->x_max   = (int) font->x_max;
+    type1_subset->y_max   = (int) font->y_max;
+    type1_subset->ascent  = (int) font->y_max;
+    type1_subset->descent = (int) font->y_min;
+
+    length = font->header_size + font->data_size +
+	font->trailer_size;
+    type1_subset->data = malloc (length);
+    if (type1_subset->data == NULL)
+	goto fail3;
+
+    memcpy (type1_subset->data,
+	    _cairo_array_index (&font->contents, 0), length);
+
+    len = snprintf(type1_subset->data + font->bbox_position,
+                   font->bbox_max_chars,
+                   "%d %d %d %d",
+                   (int)type1_subset->x_min,
+                   (int)type1_subset->y_min,
+                   (int)type1_subset->x_max,
+                   (int)type1_subset->y_max);
+    type1_subset->data[font->bbox_position + len] = ' ';
+
+    type1_subset->header_length = font->header_size;
+    type1_subset->data_length = font->data_size;
+    type1_subset->trailer_length = font->trailer_size;
+
+    cairo_type1_font_destroy (font);
+    return CAIRO_STATUS_SUCCESS;
+
+ fail3:
+    free (type1_subset->widths);
+ fail2:
+    free (type1_subset->base_font);
+ fail1:
+    cairo_type1_font_destroy (font);
+
+    return status;
+}
+
+void
+_cairo_type1_fallback_fini (cairo_type1_subset_t *subset)
+{
+    free (subset->base_font);
+    free (subset->widths);
+    free (subset->data);
+}
-- 
1.4.2



More information about the cairo mailing list