[cairo-commit] 8 commits - src/cairo.c src/cairo-gstate.c src/cairo-paginated-surface.c src/cairo-pattern.c test/.gitignore test/Makefile.am test/rel-path.c test/text-zero-len.c

Chris Wilson ickle at kemper.freedesktop.org
Sun Jan 13 03:15:38 PST 2008


 src/cairo-gstate.c            |   37 +++++++++++++++++++++++
 src/cairo-paginated-surface.c |    5 +--
 src/cairo-pattern.c           |    3 +
 src/cairo.c                   |    6 +++
 test/.gitignore               |    2 -
 test/Makefile.am              |    6 +--
 test/rel-path.c               |   66 ++++++++++++++++++++++++++++++++++++++++++
 test/text-zero-len.c          |   45 ++++++++++++++++++++++++++++
 8 files changed, 162 insertions(+), 8 deletions(-)

New commits:
commit 5e32dcf863cc8f40e2679c8c8c42e3ac927ab3c9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 13 11:10:28 2008 +0000

    [cairo-gstate] Check that the matrix remains invertible.
    
    Ensure that the ctm remains invertible after multiplying the user
    supplied matrices. Although the arguments are checked so that they are
    valid per se, we double check that the result after multiplication is
    still a valid invertible matrix. This should catch pathological cases
    where the user concatenates a long series of matrix operations, which
    either exceed our numerical limits or become degenerate through rounding
    errors.

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 1f040d0..508cf97 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -642,6 +642,10 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
     cairo_matrix_init_translate (&tmp, tx, ty);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
+    /* paranoid check against gradual numerical instability */
+    if (! _cairo_matrix_is_invertible (&gstate->ctm))
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+
     cairo_matrix_init_translate (&tmp, -tx, -ty);
     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
@@ -668,6 +672,10 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
     cairo_matrix_init_scale (&tmp, sx, sy);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
+    /* paranoid check against gradual numerical instability */
+    if (! _cairo_matrix_is_invertible (&gstate->ctm))
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+
     cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
@@ -695,6 +703,10 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
     cairo_matrix_init_rotate (&tmp, angle);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
+    /* paranoid check against gradual numerical instability */
+    if (! _cairo_matrix_is_invertible (&gstate->ctm))
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+
     cairo_matrix_init_rotate (&tmp, -angle);
     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
@@ -718,6 +730,10 @@ _cairo_gstate_transform (cairo_gstate_t	      *gstate,
     cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
+    /* paranoid check against gradual numerical instability */
+    if (! _cairo_matrix_is_invertible (&gstate->ctm))
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
commit 2f600affaa9ac3537013c69643878731a2f4389e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 13 11:02:55 2008 +0000

    [cairo-gstate] Add isfinite guards to the transformation ops.
    
    If we have isfinite() available use it to check that the user supplied
    arguments are valid.

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 5c626cd..1f040d0 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -35,11 +35,17 @@
  *	Carl D. Worth <cworth at cworth.org>
  */
 
+#define _GNU_SOURCE
+
 #include "cairoint.h"
 
 #include "cairo-clip-private.h"
 #include "cairo-gstate-private.h"
 
+#if _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE
+#define HAVE_ISFINITE 1
+#endif
+
 static cairo_status_t
 _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
 
@@ -623,8 +629,13 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
 {
     cairo_matrix_t tmp;
 
+#if HAVE_ISFINITE
+    if (! isfinite (tx) || ! isfinite (ty))
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+#else
     if (! (tx * tx >= 0.) || ! (ty * ty >= 0.)) /* check for NaNs */
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+#endif
 
     _cairo_gstate_unset_scaled_font (gstate);
 
@@ -644,8 +655,13 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
 
     if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+#if HAVE_ISFINITE
+    if (! isfinite (sx) || ! isfinite (sy))
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+#else
     if (! (sx * sx > 0.) || ! (sy * sy > 0.)) /* check for NaNs */
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+#endif
 
     _cairo_gstate_unset_scaled_font (gstate);
 
@@ -666,8 +682,13 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
     if (angle == 0.)
 	return CAIRO_STATUS_SUCCESS;
 
+#if HAVE_ISFINITE
+    if (! isfinite (angle))
+	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+#else
     if (! (angle * angle >= 0.)) /* check for NaNs */
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+#endif
 
     _cairo_gstate_unset_scaled_font (gstate);
 
commit 3fed79d1c24f07618243bb197b44a9fd106aebbc
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 13 10:28:11 2008 +0000

    [cairo-paginated-surface] Set error on surface for operations done its behalf.
    
    Ensure that the error is propagated to the target surface if we fail
    whilst performing an operation on its behalf, for example set the size
    of the paginated surface.

diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index eb9699a..6af4be6 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -149,7 +149,7 @@ _cairo_paginated_surface_set_size (cairo_surface_t	*surface,
 							  width, height);
     status = cairo_surface_status (paginated_surface->meta);
     if (status)
-	return status;
+	return _cairo_surface_set_error (surface, status);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -293,7 +293,8 @@ _paint_page (cairo_paginated_surface_t *surface)
     analysis = _cairo_analysis_surface_create (surface->target,
 					       surface->width, surface->height);
     if (analysis == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	return _cairo_surface_set_error (surface->target,
+		                         CAIRO_STATUS_NO_MEMORY);
 
     surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE);
     status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis);
commit 481b88dd6b19c267feaf05652974225e86aa8007
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jan 12 20:35:56 2008 +0000

    [cairo-pattern] Add an ASSERT_NOT_REACHED
    
    On the default case for an unknown pattern type, add an assert that the
    code is never reached, and just in case upgrade the error to a fatal
    PATTERN_TYPE_MISMATCH.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 050c0d4..ccd7622 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1828,7 +1828,8 @@ _cairo_pattern_acquire_surface (cairo_pattern_t		   *pattern,
 							     attributes);
     } break;
     default:
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	ASSERT_NOT_REACHED;
+	status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
     }
 
     return status;
commit 973d5fa8a50fbb0fb760f2e32a227a6238d074da
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jan 12 11:04:03 2008 +0000

    [test] Sort TESTS
    
    A couple of tests were out of order, causing a bit of confusion in the
    user.

diff --git a/test/.gitignore b/test/.gitignore
index f4aabd2..5665cbe 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -20,9 +20,9 @@ clip-push-group
 clip-twice
 clip-zero
 close-path
-composite-integer-translate-source
 composite-integer-translate-over
 composite-integer-translate-over-repeat
+composite-integer-translate-source
 copy-path
 coverage
 create-for-stream
diff --git a/test/Makefile.am b/test/Makefile.am
index b462470..8f5a198 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -28,8 +28,8 @@ dash-caps-joins$(EXEEXT)				\
 dash-no-dash$(EXEEXT)					\
 dash-offset-negative$(EXEEXT)				\
 dash-scale$(EXEEXT)					\
-dash-zero-length$(EXEEXT)				\
 dash-state$(EXEEXT)					\
+dash-zero-length$(EXEEXT)				\
 degenerate-path$(EXEEXT)				\
 degenerate-pen$(EXEEXT)					\
 device-offset$(EXEEXT)					\
@@ -84,10 +84,12 @@ paint-with-alpha$(EXEEXT)				\
 pattern-get-type$(EXEEXT)				\
 pattern-getters$(EXEEXT)				\
 pixman-rotate$(EXEEXT)					\
+push-group$(EXEEXT)					\
 radial-gradient$(EXEEXT)				\
 random-intersections$(EXEEXT)				\
 rectangle-rounding-error$(EXEEXT)			\
 rectilinear-stroke$(EXEEXT)				\
+rel-path$(EXEEXT)					\
 rgb24-ignore-alpha$(EXEEXT)				\
 rotate-image-surface-paint$(EXEEXT)			\
 scale-down-source-surface-paint$(EXEEXT)		\
@@ -122,8 +124,6 @@ truetype-tables$(EXEEXT)				\
 unantialiased-shapes$(EXEEXT)				\
 unbounded-operator$(EXEEXT)				\
 user-data$(EXEEXT)					\
-rel-path$(EXEEXT)					\
-push-group$(EXEEXT)					\
 zero-alpha$(EXEEXT)
 
 # XXX: Here are some existing tests that are currently disabled for
commit ac98c9e572135f5f46303ce49e6a04f86efe2676
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jan 12 10:49:48 2008 +0000

    [test/rel-path] Check that invalid relative paths raise an error.
    
    Check that NO_CURRENT_PATH is raised if a relative path op is used
    on a new path.

diff --git a/test/rel-path.c b/test/rel-path.c
index 1da3557..0f42321 100644
--- a/test/rel-path.c
+++ b/test/rel-path.c
@@ -33,9 +33,75 @@ cairo_test_t test = {
     draw
 };
 
+static cairo_status_t
+invalid_rel_move_to (cairo_surface_t *target)
+{
+    cairo_t *cr;
+    cairo_status_t status;
+
+    cr = cairo_create (target);
+    cairo_rel_move_to (cr, SIZE, SIZE/2);
+    status = cairo_status (cr);
+    cairo_destroy (cr);
+
+    return status;
+}
+
+static cairo_status_t
+invalid_rel_line_to (cairo_surface_t *target)
+{
+    cairo_t *cr;
+    cairo_status_t status;
+
+    cr = cairo_create (target);
+    cairo_rel_line_to (cr, -SIZE, SIZE/2);
+    status = cairo_status (cr);
+    cairo_destroy (cr);
+
+    return status;
+}
+
+static cairo_status_t
+invalid_rel_curve_to (cairo_surface_t *target)
+{
+    cairo_t *cr;
+    cairo_status_t status;
+
+    cr = cairo_create (target);
+    cairo_rel_curve_to (cr,
+			SIZE/2, -SIZE/2,
+			SIZE*2/3, -SIZE/3,
+			SIZE/2, -SIZE);
+    status = cairo_status (cr);
+    cairo_destroy (cr);
+
+    return status;
+}
+
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
+    cairo_status_t status;
+
+    /* first test that a relative move without a current point fails... */
+    status = invalid_rel_move_to (cairo_get_target (cr));
+    if (status != CAIRO_STATUS_NO_CURRENT_POINT) {
+	cairo_test_log ("Error: invalid cairo_rel_move_to() did not raise NO_CURRENT_POINT\n");
+	return CAIRO_TEST_FAILURE;
+    }
+
+    status = invalid_rel_line_to (cairo_get_target (cr));
+    if (status != CAIRO_STATUS_NO_CURRENT_POINT) {
+	cairo_test_log ("Error: invalid cairo_rel_line_to() did not raise NO_CURRENT_POINT\n");
+	return CAIRO_TEST_FAILURE;
+    }
+
+    status = invalid_rel_curve_to (cairo_get_target (cr));
+    if (status != CAIRO_STATUS_NO_CURRENT_POINT) {
+	cairo_test_log ("Error: invalid cairo_rel_curve_to() did not raise NO_CURRENT_POINT\n");
+	return CAIRO_TEST_FAILURE;
+    }
+
     cairo_set_source_rgb (cr, 1, 1, 1);
     cairo_move_to (cr, 0, 0);
     cairo_rel_move_to (cr, SIZE, SIZE/2);
commit 6cc75cfe5b962566938189b5a7dd63135e981300
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jan 12 10:30:15 2008 +0000

    [cairo] Harden the text API against NULL strings.
    
    Handle NULL strings in cairo_show_(text|glyph),
    cairo_(text|glyph)_(extents|path) without crashing.

diff --git a/src/cairo.c b/src/cairo.c
index 170082f..6136597 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -3019,6 +3019,9 @@ cairo_text_path  (cairo_t *cr, const char *utf8)
     if (cr->status)
 	return;
 
+    if (utf8 == NULL)
+	return;
+
     cairo_get_current_point (cr, &x, &y);
 
     status = _cairo_gstate_text_to_glyphs (cr->gstate, utf8,
@@ -3076,6 +3079,9 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
     if (cr->status)
 	return;
 
+    if (num_glyphs == 0)
+	return;
+
     status = _cairo_gstate_glyph_path (cr->gstate,
 				       glyphs, num_glyphs,
 				       cr->path);
commit 864dab828b4c860668adb48ff9361e9969b5259f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jan 12 10:01:36 2008 +0000

    [test/text-zero-len] Test passing NULLs to the API.
    
    Check that the public API handles NULL - at the moment the code
    is a little inconsistent and crashes!

diff --git a/test/text-zero-len.c b/test/text-zero-len.c
index 57c36fd..e64daa8 100644
--- a/test/text-zero-len.c
+++ b/test/text-zero-len.c
@@ -54,10 +54,22 @@ cairo_test_t test = {
     draw
 };
 
-/* Draw the word cairo at NUM_TEXT different angles */
+static cairo_bool_t
+text_extents_equal (const cairo_text_extents_t *A,
+	            const cairo_text_extents_t *B)
+{
+    return A->x_bearing == B->x_bearing &&
+	   A->y_bearing == B->y_bearing &&
+	   A->width     == B->width     &&
+	   A->height    == B->height    &&
+	   A->x_advance == B->x_advance &&
+	   A->y_advance == B->y_advance;
+}
+
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
+    cairo_text_extents_t nil_extents;
     cairo_text_extents_t extents;
 
     cairo_select_font_face (cr, "Bitstream Vera Sans",
@@ -66,17 +78,48 @@ draw (cairo_t *cr, int width, int height)
     cairo_set_font_size (cr, 16);
 
     cairo_move_to (cr, 10, 25);
+    cairo_show_text (cr, NULL);
     cairo_show_text (cr, "");
     cairo_show_glyphs (cr, NULL, 0);
     cairo_show_glyphs (cr, (void*)8, 0);
 
     cairo_move_to (cr, 10, 55);
+    cairo_text_path (cr, NULL);
     cairo_text_path (cr, "");
     cairo_glyph_path (cr, (void*)8, 0);
     cairo_fill (cr);
 
+    memset (&nil_extents, 0, sizeof (cairo_text_extents_t));
+
+    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
     cairo_text_extents (cr, "", &extents);
+    if (! text_extents_equal (&extents, &nil_extents)) {
+	cairo_test_log ("Error: cairo_text_extents(\"\"); extents (%g, %g, %g, %g, %g, %g)\n",
+		        extents.x_bearing, extents.y_bearing,
+			extents.width, extents.height,
+			extents.x_advance, extents.y_advance);
+	return CAIRO_TEST_FAILURE;
+    }
+
+    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
+    cairo_text_extents (cr, NULL, &extents);
+    if (! text_extents_equal (&extents, &nil_extents)) {
+	cairo_test_log ("Error: cairo_text_extents(NULL); extents (%g, %g, %g, %g, %g, %g)\n",
+		        extents.x_bearing, extents.y_bearing,
+			extents.width, extents.height,
+			extents.x_advance, extents.y_advance);
+	return CAIRO_TEST_FAILURE;
+    }
+
+    memset (&extents, 0xff, sizeof (cairo_text_extents_t));
     cairo_glyph_extents (cr, (void*)8, 0, &extents);
+    if (! text_extents_equal (&extents, &nil_extents)) {
+	cairo_test_log ("Error: cairo_glyph_extents(); extents (%g, %g, %g, %g, %g, %g)\n",
+		        extents.x_bearing, extents.y_bearing,
+			extents.width, extents.height,
+			extents.x_advance, extents.y_advance);
+	return CAIRO_TEST_FAILURE;
+    }
 
     return CAIRO_TEST_SUCCESS;
 }


More information about the cairo-commit mailing list