[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