diff options
author | Kristian Høgsberg <krh@redhat.com> | 2005-06-21 15:38:51 +0000 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2005-06-21 15:38:51 +0000 |
commit | b1130276d59a219e70d43dd1d199ddf391fa3330 (patch) | |
tree | bb411978e5bc985f7a8e0c38c38e95f413e95710 | |
parent | 7283ba6d470950e0e49f33fc25f3358113dda51e (diff) |
Split out font subsetting code from here,
and put it here.
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | src/Makefile.am | 91 | ||||
-rw-r--r-- | src/cairo-font-subset-private.h | 68 | ||||
-rw-r--r-- | src/cairo-font-subset.c | 645 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 657 |
5 files changed, 784 insertions, 684 deletions
@@ -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; |