Split out font subsetting code from here,

and put it here.
This commit is contained in:
Kristian Høgsberg 2005-06-21 15:38:51 +00:00
parent 7283ba6d47
commit b1130276d5
5 changed files with 784 additions and 684 deletions

View file

@ -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.

View file

@ -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

View file

@ -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 */

645
src/cairo-font-subset.c Normal file
View file

@ -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
};

View file

@ -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;