mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-22 03:00:29 +01:00
xlib: Handle lack of XRenderFillRectangles
Remember to check for a supported render version before making a FillRectangle request, and fallback to the core protocol where possible instead. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
503b6b9e2e
commit
7012334ebb
4 changed files with 157 additions and 37 deletions
|
|
@ -83,6 +83,7 @@ struct _fill_box {
|
|||
Display *dpy;
|
||||
Drawable drawable;
|
||||
GC gc;
|
||||
//cairo_surface_t *dither = NULL;
|
||||
};
|
||||
|
||||
static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
|
||||
|
|
@ -128,27 +129,25 @@ color_to_pixel (cairo_xlib_surface_t *dst,
|
|||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
fill_boxes (cairo_xlib_surface_t *dst,
|
||||
const cairo_color_t *color,
|
||||
cairo_boxes_t *boxes)
|
||||
_fill_box_init (struct _fill_box *fb,
|
||||
cairo_xlib_surface_t *dst,
|
||||
const cairo_color_t *color)
|
||||
{
|
||||
cairo_surface_t *dither = NULL;
|
||||
cairo_status_t status;
|
||||
struct _fill_box fb;
|
||||
cairo_int_status_t status;
|
||||
|
||||
status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb.gc);
|
||||
status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
fb.dpy = dst->display->display;
|
||||
fb.drawable = dst->drawable;
|
||||
fb->dpy = dst->display->display;
|
||||
fb->drawable = dst->drawable;
|
||||
|
||||
if (dst->visual && dst->visual->class != TrueColor && 0) {
|
||||
#if 0
|
||||
cairo_solid_pattern_t solid;
|
||||
cairo_surface_attributes_t attrs;
|
||||
|
||||
_cairo_pattern_init_solid (&solid, color);
|
||||
#if 0
|
||||
status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
|
||||
0, 0,
|
||||
ARRAY_LENGTH (dither_pattern[0]),
|
||||
|
|
@ -160,27 +159,70 @@ fill_boxes (cairo_xlib_surface_t *dst,
|
|||
_cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
XSetTSOrigin (fb.dpy, fb.gc,
|
||||
XSetTSOrigin (fb->dpy, fb->gc,
|
||||
- (dst->base.device_transform.x0 + attrs.x_offset),
|
||||
- (dst->base.device_transform.y0 + attrs.y_offset));
|
||||
XSetTile (fb.dpy, fb.gc, ((cairo_xlib_surface_t *) dither)->drawable);
|
||||
XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable);
|
||||
#endif
|
||||
} else {
|
||||
XGCValues gcv;
|
||||
|
||||
gcv.foreground = color_to_pixel (dst, color);
|
||||
gcv.fill_style = FillSolid;
|
||||
|
||||
XChangeGC (fb.dpy, fb.gc, GCFillStyle | GCForeground, &gcv);
|
||||
XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv);
|
||||
}
|
||||
|
||||
return CAIRO_INT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_fill_box_fini (struct _fill_box *fb,
|
||||
cairo_xlib_surface_t *dst)
|
||||
{
|
||||
_cairo_xlib_surface_put_gc (dst->display, dst, fb->gc);
|
||||
//cairo_surface_destroy (fb->dither);
|
||||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst,
|
||||
const cairo_color_t *color,
|
||||
cairo_boxes_t *boxes)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
struct _fill_box fb;
|
||||
|
||||
status = _fill_box_init (&fb, dst, color);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
_cairo_boxes_for_each_box (boxes, fill_box, &fb);
|
||||
|
||||
_cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
|
||||
_fill_box_fini (&fb, dst);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_surface_destroy (dither);
|
||||
cairo_int_status_t
|
||||
_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst,
|
||||
const cairo_color_t *color,
|
||||
int num_rects,
|
||||
cairo_rectangle_int_t *rects)
|
||||
{
|
||||
cairo_int_status_t status;
|
||||
struct _fill_box fb;
|
||||
int i;
|
||||
|
||||
status = _fill_box_init (&fb, dst, color);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
for (i = 0; i < num_rects; i++)
|
||||
XFillRectangle (fb.dpy, fb.drawable, fb.gc,
|
||||
rects[i].x, rects[i].y,
|
||||
rects[i].width, rects[i].height);
|
||||
|
||||
_fill_box_fini (&fb, dst);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -495,9 +537,8 @@ draw_boxes (cairo_composite_rectangles_t *extents,
|
|||
return status;
|
||||
|
||||
if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
|
||||
status = fill_boxes (dst,
|
||||
&((cairo_solid_pattern_t *) src)->color,
|
||||
boxes);
|
||||
status = _cairo_xlib_core_fill_boxes
|
||||
(dst, &((cairo_solid_pattern_t *) src)->color, boxes);
|
||||
} else {
|
||||
status = upload_image_inplace (dst, src, boxes);
|
||||
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ struct _cairo_xlib_surface {
|
|||
cairo_surface_t base;
|
||||
|
||||
Picture picture;
|
||||
Drawable drawable;
|
||||
|
||||
const cairo_compositor_t *compositor;
|
||||
cairo_surface_t *shm;
|
||||
|
|
@ -181,7 +182,6 @@ struct _cairo_xlib_surface {
|
|||
cairo_list_t link;
|
||||
|
||||
Display *dpy; /* only valid between acquire/release */
|
||||
Drawable drawable;
|
||||
cairo_bool_t owns_pixmap;
|
||||
Visual *visual;
|
||||
|
||||
|
|
@ -203,6 +203,7 @@ struct _cairo_xlib_surface {
|
|||
cairo_surface_t base;
|
||||
|
||||
Picture picture;
|
||||
Pixmap pixmap;
|
||||
Display *dpy;
|
||||
|
||||
unsigned int filter:3;
|
||||
|
|
@ -395,6 +396,17 @@ _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
|
|||
return dst->screen == src->screen;
|
||||
}
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst,
|
||||
const cairo_color_t *color,
|
||||
cairo_boxes_t *boxes);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst,
|
||||
const cairo_color_t *color,
|
||||
int num_rects,
|
||||
cairo_rectangle_int_t *rects);
|
||||
|
||||
static inline void
|
||||
_cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
|
||||
cairo_xlib_surface_t *surface,
|
||||
|
|
@ -453,5 +465,4 @@ _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface);
|
|||
cairo_private pixman_format_code_t
|
||||
_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface);
|
||||
|
||||
|
||||
#endif /* CAIRO_XLIB_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -608,14 +608,23 @@ fill_rectangles (void *abstract_surface,
|
|||
|
||||
//X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
|
||||
|
||||
if (fill_reduces_to_source (op, color, dst))
|
||||
op = CAIRO_OPERATOR_SOURCE;
|
||||
|
||||
if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
|
||||
cairo_int_status_t status;
|
||||
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
if (op == CAIRO_OPERATOR_SOURCE)
|
||||
status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects);
|
||||
return status;
|
||||
}
|
||||
|
||||
render_color.red = color->red_short;
|
||||
render_color.green = color->green_short;
|
||||
render_color.blue = color->blue_short;
|
||||
render_color.alpha = color->alpha_short;
|
||||
|
||||
if (fill_reduces_to_source (op, color, dst))
|
||||
op = CAIRO_OPERATOR_SOURCE;
|
||||
|
||||
_cairo_xlib_surface_ensure_picture (dst);
|
||||
if (num_rects == 1) {
|
||||
/* Take advantage of the protocol compaction that libXrender performs
|
||||
|
|
@ -665,14 +674,23 @@ fill_boxes (void *abstract_surface,
|
|||
cairo_xlib_surface_t *dst = abstract_surface;
|
||||
XRenderColor render_color;
|
||||
|
||||
if (fill_reduces_to_source (op, color, dst))
|
||||
op = CAIRO_OPERATOR_SOURCE;
|
||||
|
||||
if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
|
||||
cairo_int_status_t status;
|
||||
|
||||
status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
if (op == CAIRO_OPERATOR_SOURCE)
|
||||
status = _cairo_xlib_core_fill_boxes (dst, color, boxes);
|
||||
return status;
|
||||
}
|
||||
|
||||
render_color.red = color->red_short;
|
||||
render_color.green = color->green_short;
|
||||
render_color.blue = color->blue_short;
|
||||
render_color.alpha = color->alpha_short;
|
||||
|
||||
if (fill_reduces_to_source (op, color, dst))
|
||||
op = CAIRO_OPERATOR_SOURCE;
|
||||
|
||||
_cairo_xlib_surface_ensure_picture (dst);
|
||||
if (boxes->num_boxes == 1) {
|
||||
int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ _cairo_xlib_source_finish (void *abstract_surface)
|
|||
cairo_xlib_source_t *source = abstract_surface;
|
||||
|
||||
XRenderFreePicture (source->dpy, source->picture);
|
||||
if (source->pixmap)
|
||||
XFreePixmap (source->dpy, source->pixmap);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +88,8 @@ _cairo_xlib_proxy_finish (void *abstract_surface)
|
|||
cairo_xlib_proxy_t *proxy = abstract_surface;
|
||||
|
||||
XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
|
||||
if (proxy->source.pixmap)
|
||||
XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
|
||||
_cairo_xlib_shm_surface_mark_active (proxy->owner);
|
||||
cairo_surface_destroy (proxy->owner);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -98,7 +102,7 @@ static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
|
|||
};
|
||||
|
||||
static cairo_surface_t *
|
||||
source (cairo_xlib_surface_t *dst, Picture picture)
|
||||
source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
|
||||
{
|
||||
cairo_xlib_source_t *source;
|
||||
|
||||
|
|
@ -108,6 +112,8 @@ source (cairo_xlib_surface_t *dst, Picture picture)
|
|||
source = malloc (sizeof (cairo_image_surface_t));
|
||||
if (unlikely (source == NULL)) {
|
||||
XRenderFreePicture (dst->display->display, picture);
|
||||
if (pixmap)
|
||||
XFreePixmap (dst->display->display, pixmap);
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +124,7 @@ source (cairo_xlib_surface_t *dst, Picture picture)
|
|||
|
||||
/* The source exists only within an operation */
|
||||
source->picture = picture;
|
||||
source->pixmap = pixmap;
|
||||
source->dpy = dst->display->display;
|
||||
|
||||
return &source->base;
|
||||
|
|
@ -433,22 +440,65 @@ gradient_source (cairo_xlib_surface_t *dst,
|
|||
return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
|
||||
}
|
||||
|
||||
return source (dst, picture);
|
||||
return source (dst, picture, None);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
|
||||
{
|
||||
XRenderColor xrender_color;
|
||||
Display *dpy = dst->display->display;
|
||||
XRenderColor xcolor;
|
||||
Picture picture;
|
||||
Pixmap pixmap = None;
|
||||
|
||||
xrender_color.red = color->red_short;
|
||||
xrender_color.green = color->green_short;
|
||||
xrender_color.blue = color->blue_short;
|
||||
xrender_color.alpha = color->alpha_short;
|
||||
xcolor.red = color->red_short;
|
||||
xcolor.green = color->green_short;
|
||||
xcolor.blue = color->blue_short;
|
||||
xcolor.alpha = color->alpha_short;
|
||||
|
||||
return source (dst,
|
||||
XRenderCreateSolidFill (dst->display->display,
|
||||
&xrender_color));
|
||||
if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
|
||||
picture = XRenderCreateSolidFill (dpy, &xcolor);
|
||||
} else {
|
||||
XRenderPictureAttributes pa;
|
||||
int mask = 0;
|
||||
|
||||
pa.repeat = RepeatNormal;
|
||||
mask |= CPRepeat;
|
||||
|
||||
pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
|
||||
picture = XRenderCreatePicture (dpy, pixmap,
|
||||
_cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
|
||||
mask, &pa);
|
||||
|
||||
if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
|
||||
XRectangle r = { 0, 0, 1, 1};
|
||||
XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
|
||||
} else {
|
||||
XGCValues gcv;
|
||||
GC gc;
|
||||
|
||||
gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
|
||||
32, pixmap);
|
||||
if (unlikely (gc == NULL)) {
|
||||
XFreePixmap (dpy, pixmap);
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
|
||||
}
|
||||
|
||||
gcv.foreground = 0;
|
||||
gcv.foreground |= color->alpha_short >> 8 << 24;
|
||||
gcv.foreground |= color->red_short >> 8 << 16;
|
||||
gcv.foreground |= color->green_short >> 8 << 8;
|
||||
gcv.foreground |= color->blue_short >> 8 << 0;
|
||||
gcv.fill_style = FillSolid;
|
||||
|
||||
XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
|
||||
XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
|
||||
|
||||
_cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
|
||||
}
|
||||
}
|
||||
|
||||
return source (dst, picture, pixmap);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue