[cairo-commit] 6 commits - src/cairoint.h src/cairo-scaled-font.c src/cairo-traps.c src/cairo-xlib-private.h src/cairo-xlib-screen.c src/cairo-xlib-surface.c test/radial-gradient-svg-ref.png

Carl Worth cworth at kemper.freedesktop.org
Wed Mar 14 17:38:17 PDT 2007


 src/cairo-scaled-font.c          |    9 ++
 src/cairo-traps.c                |  103 +++++---------------------
 src/cairo-xlib-private.h         |   15 +++
 src/cairo-xlib-screen.c          |  153 ++++++++++++++++++++++++++++++---------
 src/cairo-xlib-surface.c         |   25 ++++++
 src/cairoint.h                   |    3 
 test/radial-gradient-svg-ref.png |binary
 7 files changed, 195 insertions(+), 113 deletions(-)

New commits:
diff-tree 6ff2439b33a9da9a517325bfd472e8cb1fdd4992 (from 53ae6ea957bac141c033f41276d93bab3a25009f)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 14 16:33:01 2007 -0700

    Implement _cairo_traps_tessellate_triangle with _cairo_traps_tessellate_convex_quad
    
    The newly rewritten convex_quad code is actually simpler than the
    triangle code being replaced here. This also allows us to throw
    away the problematic _compute_x function which can't handle
    horizontal lines, (divide by zero). So the cairo world becomes a
    better place.

diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 0dd416f..dd5837b 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -50,9 +50,6 @@ _cairo_traps_add_trap (cairo_traps_t *tr
 static int
 _compare_point_fixed_by_y (const void *av, const void *bv);
 
-static cairo_fixed_16_16_t
-_compute_x (cairo_line_t *line, cairo_fixed_t y);
-
 void
 _cairo_traps_init (cairo_traps_t *traps)
 {
@@ -314,57 +311,20 @@ _cairo_trapezoid_array_translate_and_sca
     }
 }
 
+/* A triangle is simply a degenerate case of a convex
+ * quadrilateral. We would not benefit from having any distinct
+ * implementation of triangle vs. quadrilateral tessellation here. */
 cairo_status_t
 _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
 {
-    cairo_line_t line;
-    cairo_fixed_16_16_t intersect;
-    cairo_point_t tsort[3];
-
-    memcpy (tsort, t, 3 * sizeof (cairo_point_t));
-    qsort (tsort, 3, sizeof (cairo_point_t), _compare_point_fixed_by_y);
-
-    /* horizontal top edge requires special handling */
-    if (tsort[0].y == tsort[1].y) {
-	if (tsort[0].x < tsort[1].x)
-	    _cairo_traps_add_trap_from_points (traps,
-					       tsort[1].y, tsort[2].y,
-					       tsort[0], tsort[2],
-					       tsort[1], tsort[2]);
-	else
-	    _cairo_traps_add_trap_from_points (traps,
-					       tsort[1].y, tsort[2].y,
-					       tsort[1], tsort[2],
-					       tsort[0], tsort[2]);
-	return traps->status;
-    }
+    cairo_point_t quad[4];
 
-    line.p1 = tsort[0];
-    line.p2 = tsort[1];
+    quad[0] = t[0];
+    quad[1] = t[0];
+    quad[2] = t[1];
+    quad[3] = t[2];
 
-    intersect = _compute_x (&line, tsort[2].y);
-
-    if (intersect < tsort[2].x) {
-	_cairo_traps_add_trap_from_points (traps,
-					   tsort[0].y, tsort[1].y,
-					   tsort[0], tsort[1],
-					   tsort[0], tsort[2]);
-	_cairo_traps_add_trap_from_points (traps,
-					   tsort[1].y, tsort[2].y,
-					   tsort[1], tsort[2],
-					   tsort[0], tsort[2]);
-    } else {
-	_cairo_traps_add_trap_from_points (traps,
-					   tsort[0].y, tsort[1].y,
-					   tsort[0], tsort[2],
-					   tsort[0], tsort[1]);
-	_cairo_traps_add_trap_from_points (traps,
-					   tsort[1].y, tsort[2].y,
-					   tsort[0], tsort[2],
-					   tsort[1], tsort[2]);
-    }
-
-    return traps->status;
+    return _cairo_traps_tessellate_convex_quad (traps, quad);
 }
 
 cairo_status_t
@@ -515,37 +475,6 @@ _cairo_traps_tessellate_convex_quad (cai
     return traps->status;
 }
 
-/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero
-   for horizontal lines. Now, we "know" that when we are tessellating
-   polygons that the polygon data structure discards all horizontal
-   edges, but there's nothing here to guarantee that. I suggest the
-   following:
-
-   A) Move all of the polygon tessellation code out of xrtraps.c and
-      into xrpoly.c, (in order to be in the same module as the code
-      discarding horizontal lines).
-
-   OR
-
-   B) Re-implement the line intersection in a way that avoids all
-      division by zero. Here's one approach. The only disadvantage
-      might be that that there are not meaningful names for all of the
-      sub-computations -- just a bunch of determinants. I haven't
-      looked at complexity, (both are probably similar and it probably
-      doesn't matter much anyway).
- */
-
-
-static cairo_fixed_16_16_t
-_compute_x (cairo_line_t *line, cairo_fixed_t y)
-{
-    cairo_fixed_16_16_t dx = line->p2.x - line->p1.x;
-    cairo_fixed_32_32_t ex = (cairo_fixed_48_16_t) (y - line->p1.y) * (cairo_fixed_48_16_t) dx;
-    cairo_fixed_16_16_t dy = line->p2.y - line->p1.y;
-
-    return line->p1.x + (ex / dy);
-}
-
 static cairo_bool_t
 _cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt)
 {
diff-tree 53ae6ea957bac141c033f41276d93bab3a25009f (from 96d8f58daf279238d3a1dfcd4ed3710014e2aeea)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 14 16:30:48 2007 -0700

    Fix _cairo_traps_tessellate_convex_quad to handle a == b
    
    This case was found in an attempt to use the convex_quad function
    for tessellating triangles as well. Fortunately the fix is very
    easy.

diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 96b0a45..0dd416f 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2002 Keith Packard
+ * Copyright © 2007 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -408,7 +409,18 @@ _cairo_traps_tessellate_convex_quad (cai
      * This should hopefully be made clear in the lame ASCII art
      * below. Since the same slope comparison is used in all cases, we
      * compute it before testing for the Y-value sort. */
-    _cairo_slope_init (&ab, &q[a], &q[b]);
+
+    /* Note: If a == b then the ab slope doesn't give us any
+     * information. In that case, we can replace it with the ac (or
+     * equivalenly the bc) slope which gives us exactly the same
+     * information we need. At worst the names of the identifiers ab
+     * and b_left_of_d are inaccurate in this case, (would be ac, and
+     * c_left_of_d). */
+    if (q[a].x == q[b].x && q[a].y == q[b].y)
+	_cairo_slope_init (&ab, &q[a], &q[c]);
+    else
+	_cairo_slope_init (&ab, &q[a], &q[b]);
+
     _cairo_slope_init (&ad, &q[a], &q[d]);
 
     b_left_of_d = (_cairo_slope_compare (&ab, &ad) > 0);
diff-tree 96d8f58daf279238d3a1dfcd4ed3710014e2aeea (from 52405533b1b191ff98ef3cbc20eaf55e97c8049c)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Mar 13 20:17:22 2007 +0000

    Clear the XRender data on display closure.
    
    Use the new hook functions to register a callback for xlib to clear
    the private glyph data when the display is closed. In order to do this
    we need to reset the glyph cache inside the generic scaled font as well.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 6a0d3e4..49bdaae 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2268,6 +2268,24 @@ typedef struct _cairo_xlib_surface_font_
     XRenderPictFormat	*xrender_format;
 } cairo_xlib_surface_font_private_t;
 
+static void
+_cairo_xlib_surface_remove_scaled_font (Display *dpy,
+	                               void    *data)
+{
+    cairo_scaled_font_t *scaled_font = data;
+    cairo_xlib_surface_font_private_t	*font_private = scaled_font->surface_private;
+
+    _cairo_scaled_font_reset_cache (scaled_font);
+
+    /* separate function to avoid deadlock if we tried to remove the
+     * close display hook ala _cairo_xlib_surface_scaled_font_fini() */
+    if (font_private) {
+	XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset);
+	free (font_private);
+	scaled_font->surface_private = NULL;
+    }
+}
+
 static cairo_status_t
 _cairo_xlib_surface_font_init (Display		    *dpy,
 			       cairo_scaled_font_t  *scaled_font,
@@ -2275,6 +2293,11 @@ _cairo_xlib_surface_font_init (Display		
 {
     cairo_xlib_surface_font_private_t	*font_private;
 
+    if (!_cairo_xlib_add_close_display_hook (dpy,
+		_cairo_xlib_surface_remove_scaled_font,
+		scaled_font, scaled_font))
+	return CAIRO_STATUS_NO_MEMORY;
+
     font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
     if (!font_private)
 	return CAIRO_STATUS_NO_MEMORY;
@@ -2285,6 +2308,7 @@ _cairo_xlib_surface_font_init (Display		
     font_private->glyphset = XRenderCreateGlyphSet (dpy, font_private->xrender_format);
     scaled_font->surface_private = font_private;
     scaled_font->surface_backend = &cairo_xlib_surface_backend;
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -2294,6 +2318,7 @@ _cairo_xlib_surface_scaled_font_fini (ca
     cairo_xlib_surface_font_private_t	*font_private = scaled_font->surface_private;
 
     if (font_private) {
+	_cairo_xlib_remove_close_display_hook (font_private->dpy, scaled_font);
 	XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset);
 	free (font_private);
     }
diff-tree 52405533b1b191ff98ef3cbc20eaf55e97c8049c (from ad7698feb5f818ba2657b01bbc04f7fb537c1297)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Mar 13 20:42:09 2007 +0000

    Privately export a function to reset the scaled font's glyph caches.

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 0162a0d..6efde80 100755
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -391,6 +391,15 @@ _cairo_scaled_font_thaw_cache (cairo_sca
 }
 
 void
+_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
+{
+    _cairo_cache_destroy (scaled_font->glyphs);
+    scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
+					       _cairo_scaled_glyph_destroy,
+					       max_glyphs_cached_per_font);
+}
+
+void
 _cairo_scaled_font_set_metrics (cairo_scaled_font_t	    *scaled_font,
 				cairo_font_extents_t	    *fs_metrics)
 {
diff --git a/src/cairoint.h b/src/cairoint.h
index 17f8187..0ac5961 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1633,6 +1633,9 @@ 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 void
 _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
 			      cairo_status_t status);
 
diff-tree ad7698feb5f818ba2657b01bbc04f7fb537c1297 (from 3d3173d176bc959682a35674c31d3155e8642c41)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Mar 13 20:11:49 2007 +0000

    Introduce hooks for _cairo_xlib_close_display()
    
    This patch adds a simple hook data type for a notifier style callback
    and introduces two functions to manipulate a list of callbacks for
    cleaning up on display closure.

diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index ddac05a..8ba46a2 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -37,6 +37,14 @@
 #include "cairo-xlib.h"
 
 typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
+typedef struct _cairo_xlib_hook cairo_xlib_hook_t;
+
+struct _cairo_xlib_hook {
+    cairo_xlib_hook_t *next;
+    void (*func) (Display *display, void *data);
+    void *data;
+    void *key;
+};
 
 struct _cairo_xlib_screen_info {
     cairo_xlib_screen_info_t *next;
@@ -46,11 +54,18 @@ struct _cairo_xlib_screen_info {
     cairo_bool_t has_render;
 
     cairo_font_options_t font_options;
+
+    cairo_xlib_hook_t *close_display_hooks;
 };
 
 cairo_private cairo_xlib_screen_info_t *
 _cairo_xlib_screen_info_get (Display *display, Screen *screen);
 
+cairo_private cairo_bool_t
+_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, void *key);
+cairo_private void
+_cairo_xlib_remove_close_display_hook (Display *display, void *key);
+
 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
 
 #include "cairo-xlib-xrender.h"
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 2316fe1..4c34608 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -247,31 +247,36 @@ CAIRO_MUTEX_DECLARE(_xlib_screen_mutex);
 
 static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL;
 
-/* XXX: From this function we should also run through and cleanup
- * anything else that still has a pointer to this Display*. For
- * example, we should clean up any Xlib-specific glyph caches. */
 static int
 _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
 {
-    cairo_xlib_screen_info_t *info, *prev;
+    cairo_xlib_screen_info_t *info, **prev, *next;
 
     /*
      * Unhook from the global list
      */
     CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
 
-    prev = NULL;
-    for (info = _cairo_xlib_screen_list; info; info = info->next) {
+    prev = &_cairo_xlib_screen_list;
+    for (info = _cairo_xlib_screen_list; info; info = next) {
+	next = info->next;
 	if (info->display == dpy) {
-	    if (prev)
-		prev->next = info->next;
-	    else
-		_cairo_xlib_screen_list = info->next;
+	    *prev = next;
+	    /* call all registered shutdown routines */
+	    while (info->close_display_hooks) {
+		cairo_xlib_hook_t *hook = info->close_display_hooks;
+		info->close_display_hooks = hook->next;
+
+		hook->func (dpy, hook->data);
+
+		free (hook);
+	    }
 	    free (info);
-	    break;
+	} else {
+	    prev = &info->next;
 	}
-	prev = info;
     }
+    *prev = NULL;
     CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
 
     /* Return value in accordance with requirements of
@@ -291,6 +296,11 @@ _cairo_xlib_screen_info_reset (void)
 
     for (info = _cairo_xlib_screen_list; info; info = next) {
 	next = info->next;
+	while (info->close_display_hooks) {
+	    cairo_xlib_hook_t *hook = info->close_display_hooks;
+	    info->close_display_hooks = hook->next;
+	    free (hook);
+	}
 	free (info);
     }
 
@@ -300,8 +310,8 @@ _cairo_xlib_screen_info_reset (void)
 
 }
 
-cairo_xlib_screen_info_t *
-_cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
+static cairo_xlib_screen_info_t *
+_cairo_xlib_screen_info_get_unlocked (Display *dpy, Screen *screen)
 {
     cairo_xlib_screen_info_t *info;
     cairo_xlib_screen_info_t **prev;
@@ -309,26 +319,15 @@ _cairo_xlib_screen_info_get (Display *dp
     XExtCodes *codes;
     cairo_bool_t seen_display = FALSE;
 
-    /* There is an apparent deadlock between this mutex and the
-     * mutex for the display, but it's actually safe. For the
-     * app to call XCloseDisplay() while any other thread is
-     * inside this function would be an error in the logic
-     * app, and the CloseDisplay hook is the only other place we
-     * acquire this mutex.
-     */
-    CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
-
     for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next)
     {
 	if (info->display == dpy) {
 	    seen_display = TRUE;
-	    if (info->screen == screen)
-	    {
+	    if (info->screen == screen || screen == NULL) {
 		/*
 		 * MRU the list
 		 */
-		if (prev != &_cairo_xlib_screen_list)
-		{
+		if (prev != &_cairo_xlib_screen_list) {
 		    *prev = info->next;
 		    info->next = _cairo_xlib_screen_list;
 		    _cairo_xlib_screen_list = info;
@@ -339,18 +338,17 @@ _cairo_xlib_screen_info_get (Display *dp
     }
 
     if (info)
-	goto out;
+	return info;
 
     info = malloc (sizeof (cairo_xlib_screen_info_t));
     if (!info)
-	goto out;
+	return NULL;
 
     if (!seen_display) {
 	codes = XAddExtension (dpy);
 	if (!codes) {
 	    free (info);
-	    info = NULL;
-	    goto out;
+	    return NULL;
 	}
 
 	XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
@@ -361,17 +359,108 @@ _cairo_xlib_screen_info_get (Display *dp
     info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
 			(XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0));
 
+    info->close_display_hooks = NULL;
+
     _cairo_xlib_init_screen_font_options (info);
 
     info->next = _cairo_xlib_screen_list;
     _cairo_xlib_screen_list = info;
 
- out:
+    return info;
+}
+cairo_xlib_screen_info_t *
+_cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
+{
+    cairo_xlib_screen_info_t *info;
+
+    /* There is an apparent deadlock between this mutex and the
+     * mutex for the display, but it's actually safe. For the
+     * app to call XCloseDisplay() while any other thread is
+     * inside this function would be an error in the logic
+     * app, and the CloseDisplay hook is the only other place we
+     * acquire this mutex.
+     */
+    CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
+
+    info = _cairo_xlib_screen_info_get_unlocked (dpy, screen);
+
     CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
 
     return info;
 }
 
+cairo_bool_t
+_cairo_xlib_add_close_display_hook (Display *dpy, void (*func) (Display *, void *), void *data, void *key)
+{
+    cairo_xlib_screen_info_t *info;
+    cairo_xlib_hook_t *hook;
+    cairo_xlib_hook_t **prev;
+    cairo_bool_t success = FALSE;
+
+    CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
+
+    info = _cairo_xlib_screen_info_get_unlocked (dpy,  NULL);
+    if (!info)
+	goto unlock;
+
+    for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next)
+    {
+	if (hook->key == key) {
+	    /*
+	     * MRU the list
+	     */
+	    if (prev != &info->close_display_hooks) {
+		*prev = hook->next;
+		hook->next = info->close_display_hooks;
+		info->close_display_hooks = hook;
+	    }
+	    break;
+	}
+    }
+
+    if (!hook) {
+	hook = malloc (sizeof (cairo_xlib_hook_t));
+	if (!hook)
+	    goto unlock;
+	hook->func = func;
+	hook->data = data;
+	hook->key = key;
+	hook->next = info->close_display_hooks;
+	info->close_display_hooks = hook;
+    }
+
+    success = TRUE;
+ unlock:
+    CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
+    return success;
+}
+
+void
+_cairo_xlib_remove_close_display_hook (Display *dpy, void *key)
+{
+    cairo_xlib_screen_info_t *info;
+    cairo_xlib_hook_t *hook;
+    cairo_xlib_hook_t **prev;
+
+    CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
+
+    info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL);
+    if (!info)
+	goto unlock;
+
+    for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next)
+    {
+	if (hook->key == key) {
+	    *prev = hook->next;
+	    free (hook);
+	    break;
+	}
+    }
+
+unlock:
+    CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
+}
+
 void
 _cairo_xlib_screen_reset_static_data (void)
 {
diff-tree 3d3173d176bc959682a35674c31d3155e8642c41 (from 75201c12be74055d6209d48d1d698797665a70b4)
Author: Carl Worth <cworth at cworth.org>
Date:   Wed Mar 14 16:56:45 2007 -0700

    Add svg-specific reference image for radial-gradient test.
    
    This isn't strictly needed, (pdiff allows the test to pass without the
    image), but it sure runs faster this way.

diff --git a/test/radial-gradient-svg-ref.png b/test/radial-gradient-svg-ref.png
new file mode 100644
index 0000000..7e04701
Binary files /dev/null and b/test/radial-gradient-svg-ref.png differ


More information about the cairo-commit mailing list