[cairo-commit] 12 commits - doc/public src/cairo-gstate.c src/cairo.h src/cairoint.h src/cairo-pattern.c src/cairo-scaled-font.c src/cairo-scaled-font-private.h src/cairo-surface.c src/cairo-user-font.c src/cairo-xlib-surface.c test/Makefile.am test/surface-finish-twice.c test/user-font-proxy.c test/user-font-proxy-ps-ref.png test/user-font-proxy-ref.png test/user-font-proxy-svg-ref.png

Behdad Esfahbod behdad at kemper.freedesktop.org
Sat May 24 17:56:45 PDT 2008


 doc/public/cairo-sections.txt          |    1 
 doc/public/tmpl/cairo-scaled-font.sgml |    9 +
 src/cairo-gstate.c                     |   93 +++++++++++++---
 src/cairo-pattern.c                    |   17 ++
 src/cairo-scaled-font-private.h        |    1 
 src/cairo-scaled-font.c                |   70 ++++++++++--
 src/cairo-surface.c                    |    7 -
 src/cairo-user-font.c                  |    5 
 src/cairo-xlib-surface.c               |    2 
 src/cairo.h                            |    4 
 src/cairoint.h                         |   43 ++++---
 test/Makefile.am                       |    4 
 test/surface-finish-twice.c            |    6 -
 test/user-font-proxy-ps-ref.png        |binary
 test/user-font-proxy-ref.png           |binary
 test/user-font-proxy-svg-ref.png       |binary
 test/user-font-proxy.c                 |  190 +++++++++++++++++++++++++++++++++
 17 files changed, 392 insertions(+), 60 deletions(-)

New commits:
commit 4c1c9d33b1b89d8098c06bbb4d430811947ed86c
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 20:48:38 2008 -0400

    [user-font] Release fontmap lock around user callback
    
    This makes the user-font-proxy to work now.

diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index df2a18c..886250a 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -326,9 +326,12 @@ _cairo_user_font_face_scaled_font_create (void                        *abstract_
 	return status;
     }
 
-    if (font_face->scaled_font_methods.init != NULL)
+    if (font_face->scaled_font_methods.init != NULL) {
+	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 	status = font_face->scaled_font_methods.init (&user_scaled_font->base,
 						      &font_extents);
+	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+    }
 
     if (status == CAIRO_STATUS_SUCCESS)
 	status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents);
commit 127c4b8e643560c029818509e20fc5ca87408611
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 20:48:07 2008 -0400

    [src/cairo-scaled-font] Only take fontmap mutex if touching it

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index b2f0c14..5cafbfe 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -811,20 +811,24 @@ slim_hidden_def (cairo_scaled_font_reference);
 void
 cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
 {
-    cairo_scaled_font_map_t *font_map;
     cairo_scaled_font_t *lru = NULL;
 
     if (scaled_font == NULL ||
 	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
 	return;
 
-    font_map = _cairo_scaled_font_map_lock ();
-    assert (font_map != NULL);
-
     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
 
     if (_cairo_reference_count_dec_and_test (&scaled_font->ref_count)) {
-	if (scaled_font->hash_entry.hash != ZOMBIE) {
+	cairo_scaled_font_map_t *font_map;
+
+	/* don't use _cairo_scaled_font_map_lock() to not create it if it's
+	 * NULL. if font_map is NULL, it means we are in the process of
+	 * destructing it.  don't err and continue */
+	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+	font_map = cairo_scaled_font_map;
+
+	if (font_map && scaled_font->hash_entry.hash != ZOMBIE) {
 	    /* Rather than immediately destroying this object, we put it into
 	     * the font_map->holdovers array in case it will get used again
 	     * soon (and is why we must hold the lock over the atomic op on
@@ -849,8 +853,9 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
 	    font_map->num_holdovers++;
 	} else
 	    lru = scaled_font;
+
+	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
     }
-    _cairo_scaled_font_map_unlock ();
 
     /* If we pulled an item from the holdovers array, (while the font
      * map lock was held, of course), then there is no way that anyone
commit a715671c6f3bd2f6f692b79cba7d7f7bc49f06f9
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 20:34:41 2008 -0400

    [test/user-font-proxy] New test using fonts inside a user-font
    
    PDF fails and needs some fixes in the PDF surface instead of a new
    ref image IMO.

diff --git a/test/Makefile.am b/test/Makefile.am
index 0723c23..f8256b4 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -159,6 +159,7 @@ unantialiased-shapes$(EXEEXT)				\
 unbounded-operator$(EXEEXT)				\
 user-data$(EXEEXT)					\
 user-font$(EXEEXT)					\
+user-font-proxy$(EXEEXT)				\
 zero-alpha$(EXEEXT)
 
 # XXX: Here are some existing tests that are currently disabled for
@@ -701,6 +702,9 @@ REFERENCE_IMAGES = \
 	user-font-ref.png	\
 	user-font-pdf-ref.png	\
 	user-font-svg-ref.png	\
+	user-font-proxy-ref.png	\
+	user-font-proxy-ps-ref.png	\
+	user-font-proxy-svg-ref.png	\
 	unbounded-operator-quartz-ref.png	\
 	unbounded-operator-quartz-rgb24-ref.png	\
 	xlib-expose-event-ref.png \
diff --git a/test/user-font-proxy-ps-ref.png b/test/user-font-proxy-ps-ref.png
new file mode 100644
index 0000000..78bee6c
Binary files /dev/null and b/test/user-font-proxy-ps-ref.png differ
diff --git a/test/user-font-proxy-ref.png b/test/user-font-proxy-ref.png
new file mode 100644
index 0000000..ebd9719
Binary files /dev/null and b/test/user-font-proxy-ref.png differ
diff --git a/test/user-font-proxy-svg-ref.png b/test/user-font-proxy-svg-ref.png
new file mode 100644
index 0000000..e5e9e9a
Binary files /dev/null and b/test/user-font-proxy-svg-ref.png differ
diff --git a/test/user-font-proxy.c b/test/user-font-proxy.c
new file mode 100644
index 0000000..f54139c
--- /dev/null
+++ b/test/user-font-proxy.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright © 2006, 2008 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Contributor(s):
+ *	Kristian Høgsberg <krh at redhat.com>
+ *	Behdad Esfahbod <behdad at behdad.org>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cairo-test.h"
+
+/*#define ROTATED 1*/
+
+#define BORDER 10
+#define TEXT_SIZE 64
+#define WIDTH  (TEXT_SIZE * 12 + 2*BORDER)
+#define HEIGHT ((TEXT_SIZE + 2*BORDER)*2)
+#define TEXT   "geez... cairo user-font"
+
+static cairo_test_draw_function_t draw;
+
+cairo_test_t test = {
+    "user-font-proxy",
+    "Tests a user-font using a native font in its render_glyph",
+#ifndef ROTATED
+    WIDTH, HEIGHT,
+#else
+    WIDTH, WIDTH,
+#endif
+    draw
+};
+
+static cairo_user_data_key_t fallback_scaled_font_key;
+
+static cairo_status_t
+test_scaled_font_init (cairo_scaled_font_t  *scaled_font,
+		       cairo_font_extents_t *extents)
+{
+  cairo_t *cr;
+  cairo_surface_t *surface;
+  cairo_matrix_t ctm;
+  cairo_font_options_t *font_options;
+  cairo_scaled_font_t *fallback_scaled_font;
+
+  /* painful way to get default font face used by toy api */
+  surface = cairo_image_surface_create (CAIRO_FORMAT_A8, 0, 0);
+  cr = cairo_create (surface);
+  cairo_surface_destroy (surface);
+
+  cairo_set_font_size (cr, 1.);
+  cairo_scaled_font_get_scale_matrix (scaled_font, &ctm);
+  cairo_set_matrix (cr, &ctm);
+
+  font_options = cairo_font_options_create ();
+  cairo_scaled_font_get_font_options (scaled_font, font_options);
+  cairo_set_font_options (cr, font_options);
+  cairo_font_options_destroy (font_options);
+
+  fallback_scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr)),
+  cairo_scaled_font_set_user_data (scaled_font,
+				   &fallback_scaled_font_key,
+				   fallback_scaled_font,
+				   cairo_scaled_font_destroy);
+
+  cairo_destroy (cr);
+
+  cairo_scaled_font_extents (fallback_scaled_font, extents);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+test_scaled_font_render_glyph (cairo_scaled_font_t  *scaled_font,
+			       unsigned long         glyph,
+			       cairo_t              *cr,
+			       cairo_text_extents_t *extents)
+{
+    char text[2] = "\0";
+
+    /* XXX only works for ASCII.  need ucs4_to_utf8 :( */
+    text[0] = glyph;
+
+    cairo_set_scaled_font (cr,
+			   cairo_scaled_font_get_user_data (scaled_font,
+							    &fallback_scaled_font_key));
+    cairo_show_text (cr, text);
+    cairo_text_extents (cr, text, extents);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_font_face_t *
+get_user_font_face (void)
+{
+    static cairo_font_face_t *user_font_face = NULL;
+
+    if (!user_font_face) {
+	user_font_face = cairo_user_font_face_create ();
+	cairo_user_font_face_set_init_func             (user_font_face, test_scaled_font_init);
+	cairo_user_font_face_set_render_glyph_func     (user_font_face, test_scaled_font_render_glyph);
+    }
+
+    return user_font_face;
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    const char text[] = TEXT;
+    cairo_font_extents_t font_extents;
+    cairo_text_extents_t extents;
+
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+#ifdef ROTATED
+    cairo_translate (cr, TEXT_SIZE, 0);
+    cairo_rotate (cr, .6);
+#endif
+
+    cairo_set_font_face (cr, get_user_font_face ());
+    cairo_set_font_size (cr, TEXT_SIZE);
+
+    cairo_font_extents (cr, &font_extents);
+    cairo_text_extents (cr, text, &extents);
+
+    /* logical boundaries in red */
+    cairo_move_to (cr, 0, BORDER);
+    cairo_rel_line_to (cr, WIDTH, 0);
+    cairo_move_to (cr, 0, BORDER + font_extents.ascent);
+    cairo_rel_line_to (cr, WIDTH, 0);
+    cairo_move_to (cr, 0, BORDER + font_extents.ascent + font_extents.descent);
+    cairo_rel_line_to (cr, WIDTH, 0);
+    cairo_move_to (cr, BORDER, 0);
+    cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE);
+    cairo_move_to (cr, BORDER + extents.x_advance, 0);
+    cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE);
+    cairo_set_source_rgb (cr, 1, 0, 0);
+    cairo_set_line_width (cr, 2);
+    cairo_stroke (cr);
+
+    /* ink boundaries in green */
+    cairo_rectangle (cr,
+		     BORDER + extents.x_bearing, BORDER + font_extents.ascent + extents.y_bearing,
+		     extents.width, extents.height);
+    cairo_set_source_rgb (cr, 0, 1, 0);
+    cairo_set_line_width (cr, 2);
+    cairo_stroke (cr);
+
+    /* text in gray */
+    cairo_set_source_rgb (cr, 0, 0, 0);
+    cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
+    cairo_show_text (cr, text);
+
+
+    /* filled version of text in light blue */
+    cairo_set_source_rgb (cr, 0, 0, 1);
+    cairo_move_to (cr, BORDER, BORDER + font_extents.height + BORDER + font_extents.ascent);
+    cairo_text_path (cr, text);
+    cairo_fill (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+    return cairo_test (&test);
+}
commit c914377f35e1e3396571fc027b7f53854db7d896
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 20:33:15 2008 -0400

    Add public API cairo_scaled_font_get_scale_matrix()

diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index b71b97a..c6d5287 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -278,6 +278,7 @@ cairo_scaled_font_get_font_face
 cairo_scaled_font_get_font_options
 cairo_scaled_font_get_font_matrix
 cairo_scaled_font_get_ctm
+cairo_scaled_font_get_scale_matrix
 cairo_scaled_font_get_type
 cairo_scaled_font_get_reference_count
 cairo_scaled_font_set_user_data
diff --git a/doc/public/tmpl/cairo-scaled-font.sgml b/doc/public/tmpl/cairo-scaled-font.sgml
index 4c8ee6c..97922ef 100644
--- a/doc/public/tmpl/cairo-scaled-font.sgml
+++ b/doc/public/tmpl/cairo-scaled-font.sgml
@@ -155,6 +155,15 @@ size and transformation and a certain set of font options.
 @ctm: 
 
 
+<!-- ##### FUNCTION cairo_scaled_font_get_scale_matrix ##### -->
+<para>
+
+</para>
+
+ at scaled_font: 
+ at scale_matrix: 
+
+
 <!-- ##### FUNCTION cairo_scaled_font_get_type ##### -->
 <para>
 
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 8104d05..b2f0c14 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1990,6 +1990,30 @@ cairo_scaled_font_get_ctm (cairo_scaled_font_t	*scaled_font,
 slim_hidden_def (cairo_scaled_font_get_ctm);
 
 /**
+ * cairo_scaled_font_get_scale_matrix:
+ * @scaled_font: a #cairo_scaled_font_t
+ * @scale_matrix: return value for the matrix
+ *
+ * Stores the scale matrix of @scaled_font into @matrix.
+ * The scale matrix is product of the font matrix and the ctm
+ * associated with the scaled font, and hence is the matrix mapping from
+ * font space to device space.
+ *
+ * Since: 1.8
+ **/
+void
+cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t	*scaled_font,
+				    cairo_matrix_t	*scale_matrix)
+{
+    if (scaled_font->status) {
+	cairo_matrix_init_identity (scale_matrix);
+	return;
+    }
+
+    *scale_matrix = scaled_font->scale;
+}
+
+/**
  * cairo_scaled_font_get_font_options:
  * @scaled_font: a #cairo_scaled_font_t
  * @options: return value for the font options
diff --git a/src/cairo.h b/src/cairo.h
index 19ef7f0..179c45f 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1276,6 +1276,10 @@ cairo_scaled_font_get_ctm (cairo_scaled_font_t	*scaled_font,
 			   cairo_matrix_t	*ctm);
 
 cairo_public void
+cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t	*scaled_font,
+				    cairo_matrix_t	*scale_matrix);
+
+cairo_public void
 cairo_scaled_font_get_font_options (cairo_scaled_font_t		*scaled_font,
 				    cairo_font_options_t	*options);
 
commit 90d62a0d33cd9e0736bb747d7f025a0fb1025732
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 20:31:24 2008 -0400

    [src] Make make check pass

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 1cb0f40..86aeff9 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -662,6 +662,7 @@ cairo_surface_flush (cairo_surface_t *surface)
 	    status = _cairo_surface_set_error (surface, status);
     }
 }
+slim_hidden_def (cairo_surface_flush);
 
 /**
  * cairo_surface_mark_dirty:
diff --git a/src/cairoint.h b/src/cairoint.h
index 841fe58..54cd0d8 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2375,6 +2375,7 @@ slim_hidden_proto (cairo_stroke_preserve);
 slim_hidden_proto (cairo_surface_create_similar);
 slim_hidden_proto (cairo_surface_destroy);
 slim_hidden_proto (cairo_surface_finish);
+slim_hidden_proto (cairo_surface_flush);
 slim_hidden_proto (cairo_surface_get_content);
 slim_hidden_proto (cairo_surface_get_device_offset);
 slim_hidden_proto (cairo_surface_get_font_options);
commit 9cc147a142e98b49b7f8289a340f2e498970ef99
Author: Jeff Muizelaar <jeff at infidigm.net>
Date:   Sat May 24 20:17:38 2008 -0400

    Avoid deadlock when clearing caches
    
    cairo_surface_destroy and _cairo_scaled_font_fini will call destroy closures
    which may call functions that attempt to acquire the mutex resulting in a
    deadlock. We fix this by releasing the lock for the call to
    cairo_surface_destroy or _cairo_scaled_font_fini.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index c0bfbaf..2685d49 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1516,13 +1516,20 @@ UNLOCK:
 static void
 _cairo_pattern_reset_solid_surface_cache (void)
 {
-    int i;
-
     CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
 
-    for (i = 0; i < solid_surface_cache.size; i++)
-	cairo_surface_destroy (solid_surface_cache.cache[i].surface);
-    solid_surface_cache.size = 0;
+    /* remove surfaces starting from the end so that solid_surface_cache.cache
+     * is always in a consistent state when we release the mutex. */
+    while (solid_surface_cache.size) {
+	cairo_surface_t *surface = solid_surface_cache.cache[solid_surface_cache.size-1].surface;
+	solid_surface_cache.size--;
+
+	/* release the lock to avoid the possibility of a recursive
+	 * deadlock when the scaled font destroy closure gets called */
+	CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
+	cairo_surface_destroy (surface);
+	CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
+    }
 
     CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
 }
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index b46f8dc..8104d05 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -347,7 +347,6 @@ _cairo_scaled_font_map_unlock (void)
 void
 _cairo_scaled_font_map_destroy (void)
 {
-    int i;
     cairo_scaled_font_map_t *font_map;
     cairo_scaled_font_t *scaled_font;
 
@@ -358,15 +357,23 @@ _cairo_scaled_font_map_destroy (void)
         goto CLEANUP_MUTEX_LOCK;
     }
 
-    for (i = 0; i < font_map->num_holdovers; i++) {
-	scaled_font = font_map->holdovers[i];
-	/* We should only get here through the reset_static_data path
-	 * and there had better not be any active references at that
-	 * point. */
+    /* remove scaled_fonts starting from the end so that font_map->holdovers
+     * is always in a consistent state when we release the mutex. */
+    while (font_map->num_holdovers) {
+	scaled_font = font_map->holdovers[font_map->num_holdovers-1];
+
 	assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
 	_cairo_hash_table_remove (font_map->hash_table,
 				  &scaled_font->hash_entry);
+
+	font_map->num_holdovers--;
+
+	/* release the lock to avoid the possibility of a recursive
+	 * deadlock when the scaled font destroy closure gets called */
+	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
 	_cairo_scaled_font_fini (scaled_font);
+	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
+
 	free (scaled_font);
     }
 
commit 4957a7894741f5a1941dcc06cc5a3a0551afcdad
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 15:16:44 2008 -0400

    [test/surface-finish-twice.c] Adapt to recent change that multiple finish is ok

diff --git a/test/surface-finish-twice.c b/test/surface-finish-twice.c
index 62acf71..3751939 100644
--- a/test/surface-finish-twice.c
+++ b/test/surface-finish-twice.c
@@ -63,7 +63,11 @@ draw (cairo_t *cr, int width, int height)
 	return CAIRO_TEST_FAILURE;
 
     cairo_surface_finish (surface);
-    if (cairo_surface_status (surface) != CAIRO_STATUS_SURFACE_FINISHED)
+    if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
+	return CAIRO_TEST_FAILURE;
+
+    cairo_surface_finish (surface);
+    if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
 	return CAIRO_TEST_FAILURE;
 
     cairo_surface_destroy (surface);
commit a30209402c7160af257e1ea027e9e2cdab5b5aec
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 14:57:56 2008 -0400

    [cairo-gstate] Drop glyphs out of surface boundaries in show_glyphs()

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 0f35b7f..fc69661 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -64,7 +64,8 @@ static void
 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
                                            const cairo_glyph_t *glyphs,
                                            int                  num_glyphs,
-                                           cairo_glyph_t       *transformed_glyphs);
+                                           cairo_glyph_t       *transformed_glyphs,
+					   int		       *num_transformed_glyphs);
 
 cairo_status_t
 _cairo_gstate_init (cairo_gstate_t  *gstate,
@@ -1543,7 +1544,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
     }
 
     _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
-                                               transformed_glyphs);
+                                               transformed_glyphs, &num_glyphs);
 
     status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
     if (status)
@@ -1587,7 +1588,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
-                                               transformed_glyphs);
+                                               transformed_glyphs, NULL);
 
     CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
     status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
@@ -1623,39 +1624,94 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
  * @num_glyphs: the number of elements in @glyphs
  * @transformed_glyphs: a pre-allocated array of at least @num_glyphs
  * #cairo_glyph_t objects
+ * @num_transformed_glyphs: the number of elements in @transformed_glyphs
+ * after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
+ * dropped
  *
  * Transform an array of glyphs to backend space by first adding the offset
  * of the font matrix, then transforming from user space to backend space.
  * The result of the transformation is placed in @transformed_glyphs.
+ *
+ * This also uses information from the scaled font and the surface to
+ * cull/drop glyphs that will not be visible.
  **/
 static void
 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
                                            const cairo_glyph_t *glyphs,
                                            int                  num_glyphs,
-                                           cairo_glyph_t *transformed_glyphs)
+                                           cairo_glyph_t       *transformed_glyphs,
+					   int		       *num_transformed_glyphs)
 {
-    int i;
+    int i, j;
     cairo_matrix_t *ctm = &gstate->ctm;
+    cairo_matrix_t *font_matrix = &gstate->font_matrix;
     cairo_matrix_t *device_transform = &gstate->target->device_transform;
+    cairo_bool_t drop = FALSE;
+    double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+
+    if (num_transformed_glyphs != NULL) {
+	cairo_rectangle_int_t surface_extents;
+	double scale = _cairo_scaled_font_get_max_scale (gstate->scaled_font);
+
+	drop = TRUE;
+
+	if (_cairo_surface_get_extents (gstate->target, &surface_extents))
+	    drop = FALSE; /* unbounded surface */
+	else {
+	    /* XXX We currently drop any glyphs that has its position outside
+	     * of the surface boundaries by a safety margin depending on the
+	     * font scale.  This however can fail in extreme cases where the
+	     * font has really long swashes for example...  We can correctly
+	     * handle that by looking the glyph up and using its device bbox
+	     * to device if it's going to be visible, but I'm not inclined to
+	     * do that now.
+	     */
+	    x1 = surface_extents.x - 2*scale;
+	    y1 = surface_extents.y - 2*scale;
+	    x2 = surface_extents.x + surface_extents.width  + scale;
+	    y2 = surface_extents.y + surface_extents.height + scale;
+	}
+
+	if (!drop)
+	    *num_transformed_glyphs = num_glyphs;
+    } else
+	num_transformed_glyphs = &j;
+
+#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
 
     if (_cairo_matrix_is_identity (ctm) &&
         _cairo_matrix_is_identity (device_transform) &&
-	gstate->font_matrix.x0 == 0 && gstate->font_matrix.y0 == 0)
+	font_matrix->x0 == 0 && font_matrix->y0 == 0)
     {
-        memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+	if (!drop)
+	    memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+	else {
+	    for (j = 0, i = 0; i < num_glyphs; i++)
+	    {
+		transformed_glyphs[j].index = glyphs[i].index;
+		transformed_glyphs[j].x = glyphs[i].x;
+		transformed_glyphs[j].y = glyphs[i].y;
+		if (KEEP_GLYPH (transformed_glyphs[j]))
+		    j++;
+	    }
+	    *num_transformed_glyphs = j;
+	}
     }
     else if (_cairo_matrix_is_translation (ctm) &&
              _cairo_matrix_is_translation (device_transform))
     {
-        double tx = gstate->font_matrix.x0 + ctm->x0 + device_transform->x0;
-        double ty = gstate->font_matrix.y0 + ctm->y0 + device_transform->y0;
+        double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
+        double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
 
-        for (i = 0; i < num_glyphs; i++)
+        for (j = 0, i = 0; i < num_glyphs; i++)
         {
-            transformed_glyphs[i].index = glyphs[i].index;
-            transformed_glyphs[i].x = glyphs[i].x + tx;
-            transformed_glyphs[i].y = glyphs[i].y + ty;
+            transformed_glyphs[j].index = glyphs[i].index;
+            transformed_glyphs[j].x = glyphs[i].x + tx;
+            transformed_glyphs[j].y = glyphs[i].y + ty;
+	    if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
+		j++;
         }
+	*num_transformed_glyphs = j;
     }
     else
     {
@@ -1669,12 +1725,15 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
         cairo_matrix_multiply (&aggregate_transform,
                                &aggregate_transform, device_transform);
 
-        for (i = 0; i < num_glyphs; i++)
+        for (j = 0, i = 0; i < num_glyphs; i++)
         {
-            transformed_glyphs[i] = glyphs[i];
+            transformed_glyphs[j] = glyphs[i];
             cairo_matrix_transform_point (&aggregate_transform,
-                                          &transformed_glyphs[i].x,
-                                          &transformed_glyphs[i].y);
+                                          &transformed_glyphs[j].x,
+                                          &transformed_glyphs[j].y);
+	    if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
+		j++;
         }
+	*num_transformed_glyphs = j;
     }
 }
commit 1b5e2144fb77ffeb0626dff558d9d82351279e0b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 14:57:31 2008 -0400

    [cairo-scaled-font] Implement _cairo_scaled_font_get_max_scale()

diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 4cf6a37..86fbec6 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -94,6 +94,7 @@ struct _cairo_scaled_font {
     /* "live" scaled_font members */
     cairo_matrix_t scale;	  /* font space => device space */
     cairo_matrix_t scale_inverse; /* device space => font space */
+    double max_scale;		  /* maximum x/y expansion of scale */
     cairo_font_extents_t extents; /* user space */
 
     /* The mutex protects modification to all subsequent fields. */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index b4c1ad3..b46f8dc 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -195,6 +195,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
     TRUE,			/* finished */
     { 1., 0., 0., 1., 0, 0},	/* scale */
     { 1., 0., 0., 1., 0, 0},	/* scale_inverse */
+    1.,				/* max_scale */
     { 0., 0., 0., 0., 0. },	/* extents */
     CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
     NULL,			/* glyphs */
@@ -480,6 +481,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
 			   &scaled_font->font_matrix,
 			   &scaled_font->ctm);
 
+    scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
+				  fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
     scaled_font->scale_inverse = scaled_font->scale;
     status = cairo_matrix_invert (&scaled_font->scale_inverse);
     if (status) {
@@ -1906,6 +1909,13 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
     return status;
 }
 
+double
+_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
+{
+    return scaled_font->max_scale;
+}
+
+
 /**
  * cairo_scaled_font_get_font_face:
  * @scaled_font: a #cairo_scaled_font_t
diff --git a/src/cairoint.h b/src/cairoint.h
index 2a7356e..841fe58 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1551,6 +1551,9 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
 			    cairo_scaled_glyph_info_t info,
 			    cairo_scaled_glyph_t **scaled_glyph_ret);
 
+cairo_private double
+_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font);
+
 cairo_private void
 _cairo_scaled_font_map_destroy (void);
 
commit 479936ecea5d0e7cf3eee1aad6b016067f63e20b
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 14:57:06 2008 -0400

    [cairoint] Sort prototypes

diff --git a/src/cairoint.h b/src/cairoint.h
index bf85e64..2a7356e 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1267,25 +1267,6 @@ _cairo_color_equal (const cairo_color_t *color_a,
 
 /* cairo-font-face.c */
 
-cairo_private void
-_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font);
-
-cairo_private void
-_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font);
-
-cairo_private void
-_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font);
-
-cairo_private cairo_status_t
-_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
-			      cairo_status_t status);
-
-cairo_private cairo_scaled_font_t *
-_cairo_scaled_font_create_in_error (cairo_status_t status);
-
-cairo_private void
-_cairo_scaled_font_reset_static_data (void);
-
 extern const cairo_private cairo_font_face_t _cairo_font_face_nil;
 
 cairo_private void
@@ -1471,6 +1452,26 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t	*path,
 
 /* cairo-scaled-font.c */
 
+cairo_private void
+_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font);
+
+cairo_private cairo_status_t
+_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
+			      cairo_status_t status);
+
+cairo_private cairo_scaled_font_t *
+_cairo_scaled_font_create_in_error (cairo_status_t status);
+
+cairo_private void
+_cairo_scaled_font_reset_static_data (void);
+
+
 cairo_private cairo_status_t
 _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
 			 cairo_font_face_t		   *font_face,
commit e638e7652f8be552b50927bd332e9f46dcd92ab7
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 14:25:13 2008 -0400

    [cairo-xlib] Fix bug introduced in yesterday's code shuffling.  Oops.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 20dc969..ec66c4d 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -3424,7 +3424,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
     }
 
     if (num_elts)
-	status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, num_glyphs,
+	status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, i,
 							scaled_font, op, src, attributes,
 							num_elts, width, glyphset_info);
 
commit 31c68e708f18c1f81efc3590346eeb684ef3702d
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sat May 24 13:17:31 2008 -0400

    [cairo-surface] Minor code reshuffling

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 7ded02d..1cb0f40 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2131,7 +2131,6 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
     cairo_status_t status;
     cairo_scaled_font_t *dev_scaled_font = scaled_font;
     cairo_pattern_t *dev_source;
-    cairo_matrix_t font_matrix;
 
     assert (! surface->is_snapshot);
 
@@ -2147,14 +2146,13 @@ _cairo_surface_show_glyphs (cairo_surface_t	*surface,
     if (status)
 	return _cairo_surface_set_error (surface, status);
 
-    cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
-
     if (_cairo_surface_has_device_transform (surface) &&
 	! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
     {
 	cairo_font_options_t font_options;
-	cairo_matrix_t dev_ctm;
+	cairo_matrix_t dev_ctm, font_matrix;
 
+	cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
 	cairo_scaled_font_get_ctm (scaled_font, &dev_ctm);
 	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform);
 	cairo_scaled_font_get_font_options (scaled_font, &font_options);


More information about the cairo-commit mailing list