mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-09 04:58:04 +02:00
Generalize font subsetting code in cairo-scaled-font-subsets for use by more than just PS backend
This commit is contained in:
parent
906a17a6b1
commit
0544515279
5 changed files with 437 additions and 296 deletions
1
ROADMAP
1
ROADMAP
|
|
@ -71,6 +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
|
||||
|
||||
Fix memory leaks
|
||||
1. Ensure 'make check-valgrind' passes with no leaks
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
if CAIRO_HAS_PS_SURFACE
|
||||
libcairo_ps_headers = cairo-ps.h
|
||||
libcairo_ps_sources = cairo-ps-surface.c cairo-ps-font.c cairo-ps-font-private.h
|
||||
libcairo_ps_sources = cairo-ps-surface.c cairo-scaled-font-subsets.c cairo-scaled-font-subsets-private.h
|
||||
libcairo_font_subset_sources = cairo-font-subset.c cairo-font-subset-private.h
|
||||
endif
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,7 @@
|
|||
|
||||
#include "cairoint.h"
|
||||
#include "cairo-ps.h"
|
||||
#include "cairo-ps-font-private.h"
|
||||
#include "cairo-font-subset-private.h"
|
||||
#include "cairo-scaled-font-subsets-private.h"
|
||||
#include "cairo-paginated-surface-private.h"
|
||||
#include "cairo-meta-surface-private.h"
|
||||
#include "cairo-ft-private.h"
|
||||
|
|
@ -75,7 +74,7 @@ typedef struct cairo_ps_surface {
|
|||
|
||||
cairo_paginated_mode_t paginated_mode;
|
||||
|
||||
cairo_hash_table_t *fonts;
|
||||
cairo_scaled_font_subsets_t *font_subsets;
|
||||
unsigned int max_font;
|
||||
|
||||
cairo_array_t dsc_header_comments;
|
||||
|
|
@ -86,7 +85,8 @@ typedef struct cairo_ps_surface {
|
|||
|
||||
} cairo_ps_surface_t;
|
||||
|
||||
#define PS_SURFACE_DPI_DEFAULT 300.0
|
||||
#define PS_SURFACE_DPI_DEFAULT 300.0
|
||||
#define PS_SURFACE_MAX_GLYPHS_PER_FONT 256
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
|
||||
|
|
@ -213,51 +213,19 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
|
|||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_find_ps_font (cairo_ps_surface_t *surface,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
cairo_ps_font_t **result)
|
||||
{
|
||||
cairo_ps_font_t key;
|
||||
cairo_ps_font_t *ps_font;
|
||||
cairo_status_t status;
|
||||
|
||||
_cairo_ps_font_key_init (&key, scaled_font);
|
||||
if (!_cairo_hash_table_lookup (surface->fonts, &key.base,
|
||||
(cairo_hash_entry_t **) &ps_font))
|
||||
{
|
||||
ps_font = _cairo_ps_font_create (scaled_font, surface->max_font++);
|
||||
if (!ps_font)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
status = _cairo_hash_table_insert (surface->fonts,
|
||||
&ps_font->base);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
*result = ps_font;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_ps_surface_destroy_ps_font (cairo_ps_surface_t *surface,
|
||||
cairo_ps_font_t *ps_font)
|
||||
{
|
||||
_cairo_hash_table_remove (surface->fonts, &ps_font->base);
|
||||
_cairo_ps_font_destroy (ps_font);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
|
||||
cairo_ps_font_t *ps_font,
|
||||
cairo_ps_glyph_t *ps_glyph)
|
||||
_cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long scaled_font_glyph_index,
|
||||
unsigned int subset_glyph_index)
|
||||
{
|
||||
cairo_scaled_glyph_t *scaled_glyph;
|
||||
cairo_status_t status;
|
||||
|
||||
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"\t\t{ %% %d\n", ps_glyph->output_glyph);
|
||||
status = _cairo_scaled_glyph_lookup (ps_font->scaled_font,
|
||||
ps_glyph->base.hash,
|
||||
"\t\t{ %% %d\n", subset_glyph_index);
|
||||
|
||||
status = _cairo_scaled_glyph_lookup (scaled_font,
|
||||
scaled_font_glyph_index,
|
||||
CAIRO_SCALED_GLYPH_INFO_METRICS|
|
||||
CAIRO_SCALED_GLYPH_INFO_PATH,
|
||||
&scaled_glyph);
|
||||
|
|
@ -265,8 +233,8 @@ _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
|
|||
* If that fails, try again but ask for an image instead
|
||||
*/
|
||||
if (status)
|
||||
status = _cairo_scaled_glyph_lookup (ps_font->scaled_font,
|
||||
ps_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);
|
||||
|
|
@ -274,6 +242,10 @@ _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
|
|||
_cairo_output_stream_printf (surface->final_stream, "\t\t}\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* XXX: Need to actually use the image not the path if that's all
|
||||
* we could get... */
|
||||
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"%f %f %f %f 0 0 setcachedevice\n",
|
||||
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
|
||||
|
|
@ -297,70 +269,57 @@ _cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_ps_surface_emit_font (void *entry, void *closure)
|
||||
static cairo_status_t
|
||||
_cairo_ps_surface_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
|
||||
void *closure)
|
||||
{
|
||||
cairo_ps_font_t *ps_font = entry;
|
||||
cairo_ps_surface_t *surface = closure;
|
||||
cairo_ps_font_glyph_select_t glyph_select;
|
||||
cairo_ps_glyph_t *ps_glyphs[256], *ps_glyph;
|
||||
int glyph, numglyph;
|
||||
int subfont, nsubfont;
|
||||
int i;
|
||||
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"%% _cairo_ps_surface_emit_font\n");
|
||||
nsubfont = (ps_font->max_glyph >> 8) + 1;
|
||||
for (subfont = 0; subfont < nsubfont; subfont++) {
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"/CairoFont-%d-%d <<\n",
|
||||
ps_font->output_font,
|
||||
subfont);
|
||||
memset (ps_glyphs, '\0', sizeof (ps_glyphs));
|
||||
glyph_select.glyphs = ps_glyphs;
|
||||
glyph_select.numglyph = 0;
|
||||
glyph_select.subfont = subfont;
|
||||
_cairo_hash_table_foreach (ps_font->glyphs,
|
||||
_cairo_ps_font_select_glyphs,
|
||||
&glyph_select);
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"\t/FontType\t3\n"
|
||||
"\t/FontMatrix\t[1 0 0 1 0 0]\n"
|
||||
"\t/Encoding\t[0]\n"
|
||||
"\t/FontBBox\t[0 0 10 10]\n"
|
||||
"\t/Glyphs [\n");
|
||||
numglyph = glyph_select.numglyph;
|
||||
for (glyph = 0; glyph < numglyph; glyph++) {
|
||||
ps_glyph = ps_glyphs[glyph];
|
||||
if (ps_glyph) {
|
||||
_cairo_ps_surface_emit_glyph (surface,
|
||||
ps_font,
|
||||
ps_glyph);
|
||||
} else {
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"\t\t{ } %% %d\n", glyph);
|
||||
}
|
||||
_cairo_ps_font_destroy_glyph (ps_font, ps_glyph);
|
||||
}
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"\t]\n"
|
||||
"\t/BuildChar {\n"
|
||||
"\t\texch /Glyphs get\n"
|
||||
"\t\texch get exec\n"
|
||||
"\t}\n"
|
||||
">> definefont pop\n");
|
||||
"%% _cairo_ps_surface_emit_font_subset\n");
|
||||
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"/CairoFont-%d-%d <<\n",
|
||||
font_subset->font_id,
|
||||
font_subset->subset_id);
|
||||
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"\t/FontType\t3\n"
|
||||
"\t/FontMatrix\t[1 0 0 1 0 0]\n"
|
||||
"\t/Encoding\t[0]\n"
|
||||
"\t/FontBBox\t[0 0 10 10]\n"
|
||||
"\t/Glyphs [\n");
|
||||
|
||||
for (i = 0; i < font_subset->num_glyphs; i++) {
|
||||
_cairo_ps_surface_emit_glyph (surface,
|
||||
font_subset->scaled_font,
|
||||
font_subset->glyphs[i], i);
|
||||
}
|
||||
_cairo_ps_surface_destroy_ps_font (surface, ps_font);
|
||||
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"\t]\n"
|
||||
"\t/BuildChar {\n"
|
||||
"\t\texch /Glyphs get\n"
|
||||
"\t\texch get exec\n"
|
||||
"\t}\n"
|
||||
">> definefont pop\n");
|
||||
|
||||
return _cairo_output_stream_get_status (surface->final_stream);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_cairo_ps_surface_emit_fonts (cairo_ps_surface_t *surface)
|
||||
_cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
|
||||
{
|
||||
_cairo_hash_table_foreach (surface->fonts,
|
||||
_cairo_ps_surface_emit_font,
|
||||
surface);
|
||||
_cairo_hash_table_destroy (surface->fonts);
|
||||
surface->fonts = NULL;
|
||||
_cairo_output_stream_printf (surface->final_stream,
|
||||
"%% _cairo_ps_surface_emit_font_subsets\n");
|
||||
|
||||
_cairo_scaled_font_subsets_foreach (surface->font_subsets,
|
||||
_cairo_ps_surface_emit_font_subset,
|
||||
surface);
|
||||
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
|
||||
surface->font_subsets = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -388,12 +347,12 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
|
|||
double height)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_ps_surface_t *surface;
|
||||
cairo_ps_surface_t *surface = NULL;
|
||||
|
||||
surface = malloc (sizeof (cairo_ps_surface_t));
|
||||
if (surface == NULL) {
|
||||
_cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_surface_t*) &_cairo_surface_nil;
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
_cairo_surface_init (&surface->base, &cairo_ps_surface_backend);
|
||||
|
|
@ -401,23 +360,18 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
|
|||
surface->final_stream = stream;
|
||||
|
||||
surface->tmpfile = tmpfile ();
|
||||
if (surface->tmpfile == NULL)
|
||||
goto CLEANUP_SURFACE;
|
||||
|
||||
surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
|
||||
status = _cairo_output_stream_get_status (surface->stream);
|
||||
if (status) {
|
||||
fclose (surface->tmpfile);
|
||||
free (surface);
|
||||
_cairo_error (status);
|
||||
return (cairo_surface_t*) &_cairo_surface_nil;
|
||||
}
|
||||
if (status)
|
||||
goto CLEANUP_TMPFILE;
|
||||
|
||||
surface->font_subsets = _cairo_scaled_font_subsets_create (PS_SURFACE_MAX_GLYPHS_PER_FONT);
|
||||
if (! surface->font_subsets)
|
||||
goto CLEANUP_OUTPUT_STREAM;
|
||||
|
||||
surface->fonts = _cairo_hash_table_create (_cairo_ps_font_equal);
|
||||
if (!surface->fonts) {
|
||||
_cairo_output_stream_destroy (surface->stream);
|
||||
fclose (surface->tmpfile);
|
||||
free (surface);
|
||||
_cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_surface_t*) &_cairo_surface_nil;
|
||||
}
|
||||
surface->max_font = 0;
|
||||
|
||||
surface->width = width;
|
||||
|
|
@ -440,6 +394,17 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
|
|||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
width, height,
|
||||
&cairo_ps_surface_paginated_backend);
|
||||
|
||||
|
||||
CLEANUP_OUTPUT_STREAM:
|
||||
_cairo_output_stream_destroy (surface->stream);
|
||||
CLEANUP_TMPFILE:
|
||||
fclose (surface->tmpfile);
|
||||
CLEANUP_SURFACE:
|
||||
free (surface);
|
||||
CLEANUP:
|
||||
_cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_surface_t*) &_cairo_surface_nil;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -955,7 +920,7 @@ _cairo_ps_surface_finish (void *abstract_surface)
|
|||
|
||||
_cairo_ps_surface_emit_header (surface);
|
||||
|
||||
_cairo_ps_surface_emit_fonts (surface);
|
||||
_cairo_ps_surface_emit_font_subsets (surface);
|
||||
|
||||
_cairo_ps_surface_emit_body (surface);
|
||||
|
||||
|
|
@ -1773,9 +1738,8 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
|
|||
cairo_int_status_t status;
|
||||
cairo_path_fixed_t *path;
|
||||
int i;
|
||||
int cur_subfont = -1, subfont;
|
||||
cairo_ps_font_t *ps_font;
|
||||
cairo_ps_glyph_t *ps_glyph;
|
||||
int current_sub_font_id = -1;
|
||||
unsigned int font_id, sub_font_id, sub_font_glyph_index;
|
||||
|
||||
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
|
||||
return _analyze_operation (surface, op, source);
|
||||
|
|
@ -1784,34 +1748,30 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
|
|||
|
||||
_cairo_output_stream_printf (stream,
|
||||
"%% _cairo_ps_surface_show_glyphs\n");
|
||||
status = _cairo_ps_surface_find_ps_font (surface, scaled_font, &ps_font);
|
||||
if (status)
|
||||
goto fallback;
|
||||
|
||||
if (num_glyphs)
|
||||
emit_pattern (surface, source);
|
||||
|
||||
for (i = 0; i < num_glyphs; i++) {
|
||||
status = _cairo_ps_font_find_glyph (ps_font, scaled_font,
|
||||
glyphs[i].index, &ps_glyph);
|
||||
status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
|
||||
scaled_font, glyphs[i].index,
|
||||
&font_id, &sub_font_id, &sub_font_glyph_index);
|
||||
if (status) {
|
||||
glyphs += i;
|
||||
num_glyphs -= i;
|
||||
goto fallback;
|
||||
}
|
||||
subfont = ps_glyph->output_glyph >> 8;
|
||||
if (subfont != cur_subfont) {
|
||||
if (sub_font_id != current_sub_font_id) {
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"/CairoFont-%d-%d 1 selectfont\n",
|
||||
ps_font->output_font,
|
||||
subfont);
|
||||
cur_subfont = subfont;
|
||||
font_id, sub_font_id);
|
||||
current_sub_font_id = sub_font_id;
|
||||
}
|
||||
_cairo_output_stream_printf (surface->stream,
|
||||
"%f %f M <%c%c> S\n",
|
||||
glyphs[i].x, glyphs[i].y,
|
||||
hex_digit (ps_glyph->output_glyph >> 4),
|
||||
hex_digit (ps_glyph->output_glyph));
|
||||
hex_digit (sub_font_glyph_index >> 4),
|
||||
hex_digit (sub_font_glyph_index));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
/* cairo - a vector graphics library with display and print output
|
||||
*
|
||||
* Copyright © 2003 University of Southern California
|
||||
* Copyright © 2005 Red Hat, Inc
|
||||
* Copyright © 2006 Keith Packard
|
||||
* Copyright © 2006 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
|
|
@ -35,67 +32,48 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Carl D. Worth <cworth@cworth.org>
|
||||
* Kristian Høgsberg <krh@redhat.com>
|
||||
* Keith Packard <keithp@keithp.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Type1 and Type3 PS fonts can hold only 256 glyphs.
|
||||
*
|
||||
* XXX Work around this by placing each set of 256 glyphs in a separate
|
||||
* font. No separate data structure is kept for this; the font name is
|
||||
* generated from all but the low 8 bits of the output glyph id.
|
||||
*/
|
||||
|
||||
#ifndef CAIRO_PS_FONT_PRIVATE_H
|
||||
#define CAIRO_PS_FONT_PRIVATE_H
|
||||
#ifndef CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H
|
||||
#define CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct cairo_ps_glyph {
|
||||
cairo_hash_entry_t base; /* font glyph index */
|
||||
unsigned int output_glyph; /* PS sub-font glyph index */
|
||||
} cairo_ps_glyph_t;
|
||||
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
|
||||
|
||||
typedef struct cairo_ps_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_ps_font_t;
|
||||
typedef struct _cairo_scaled_font_subset {
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
unsigned int font_id;
|
||||
unsigned int subset_id;
|
||||
|
||||
typedef struct _cairo_ps_font_glyph_select {
|
||||
cairo_ps_glyph_t **glyphs;
|
||||
int subfont;
|
||||
int numglyph;
|
||||
} cairo_ps_font_glyph_select_t;
|
||||
/* Index of glyphs array is subset_glyph_index.
|
||||
* Value of glyphs array is scaled_font_glyph_index.
|
||||
*/
|
||||
unsigned long *glyphs;
|
||||
int num_glyphs;
|
||||
} cairo_scaled_font_subset_t;
|
||||
|
||||
cairo_private cairo_ps_font_t *
|
||||
_cairo_ps_font_create (cairo_scaled_font_t *scaled_font,
|
||||
unsigned int id);
|
||||
cairo_private cairo_scaled_font_subsets_t *
|
||||
_cairo_scaled_font_subsets_create (int max_glyphs_per_subset);
|
||||
|
||||
cairo_private void
|
||||
_cairo_ps_font_destroy (cairo_ps_font_t *ps_font);
|
||||
|
||||
cairo_private void
|
||||
_cairo_ps_font_key_init (cairo_ps_font_t *ps_font,
|
||||
cairo_scaled_font_t *scaled_font);
|
||||
|
||||
cairo_private void
|
||||
_cairo_ps_font_select_glyphs (void *entry, void *closure);
|
||||
|
||||
cairo_private void
|
||||
_cairo_ps_font_destroy_glyph (cairo_ps_font_t *ps_font,
|
||||
cairo_ps_glyph_t *ps_glyph);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_ps_font_equal (const void *key_a, const void *key_b);
|
||||
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *font_subsets);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_ps_font_find_glyph (cairo_ps_font_t *font,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long index,
|
||||
cairo_ps_glyph_t **result);
|
||||
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long scaled_font_glyph_index,
|
||||
unsigned int *font_id,
|
||||
unsigned int *subset_id,
|
||||
unsigned int *subset_glyph_index);
|
||||
|
||||
#endif /* CAIRO_PS_FONT_PRIVATE_H */
|
||||
typedef cairo_status_t
|
||||
(*cairo_scaled_font_subset_callback_func_t) (cairo_scaled_font_subset_t *font_subset,
|
||||
void *closure);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets,
|
||||
cairo_scaled_font_subset_callback_func_t font_subset_callback,
|
||||
void *closure);
|
||||
|
||||
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -39,143 +39,345 @@
|
|||
* Keith Packard <keithp@keithp.com>
|
||||
*/
|
||||
|
||||
|
||||
#include "cairoint.h"
|
||||
#include "cairo-ps-font-private.h"
|
||||
#include "cairo-scaled-font-subsets-private.h"
|
||||
|
||||
struct _cairo_scaled_font_subsets {
|
||||
int max_glyphs_per_subset_limit;
|
||||
int max_glyphs_per_subset_used;
|
||||
int num_sub_fonts;
|
||||
|
||||
cairo_hash_table_t *sub_fonts;
|
||||
};
|
||||
|
||||
typedef struct _cairo_sub_font {
|
||||
cairo_hash_entry_t base;
|
||||
|
||||
cairo_scaled_font_subsets_t *parent;
|
||||
cairo_scaled_font_t *scaled_font;
|
||||
unsigned int font_id;
|
||||
|
||||
int current_subset;
|
||||
int num_glyphs_in_current_subset;
|
||||
int max_glyphs_per_subset;
|
||||
|
||||
cairo_hash_table_t *sub_font_glyphs;
|
||||
} cairo_sub_font_t;
|
||||
|
||||
typedef struct _cairo_sub_font_glyph {
|
||||
cairo_hash_entry_t base;
|
||||
|
||||
unsigned int subset_id;
|
||||
unsigned int subset_glyph_index;
|
||||
} cairo_sub_font_glyph_t;
|
||||
|
||||
typedef struct _cairo_sub_font_collection {
|
||||
unsigned long *glyphs; /* scaled_font_glyph_index */
|
||||
int glyphs_size;
|
||||
int max_glyph;
|
||||
int num_glyphs;
|
||||
|
||||
unsigned int subset_id;
|
||||
|
||||
cairo_scaled_font_subset_callback_func_t font_subset_callback;
|
||||
void *font_subset_callback_closure;
|
||||
} cairo_sub_font_collection_t;
|
||||
|
||||
static void
|
||||
_cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph,
|
||||
unsigned long scaled_font_glyph_index)
|
||||
{
|
||||
sub_font_glyph->base.hash = scaled_font_glyph_index;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_ps_glyph_equal (const void *key_a, const void *key_b)
|
||||
_cairo_sub_font_glyphs_equal (const void *key_a, const void *key_b)
|
||||
{
|
||||
const cairo_ps_glyph_t *ps_glyph_a = key_a;
|
||||
const cairo_ps_glyph_t *ps_glyph_b = key_b;
|
||||
const cairo_sub_font_glyph_t *sub_font_glyph_a = key_a;
|
||||
const cairo_sub_font_glyph_t *sub_font_glyph_b = key_b;
|
||||
|
||||
return ps_glyph_a->base.hash == ps_glyph_b->base.hash;
|
||||
return sub_font_glyph_a->base.hash == sub_font_glyph_b->base.hash;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_ps_glyph_key_init (cairo_ps_glyph_t *ps_glyph,
|
||||
unsigned long index)
|
||||
static cairo_sub_font_glyph_t *
|
||||
_cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
|
||||
unsigned int subset_id,
|
||||
unsigned int subset_glyph_index)
|
||||
{
|
||||
ps_glyph->base.hash = index;
|
||||
}
|
||||
cairo_sub_font_glyph_t *sub_font_glyph;
|
||||
|
||||
static cairo_ps_glyph_t *
|
||||
_cairo_ps_glyph_create (cairo_ps_font_t *ps_font,
|
||||
unsigned long index)
|
||||
{
|
||||
cairo_ps_glyph_t *ps_glyph = malloc (sizeof (cairo_ps_glyph_t));
|
||||
|
||||
if (!ps_glyph)
|
||||
sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
|
||||
if (sub_font_glyph == NULL)
|
||||
return NULL;
|
||||
_cairo_ps_glyph_key_init (ps_glyph, index);
|
||||
ps_glyph->output_glyph = ps_font->max_glyph++;
|
||||
return ps_glyph;
|
||||
|
||||
_cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
|
||||
sub_font_glyph->subset_id = subset_id;
|
||||
sub_font_glyph->subset_glyph_index = subset_glyph_index;
|
||||
|
||||
return sub_font_glyph;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_ps_glyph_destroy (cairo_ps_glyph_t *ps_glyph)
|
||||
_cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
|
||||
{
|
||||
free (ps_glyph);
|
||||
free (sub_font_glyph);
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_ps_font_find_glyph (cairo_ps_font_t *font,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long index,
|
||||
cairo_ps_glyph_t **result)
|
||||
static void
|
||||
_cairo_sub_font_glyph_pluck (void *entry, void *closure)
|
||||
{
|
||||
cairo_ps_glyph_t key;
|
||||
cairo_ps_glyph_t *ps_glyph;
|
||||
cairo_status_t status;
|
||||
cairo_sub_font_glyph_t *sub_font_glyph = entry;
|
||||
cairo_hash_table_t *sub_font_glyphs = closure;
|
||||
|
||||
_cairo_ps_glyph_key_init (&key, index);
|
||||
if (! _cairo_hash_table_lookup (font->glyphs,
|
||||
&key.base,
|
||||
(cairo_hash_entry_t **) &ps_glyph)) {
|
||||
ps_glyph = _cairo_ps_glyph_create (font, index);
|
||||
if (!ps_glyph)
|
||||
_cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
|
||||
_cairo_sub_font_glyph_destroy (sub_font_glyph);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_sub_font_glyph_collect (void *entry, void *closure)
|
||||
{
|
||||
cairo_sub_font_glyph_t *sub_font_glyph = entry;
|
||||
cairo_sub_font_collection_t *collection = closure;
|
||||
unsigned long scaled_font_glyph_index;
|
||||
unsigned int subset_glyph_index;
|
||||
|
||||
if (sub_font_glyph->subset_id != collection->subset_id)
|
||||
return;
|
||||
|
||||
scaled_font_glyph_index = sub_font_glyph->base.hash;
|
||||
subset_glyph_index = sub_font_glyph->subset_glyph_index;
|
||||
|
||||
/* Ensure we don't exceed the allocated bounds. */
|
||||
assert (subset_glyph_index < collection->glyphs_size);
|
||||
|
||||
collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
|
||||
if (subset_glyph_index > collection->max_glyph)
|
||||
collection->max_glyph = subset_glyph_index;
|
||||
|
||||
collection->num_glyphs++;
|
||||
}
|
||||
|
||||
static cairo_bool_t
|
||||
_cairo_sub_fonts_equal (const void *key_a, const void *key_b)
|
||||
{
|
||||
const cairo_sub_font_t *sub_font_a = key_a;
|
||||
const cairo_sub_font_t *sub_font_b = key_b;
|
||||
|
||||
return sub_font_a->scaled_font == sub_font_b->scaled_font;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_sub_font_init_key (cairo_sub_font_t *sub_font,
|
||||
cairo_scaled_font_t *scaled_font)
|
||||
{
|
||||
sub_font->base.hash = (unsigned long) scaled_font;
|
||||
sub_font->scaled_font = scaled_font;
|
||||
}
|
||||
|
||||
static cairo_sub_font_t *
|
||||
_cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned int font_id,
|
||||
int max_glyphs_per_subset)
|
||||
{
|
||||
cairo_sub_font_t *sub_font;
|
||||
|
||||
sub_font = malloc (sizeof (cairo_sub_font_t));
|
||||
if (sub_font == NULL)
|
||||
return NULL;
|
||||
|
||||
_cairo_sub_font_init_key (sub_font, scaled_font);
|
||||
|
||||
sub_font->parent = parent;
|
||||
sub_font->scaled_font = cairo_scaled_font_reference (scaled_font);
|
||||
sub_font->font_id = font_id;
|
||||
|
||||
sub_font->current_subset = 0;
|
||||
sub_font->num_glyphs_in_current_subset = 0;
|
||||
sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
|
||||
|
||||
sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
|
||||
if (! sub_font->sub_font_glyphs) {
|
||||
free (sub_font);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sub_font;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
|
||||
{
|
||||
_cairo_hash_table_foreach (sub_font->sub_font_glyphs,
|
||||
_cairo_sub_font_glyph_pluck,
|
||||
sub_font->sub_font_glyphs);
|
||||
_cairo_hash_table_destroy (sub_font->sub_font_glyphs);
|
||||
cairo_scaled_font_destroy (sub_font->scaled_font);
|
||||
free (sub_font);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_sub_font_pluck (void *entry, void *closure)
|
||||
{
|
||||
cairo_sub_font_t *sub_font = entry;
|
||||
cairo_hash_table_t *sub_fonts = closure;
|
||||
|
||||
_cairo_hash_table_remove (sub_fonts, &sub_font->base);
|
||||
_cairo_sub_font_destroy (sub_font);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
|
||||
unsigned long scaled_font_glyph_index,
|
||||
unsigned int *subset_id,
|
||||
unsigned int *subset_glyph_index)
|
||||
{
|
||||
cairo_sub_font_glyph_t key, *sub_font_glyph;
|
||||
cairo_status_t status;
|
||||
|
||||
_cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
|
||||
if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
|
||||
(cairo_hash_entry_t **) &sub_font_glyph))
|
||||
{
|
||||
if (sub_font->max_glyphs_per_subset &&
|
||||
sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
|
||||
{
|
||||
sub_font->current_subset++;
|
||||
sub_font->num_glyphs_in_current_subset = 0;
|
||||
}
|
||||
|
||||
sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
|
||||
sub_font->current_subset,
|
||||
sub_font->num_glyphs_in_current_subset++);
|
||||
if (sub_font_glyph == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
status = _cairo_hash_table_insert (font->glyphs, &ps_glyph->base);
|
||||
|
||||
if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_subset_used)
|
||||
sub_font->parent->max_glyphs_per_subset_used = sub_font->num_glyphs_in_current_subset;
|
||||
|
||||
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
*result = ps_glyph;
|
||||
|
||||
*subset_id = sub_font_glyph->subset_id;
|
||||
*subset_glyph_index = sub_font_glyph->subset_glyph_index;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_ps_font_equal (const void *key_a, const void *key_b)
|
||||
{
|
||||
const cairo_ps_font_t *ps_font_a = key_a;
|
||||
const cairo_ps_font_t *ps_font_b = key_b;
|
||||
|
||||
return ps_font_a->scaled_font == ps_font_b->scaled_font;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_ps_font_key_init (cairo_ps_font_t *ps_font,
|
||||
cairo_scaled_font_t *scaled_font)
|
||||
{
|
||||
ps_font->base.hash = (unsigned long) scaled_font;
|
||||
ps_font->scaled_font = scaled_font;
|
||||
}
|
||||
|
||||
cairo_ps_font_t *
|
||||
_cairo_ps_font_create (cairo_scaled_font_t *scaled_font,
|
||||
unsigned int id)
|
||||
{
|
||||
cairo_ps_font_t *ps_font = malloc (sizeof (cairo_ps_font_t));
|
||||
if (!ps_font)
|
||||
return NULL;
|
||||
_cairo_ps_font_key_init (ps_font, scaled_font);
|
||||
ps_font->glyphs = _cairo_hash_table_create (_cairo_ps_glyph_equal);
|
||||
if (!ps_font->glyphs) {
|
||||
free (ps_font);
|
||||
return NULL;
|
||||
}
|
||||
ps_font->max_glyph = 0;
|
||||
ps_font->output_font = id;
|
||||
cairo_scaled_font_reference (ps_font->scaled_font);
|
||||
return ps_font;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_ps_font_destroy_glyph (cairo_ps_font_t *ps_font,
|
||||
cairo_ps_glyph_t *ps_glyph)
|
||||
{
|
||||
_cairo_hash_table_remove (ps_font->glyphs, &ps_glyph->base);
|
||||
_cairo_ps_glyph_destroy (ps_glyph);
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_ps_font_destroy_glyph_callback (void *entry, void *closure)
|
||||
_cairo_sub_font_collect (void *entry, void *closure)
|
||||
{
|
||||
cairo_ps_glyph_t *ps_glyph = entry;
|
||||
cairo_ps_font_t *ps_font = closure;
|
||||
cairo_sub_font_t *sub_font = entry;
|
||||
cairo_sub_font_collection_t *collection = closure;
|
||||
cairo_scaled_font_subset_t subset;
|
||||
int i;
|
||||
|
||||
_cairo_ps_font_destroy_glyph (ps_font, ps_glyph);
|
||||
}
|
||||
for (i = 0; i <= sub_font->current_subset; i++) {
|
||||
collection->subset_id = i;
|
||||
|
||||
void
|
||||
_cairo_ps_font_destroy (cairo_ps_font_t *ps_font)
|
||||
{
|
||||
_cairo_hash_table_foreach (ps_font->glyphs,
|
||||
_cairo_ps_font_destroy_glyph_callback,
|
||||
ps_font);
|
||||
_cairo_hash_table_destroy (ps_font->glyphs);
|
||||
cairo_scaled_font_destroy (ps_font->scaled_font);
|
||||
free (ps_font);
|
||||
}
|
||||
collection->num_glyphs = 0;
|
||||
collection->max_glyph = 0;
|
||||
|
||||
void
|
||||
_cairo_ps_font_select_glyphs (void *entry, void *closure)
|
||||
{
|
||||
cairo_ps_glyph_t *ps_glyph = entry;
|
||||
cairo_ps_font_glyph_select_t *ps_glyph_select = closure;
|
||||
_cairo_hash_table_foreach (sub_font->sub_font_glyphs,
|
||||
_cairo_sub_font_glyph_collect, collection);
|
||||
|
||||
if (ps_glyph->output_glyph >> 8 == ps_glyph_select->subfont) {
|
||||
unsigned long sub_glyph = ps_glyph->output_glyph & 0xff;
|
||||
ps_glyph_select->glyphs[sub_glyph] = ps_glyph;
|
||||
if (sub_glyph >= ps_glyph_select->numglyph)
|
||||
ps_glyph_select->numglyph = sub_glyph + 1;
|
||||
/* Ensure the resulting array has no uninitialized holes */
|
||||
assert (collection->num_glyphs == collection->max_glyph + 1);
|
||||
|
||||
subset.scaled_font = sub_font->scaled_font;
|
||||
subset.font_id = sub_font->font_id;
|
||||
subset.subset_id = i;
|
||||
subset.glyphs = collection->glyphs;
|
||||
subset.num_glyphs = collection->num_glyphs;
|
||||
|
||||
(collection->font_subset_callback) (&subset,
|
||||
collection->font_subset_callback_closure);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_scaled_font_subsets_t *
|
||||
_cairo_scaled_font_subsets_create (int max_glyphs_per_subset)
|
||||
{
|
||||
cairo_scaled_font_subsets_t *subsets;
|
||||
|
||||
subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
|
||||
if (subsets == NULL)
|
||||
return NULL;
|
||||
|
||||
subsets->max_glyphs_per_subset_limit = max_glyphs_per_subset;
|
||||
subsets->max_glyphs_per_subset_used = 0;
|
||||
subsets->num_sub_fonts = 0;
|
||||
|
||||
subsets->sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
|
||||
if (! subsets->sub_fonts) {
|
||||
free (subsets);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return subsets;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
|
||||
{
|
||||
_cairo_hash_table_foreach (subsets->sub_fonts, _cairo_sub_font_pluck, subsets->sub_fonts);
|
||||
_cairo_hash_table_destroy (subsets->sub_fonts);
|
||||
free (subsets);
|
||||
}
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
|
||||
cairo_scaled_font_t *scaled_font,
|
||||
unsigned long scaled_font_glyph_index,
|
||||
unsigned int *font_id,
|
||||
unsigned int *subset_id,
|
||||
unsigned int *subset_glyph_index)
|
||||
{
|
||||
cairo_sub_font_t key, *sub_font;
|
||||
cairo_status_t status;
|
||||
|
||||
_cairo_sub_font_init_key (&key, scaled_font);
|
||||
if (! _cairo_hash_table_lookup (subsets->sub_fonts, &key.base,
|
||||
(cairo_hash_entry_t **) &sub_font))
|
||||
{
|
||||
sub_font = _cairo_sub_font_create (subsets, scaled_font,
|
||||
subsets->num_sub_fonts++,
|
||||
subsets->max_glyphs_per_subset_limit);
|
||||
if (sub_font == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
status = _cairo_hash_table_insert (subsets->sub_fonts,
|
||||
&sub_font->base);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
*font_id = sub_font->font_id;
|
||||
|
||||
return _cairo_sub_font_map_glyph (sub_font, scaled_font_glyph_index,
|
||||
subset_id, subset_glyph_index);
|
||||
}
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_scaled_font_subsets_foreach (cairo_scaled_font_subsets_t *font_subsets,
|
||||
cairo_scaled_font_subset_callback_func_t font_subset_callback,
|
||||
void *closure)
|
||||
{
|
||||
cairo_sub_font_collection_t collection;
|
||||
|
||||
collection.glyphs_size = font_subsets->max_glyphs_per_subset_used;
|
||||
collection.glyphs = malloc (collection.glyphs_size * sizeof(unsigned long));
|
||||
if (collection.glyphs == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
collection.font_subset_callback = font_subset_callback;
|
||||
collection.font_subset_callback_closure = closure;
|
||||
|
||||
_cairo_hash_table_foreach (font_subsets->sub_fonts,
|
||||
_cairo_sub_font_collect, &collection);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue