summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2005-06-21 15:38:51 +0000
committerKristian Høgsberg <krh@redhat.com>2005-06-21 15:38:51 +0000
commitb1130276d59a219e70d43dd1d199ddf391fa3330 (patch)
treebb411978e5bc985f7a8e0c38c38e95f413e95710
parent7283ba6d470950e0e49f33fc25f3358113dda51e (diff)
Split out font subsetting code from here,
and put it here.
-rw-r--r--ChangeLog7
-rw-r--r--src/Makefile.am91
-rw-r--r--src/cairo-font-subset-private.h68
-rw-r--r--src/cairo-font-subset.c645
-rw-r--r--src/cairo-pdf-surface.c657
5 files changed, 784 insertions, 684 deletions
diff --git a/ChangeLog b/ChangeLog
index 3d1ad2c6..727f83fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2005-06-21 Kristian Høgsberg <krh@redhat.com>
+
+ * src/cairo-pdf-surface.c: Split out font subsetting code from here,
+
+ * src/cairo-font-subset-private.h:
+ * src/cairo-font-subset.c: and put it here.
+
2005-06-21 T Rowley <tim.rowley@gmail.com>
* src/cairo-atsui-font.c: allow building against < 10.3 SDK.
diff --git a/src/Makefile.am b/src/Makefile.am
index 8c624f24..68e4235e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,11 +2,13 @@
if CAIRO_HAS_PS_SURFACE
libcairo_ps_headers = cairo-ps.h
libcairo_ps_sources = cairo-ps-surface.c
+libcairo_font_subset_sources = cairo-font-subset.c cairo-font-subset-private.h
endif
if CAIRO_HAS_PDF_SURFACE
libcairo_pdf_headers = cairo-pdf.h
libcairo_pdf_sources = cairo-pdf-surface.c
+libcairo_font_subset_sources = cairo-font-subset.c cairo-font-subset-private.h
endif
if CAIRO_HAS_PNG_FUNCTIONS
@@ -75,50 +77,51 @@ cairoinclude_HEADERS = \
lib_LTLIBRARIES = libcairo.la
-libcairo_la_SOURCES = \
- cairo.c \
- cairo.h \
- cairo-private.h \
- cairo-arc.c \
- cairo-arc-private.h \
- cairo-array.c \
- cairo-cache.c \
- cairo-color.c \
- cairo-fixed.c \
- cairo-font.c \
- cairo-gstate.c \
- cairo-gstate-private.h \
- cairo-hull.c \
- cairo-image-surface.c \
- cairo-matrix.c \
- cairo-path.c \
- cairo-path-bounds.c \
- cairo-path-data.c \
- cairo-path-data-private.h \
- cairo-path-fill.c \
- cairo-path-fixed-private.h \
- cairo-path-stroke.c \
- cairo-pen.c \
- cairo-polygon.c \
- cairo-slope.c \
- cairo-spline.c \
- cairo-surface.c \
- cairo-traps.c \
- cairo-pattern.c \
- cairo-unicode.c \
- cairo-output-stream.c \
- cairo-wideint.c \
- cairo-wideint.h \
- $(libcairo_atsui_sources)\
- $(libcairo_ft_sources)\
- $(libcairo_ps_sources) \
- $(libcairo_pdf_sources) \
- $(libcairo_png_sources) \
- $(libcairo_xlib_sources)\
- $(libcairo_quartz_sources)\
- $(libcairo_xcb_sources) \
- $(libcairo_glitz_sources)\
- $(libcairo_win32_sources)\
+libcairo_la_SOURCES = \
+ cairo.c \
+ cairo.h \
+ cairo-private.h \
+ cairo-arc.c \
+ cairo-arc-private.h \
+ cairo-array.c \
+ cairo-cache.c \
+ cairo-color.c \
+ cairo-fixed.c \
+ cairo-font.c \
+ cairo-gstate.c \
+ cairo-gstate-private.h \
+ cairo-hull.c \
+ cairo-image-surface.c \
+ cairo-matrix.c \
+ cairo-path.c \
+ cairo-path-bounds.c \
+ cairo-path-data.c \
+ cairo-path-data-private.h \
+ cairo-path-fill.c \
+ cairo-path-fixed-private.h \
+ cairo-path-stroke.c \
+ cairo-pen.c \
+ cairo-polygon.c \
+ cairo-slope.c \
+ cairo-spline.c \
+ cairo-surface.c \
+ cairo-traps.c \
+ cairo-pattern.c \
+ cairo-unicode.c \
+ cairo-output-stream.c \
+ cairo-wideint.c \
+ cairo-wideint.h \
+ $(libcairo_atsui_sources) \
+ $(libcairo_ft_sources) \
+ $(libcairo_ps_sources) \
+ $(libcairo_pdf_sources) \
+ $(libcairo_font_subset_sources) \
+ $(libcairo_png_sources) \
+ $(libcairo_xlib_sources) \
+ $(libcairo_quartz_sources) \
+ $(libcairo_xcb_sources) \
+ $(libcairo_glitz_sources) \
+ $(libcairo_win32_sources) \
cairoint.h
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
diff --git a/src/cairo-font-subset-private.h b/src/cairo-font-subset-private.h
new file mode 100644
index 00000000..5b43f52d
--- /dev/null
+++ b/src/cairo-font-subset-private.h
@@ -0,0 +1,68 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 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):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+
+#ifndef CAIRO_FONT_SUBSET_PRIVATE_H
+#define CAIRO_FONT_SUBSET_PRIVATE_H
+
+typedef struct cairo_font_subset_backend cairo_font_subset_backend_t;
+typedef struct cairo_font_subset cairo_font_subset_t;
+struct cairo_font_subset {
+ cairo_font_subset_backend_t *backend;
+ cairo_unscaled_font_t *unscaled_font;
+ unsigned int font_id;
+ char *base_font;
+ int num_glyphs;
+ int *widths;
+ long x_min, y_min, x_max, y_max;
+ long ascent, descent;
+};
+
+
+cairo_private int
+_cairo_font_subset_use_glyph (cairo_font_subset_t *font, int glyph);
+
+cairo_private cairo_status_t
+_cairo_font_subset_generate (cairo_font_subset_t *font,
+ const char **data, unsigned long *length);
+
+cairo_private void
+_cairo_font_subset_destroy (cairo_font_subset_t *font);
+
+cairo_private cairo_font_subset_t *
+_cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font);
+
+#endif /* CAIRO_FONT_SUBSET_PRIVATE_H */
diff --git a/src/cairo-font-subset.c b/src/cairo-font-subset.c
new file mode 100644
index 00000000..2fac7f3e
--- /dev/null
+++ b/src/cairo-font-subset.c
@@ -0,0 +1,645 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 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):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-pdf.h"
+/* XXX: Eventually, we need to handle other font backends */
+#include "cairo-font-subset-private.h"
+#include "cairo-ft-private.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_TRUETYPE_TABLES_H
+
+typedef struct ft_subset_glyph ft_subset_glyph_t;
+struct ft_subset_glyph {
+ int parent_index;
+ unsigned long location;
+};
+
+struct cairo_font_subset_backend {
+ int (*use_glyph) (void *abstract_font,
+ int glyph);
+ cairo_status_t (*generate) (void *abstract_font,
+ const char **data,
+ unsigned long *length);
+ void (*destroy) (void *abstract_font);
+};
+
+typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t;
+struct cairo_pdf_ft_font {
+ cairo_font_subset_t base;
+ ft_subset_glyph_t *glyphs;
+ FT_Face face;
+ int checksum_index;
+ cairo_array_t output;
+ int *parent_to_subset;
+ cairo_status_t status;
+};
+
+#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
+
+#define SFNT_VERSION 0x00010000
+
+#ifdef WORDS_BIGENDIAN
+
+#define cpu_to_be16(v) (v)
+#define be16_to_cpu(v) (v)
+#define cpu_to_be32(v) (v)
+#define be32_to_cpu(v) (v)
+
+#else
+
+static inline unsigned short
+cpu_to_be16(unsigned short v)
+{
+ return (v << 8) | (v >> 8);
+}
+
+static inline unsigned short
+be16_to_cpu(unsigned short v)
+{
+ return cpu_to_be16 (v);
+}
+
+static inline unsigned long
+cpu_to_be32(unsigned long v)
+{
+ return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
+}
+
+static inline unsigned long
+be32_to_cpu(unsigned long v)
+{
+ return cpu_to_be32 (v);
+}
+
+#endif
+
+static cairo_font_subset_backend_t cairo_pdf_ft_font_backend;
+
+int
+_cairo_font_subset_use_glyph (cairo_font_subset_t *font, int glyph)
+{
+ return font->backend->use_glyph (font, glyph);
+}
+
+cairo_status_t
+_cairo_font_subset_generate (cairo_font_subset_t *font,
+ const char **data, unsigned long *length)
+{
+ return font->backend->generate (font, data, length);
+}
+
+void
+_cairo_font_subset_destroy (cairo_font_subset_t *font)
+{
+ font->backend->destroy (font);
+}
+
+cairo_font_subset_t *
+_cairo_font_subset_create (cairo_unscaled_font_t *unscaled_font)
+{
+ FT_Face face;
+ cairo_pdf_ft_font_t *font;
+ unsigned long size;
+ int i, j;
+
+ face = _cairo_ft_unscaled_font_lock_face (unscaled_font);
+
+ /* We currently only support freetype truetype fonts. */
+ size = 0;
+ if (!FT_IS_SFNT (face) ||
+ FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0)
+ return NULL;
+
+ font = malloc (sizeof (cairo_pdf_ft_font_t));
+ if (font == NULL)
+ return NULL;
+
+ font->base.unscaled_font = unscaled_font;
+ _cairo_unscaled_font_reference (unscaled_font);
+ font->base.backend = &cairo_pdf_ft_font_backend;
+
+ _cairo_array_init (&font->output, sizeof (char));
+ if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
+ goto fail1;
+
+ font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
+ if (font->glyphs == NULL)
+ goto fail2;
+
+ font->parent_to_subset = calloc (face->num_glyphs, sizeof (int));
+ if (font->parent_to_subset == NULL)
+ goto fail3;
+
+ font->base.num_glyphs = 1;
+ font->base.x_min = face->bbox.xMin;
+ font->base.y_min = face->bbox.yMin;
+ font->base.x_max = face->bbox.xMax;
+ font->base.y_max = face->bbox.yMax;
+ font->base.ascent = face->ascender;
+ font->base.descent = face->descender;
+ font->base.base_font = strdup (face->family_name);
+ if (font->base.base_font == NULL)
+ goto fail4;
+
+ for (i = 0, j = 0; font->base.base_font[j]; j++) {
+ if (font->base.base_font[j] == ' ')
+ continue;
+ font->base.base_font[i++] = font->base.base_font[j];
+ }
+ font->base.base_font[i] = '\0';
+
+ font->base.widths = calloc (face->num_glyphs, sizeof (int));
+ if (font->base.widths == NULL)
+ goto fail5;
+
+ _cairo_ft_unscaled_font_unlock_face (unscaled_font);
+
+ font->status = CAIRO_STATUS_SUCCESS;
+
+ return &font->base;
+
+ fail5:
+ free (font->base.base_font);
+ fail4:
+ free (font->parent_to_subset);
+ fail3:
+ free (font->glyphs);
+ fail2:
+ _cairo_array_fini (&font->output);
+ fail1:
+ free (font);
+ return NULL;
+}
+
+static void
+cairo_pdf_ft_font_destroy (void *abstract_font)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+
+ _cairo_unscaled_font_destroy (font->base.unscaled_font);
+ free (font->base.base_font);
+ free (font->parent_to_subset);
+ free (font->glyphs);
+ _cairo_array_fini (&font->output);
+ free (font);
+}
+
+static void *
+cairo_pdf_ft_font_write (cairo_pdf_ft_font_t *font,
+ const void *data, size_t length)
+{
+ void *p;
+
+ p = _cairo_array_append (&font->output, data, length);
+ if (p == NULL)
+ font->status = CAIRO_STATUS_NO_MEMORY;
+
+ return p;
+}
+
+static void
+cairo_pdf_ft_font_write_be16 (cairo_pdf_ft_font_t *font,
+ unsigned short value)
+{
+ unsigned short be16_value;
+
+ be16_value = cpu_to_be16 (value);
+ cairo_pdf_ft_font_write (font, &be16_value, sizeof be16_value);
+}
+
+static void
+cairo_pdf_ft_font_write_be32 (cairo_pdf_ft_font_t *font, unsigned long value)
+{
+ unsigned long be32_value;
+
+ be32_value = cpu_to_be32 (value);
+ cairo_pdf_ft_font_write (font, &be32_value, sizeof be32_value);
+}
+
+static unsigned long
+cairo_pdf_ft_font_align_output (cairo_pdf_ft_font_t *font)
+{
+ int length, aligned;
+ static const char pad[4];
+
+ length = _cairo_array_num_elements (&font->output);
+ aligned = (length + 3) & ~3;
+ cairo_pdf_ft_font_write (font, pad, aligned - length);
+
+ return aligned;
+}
+
+static int
+cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag)
+{
+ int i;
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1);
+
+ cairo_pdf_ft_font_write_be16 (font, 1);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be32 (font, 12);
+
+ /* Output a format 6 encoding table. */
+
+ cairo_pdf_ft_font_write_be16 (font, 6);
+ cairo_pdf_ft_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1));
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 1); /* First glyph */
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs - 1);
+ for (i = 1; i < font->base.num_glyphs; i++)
+ cairo_pdf_ft_font_write_be16 (font, i);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ unsigned char *buffer;
+ unsigned long size;
+
+ size = 0;
+ FT_Load_Sfnt_Table (font->face, tag, 0, NULL, &size);
+ buffer = cairo_pdf_ft_font_write (font, NULL, size);
+ FT_Load_Sfnt_Table (font->face, tag, 0, buffer, &size);
+
+ return 0;
+}
+
+static int
+cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ unsigned long start_offset, index, size;
+ TT_Header *header;
+ unsigned long begin, end;
+ unsigned char *buffer;
+ int i;
+ union {
+ unsigned char *bytes;
+ unsigned short *short_offsets;
+ unsigned long *long_offsets;
+ } u;
+
+ header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+ if (header->Index_To_Loc_Format == 0)
+ size = sizeof (short) * (font->face->num_glyphs + 1);
+ else
+ size = sizeof (long) * (font->face->num_glyphs + 1);
+
+ u.bytes = malloc (size);
+ if (u.bytes == NULL) {
+ font->status = CAIRO_STATUS_NO_MEMORY;
+ return font->status;
+ }
+ FT_Load_Sfnt_Table (font->face, TTAG_loca, 0, u.bytes, &size);
+
+ start_offset = _cairo_array_num_elements (&font->output);
+ for (i = 0; i < font->base.num_glyphs; i++) {
+ index = font->glyphs[i].parent_index;
+ if (header->Index_To_Loc_Format == 0) {
+ begin = be16_to_cpu (u.short_offsets[index]) * 2;
+ end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
+ }
+ else {
+ begin = be32_to_cpu (u.long_offsets[index]);
+ end = be32_to_cpu (u.long_offsets[index + 1]);
+ }
+
+ size = end - begin;
+
+ font->glyphs[i].location =
+ cairo_pdf_ft_font_align_output (font) - start_offset;
+ buffer = cairo_pdf_ft_font_write (font, NULL, size);
+ if (buffer == NULL)
+ break;
+ FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size);
+ /* FIXME: remap composite glyphs */
+ }
+
+ font->glyphs[i].location =
+ cairo_pdf_ft_font_align_output (font) - start_offset;
+
+ free (u.bytes);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ TT_Header *head;
+
+ head = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+
+ cairo_pdf_ft_font_write_be32 (font, head->Table_Version);
+ cairo_pdf_ft_font_write_be32 (font, head->Font_Revision);
+
+ font->checksum_index = _cairo_array_num_elements (&font->output);
+ cairo_pdf_ft_font_write_be32 (font, 0);
+ cairo_pdf_ft_font_write_be32 (font, head->Magic_Number);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Flags);
+ cairo_pdf_ft_font_write_be16 (font, head->Units_Per_EM);
+
+ cairo_pdf_ft_font_write_be32 (font, head->Created[0]);
+ cairo_pdf_ft_font_write_be32 (font, head->Created[1]);
+ cairo_pdf_ft_font_write_be32 (font, head->Modified[0]);
+ cairo_pdf_ft_font_write_be32 (font, head->Modified[1]);
+
+ cairo_pdf_ft_font_write_be16 (font, head->xMin);
+ cairo_pdf_ft_font_write_be16 (font, head->yMin);
+ cairo_pdf_ft_font_write_be16 (font, head->xMax);
+ cairo_pdf_ft_font_write_be16 (font, head->yMax);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Mac_Style);
+ cairo_pdf_ft_font_write_be16 (font, head->Lowest_Rec_PPEM);
+
+ cairo_pdf_ft_font_write_be16 (font, head->Font_Direction);
+ cairo_pdf_ft_font_write_be16 (font, head->Index_To_Loc_Format);
+ cairo_pdf_ft_font_write_be16 (font, head->Glyph_Data_Format);
+
+ return font->status;
+}
+
+static int cairo_pdf_ft_font_write_hhea_table (cairo_pdf_ft_font_t *font, unsigned long tag)
+{
+ TT_HoriHeader *hhea;
+
+ hhea = FT_Get_Sfnt_Table (font->face, ft_sfnt_hhea);
+
+ cairo_pdf_ft_font_write_be32 (font, hhea->Version);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Ascender);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Descender);
+ cairo_pdf_ft_font_write_be16 (font, hhea->Line_Gap);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->advance_Width_Max);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->min_Left_Side_Bearing);
+ cairo_pdf_ft_font_write_be16 (font, hhea->min_Right_Side_Bearing);
+ cairo_pdf_ft_font_write_be16 (font, hhea->xMax_Extent);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Rise);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Run);
+ cairo_pdf_ft_font_write_be16 (font, hhea->caret_Offset);
+
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+ cairo_pdf_ft_font_write_be16 (font, 0);
+
+ cairo_pdf_ft_font_write_be16 (font, hhea->metric_Data_Format);
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_hmtx_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ unsigned long entry_size;
+ short *p;
+ int i;
+
+ for (i = 0; i < font->base.num_glyphs; i++) {
+ entry_size = 2 * sizeof (short);
+ p = cairo_pdf_ft_font_write (font, NULL, entry_size);
+ FT_Load_Sfnt_Table (font->face, TTAG_hmtx,
+ font->glyphs[i].parent_index * entry_size,
+ (FT_Byte *) p, &entry_size);
+ font->base.widths[i] = be16_to_cpu (p[0]);
+ }
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ int i;
+ TT_Header *header;
+
+ header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
+
+ if (header->Index_To_Loc_Format == 0) {
+ for (i = 0; i < font->base.num_glyphs + 1; i++)
+ cairo_pdf_ft_font_write_be16 (font, font->glyphs[i].location / 2);
+ }
+ else {
+ for (i = 0; i < font->base.num_glyphs + 1; i++)
+ cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location);
+ }
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_write_maxp_table (cairo_pdf_ft_font_t *font,
+ unsigned long tag)
+{
+ TT_MaxProfile *maxp;
+
+ maxp = FT_Get_Sfnt_Table (font->face, ft_sfnt_maxp);
+
+ cairo_pdf_ft_font_write_be32 (font, maxp->version);
+ cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxPoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxContours);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositePoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositeContours);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxZones);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxTwilightPoints);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxStorage);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxFunctionDefs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxInstructionDefs);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxStackElements);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxSizeOfInstructions);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentElements);
+ cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentDepth);
+
+ return font->status;
+}
+
+typedef struct table table_t;
+struct table {
+ unsigned long tag;
+ int (*write) (cairo_pdf_ft_font_t *font, unsigned long tag);
+};
+
+static const table_t truetype_tables[] = {
+ { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table },
+ { TTAG_cvt, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table },
+ { TTAG_head, cairo_pdf_ft_font_write_head_table },
+ { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table },
+ { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table },
+ { TTAG_loca, cairo_pdf_ft_font_write_loca_table },
+ { TTAG_maxp, cairo_pdf_ft_font_write_maxp_table },
+ { TTAG_name, cairo_pdf_ft_font_write_generic_table },
+ { TTAG_prep, cairo_pdf_ft_font_write_generic_table },
+};
+
+static cairo_status_t
+cairo_pdf_ft_font_write_offset_table (cairo_pdf_ft_font_t *font)
+{
+ unsigned short search_range, entry_selector, range_shift;
+ int num_tables;
+
+ num_tables = ARRAY_LENGTH (truetype_tables);
+ search_range = 1;
+ entry_selector = 0;
+ while (search_range * 2 <= num_tables) {
+ search_range *= 2;
+ entry_selector++;
+ }
+ search_range *= 16;
+ range_shift = num_tables * 16 - search_range;
+
+ cairo_pdf_ft_font_write_be32 (font, SFNT_VERSION);
+ cairo_pdf_ft_font_write_be16 (font, num_tables);
+ cairo_pdf_ft_font_write_be16 (font, search_range);
+ cairo_pdf_ft_font_write_be16 (font, entry_selector);
+ cairo_pdf_ft_font_write_be16 (font, range_shift);
+
+ cairo_pdf_ft_font_write (font, NULL, ARRAY_LENGTH (truetype_tables) * 16);
+
+ return font->status;
+}
+
+static unsigned long
+cairo_pdf_ft_font_calculate_checksum (cairo_pdf_ft_font_t *font,
+ unsigned long start, unsigned long end)
+{
+ unsigned long *padded_end;
+ unsigned long *p;
+ unsigned long checksum;
+ char *data;
+
+ checksum = 0;
+ data = _cairo_array_index (&font->output, 0);
+ p = (unsigned long *) (data + start);
+ padded_end = (unsigned long *) (data + ((end + 3) & ~3));
+ while (p < padded_end)
+ checksum += *p++;
+
+ return checksum;
+}
+
+static void
+cairo_pdf_ft_font_update_entry (cairo_pdf_ft_font_t *font, int index, unsigned long tag,
+ unsigned long start, unsigned long end)
+{
+ unsigned long *entry;
+
+ entry = _cairo_array_index (&font->output, 12 + 16 * index);
+ entry[0] = cpu_to_be32 (tag);
+ entry[1] = cpu_to_be32 (cairo_pdf_ft_font_calculate_checksum (font, start, end));
+ entry[2] = cpu_to_be32 (start);
+ entry[3] = cpu_to_be32 (end - start);
+}
+
+static cairo_status_t
+cairo_pdf_ft_font_generate (void *abstract_font,
+ const char **data, unsigned long *length)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+ unsigned long start, end, next, checksum, *checksum_location;
+ int i;
+
+ font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font);
+
+ if (cairo_pdf_ft_font_write_offset_table (font))
+ goto fail;
+
+ start = cairo_pdf_ft_font_align_output (font);
+ end = start;
+
+ end = 0;
+ for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
+ if (truetype_tables[i].write (font, truetype_tables[i].tag))
+ goto fail;
+
+ end = _cairo_array_num_elements (&font->output);
+ next = cairo_pdf_ft_font_align_output (font);
+ cairo_pdf_ft_font_update_entry (font, i, truetype_tables[i].tag,
+ start, end);
+ start = next;
+ }
+
+ checksum =
+ 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end);
+ checksum_location = _cairo_array_index (&font->output, font->checksum_index);
+ *checksum_location = cpu_to_be32 (checksum);
+
+ *data = _cairo_array_index (&font->output, 0);
+ *length = _cairo_array_num_elements (&font->output);
+
+ fail:
+ _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font);
+ font->face = NULL;
+
+ return font->status;
+}
+
+static int
+cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph)
+{
+ cairo_pdf_ft_font_t *font = abstract_font;
+
+ if (font->parent_to_subset[glyph] == 0) {
+ font->parent_to_subset[glyph] = font->base.num_glyphs;
+ font->glyphs[font->base.num_glyphs].parent_index = glyph;
+ font->base.num_glyphs++;
+ }
+
+ return font->parent_to_subset[glyph];
+}
+
+static cairo_font_subset_backend_t cairo_pdf_ft_font_backend = {
+ cairo_pdf_ft_font_use_glyph,
+ cairo_pdf_ft_font_generate,
+ cairo_pdf_ft_font_destroy
+};
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 3d65aa75..34b79c4b 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -36,15 +36,9 @@
#include "cairoint.h"
#include "cairo-pdf.h"
-/* XXX: Eventually, we need to handle other font backends */
+#include "cairo-font-subset-private.h"
#include "cairo-ft-private.h"
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_OUTLINE_H
-#include FT_TRUETYPE_TAGS_H
-#include FT_TRUETYPE_TABLES_H
-
#include <time.h>
#include <zlib.h>
@@ -93,45 +87,6 @@
* instead of outputting the cm operator in every page.
*/
-typedef struct ft_subset_glyph ft_subset_glyph_t;
-struct ft_subset_glyph {
- int parent_index;
- unsigned long location;
-};
-
-typedef struct cairo_pdf_font_backend cairo_pdf_font_backend_t;
-struct cairo_pdf_font_backend {
- int (*use_glyph) (void *abstract_font,
- int glyph);
- cairo_status_t (*generate) (void *abstract_font,
- const char **data,
- unsigned long *length);
- void (*destroy) (void *abstract_font);
-};
-
-typedef struct cairo_pdf_font cairo_pdf_font_t;
-struct cairo_pdf_font {
- cairo_pdf_font_backend_t *backend;
- cairo_unscaled_font_t *unscaled_font;
- unsigned int font_id;
- char *base_font;
- int num_glyphs;
- int *widths;
- long x_min, y_min, x_max, y_max;
- long ascent, descent;
-};
-
-typedef struct cairo_pdf_ft_font cairo_pdf_ft_font_t;
-struct cairo_pdf_ft_font {
- cairo_pdf_font_t base;
- ft_subset_glyph_t *glyphs;
- FT_Face face;
- int checksum_index;
- cairo_array_t output;
- int *parent_to_subset;
- cairo_status_t status;
-};
-
typedef struct cairo_pdf_object cairo_pdf_object_t;
typedef struct cairo_pdf_resource cairo_pdf_resource_t;
typedef struct cairo_pdf_stream cairo_pdf_stream_t;
@@ -221,6 +176,9 @@ static cairo_pdf_stream_t *
_cairo_pdf_document_open_stream (cairo_pdf_document_t *document,
const char *fmt,
...);
+static void
+_cairo_pdf_document_close_stream (cairo_pdf_document_t *document);
+
static cairo_surface_t *
_cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
double width,
@@ -233,590 +191,6 @@ _cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface);
static const cairo_surface_backend_t cairo_pdf_surface_backend;
-/* Truetype font subsetting code */
-
-#define ARRAY_LENGTH(a) ( (sizeof (a)) / (sizeof ((a)[0])) )
-
-#define SFNT_VERSION 0x00010000
-
-#ifdef WORDS_BIGENDIAN
-
-#define cpu_to_be16(v) (v)
-#define be16_to_cpu(v) (v)
-#define cpu_to_be32(v) (v)
-#define be32_to_cpu(v) (v)
-
-#else
-
-static inline unsigned short
-cpu_to_be16(unsigned short v)
-{
- return (v << 8) | (v >> 8);
-}
-
-static inline unsigned short
-be16_to_cpu(unsigned short v)
-{
- return cpu_to_be16 (v);
-}
-
-static inline unsigned long
-cpu_to_be32(unsigned long v)
-{
- return (cpu_to_be16 (v) << 16) | cpu_to_be16 (v >> 16);
-}
-
-static inline unsigned long
-be32_to_cpu(unsigned long v)
-{
- return cpu_to_be32 (v);
-}
-
-#endif
-
-static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend;
-
-static int
-cairo_pdf_font_use_glyph (cairo_pdf_font_t *font, int glyph)
-{
- return font->backend->use_glyph (font, glyph);
-}
-
-static cairo_status_t
-cairo_pdf_font_generate (cairo_pdf_font_t *font,
- const char **data, unsigned long *length)
-{
- return font->backend->generate (font, data, length);
-}
-
-static void
-cairo_pdf_font_destroy (cairo_pdf_font_t *font)
-{
- if (font == NULL)
- return;
-
- font->backend->destroy (font);
-}
-
-static cairo_pdf_font_t *
-cairo_pdf_ft_font_create (cairo_pdf_document_t *document,
- cairo_unscaled_font_t *unscaled_font)
-{
- FT_Face face;
- cairo_pdf_ft_font_t *font;
- unsigned long size;
- int i, j;
-
- face = _cairo_ft_unscaled_font_lock_face (unscaled_font);
-
- /* We currently only support freetype truetype fonts. */
- size = 0;
- if (!FT_IS_SFNT (face) ||
- FT_Load_Sfnt_Table (face, TTAG_glyf, 0, NULL, &size) != 0)
- return NULL;
-
- font = malloc (sizeof (cairo_pdf_ft_font_t));
- if (font == NULL)
- return NULL;
-
- font->base.unscaled_font = unscaled_font;
- _cairo_unscaled_font_reference (unscaled_font);
- font->base.backend = &cairo_pdf_ft_font_backend;
- font->base.font_id = _cairo_pdf_document_new_object (document);
-
- _cairo_array_init (&font->output, sizeof (char));
- if (_cairo_array_grow_by (&font->output, 4096) != CAIRO_STATUS_SUCCESS)
- goto fail1;
-
- font->glyphs = calloc (face->num_glyphs + 1, sizeof (ft_subset_glyph_t));
- if (font->glyphs == NULL)
- goto fail2;
-
- font->parent_to_subset = calloc (face->num_glyphs, sizeof (int));
- if (font->parent_to_subset == NULL)
- goto fail3;
-
- font->base.num_glyphs = 1;
- font->base.x_min = face->bbox.xMin;
- font->base.y_min = face->bbox.yMin;
- font->base.x_max = face->bbox.xMax;
- font->base.y_max = face->bbox.yMax;
- font->base.ascent = face->ascender;
- font->base.descent = face->descender;
- font->base.base_font = strdup (face->family_name);
- if (font->base.base_font == NULL)
- goto fail4;
-
- for (i = 0, j = 0; font->base.base_font[j]; j++) {
- if (font->base.base_font[j] == ' ')
- continue;
- font->base.base_font[i++] = font->base.base_font[j];
- }
- font->base.base_font[i] = '\0';
-
- font->base.widths = calloc (face->num_glyphs, sizeof (int));
- if (font->base.widths == NULL)
- goto fail5;
-
- _cairo_ft_unscaled_font_unlock_face (unscaled_font);
-
- font->status = CAIRO_STATUS_SUCCESS;
-
- return &font->base;
-
- fail5:
- free (font->base.base_font);
- fail4:
- free (font->parent_to_subset);
- fail3:
- free (font->glyphs);
- fail2:
- _cairo_array_fini (&font->output);
- fail1:
- free (font);
- return NULL;
-}
-
-static void
-cairo_pdf_ft_font_destroy (void *abstract_font)
-{
- cairo_pdf_ft_font_t *font = abstract_font;
-
- if (font == NULL)
- return;
-
- _cairo_unscaled_font_destroy (font->base.unscaled_font);
- free (font->base.base_font);
- free (font->parent_to_subset);
- free (font->glyphs);
- _cairo_array_fini (&font->output);
- free (font);
-}
-
-static void *
-cairo_pdf_ft_font_write (cairo_pdf_ft_font_t *font,
- const void *data, size_t length)
-{
- void *p;
-
- p = _cairo_array_append (&font->output, data, length);
- if (p == NULL)
- font->status = CAIRO_STATUS_NO_MEMORY;
-
- return p;
-}
-
-static void
-cairo_pdf_ft_font_write_be16 (cairo_pdf_ft_font_t *font,
- unsigned short value)
-{
- unsigned short be16_value;
-
- be16_value = cpu_to_be16 (value);
- cairo_pdf_ft_font_write (font, &be16_value, sizeof be16_value);
-}
-
-static void
-cairo_pdf_ft_font_write_be32 (cairo_pdf_ft_font_t *font, unsigned long value)
-{
- unsigned long be32_value;
-
- be32_value = cpu_to_be32 (value);
- cairo_pdf_ft_font_write (font, &be32_value, sizeof be32_value);
-}
-
-static unsigned long
-cairo_pdf_ft_font_align_output (cairo_pdf_ft_font_t *font)
-{
- int length, aligned;
- static const char pad[4];
-
- length = _cairo_array_num_elements (&font->output);
- aligned = (length + 3) & ~3;
- cairo_pdf_ft_font_write (font, pad, aligned - length);
-
- return aligned;
-}
-
-static int
-cairo_pdf_ft_font_write_cmap_table (cairo_pdf_ft_font_t *font, unsigned long tag)
-{
- int i;
-
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 1);
-
- cairo_pdf_ft_font_write_be16 (font, 1);
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be32 (font, 12);
-
- /* Output a format 6 encoding table. */
-
- cairo_pdf_ft_font_write_be16 (font, 6);
- cairo_pdf_ft_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1));
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 1); /* First glyph */
- cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs - 1);
- for (i = 1; i < font->base.num_glyphs; i++)
- cairo_pdf_ft_font_write_be16 (font, i);
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_generic_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- unsigned char *buffer;
- unsigned long size;
-
- size = 0;
- FT_Load_Sfnt_Table (font->face, tag, 0, NULL, &size);
- buffer = cairo_pdf_ft_font_write (font, NULL, size);
- FT_Load_Sfnt_Table (font->face, tag, 0, buffer, &size);
-
- return 0;
-}
-
-static int
-cairo_pdf_ft_font_write_glyf_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- unsigned long start_offset, index, size;
- TT_Header *header;
- unsigned long begin, end;
- unsigned char *buffer;
- int i;
- union {
- unsigned char *bytes;
- unsigned short *short_offsets;
- unsigned long *long_offsets;
- } u;
-
- header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
- if (header->Index_To_Loc_Format == 0)
- size = sizeof (short) * (font->face->num_glyphs + 1);
- else
- size = sizeof (long) * (font->face->num_glyphs + 1);
-
- u.bytes = malloc (size);
- if (u.bytes == NULL) {
- font->status = CAIRO_STATUS_NO_MEMORY;
- return font->status;
- }
- FT_Load_Sfnt_Table (font->face, TTAG_loca, 0, u.bytes, &size);
-
- start_offset = _cairo_array_num_elements (&font->output);
- for (i = 0; i < font->base.num_glyphs; i++) {
- index = font->glyphs[i].parent_index;
- if (header->Index_To_Loc_Format == 0) {
- begin = be16_to_cpu (u.short_offsets[index]) * 2;
- end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
- } else {
- begin = be32_to_cpu (u.long_offsets[index]);
- end = be32_to_cpu (u.long_offsets[index + 1]);
- }
-
- size = end - begin;
-
- font->glyphs[i].location =
- cairo_pdf_ft_font_align_output (font) - start_offset;
- buffer = cairo_pdf_ft_font_write (font, NULL, size);
- if (buffer == NULL)
- break;
- FT_Load_Sfnt_Table (font->face, TTAG_glyf, begin, buffer, &size);
- /* FIXME: remap composite glyphs */
- }
-
- font->glyphs[i].location =
- cairo_pdf_ft_font_align_output (font) - start_offset;
-
- free (u.bytes);
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_head_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- TT_Header *head;
-
- head = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
-
- cairo_pdf_ft_font_write_be32 (font, head->Table_Version);
- cairo_pdf_ft_font_write_be32 (font, head->Font_Revision);
-
- font->checksum_index = _cairo_array_num_elements (&font->output);
- cairo_pdf_ft_font_write_be32 (font, 0);
- cairo_pdf_ft_font_write_be32 (font, head->Magic_Number);
-
- cairo_pdf_ft_font_write_be16 (font, head->Flags);
- cairo_pdf_ft_font_write_be16 (font, head->Units_Per_EM);
-
- cairo_pdf_ft_font_write_be32 (font, head->Created[0]);
- cairo_pdf_ft_font_write_be32 (font, head->Created[1]);
- cairo_pdf_ft_font_write_be32 (font, head->Modified[0]);
- cairo_pdf_ft_font_write_be32 (font, head->Modified[1]);
-
- cairo_pdf_ft_font_write_be16 (font, head->xMin);
- cairo_pdf_ft_font_write_be16 (font, head->yMin);
- cairo_pdf_ft_font_write_be16 (font, head->xMax);
- cairo_pdf_ft_font_write_be16 (font, head->yMax);
-
- cairo_pdf_ft_font_write_be16 (font, head->Mac_Style);
- cairo_pdf_ft_font_write_be16 (font, head->Lowest_Rec_PPEM);
-
- cairo_pdf_ft_font_write_be16 (font, head->Font_Direction);
- cairo_pdf_ft_font_write_be16 (font, head->Index_To_Loc_Format);
- cairo_pdf_ft_font_write_be16 (font, head->Glyph_Data_Format);
-
- return font->status;
-}
-
-static int cairo_pdf_ft_font_write_hhea_table (cairo_pdf_ft_font_t *font, unsigned long tag)
-{
- TT_HoriHeader *hhea;
-
- hhea = FT_Get_Sfnt_Table (font->face, ft_sfnt_hhea);
-
- cairo_pdf_ft_font_write_be32 (font, hhea->Version);
- cairo_pdf_ft_font_write_be16 (font, hhea->Ascender);
- cairo_pdf_ft_font_write_be16 (font, hhea->Descender);
- cairo_pdf_ft_font_write_be16 (font, hhea->Line_Gap);
-
- cairo_pdf_ft_font_write_be16 (font, hhea->advance_Width_Max);
-
- cairo_pdf_ft_font_write_be16 (font, hhea->min_Left_Side_Bearing);
- cairo_pdf_ft_font_write_be16 (font, hhea->min_Right_Side_Bearing);
- cairo_pdf_ft_font_write_be16 (font, hhea->xMax_Extent);
- cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Rise);
- cairo_pdf_ft_font_write_be16 (font, hhea->caret_Slope_Run);
- cairo_pdf_ft_font_write_be16 (font, hhea->caret_Offset);
-
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 0);
- cairo_pdf_ft_font_write_be16 (font, 0);
-
- cairo_pdf_ft_font_write_be16 (font, hhea->metric_Data_Format);
- cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_hmtx_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- unsigned long entry_size;
- short *p;
- int i;
-
- for (i = 0; i < font->base.num_glyphs; i++) {
- entry_size = 2 * sizeof (short);
- p = cairo_pdf_ft_font_write (font, NULL, entry_size);
- FT_Load_Sfnt_Table (font->face, TTAG_hmtx,
- font->glyphs[i].parent_index * entry_size,
- (FT_Byte *) p, &entry_size);
- font->base.widths[i] = be16_to_cpu (p[0]);
- }
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_loca_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- int i;
- TT_Header *header;
-
- header = FT_Get_Sfnt_Table (font->face, ft_sfnt_head);
-
- if (header->Index_To_Loc_Format == 0) {
- for (i = 0; i < font->base.num_glyphs + 1; i++)
- cairo_pdf_ft_font_write_be16 (font, font->glyphs[i].location / 2);
- } else {
- for (i = 0; i < font->base.num_glyphs + 1; i++)
- cairo_pdf_ft_font_write_be32 (font, font->glyphs[i].location);
- }
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_write_maxp_table (cairo_pdf_ft_font_t *font,
- unsigned long tag)
-{
- TT_MaxProfile *maxp;
-
- maxp = FT_Get_Sfnt_Table (font->face, ft_sfnt_maxp);
-
- cairo_pdf_ft_font_write_be32 (font, maxp->version);
- cairo_pdf_ft_font_write_be16 (font, font->base.num_glyphs);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxPoints);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxContours);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositePoints);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxCompositeContours);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxZones);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxTwilightPoints);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxStorage);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxFunctionDefs);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxInstructionDefs);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxStackElements);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxSizeOfInstructions);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentElements);
- cairo_pdf_ft_font_write_be16 (font, maxp->maxComponentDepth);
-
- return font->status;
-}
-
-typedef struct table table_t;
-struct table {
- unsigned long tag;
- int (*write) (cairo_pdf_ft_font_t *font, unsigned long tag);
-};
-
-static const table_t truetype_tables[] = {
- { TTAG_cmap, cairo_pdf_ft_font_write_cmap_table },
- { TTAG_cvt, cairo_pdf_ft_font_write_generic_table },
- { TTAG_fpgm, cairo_pdf_ft_font_write_generic_table },
- { TTAG_glyf, cairo_pdf_ft_font_write_glyf_table },
- { TTAG_head, cairo_pdf_ft_font_write_head_table },
- { TTAG_hhea, cairo_pdf_ft_font_write_hhea_table },
- { TTAG_hmtx, cairo_pdf_ft_font_write_hmtx_table },
- { TTAG_loca, cairo_pdf_ft_font_write_loca_table },
- { TTAG_maxp, cairo_pdf_ft_font_write_maxp_table },
- { TTAG_name, cairo_pdf_ft_font_write_generic_table },
- { TTAG_prep, cairo_pdf_ft_font_write_generic_table },
-};
-
-static cairo_status_t
-cairo_pdf_ft_font_write_offset_table (cairo_pdf_ft_font_t *font)
-{
- unsigned short search_range, entry_selector, range_shift;
- int num_tables;
-
- num_tables = ARRAY_LENGTH (truetype_tables);
- search_range = 1;
- entry_selector = 0;
- while (search_range * 2 <= num_tables) {
- search_range *= 2;
- entry_selector++;
- }
- search_range *= 16;
- range_shift = num_tables * 16 - search_range;
-
- cairo_pdf_ft_font_write_be32 (font, SFNT_VERSION);
- cairo_pdf_ft_font_write_be16 (font, num_tables);
- cairo_pdf_ft_font_write_be16 (font, search_range);
- cairo_pdf_ft_font_write_be16 (font, entry_selector);
- cairo_pdf_ft_font_write_be16 (font, range_shift);
-
- cairo_pdf_ft_font_write (font, NULL, ARRAY_LENGTH (truetype_tables) * 16);
-
- return font->status;
-}
-
-static unsigned long
-cairo_pdf_ft_font_calculate_checksum (cairo_pdf_ft_font_t *font,
- unsigned long start, unsigned long end)
-{
- unsigned long *padded_end;
- unsigned long *p;
- unsigned long checksum;
- char *data;
-
- checksum = 0;
- data = _cairo_array_index (&font->output, 0);
- p = (unsigned long *) (data + start);
- padded_end = (unsigned long *) (data + ((end + 3) & ~3));
- while (p < padded_end)
- checksum += *p++;
-
- return checksum;
-}
-
-static void
-cairo_pdf_ft_font_update_entry (cairo_pdf_ft_font_t *font, int index, unsigned long tag,
- unsigned long start, unsigned long end)
-{
- unsigned long *entry;
-
- entry = _cairo_array_index (&font->output, 12 + 16 * index);
- entry[0] = cpu_to_be32 (tag);
- entry[1] = cpu_to_be32 (cairo_pdf_ft_font_calculate_checksum (font, start, end));
- entry[2] = cpu_to_be32 (start);
- entry[3] = cpu_to_be32 (end - start);
-}
-
-static cairo_status_t
-cairo_pdf_ft_font_generate (void *abstract_font,
- const char **data, unsigned long *length)
-{
- cairo_pdf_ft_font_t *font = abstract_font;
- unsigned long start, end, next, checksum;
- unsigned long *checksum_location;
- int i;
-
- font->face = _cairo_ft_unscaled_font_lock_face (font->base.unscaled_font);
-
- if (cairo_pdf_ft_font_write_offset_table (font))
- goto fail;
-
- start = cairo_pdf_ft_font_align_output (font);
- end = start;
-
- end = 0;
- for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) {
- if (truetype_tables[i].write (font, truetype_tables[i].tag))
- goto fail;
-
- end = _cairo_array_num_elements (&font->output);
- next = cairo_pdf_ft_font_align_output (font);
- cairo_pdf_ft_font_update_entry (font, i, truetype_tables[i].tag,
- start, end);
- start = next;
- }
-
- checksum =
- 0xb1b0afba - cairo_pdf_ft_font_calculate_checksum (font, 0, end);
- checksum_location = _cairo_array_index (&font->output, font->checksum_index);
- *checksum_location = cpu_to_be32 (checksum);
-
- *data = _cairo_array_index (&font->output, 0);
- *length = _cairo_array_num_elements (&font->output);
-
- fail:
- _cairo_ft_unscaled_font_unlock_face (font->base.unscaled_font);
- font->face = NULL;
-
- return font->status;
-}
-
-static int
-cairo_pdf_ft_font_use_glyph (void *abstract_font, int glyph)
-{
- cairo_pdf_ft_font_t *font = abstract_font;
-
- if (font->parent_to_subset[glyph] == 0) {
- font->parent_to_subset[glyph] = font->base.num_glyphs;
- font->glyphs[font->base.num_glyphs].parent_index = glyph;
- font->base.num_glyphs++;
- }
-
- return font->parent_to_subset[glyph];
-}
-
-static cairo_pdf_font_backend_t cairo_pdf_ft_font_backend = {
- cairo_pdf_ft_font_use_glyph,
- cairo_pdf_ft_font_generate,
- cairo_pdf_ft_font_destroy
-};
-
-/* PDF Generation */
-
static unsigned int
_cairo_pdf_document_new_object (cairo_pdf_document_t *document)
{
@@ -1851,14 +1225,15 @@ _cairo_pdf_surface_get_extents (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_pdf_font_t *
+static cairo_font_subset_t *
_cairo_pdf_document_get_font (cairo_pdf_document_t *document,
cairo_scaled_font_t *scaled_font)
{
cairo_unscaled_font_t *unscaled_font;
- cairo_pdf_font_t *pdf_font;
+ cairo_font_subset_t *pdf_font;
unsigned int num_fonts, i;
+ /* XXX Why is this an ft specific function? */
unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
num_fonts = _cairo_array_num_elements (&document->fonts);
@@ -1870,12 +1245,14 @@ _cairo_pdf_document_get_font (cairo_pdf_document_t *document,
/* FIXME: Figure out here which font backend is in use and call
* the appropriate constructor. */
- pdf_font = cairo_pdf_ft_font_create (document, unscaled_font);
+ pdf_font = _cairo_font_subset_create (unscaled_font);
if (pdf_font == NULL)
return NULL;
+ pdf_font->font_id = _cairo_pdf_document_new_object (document);
+
if (_cairo_array_append (&document->fonts, &pdf_font, 1) == NULL) {
- cairo_pdf_font_destroy (pdf_font);
+ _cairo_font_subset_destroy (pdf_font);
return NULL;
}
@@ -1899,7 +1276,7 @@ _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_document_t *document = surface->document;
cairo_output_stream_t *output = document->output_stream;
- cairo_pdf_font_t *pdf_font;
+ cairo_font_subset_t *pdf_font;
int i, index;
pdf_font = _cairo_pdf_document_get_font (document, scaled_font);
@@ -1912,7 +1289,7 @@ _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
"BT /res%u 1 Tf", pdf_font->font_id);
for (i = 0; i < num_glyphs; i++) {
- index = cairo_pdf_font_use_glyph (pdf_font, glyphs[i].index);
+ index = _cairo_font_subset_use_glyph (pdf_font, glyphs[i].index);
_cairo_output_stream_printf (output,
" %f %f %f %f %f %f Tm (\\%o) Tj",
@@ -2036,7 +1413,7 @@ _cairo_pdf_document_create (cairo_output_stream_t *output_stream,
document->pages_id = _cairo_pdf_document_new_object (document);
- _cairo_array_init (&document->fonts, sizeof (cairo_pdf_font_t *));
+ _cairo_array_init (&document->fonts, sizeof (cairo_font_subset_t *));
/* Document header */
_cairo_output_stream_printf (output_stream,
@@ -2100,7 +1477,7 @@ static cairo_status_t
_cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
{
cairo_output_stream_t *output = document->output_stream;
- cairo_pdf_font_t *font;
+ cairo_font_subset_t *font;
int num_fonts, i, j;
const char *data;
char *compressed;
@@ -2112,7 +1489,7 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
for (i = 0; i < num_fonts; i++) {
_cairo_array_copy_element (&document->fonts, i, &font);
- status = cairo_pdf_font_generate (font, &data, &data_size);
+ status = _cairo_font_subset_generate (font, &data, &data_size);
if (status)
goto fail;
@@ -2195,7 +1572,7 @@ _cairo_pdf_document_write_fonts (cairo_pdf_document_t *document)
"endobj\r\n");
fail:
- cairo_pdf_ft_font_destroy (font);
+ _cairo_font_subset_destroy (font);
}
return status;