From da2c5e44abd98f1f1aed4f716b7e9bc97a667058 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2006 00:37:58 -0700 Subject: [PATCH 1/2] Allow hash entry deletion during cairo_hash_foreach --- src/cairo-hash.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cairo-hash.c b/src/cairo-hash.c index e44ab3025..9ea5909c8 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_keys_equal_func_t keys_equal) } hash_table->live_entries = 0; + hash_table->locked = 0; return hash_table; } @@ -188,6 +190,8 @@ _cairo_hash_table_destroy (cairo_hash_table_t *hash_table) /* 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_table_t *hash_table) 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_table_t *hash_table, * 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_table_t *hash_table, 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); } From 0727e3c1a980f57d48f3dfaee801f05e5395a71a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2006 00:38:43 -0700 Subject: [PATCH 2/2] Use Type3 fonts for PostScript output. No bitmap support yet. --- src/cairo-ps-surface.c | 737 ++++++++++++++++++++++++----------------- 1 file changed, 440 insertions(+), 297 deletions(-) diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 756b774e4..24e31111d 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_surface_t *surface) "%%%%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_internal (cairo_output_stream_t *stream, 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_t *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_surface) _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 *abstract_surface) 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 *surface, cairo_pattern_t *pattern) } } -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 *abstract_surface, 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_surface, 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 *abstract_surface, 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 *abstract_surface, _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 cairo_ps_surface_backend = { 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 */