[cairo-commit] 3 commits - src/cairo-ps-surface.c
Carl Worth
cworth at kemper.freedesktop.org
Wed Apr 12 14:24:42 PDT 2006
src/cairo-ps-surface.c | 737 +++++++++++++++++++++++++++++--------------------
1 files changed, 440 insertions(+), 297 deletions(-)
New commits:
diff-tree 6a5d8fc7ffb5f425ceffd313b8a875f38126b324 (from parents)
Merge: b30e281627d86f3c0d0f4d5008bbbf7e77c09350 0727e3c1a980f57d48f3dfaee801f05e5395a71a
Author: Carl Worth <cworth at cworth.org>
Date: Wed Apr 12 14:15:08 2006 -0700
Merge branch 'ps-type3' into cairo (no bitmap support for type 3 yet).
Conflicts:
src/cairo-hash.c
src/cairo-ps-surface.c
diff --cc src/cairo-ps-surface.c
index 2787538,24e3111..93a3e93
@@@ -316,12 -693,9 +694,8 @@@
ps_surface->x_dpi = x_dpi;
ps_surface->y_dpi = y_dpi;
- #if DONE_ADDING_DEVICE_SCALE_SUPPORT_AFTER_SWITCHING_TO_PAGINATED
- ps_surface->base.device_x_scale = ps_surface->x_dpi / 72.0;
- ps_surface->base.device_y_scale = ps_surface->y_dpi / 72.0;
- #endif
}
-/* XXX */
static cairo_status_t
_cairo_ps_surface_finish (void *abstract_surface)
{
@@@ -337,16 -709,6 +710,8 @@@
_cairo_ps_surface_emit_footer (surface);
- #if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- for (i = 0; i < surface->fonts.num_elements; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &subset);
- _cairo_font_subset_destroy (subset);
- }
- _cairo_array_fini (&surface->fonts);
- #endif
-
+ _cairo_output_stream_close (surface->stream);
+ status = _cairo_output_stream_get_status (surface->stream);
_cairo_output_stream_destroy (surface->stream);
fclose (surface->tmpfile);
diff-tree 0727e3c1a980f57d48f3dfaee801f05e5395a71a (from da2c5e44abd98f1f1aed4f716b7e9bc97a667058)
Author: Keith Packard <keithp at neko.keithp.com>
Date: Sun Apr 9 00:38:43 2006 -0700
Use Type3 fonts for PostScript output. No bitmap support yet.
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 756b774..24e3111 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -60,6 +60,27 @@ static void
_cairo_ps_set_paginated_mode (cairo_surface_t *target,
cairo_paginated_mode_t mode);
+/*
+ * 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.
+ */
+
+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_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_ps_surface {
cairo_surface_t base;
@@ -79,17 +100,86 @@ typedef struct cairo_ps_surface {
cairo_paginated_mode_t paginated_mode;
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- cairo_array_t fonts;
-#endif
+ cairo_hash_table_t *fonts;
+ unsigned int max_font;
+
} cairo_ps_surface_t;
#define PS_SURFACE_DPI_DEFAULT 300.0
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
-static cairo_int_status_t
-_cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface);
-#endif
+typedef struct
+{
+ cairo_output_stream_t *output_stream;
+ cairo_bool_t has_current_point;
+} cairo_ps_surface_path_info_t;
+
+static cairo_status_t
+_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
+{
+ cairo_ps_surface_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f moveto ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+ info->has_current_point = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
+{
+ cairo_ps_surface_path_info_t *info = closure;
+ const char *ps_operator;
+
+ if (info->has_current_point)
+ ps_operator = "lineto";
+ else
+ ps_operator = "moveto";
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f %s ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y),
+ ps_operator);
+ info->has_current_point = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_path_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
+{
+ cairo_ps_surface_path_info_t *info = closure;
+
+ _cairo_output_stream_printf (info->output_stream,
+ "%f %f %f %f %f %f curveto ",
+ _cairo_fixed_to_double (b->x),
+ _cairo_fixed_to_double (b->y),
+ _cairo_fixed_to_double (c->x),
+ _cairo_fixed_to_double (c->y),
+ _cairo_fixed_to_double (d->x),
+ _cairo_fixed_to_double (d->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_path_close_path (void *closure)
+{
+ cairo_ps_surface_path_info_t *info = closure;
+
+ if (info->has_current_point)
+ _cairo_output_stream_printf (info->output_stream,
+ "closepath\n");
+ info->has_current_point = FALSE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
static void
_cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
@@ -117,9 +207,295 @@ _cairo_ps_surface_emit_header (cairo_ps_
"%%%%EndComments\n");
}
+static cairo_bool_t
+_cairo_ps_glyph_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;
+
+ return ps_glyph_a->base.hash == ps_glyph_b->base.hash;
+}
+
+static void
+_cairo_ps_glyph_key_init (cairo_ps_glyph_t *ps_glyph,
+ unsigned long index)
+{
+ ps_glyph->base.hash = index;
+}
+
+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)
+ return NULL;
+ _cairo_ps_glyph_key_init (ps_glyph, index);
+ ps_glyph->output_glyph = ps_font->max_glyph++;
+ return ps_glyph;
+}
+
+static void
+_cairo_ps_glyph_destroy (cairo_ps_glyph_t *ps_glyph)
+{
+ free (ps_glyph);
+}
+
+static cairo_status_t
+_cairo_ps_glyph_find (cairo_ps_font_t *font,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long index,
+ cairo_ps_glyph_t **result)
+{
+ cairo_ps_glyph_t key;
+ cairo_ps_glyph_t *ps_glyph;
+ cairo_status_t status;
+
+ _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)
+ return CAIRO_STATUS_NO_MEMORY;
+ status = _cairo_hash_table_insert (font->glyphs, &ps_glyph->base);
+ if (status)
+ return status;
+ }
+ *result = ps_glyph;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static cairo_ps_font_t *
+_cairo_ps_font_create (cairo_ps_surface_t *surface,
+ cairo_scaled_font_t *scaled_font)
+{
+ 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 = surface->max_font++;
+ cairo_scaled_font_reference (ps_font->scaled_font);
+ return ps_font;
+}
+
+static void
+_cairo_ps_font_destroy_glyph (void *entry, void *closure)
+{
+ cairo_ps_glyph_t *ps_glyph = entry;
+ cairo_ps_font_t *ps_font = closure;
+
+ _cairo_hash_table_remove (ps_font->glyphs, &ps_glyph->base);
+ _cairo_ps_glyph_destroy (ps_glyph);
+}
+
+static void
+_cairo_ps_font_destroy (cairo_ps_font_t *ps_font)
+{
+ _cairo_hash_table_foreach (ps_font->glyphs,
+ _cairo_ps_font_destroy_glyph,
+ ps_font);
+ _cairo_hash_table_destroy (ps_font->glyphs);
+ cairo_scaled_font_destroy (ps_font->scaled_font);
+ free (ps_font);
+}
+
+static void
+_cairo_ps_surface_destroy_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_font_find (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 (surface, scaled_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;
+}
+
+typedef struct _cairo_ps_font_glyph_select {
+ cairo_ps_glyph_t **glyphs;
+ int subfont;
+ int numglyph;
+} cairo_ps_font_glyph_select_t;
+
+static 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;
+
+ 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;
+ }
+}
+
+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_scaled_glyph_t *scaled_glyph;
+ cairo_status_t status;
+ cairo_ps_surface_path_info_t info;
+
+ _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,
+ CAIRO_SCALED_GLYPH_INFO_METRICS|
+ CAIRO_SCALED_GLYPH_INFO_PATH,
+ &scaled_glyph);
+ /*
+ * 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,
+ CAIRO_SCALED_GLYPH_INFO_METRICS|
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+ if (status) {
+ _cairo_output_stream_printf (surface->final_stream, "\t\t}\n");
+ return status;
+ }
+ _cairo_output_stream_printf (surface->final_stream,
+ "%f %f %f %f 0 0 setcachedevice\n",
+ _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
+ -_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
+ _cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
+ -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
+
+ info.output_stream = surface->final_stream;
+ info.has_current_point = FALSE;
+
+ status = _cairo_path_fixed_interpret (scaled_glyph->path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_ps_surface_path_move_to,
+ _cairo_ps_surface_path_line_to,
+ _cairo_ps_surface_path_curve_to,
+ _cairo_ps_surface_path_close_path,
+ &info);
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "fill\n");
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "\t\t}\n");
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_ps_surface_emit_font (void *entry, 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;
+
+ _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_glyph, 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");
+ }
+ _cairo_ps_surface_destroy_font (surface, ps_font);
+}
+
+
static void
_cairo_ps_surface_emit_fonts (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;
}
static void
@@ -172,23 +548,25 @@ _cairo_ps_surface_create_for_stream_inte
return (cairo_surface_t*) &_cairo_surface_nil;
}
+ 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;
surface->height = height;
surface->x_dpi = PS_SURFACE_DPI_DEFAULT;
surface->y_dpi = PS_SURFACE_DPI_DEFAULT;
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
-#if DONE_ADDING_DEVICE_SCALE_SUPPORT_AFTER_SWITCHING_TO_PAGINATED
- surface->base.device_x_scale = surface->x_dpi / 72.0;
- surface->base.device_y_scale = surface->y_dpi / 72.0;
-#endif
surface->need_start_page = TRUE;
surface->num_pages = 0;
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- _cairo_array_init (&surface->fonts, sizeof (cairo_font_subset_t *));
-#endif
-
return _cairo_paginated_surface_create (&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
width, height,
@@ -315,10 +693,6 @@ cairo_ps_surface_set_dpi (cairo_surface_
ps_surface->x_dpi = x_dpi;
ps_surface->y_dpi = y_dpi;
-#if DONE_ADDING_DEVICE_SCALE_SUPPORT_AFTER_SWITCHING_TO_PAGINATED
- ps_surface->base.device_x_scale = ps_surface->x_dpi / 72.0;
- ps_surface->base.device_y_scale = ps_surface->y_dpi / 72.0;
-#endif
}
/* XXX */
@@ -329,21 +703,12 @@ _cairo_ps_surface_finish (void *abstract
_cairo_ps_surface_emit_header (surface);
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- _cairo_ps_surface_write_font_subsets (surface);
-#endif
+ _cairo_ps_surface_emit_fonts (surface);
+
_cairo_ps_surface_emit_body (surface);
_cairo_ps_surface_emit_footer (surface);
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- for (i = 0; i < surface->fonts.num_elements; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &subset);
- _cairo_font_subset_destroy (subset);
- }
- _cairo_array_fini (&surface->fonts);
-#endif
-
_cairo_output_stream_destroy (surface->stream);
fclose (surface->tmpfile);
@@ -405,119 +770,6 @@ _cairo_ps_surface_show_page (void *abstr
return CAIRO_STATUS_SUCCESS;
}
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
-static cairo_font_subset_t *
-_cairo_ps_surface_get_font (cairo_ps_surface_t *surface,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_status_t status;
- cairo_unscaled_font_t *unscaled_font;
- cairo_font_subset_t *subset;
- unsigned int num_fonts, i;
-
- /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */
- if (! _cairo_scaled_font_is_ft (scaled_font))
- return NULL;
-
- /* 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 (&surface->fonts);
- for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &subset);
- if (subset->unscaled_font == unscaled_font)
- return subset;
- }
-
- subset = _cairo_font_subset_create (unscaled_font);
- if (subset == NULL)
- return NULL;
-
- subset->font_id = surface->fonts.num_elements;
-
- status = _cairo_array_append (&surface->fonts, &subset);
- if (status) {
- _cairo_font_subset_destroy (subset);
- return NULL;
- }
-
- return subset;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_write_type42_dict (cairo_ps_surface_t *surface,
- cairo_font_subset_t *subset)
-{
- const char *data;
- unsigned long data_size;
- cairo_status_t status;
- int i;
-
- status = CAIRO_STATUS_SUCCESS;
-
- /* FIXME: Figure out document structure convention for fonts */
-
- _cairo_output_stream_printf (surface->stream,
- "11 dict begin\n"
- "/FontType 42 def\n"
- "/FontName /f%d def\n"
- "/PaintType 0 def\n"
- "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
- "/FontBBox [ 0 0 0 0 ] def\n"
- "/Encoding 256 array def\n"
- "0 1 255 { Encoding exch /.notdef put } for\n",
- subset->font_id);
-
- /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
-
- for (i = 1; i < subset->num_glyphs; i++)
- _cairo_output_stream_printf (surface->stream,
- "Encoding %d /g%d put\n", i, i);
-
- _cairo_output_stream_printf (surface->stream,
- "/CharStrings %d dict dup begin\n"
- "/.notdef 0 def\n",
- subset->num_glyphs);
-
- for (i = 1; i < subset->num_glyphs; i++)
- _cairo_output_stream_printf (surface->stream,
- "/g%d %d def\n", i, i);
-
- _cairo_output_stream_printf (surface->stream,
- "end readonly def\n");
-
- status = _cairo_font_subset_generate (subset, &data, &data_size);
-
- /* FIXME: We need to break up fonts bigger than 64k so we don't
- * exceed string size limitation. At glyph boundaries. Stupid
- * postscript. */
- _cairo_output_stream_printf (surface->stream,
- "/sfnts [<");
-
- _cairo_output_stream_write_hex_string (surface->stream, data, data_size);
-
- _cairo_output_stream_printf (surface->stream,
- ">] def\n"
- "FontName currentdict end definefont pop\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface)
-{
- cairo_font_subset_t *subset;
- int i;
-
- for (i = 0; i < surface->fonts.num_elements; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &subset);
- _cairo_ps_surface_write_type42_dict (surface, subset);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-#endif
-
static cairo_bool_t
color_is_gray (cairo_color_t *color)
{
@@ -1052,79 +1304,6 @@ emit_pattern (cairo_ps_surface_t *surfac
}
}
-typedef struct
-{
- cairo_output_stream_t *output_stream;
- cairo_bool_t has_current_point;
-} cairo_ps_surface_path_info_t;
-
-static cairo_status_t
-_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
-{
- cairo_ps_surface_path_info_t *info = closure;
-
- _cairo_output_stream_printf (info->output_stream,
- "%f %f moveto ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
- info->has_current_point = TRUE;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
-{
- cairo_ps_surface_path_info_t *info = closure;
- const char *ps_operator;
-
- if (info->has_current_point)
- ps_operator = "lineto";
- else
- ps_operator = "moveto";
-
- _cairo_output_stream_printf (info->output_stream,
- "%f %f %s ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y),
- ps_operator);
- info->has_current_point = TRUE;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- cairo_ps_surface_path_info_t *info = closure;
-
- _cairo_output_stream_printf (info->output_stream,
- "%f %f %f %f %f %f curveto ",
- _cairo_fixed_to_double (b->x),
- _cairo_fixed_to_double (b->y),
- _cairo_fixed_to_double (c->x),
- _cairo_fixed_to_double (c->y),
- _cairo_fixed_to_double (d->x),
- _cairo_fixed_to_double (d->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_close_path (void *closure)
-{
- cairo_ps_surface_path_info_t *info = closure;
-
- _cairo_output_stream_printf (info->output_stream,
- "closepath\n");
- info->has_current_point = FALSE;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
_cairo_ps_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
@@ -1200,83 +1379,6 @@ _cairo_ps_surface_get_extents (void *
return CAIRO_STATUS_SUCCESS;
}
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
-static cairo_int_status_t
-_cairo_ps_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
- cairo_font_subset_t *subset;
- int i, subset_index;
-
- if (surface->fallback)
- return CAIRO_STATUS_SUCCESS;
-
- if (surface->need_start_page) {
- /* Optimize away erasing of nothing. */
- if (op == CAIRO_OPERATOR_CLEAR)
- return CAIRO_STATUS_SUCCESS;
- _cairo_ps_surface_start_page (surface);
- }
-
- /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */
- if (! _cairo_scaled_font_is_ft (scaled_font))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (surface->fallback)
- return CAIRO_STATUS_SUCCESS;
-
- if (pattern_operation_needs_fallback (op, pattern))
- return _cairo_ps_surface_add_fallback_area (surface, dest_x, dest_y, width, height);
-
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_old_show_glyphs\n");
-
- emit_pattern (surface, pattern);
-
- /* FIXME: Need to optimize this so we only do this sequence if the
- * font isn't already set. */
-
- subset = _cairo_ps_surface_get_font (surface, scaled_font);
- _cairo_output_stream_printf (stream,
- "/f%d findfont\n"
- "[ %f %f %f %f 0 0 ] makefont\n"
- "setfont\n",
- subset->font_id,
- scaled_font->scale.xx,
- scaled_font->scale.yx,
- scaled_font->scale.xy,
- -scaled_font->scale.yy);
-
- /* FIXME: Need to optimize per glyph code. Should detect when
- * glyphs share the same baseline and when the spacing corresponds
- * to the glyph widths. */
-
- for (i = 0; i < num_glyphs; i++) {
- subset_index = _cairo_font_subset_use_glyph (subset, glyphs[i].index);
- _cairo_output_stream_printf (stream,
- "%f %f moveto (\\%o) show\n",
- glyphs[i].x,
- glyphs[i].y,
- subset_index);
-
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-#endif
-
static cairo_int_status_t
_cairo_ps_surface_paint (void *abstract_surface,
cairo_operator_t op,
@@ -1496,6 +1598,14 @@ _cairo_ps_surface_fill (void *abstract_
return status;
}
+static char
+hex_digit (int i)
+{
+ i &= 0xf;
+ if (i < 10) return '0' + i;
+ return 'a' + (i - 10);
+}
+
static cairo_int_status_t
_cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
@@ -1508,6 +1618,10 @@ _cairo_ps_surface_show_glyphs (void
cairo_output_stream_t *stream = surface->stream;
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;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _analyze_operation (surface, op, source);
@@ -1523,7 +1637,40 @@ _cairo_ps_surface_show_glyphs (void
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_show_glyphs\n");
+ status = _cairo_ps_font_find (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_glyph_find (ps_font, scaled_font,
+ glyphs[i].index, &ps_glyph);
+ if (status) {
+ glyphs += i;
+ num_glyphs -= i;
+ goto fallback;
+ }
+ subfont = ps_glyph->output_glyph >> 8;
+ if (subfont != cur_subfont) {
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoFont-%d-%d 1 selectfont\n",
+ ps_font->output_font,
+ subfont);
+ cur_subfont = subfont;
+ }
+ _cairo_output_stream_printf (surface->stream,
+ "%f %f moveto <%c%c> show\n",
+ glyphs[i].x, glyphs[i].y,
+ hex_digit (ps_glyph->output_glyph >> 4),
+ hex_digit (ps_glyph->output_glyph));
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+fallback:
+
path = _cairo_path_fixed_create ();
_cairo_scaled_font_glyph_path (scaled_font, glyphs, num_glyphs, path);
status = _cairo_ps_surface_fill (abstract_surface, op, source,
@@ -1551,11 +1698,7 @@ static const cairo_surface_backend_t cai
NULL, /* set_clip_region */
_cairo_ps_surface_intersect_clip_path,
_cairo_ps_surface_get_extents,
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- _cairo_ps_surface_old_show_glyphs,
-#else
NULL, /* old_show_glyphs */
-#endif
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
diff-tree da2c5e44abd98f1f1aed4f716b7e9bc97a667058 (from ade195cdba5b0d13c121e44709151bfbb0c44085)
Author: Keith Packard <keithp at neko.keithp.com>
Date: Sun Apr 9 00:37:58 2006 -0700
Allow hash entry deletion during cairo_hash_foreach
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index e44ab30..9ea5909 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -124,6 +124,7 @@ struct _cairo_hash_table {
cairo_hash_entry_t **entries;
unsigned long live_entries;
+ unsigned long locked; /* don't resize array */
};
/**
@@ -163,6 +164,7 @@ _cairo_hash_table_create (cairo_hash_key
}
hash_table->live_entries = 0;
+ hash_table->locked = 0;
return hash_table;
}
@@ -188,6 +190,8 @@ _cairo_hash_table_destroy (cairo_hash_ta
/* The hash table must be empty. Otherwise, halt. */
assert (hash_table->live_entries == 0);
+ /* The hash table must be unlocked. Otherwise, halt. */
+ assert (hash_table->locked == 0);
free (hash_table->entries);
hash_table->entries = NULL;
@@ -298,6 +302,9 @@ _cairo_hash_table_resize (cairo_hash_ta
unsigned long high = hash_table->arrangement->high_water_mark;
unsigned long low = high >> 2;
+ /* The hash table must be unlocked. Otherwise, halt. */
+ assert (hash_table->locked == 0);
+
if (hash_table->live_entries >= low && hash_table->live_entries <= high)
return CAIRO_STATUS_SUCCESS;
@@ -502,7 +509,8 @@ _cairo_hash_table_remove (cairo_hash_tab
* memory to shrink the hash table. It does leave the table in a
* consistent state, and we've already succeeded in removing the
* entry, so we don't examine the failure status of this call. */
- _cairo_hash_table_resize (hash_table);
+ if (hash_table->locked == 0)
+ _cairo_hash_table_resize (hash_table);
}
/**
@@ -525,9 +533,13 @@ _cairo_hash_table_foreach (cairo_hash_ta
if (hash_table == NULL)
return;
+ /* Lock while walking to avoid missing entries on delete */
+ ++hash_table->locked;
for (i = 0; i < hash_table->arrangement->size; i++) {
entry = hash_table->entries[i];
if (ENTRY_IS_LIVE(entry))
hash_callback (entry, closure);
}
+ if (--hash_table->locked == 0)
+ _cairo_hash_table_resize (hash_table);
}
More information about the cairo-commit
mailing list