Fix for bug #4088:

New function to return the current nil pattern depending on the status.
Add missing early bailout on surface->status with error propagation to the pattern.
Related cleanups for cairo_pattern_t:
Don't check other->status since this is a static function.
Add missing early bailout on other->status.
Cleanup identifier names.
Track rename of nil patterns.
Don't call _cairo_error for pre-existing errors.
Take care to initialize some fields to that _cairo_pattern_release_surface will work even after an error.
Track rename of cairo_solid_pattern_nil to cairo_pattern_nil.
New test to ensure that a file-not-found error will propagate from a surface, through a pattern, and onto a cairo_t.
This commit is contained in:
Carl Worth 2005-08-18 23:10:37 +00:00
parent 0e56f2ea0a
commit 435fb3c65f
8 changed files with 184 additions and 57 deletions

View file

@ -1,3 +1,51 @@
2005-08-18 Carl Worth <cworth@cworth.org>
Fix for bug #4088:
* src/cairo-pattern.c: (_cairo_pattern_nil_for_status):
New function to return the current nil pattern depending on the
status.
* src/cairo-pattern.c: (cairo_pattern_create_for_surface):
* src/cairo-pattern.c: (_cairo_pattern_init_for_surface): Add
missing early bailout on surface->status with error propagation to
the pattern.
Related cleanups for cairo_pattern_t:
* src/cairo-pattern.c: (_cairo_gradient_pattern_init_copy): Don't
check other->status since this is a static function.
* src/cairo-pattern.c: (_cairo_pattern_init_copy): Add missing
early bailout on other->status.
* src/cairo-pattern.c: (_cairo_pattern_fini): Cleanup identifier
names.
* src/cairo-pattern.c: (_cairo_pattern_create_solid),
(cairo_pattern_create_linear), (cairo_pattern_create_radial):
Track rename of nil patterns.
* src/cairo-pattern.c: (cairo_pattern_set_matrix),
(cairo_pattern_set_filter),
(cairo_pattern_set_extend): Don't call _cairo_error for
pre-existing errors.
* src/cairo-pattern.c: (_cairo_pattern_acquire_surface): Take care
to initialize some fields to that _cairo_pattern_release_surface
will work even after an error.
* src/cairoint.h:
* src/cairo.c: (cairo_get_source): Track rename of
cairo_solid_pattern_nil to cairo_pattern_nil.
* test/.cvsignore:
* test/Makefile.am:
* test/nil-surface-ref.png:
* test/nil-surface.c: (draw), (main): New test to ensure that a
file-not-found error will propagate from a surface, through a
pattern, and onto a cairo_t.
2005-08-18 Carl Worth <cworth@cworth.org>
* test/.valgrind-suppressions: Suppress a pthread initialization

View file

@ -50,51 +50,46 @@ typedef struct _cairo_shader_op {
((unsigned char) \
((((unsigned char) (c1)) * (int) ((unsigned char) (c2))) / 0xff))
const cairo_solid_pattern_t cairo_solid_pattern_nil = {
const cairo_solid_pattern_t cairo_pattern_nil = {
{ CAIRO_PATTERN_SOLID, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_DEFAULT }, /* extend */
{ 0.0, 0.0, 0.0, 1.0, /* solid black */
0x0, 0x0, 0x0, 0xffff }
};
static const cairo_surface_pattern_t cairo_surface_pattern_nil = {
{ CAIRO_PATTERN_SURFACE, /* type */
const cairo_solid_pattern_t cairo_pattern_nil_file_not_found = {
{ CAIRO_PATTERN_SOLID, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_STATUS_FILE_NOT_FOUND, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_DEFAULT }, /* extend */
NULL /* surface */
};
static const cairo_linear_pattern_t cairo_linear_pattern_nil = {
{ { CAIRO_PATTERN_LINEAR, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_DEFAULT }, /* extend */
NULL, /* stops */
0 }, /* n_stops */
{ 0., 0. }, { 1.0, 1.0 } /* point0, point1 */
const cairo_solid_pattern_t cairo_pattern_nil_read_error = {
{ CAIRO_PATTERN_SOLID, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_READ_ERROR, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_DEFAULT }, /* extend */
};
static const cairo_radial_pattern_t cairo_radial_pattern_nil = {
{ { CAIRO_PATTERN_RADIAL, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_DEFAULT }, /* extend */
NULL, /* stops */
0 }, /* n_stops */
{ 0., 0. }, { 0.0, 0.0 }, /* center0, center1 */
1.0, 1.0, /* radius0, radius1 */
};
static const cairo_pattern_t *
_cairo_pattern_nil_for_status (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_FILE_NOT_FOUND:
return &cairo_pattern_nil_file_not_found.base;
case CAIRO_STATUS_READ_ERROR:
return &cairo_pattern_nil_read_error.base;
default:
case CAIRO_STATUS_NO_MEMORY:
return &cairo_pattern_nil.base;
}
}
/**
* _cairo_pattern_set_error:
@ -152,17 +147,11 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
*dst = *src;
}
if (other->base.status)
_cairo_pattern_set_error (&pattern->base, other->base.status);
if (other->n_stops)
{
pattern->stops = malloc (other->n_stops * sizeof (cairo_color_stop_t));
if (pattern->stops == NULL) {
if (other->base.type == CAIRO_PATTERN_LINEAR)
_cairo_gradient_pattern_init_copy (pattern, &cairo_linear_pattern_nil.base);
else
_cairo_gradient_pattern_init_copy (pattern, &cairo_radial_pattern_nil.base);
_cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
return;
}
@ -175,6 +164,11 @@ void
_cairo_pattern_init_copy (cairo_pattern_t *pattern,
const cairo_pattern_t *other)
{
if (other->status) {
_cairo_pattern_set_error (pattern, other->status);
return;
}
switch (other->type) {
case CAIRO_PATTERN_SOLID: {
cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
@ -208,16 +202,18 @@ _cairo_pattern_fini (cairo_pattern_t *pattern)
case CAIRO_PATTERN_SOLID:
break;
case CAIRO_PATTERN_SURFACE: {
cairo_surface_pattern_t *fini = (cairo_surface_pattern_t *) pattern;
cairo_surface_pattern_t *surface_pattern =
(cairo_surface_pattern_t *) pattern;
cairo_surface_destroy (fini->surface);
cairo_surface_destroy (surface_pattern->surface);
} break;
case CAIRO_PATTERN_LINEAR:
case CAIRO_PATTERN_RADIAL: {
cairo_gradient_pattern_t *fini = (cairo_gradient_pattern_t *) pattern;
cairo_gradient_pattern_t *gradient =
(cairo_gradient_pattern_t *) pattern;
if (fini->n_stops)
free (fini->stops);
if (gradient->stops)
free (gradient->stops);
} break;
}
}
@ -234,6 +230,13 @@ void
_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
cairo_surface_t *surface)
{
if (surface->status) {
/* Force to solid to simplify the pattern_fini process. */
pattern->base.type = CAIRO_PATTERN_SOLID;
_cairo_pattern_set_error (&pattern->base, surface->status);
return;
}
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE);
pattern->surface = cairo_surface_reference (surface);
@ -283,7 +286,7 @@ _cairo_pattern_create_solid (const cairo_color_t *color)
pattern = malloc (sizeof (cairo_solid_pattern_t));
if (pattern == NULL)
return (cairo_pattern_t *) &cairo_solid_pattern_nil.base;
return (cairo_pattern_t *) &cairo_pattern_nil.base;
_cairo_pattern_init_solid (pattern, color);
@ -391,10 +394,13 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
{
cairo_surface_pattern_t *pattern;
if (surface->status)
return (cairo_pattern_t*) _cairo_pattern_nil_for_status (surface->status);
pattern = malloc (sizeof (cairo_surface_pattern_t));
if (pattern == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *)&cairo_surface_pattern_nil.base;
return (cairo_pattern_t *)&cairo_pattern_nil.base;
}
_cairo_pattern_init_for_surface (pattern, surface);
@ -436,7 +442,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
pattern = malloc (sizeof (cairo_linear_pattern_t));
if (pattern == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &cairo_linear_pattern_nil.base;
return (cairo_pattern_t *) &cairo_pattern_nil.base;
}
_cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
@ -481,7 +487,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
pattern = malloc (sizeof (cairo_radial_pattern_t));
if (pattern == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &cairo_radial_pattern_nil.base;
return (cairo_pattern_t *) &cairo_pattern_nil.base;
}
_cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
@ -717,10 +723,8 @@ void
cairo_pattern_set_matrix (cairo_pattern_t *pattern,
const cairo_matrix_t *matrix)
{
if (pattern->status) {
_cairo_pattern_set_error (pattern, pattern->status);
if (pattern->status)
return;
}
pattern->matrix = *matrix;
}
@ -741,10 +745,8 @@ cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
void
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
{
if (pattern->status) {
_cairo_pattern_set_error (pattern, pattern->status);
if (pattern->status)
return;
}
pattern->filter = filter;
}
@ -758,10 +760,8 @@ cairo_pattern_get_filter (cairo_pattern_t *pattern)
void
cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
{
if (pattern->status) {
_cairo_pattern_set_error (pattern, pattern->status);
if (pattern->status)
return;
}
pattern->extend = extend;
}
@ -1457,8 +1457,11 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
{
cairo_status_t status;
if (pattern->status)
if (pattern->status) {
*surface_out = NULL;
attributes->acquired = FALSE;
return pattern->status;
}
switch (pattern->type) {
case CAIRO_PATTERN_SOLID: {

View file

@ -549,7 +549,7 @@ cairo_pattern_t *
cairo_get_source (cairo_t *cr)
{
if (cr->status)
return (cairo_pattern_t*) &cairo_solid_pattern_nil.base;
return (cairo_pattern_t*) &cairo_pattern_nil.base;
return _cairo_gstate_get_source (cr->gstate);
}

View file

@ -936,7 +936,7 @@ typedef struct _cairo_solid_pattern {
cairo_color_t color;
} cairo_solid_pattern_t;
extern const cairo_private cairo_solid_pattern_t cairo_solid_pattern_nil;
extern const cairo_private cairo_solid_pattern_t cairo_pattern_nil;
typedef struct _cairo_surface_pattern {
cairo_pattern_t base;

View file

@ -26,6 +26,7 @@ mask
mask-ctm
mask-surface-ctm
move-to-show-surface
nil-surface
operator-clear
operator-source
paint

View file

@ -21,6 +21,7 @@ mask \
mask-ctm \
mask-surface-ctm \
move-to-show-surface \
nil-surface \
operator-clear \
operator-source \
paint \
@ -194,6 +195,7 @@ mask_LDADD = $(LDADDS)
mask_ctm_LDADD = $(LDADDS)
mask_surface_ctm_LDADD = $(LDADDS)
move_to_show_surface_LDADD = $(LDADDS)
nil_surface_LDADD = $(LDADDS)
operator_clear_LDADD = $(LDADDS)
operator_source_LDADD = $(LDADDS)
paint_LDADD = $(LDADDS)

BIN
test/nil-surface-ref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

73
test/nil-surface.c Normal file
View file

@ -0,0 +1,73 @@
/*
* Copyright © 2005 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.
*
* Author: Carl D. Worth <cworth@cworth.org>
*/
#include "cairo-test.h"
#include <cairo-ft.h>
/* Test case for: https://bugs.freedesktop.org/show_bug.cgi?id=4088 */
cairo_test_t test = {
"nil-surface",
"Test that nil surfaces do not make cairo crash.",
1, 1
};
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_surface_t *surface;
cairo_pattern_t *pattern;
cairo_t *cr2;
/* Make a custom context to not interfere with the one passed in. */
cr2 = cairo_create (cairo_get_target (cr));
/* First, let's make a nil surface. */
surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___");
/* Let the error propagate into a nil pattern. */
pattern = cairo_pattern_create_for_surface (surface);
/* Then let it propagate into the cairo_t. */
cairo_set_source (cr2, pattern);
cairo_paint (cr2);
cairo_pattern_destroy (pattern);
cairo_surface_destroy (surface);
/* Check that the error made it all that way. */
if (cairo_status (cr2) != CAIRO_STATUS_FILE_NOT_FOUND)
return CAIRO_TEST_FAILURE;
cairo_destroy (cr2);
return CAIRO_TEST_SUCCESS;
}
int
main (void)
{
return cairo_test (&test, draw);
}