SVG: Discard custom font subsetting in favor of sharing cairo-scaled-font-subsets

This commit is contained in:
Carl Worth 2006-05-10 15:14:10 -07:00
parent f459c1f0de
commit 7c137b7e2c
2 changed files with 45 additions and 229 deletions

View file

@ -71,7 +71,7 @@ We don't expect to release without these being complete.
cairo_set_line_width should immediately use CTM
_transform_glyph_bitmap http://lists.freedesktop.org/archives/cairo/2005-October/005564.html
6759 fontconfig option AntiAlias doesn't work in cairo 1.1.2
PS/PDF subsetting code needs bitmapped-glyph support
SVG/PS/PDF emit_glyph functions need to support bitmapped glyphs
Fix memory leaks
1. Ensure 'make check-valgrind' passes with no leaks

View file

@ -2,6 +2,7 @@
*
* Copyright © 2004 Red Hat, Inc
* Copyright © 2005-2006 Emmanuel Pacaud <emmanuel.pacaud@free.fr>
* Copyright © 2006 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@ -34,6 +35,7 @@
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr>
* Carl Worth <cworth@cworth.org>
*/
#include "cairoint.h"
@ -42,6 +44,7 @@
#include "cairo-ft-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-paginated-surface-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include <libxml/tree.h>
@ -73,19 +76,6 @@ static const char * _cairo_svg_internal_version_strings[CAIRO_SVG_VERSION_LAST]
"1.2"
};
typedef struct cairo_svg_glyph {
cairo_hash_entry_t base; /* font glyph index */
unsigned int output_glyph; /* font glyph index */
} cairo_svg_glyph_t;
typedef struct cairo_svg_font {
cairo_hash_entry_t base;
cairo_scaled_font_t *scaled_font;
unsigned int output_font;
cairo_hash_table_t *glyphs;
unsigned int max_glyph;
} cairo_svg_font_t;
struct cairo_svg_document {
cairo_output_stream_t *output_stream;
unsigned long refcount;
@ -116,8 +106,7 @@ struct cairo_svg_document {
cairo_svg_version_t svg_version;
cairo_hash_table_t *fonts;
unsigned int max_font;
cairo_scaled_font_subsets_t *font_subsets;
};
struct cairo_svg_surface {
@ -556,167 +545,12 @@ _cairo_svg_path_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
_cairo_svg_glyph_equal (const void *key_a, const void *key_b)
{
const cairo_svg_glyph_t *svg_glyph_a = key_a;
const cairo_svg_glyph_t *svg_glyph_b = key_b;
return svg_glyph_a->base.hash == svg_glyph_b->base.hash;
}
static void
_cairo_svg_glyph_key_init (cairo_svg_glyph_t *svg_glyph,
unsigned long index)
{
svg_glyph->base.hash = index;
}
static cairo_svg_glyph_t *
_cairo_svg_glyph_create (cairo_svg_font_t *svg_font,
unsigned long index)
{
cairo_svg_glyph_t *svg_glyph = malloc (sizeof (cairo_svg_glyph_t));
if (!svg_glyph)
return NULL;
_cairo_svg_glyph_key_init (svg_glyph, index);
svg_glyph->output_glyph = svg_font->max_glyph++;
return svg_glyph;
}
static void
_cairo_svg_glyph_destroy (cairo_svg_glyph_t *svg_glyph)
{
free (svg_glyph);
}
static cairo_status_t
_cairo_svg_glyph_find (cairo_svg_font_t *font,
cairo_scaled_font_t *scaled_font,
unsigned long index,
cairo_svg_glyph_t **result)
{
cairo_svg_glyph_t key;
cairo_svg_glyph_t *svg_glyph;
cairo_status_t status;
_cairo_svg_glyph_key_init (&key, index);
if (!_cairo_hash_table_lookup (font->glyphs,
&key.base,
(cairo_hash_entry_t **) &svg_glyph)) {
svg_glyph = _cairo_svg_glyph_create (font, index);
if (!svg_glyph)
return CAIRO_STATUS_NO_MEMORY;
status = _cairo_hash_table_insert (font->glyphs, &svg_glyph->base);
if (status)
return status;
}
*result = svg_glyph;
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
_cairo_svg_font_equal (const void *key_a, const void *key_b)
{
const cairo_svg_font_t *svg_font_a = key_a;
const cairo_svg_font_t *svg_font_b = key_b;
return svg_font_a->scaled_font == svg_font_b->scaled_font;
}
static void
_cairo_svg_font_key_init (cairo_svg_font_t *svg_font,
cairo_scaled_font_t *scaled_font)
{
/* FIXME cast a pointer to unsigned long, really ? */
svg_font->base.hash = (unsigned long) scaled_font;
svg_font->scaled_font = scaled_font;
}
static cairo_svg_font_t *
_cairo_svg_document_font_create (cairo_svg_document_t *document,
cairo_scaled_font_t *scaled_font)
{
cairo_svg_font_t *svg_font = malloc (sizeof (cairo_svg_font_t));
if (!svg_font)
return NULL;
_cairo_svg_font_key_init (svg_font, scaled_font);
svg_font->glyphs = _cairo_hash_table_create (_cairo_svg_glyph_equal);
if (!svg_font->glyphs) {
free (svg_font);
return NULL;
}
svg_font->max_glyph = 0;
svg_font->output_font = document->max_font++;
cairo_scaled_font_reference (svg_font->scaled_font);
return svg_font;
}
static void
_cairo_svg_font_destroy_glyph (void *entry, void *closure)
{
cairo_svg_glyph_t *svg_glyph = entry;
cairo_svg_font_t *svg_font = closure;
_cairo_hash_table_remove (svg_font->glyphs, &svg_glyph->base);
_cairo_svg_glyph_destroy (svg_glyph);
}
static void
_cairo_svg_font_destroy (cairo_svg_font_t *svg_font)
{
_cairo_hash_table_foreach (svg_font->glyphs,
_cairo_svg_font_destroy_glyph,
svg_font);
_cairo_hash_table_destroy (svg_font->glyphs);
cairo_scaled_font_destroy (svg_font->scaled_font);
free (svg_font);
}
static void
_cairo_svg_document_destroy_font (cairo_svg_document_t *document,
cairo_svg_font_t *svg_font)
{
_cairo_hash_table_remove (document->fonts, &svg_font->base);
_cairo_svg_font_destroy (svg_font);
}
static cairo_status_t
_cairo_svg_document_font_find (cairo_svg_document_t *document,
cairo_scaled_font_t *scaled_font,
cairo_svg_font_t **result)
{
cairo_svg_font_t key;
cairo_svg_font_t *svg_font;
cairo_status_t status;
_cairo_svg_font_key_init (&key, scaled_font);
if (!_cairo_hash_table_lookup (document->fonts, &key.base,
(cairo_hash_entry_t **) &svg_font))
{
svg_font = _cairo_svg_document_font_create (document, scaled_font);
if (!svg_font)
return CAIRO_STATUS_NO_MEMORY;
status = _cairo_hash_table_insert (document->fonts,
&svg_font->base);
if (status)
return status;
}
*result = svg_font;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
cairo_svg_font_t *svg_font,
cairo_svg_glyph_t *svg_glyph)
_cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
unsigned int font_id,
unsigned int subset_glyph_index)
{
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
@ -724,8 +558,8 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
xmlNodePtr symbol, child;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
status = _cairo_scaled_glyph_lookup (svg_font->scaled_font,
svg_glyph->base.hash,
status = _cairo_scaled_glyph_lookup (scaled_font,
scaled_font_glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
@ -733,8 +567,8 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
* If that fails, try again but ask for an image instead
*/
if (status)
status = _cairo_scaled_glyph_lookup (svg_font->scaled_font,
svg_glyph->base.hash,
status = _cairo_scaled_glyph_lookup (scaled_font,
scaled_font_glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
@ -755,8 +589,8 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
symbol = xmlNewChild (document->xml_node_glyphs, NULL,
CC2XML ("symbol"), NULL);
snprintf (buffer, sizeof buffer, "glyph%d-%d",
svg_font->output_font,
svg_glyph->output_glyph);
font_id,
subset_glyph_index);
xmlSetProp (symbol, CC2XML ("id"), C2XML (buffer));
child = xmlNewChild (symbol, NULL, CC2XML ("path"), NULL);
xmlSetProp (child, CC2XML ("d"), xmlBufferContent (info.path));
@ -767,47 +601,34 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
return CAIRO_STATUS_SUCCESS;
}
typedef struct {
cairo_svg_document_t *document;
cairo_svg_font_t *svg_font;
} emit_glyph_info_t;
static void
_emit_glyph (void *entry, void *closure)
static cairo_status_t
_cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
void *closure)
{
cairo_svg_glyph_t *svg_glyph = entry;
emit_glyph_info_t *info = closure;
_cairo_svg_document_emit_glyph (info->document,
info->svg_font,
svg_glyph);
_cairo_svg_font_destroy_glyph (svg_glyph, info->svg_font);
}
static void
_cairo_svg_document_emit_font (void *entry, void *closure)
{
cairo_svg_font_t *svg_font = entry;
cairo_svg_document_t *document = closure;
emit_glyph_info_t info;
cairo_status_t status;
int i;
info.document = document;
info.svg_font = svg_font;
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_svg_document_emit_glyph (document,
font_subset->scaled_font,
font_subset->glyphs[i],
font_subset->font_id, i);
if (status)
return status;
}
_cairo_hash_table_foreach (svg_font->glyphs,
_emit_glyph,
&info);
_cairo_svg_document_destroy_font (document, svg_font);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_svg_document_emit_fonts (cairo_svg_document_t *document)
_cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document)
{
_cairo_hash_table_foreach (document->fonts,
_cairo_svg_document_emit_font,
document);
_cairo_hash_table_destroy (document->fonts);
document->fonts = NULL;
_cairo_scaled_font_subsets_foreach (document->font_subsets,
_cairo_svg_document_emit_font_subset,
document);
_cairo_scaled_font_subsets_destroy (document->font_subsets);
document->font_subsets = NULL;
}
static cairo_int_status_t
@ -1813,12 +1634,11 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
cairo_svg_document_t *document = surface->document;
cairo_path_fixed_t path;
cairo_status_t status;
cairo_svg_font_t *svg_font;
cairo_svg_glyph_t *svg_glyph;
xmlNodePtr glyph_node;
xmlNodePtr child;
xmlBufferPtr style;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
unsigned int font_id, subset_id, subset_glyph_index;
int i;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
@ -1835,10 +1655,6 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
goto FALLBACK;
status = _cairo_svg_document_font_find (document, scaled_font, &svg_font);
if (status)
goto FALLBACK;
child = xmlNewChild (surface->xml_node, NULL, CC2XML ("g"), NULL);
style = xmlBufferCreate ();
emit_pattern (surface, pattern, style, 0);
@ -1846,8 +1662,9 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
xmlBufferFree (style);
for (i = 0; i < num_glyphs; i++) {
status = _cairo_svg_glyph_find (svg_font, scaled_font,
glyphs[i].index, &svg_glyph);
status = _cairo_scaled_font_subsets_map_glyph (document->font_subsets,
scaled_font, glyphs[i].index,
&font_id, &subset_id, &subset_glyph_index);
if (status) {
glyphs += i;
num_glyphs -= i;
@ -1856,8 +1673,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
glyph_node = xmlNewChild (child, NULL, CC2XML ("use"), NULL);
snprintf (buffer, sizeof buffer, "#glyph%d-%d",
svg_font->output_font,
svg_glyph->output_glyph);
font_id, subset_glyph_index);
xmlSetProp (glyph_node, CC2XML ("xlink:href"), C2XML (buffer));
_cairo_dtostr (buffer, sizeof buffer, glyphs[i].x);
xmlSetProp (glyph_node, CC2XML ("x"), C2XML (buffer));
@ -1997,13 +1813,13 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
return NULL;
}
document->fonts = _cairo_hash_table_create (_cairo_svg_font_equal);
if (!document->fonts) {
/* The use of defs for font glyphs imposes no per-subset limit. */
document->font_subsets = _cairo_scaled_font_subsets_create (0);
if (document->font_subsets == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
free (document);
return NULL;
}
document->max_font = 0;
document->output_stream = output_stream;
document->refcount = 1;
@ -2119,7 +1935,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
if (document->finished)
return CAIRO_STATUS_SUCCESS;
_cairo_svg_document_emit_fonts (document);
_cairo_svg_document_emit_font_subsets (document);
xmlSetProp (document->xml_node_main, CC2XML ("version"),
CC2XML (_cairo_svg_internal_version_strings [document->svg_version]));