mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 01:48:07 +02:00
xcb,xlib: Fix 1-stop gradients
The RENDER specification does not specify the constraints on the gradient stops, but its implementation returns an error if less than 2 stops are used. Xlib and XCB can work around this because gradients with just one stop are by-definition the same as gradients with that stop repeated twice. Fixes radial-gradient-one-stop.
This commit is contained in:
parent
c42d7f7acf
commit
426fe6fadf
2 changed files with 48 additions and 17 deletions
|
|
@ -735,26 +735,30 @@ _render_to_picture (cairo_xcb_surface_t *target,
|
|||
|
||||
static xcb_render_fixed_t *
|
||||
_gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
|
||||
unsigned int *n_stops,
|
||||
char *buf, unsigned int buflen)
|
||||
{
|
||||
xcb_render_fixed_t *stops;
|
||||
xcb_render_color_t *colors;
|
||||
unsigned int i;
|
||||
|
||||
if (gradient->n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
|
||||
assert (gradient->n_stops > 0);
|
||||
*n_stops = MAX (gradient->n_stops, 2);
|
||||
|
||||
if (*n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
|
||||
{
|
||||
stops = (xcb_render_fixed_t *) buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
stops =
|
||||
_cairo_malloc_ab (gradient->n_stops,
|
||||
_cairo_malloc_ab (*n_stops,
|
||||
sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t));
|
||||
if (unlikely (stops == NULL))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
colors = (xcb_render_color_t *) (stops + gradient->n_stops);
|
||||
colors = (xcb_render_color_t *) (stops + *n_stops);
|
||||
for (i = 0; i < gradient->n_stops; i++) {
|
||||
stops[i] =
|
||||
_cairo_fixed_16_16_from_double (gradient->stops[i].offset);
|
||||
|
|
@ -765,6 +769,18 @@ _gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
|
|||
colors[i].alpha = gradient->stops[i].color.alpha_short;
|
||||
}
|
||||
|
||||
/* RENDER does not support gradients with less than 2 stops. If a
|
||||
* gradient has only a single stop, duplicate it to make RENDER
|
||||
* happy. */
|
||||
if (gradient->n_stops == 1) {
|
||||
stops[1] = _cairo_fixed_16_16_from_double (gradient->stops[0].offset);
|
||||
|
||||
colors[1].red = gradient->stops[0].color.red_short;
|
||||
colors[1].green = gradient->stops[0].color.green_short;
|
||||
colors[1].blue = gradient->stops[0].color.blue_short;
|
||||
colors[1].alpha = gradient->stops[0].color.alpha_short;
|
||||
}
|
||||
|
||||
return stops;
|
||||
}
|
||||
|
||||
|
|
@ -781,6 +797,7 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
|
|||
cairo_circle_double_t extremes[2];
|
||||
cairo_xcb_picture_t *picture;
|
||||
cairo_status_t status;
|
||||
unsigned int n_stops;
|
||||
|
||||
_cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
|
||||
|
||||
|
|
@ -789,7 +806,7 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
|
|||
if (picture != NULL)
|
||||
goto setup_picture;
|
||||
|
||||
stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
|
||||
stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
|
||||
if (unlikely (stops == NULL))
|
||||
return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
|
|
@ -804,7 +821,7 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
|
|||
}
|
||||
picture->filter = CAIRO_FILTER_DEFAULT;
|
||||
|
||||
colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
|
||||
colors = (xcb_render_color_t *) (stops + n_stops);
|
||||
|
||||
p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
|
||||
p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
|
||||
|
|
@ -814,7 +831,7 @@ _cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
|
|||
_cairo_xcb_connection_render_create_linear_gradient (target->connection,
|
||||
picture->picture,
|
||||
p1, p2,
|
||||
pattern->base.n_stops,
|
||||
n_stops,
|
||||
stops, colors);
|
||||
|
||||
if (stops != (xcb_render_fixed_t *) buf)
|
||||
|
|
@ -855,6 +872,7 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
|
|||
cairo_circle_double_t extremes[2];
|
||||
cairo_xcb_picture_t *picture;
|
||||
cairo_status_t status;
|
||||
unsigned int n_stops;
|
||||
|
||||
_cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes);
|
||||
|
||||
|
|
@ -863,7 +881,7 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
|
|||
if (picture != NULL)
|
||||
goto setup_picture;
|
||||
|
||||
stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
|
||||
stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf));
|
||||
if (unlikely (stops == NULL))
|
||||
return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
|
|
@ -878,7 +896,7 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
|
|||
}
|
||||
picture->filter = CAIRO_FILTER_DEFAULT;
|
||||
|
||||
colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
|
||||
colors = (xcb_render_color_t *) (stops + n_stops);
|
||||
|
||||
p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x);
|
||||
p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y);
|
||||
|
|
@ -891,7 +909,7 @@ _cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
|
|||
_cairo_xcb_connection_render_create_radial_gradient (target->connection,
|
||||
picture->picture,
|
||||
p1, p2, r1, r2,
|
||||
pattern->base.n_stops,
|
||||
n_stops,
|
||||
stops, colors);
|
||||
|
||||
if (stops != (xcb_render_fixed_t *) buf)
|
||||
|
|
|
|||
|
|
@ -2100,28 +2100,28 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
|
|||
XRenderColor *colors;
|
||||
XRenderPictFormat *format;
|
||||
Picture picture;
|
||||
unsigned int i;
|
||||
unsigned int i, n_stops;
|
||||
|
||||
if (dst->buggy_gradients)
|
||||
break;
|
||||
|
||||
if (gradient->n_stops < 2) /* becomes a solid */
|
||||
break;
|
||||
assert (gradient->n_stops > 0);
|
||||
n_stops = MAX (gradient->n_stops, 2);
|
||||
|
||||
if (gradient->n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
|
||||
if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
|
||||
{
|
||||
stops = (XFixed *) buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
stops =
|
||||
_cairo_malloc_ab (gradient->n_stops,
|
||||
_cairo_malloc_ab (n_stops,
|
||||
sizeof (XFixed) + sizeof (XRenderColor));
|
||||
if (unlikely (stops == NULL))
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
colors = (XRenderColor *) (stops + gradient->n_stops);
|
||||
colors = (XRenderColor *) (stops + n_stops);
|
||||
for (i = 0; i < gradient->n_stops; i++) {
|
||||
stops[i] =
|
||||
_cairo_fixed_16_16_from_double (gradient->stops[i].offset);
|
||||
|
|
@ -2132,6 +2132,19 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
|
|||
colors[i].alpha = gradient->stops[i].color.alpha_short;
|
||||
}
|
||||
|
||||
/* RENDER does not support gradients with less than 2
|
||||
* stops. If a gradient has only a single stop, duplicate
|
||||
* it to make RENDER happy. */
|
||||
if (gradient->n_stops == 1) {
|
||||
stops[1] =
|
||||
_cairo_fixed_16_16_from_double (gradient->stops[0].offset);
|
||||
|
||||
colors[1].red = gradient->stops[0].color.red_short;
|
||||
colors[1].green = gradient->stops[0].color.green_short;
|
||||
colors[1].blue = gradient->stops[0].color.blue_short;
|
||||
colors[1].alpha = gradient->stops[0].color.alpha_short;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* For some weird reason the X server is sometimes getting
|
||||
* CreateGradient requests with bad length. So far I've only seen
|
||||
|
|
@ -2157,7 +2170,7 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
|
|||
|
||||
picture = XRenderCreateLinearGradient (display->display, &grad,
|
||||
stops, colors,
|
||||
gradient->n_stops);
|
||||
n_stops);
|
||||
} else {
|
||||
XRadialGradient grad;
|
||||
|
||||
|
|
@ -2170,7 +2183,7 @@ _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
|
|||
|
||||
picture = XRenderCreateRadialGradient (display->display, &grad,
|
||||
stops, colors,
|
||||
gradient->n_stops);
|
||||
n_stops);
|
||||
}
|
||||
|
||||
if (stops != (XFixed *) buf)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue