/** * cairo_region_xor_rectangle: * @dst: a #cairo_region_t * @rectangle: a #cairo_rectangle_int_t * * Computes the exclusive difference of @dst with @rectangle and places the * result in @dst. That is, @dst will be set to contain all areas that are * either in @dst or in @rectangle, but not in both. * * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY * * Since: 1.10 **/ cairo_status_t cairo_region_xor_rectangle (cairo_region_t *dst, const cairo_rectangle_int_t *rectangle) { cairo_status_t status = CAIRO_STATUS_SUCCESS; pixman_region32_t region, tmp; if (dst->status) return dst->status; pixman_region32_init_rect (®ion, rectangle->x, rectangle->y, rectangle->width, rectangle->height); pixman_region32_init (&tmp); /* XXX: get an xor function into pixman */ if (! pixman_region32_subtract (&tmp, ®ion, &dst->rgn) || ! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion) || ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp)) status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); pixman_region32_fini (&tmp); pixman_region32_fini (®ion); return status; }
static void draw_view(struct weston_view *ev, struct weston_output *output, pixman_region32_t *damage) /* in global coordinates */ { struct pixman_surface_state *ps = get_surface_state(ev->surface); /* repaint bounding region in global coordinates: */ pixman_region32_t repaint; /* non-opaque region in surface coordinates: */ pixman_region32_t surface_blend; /* No buffer attached */ if (!ps->image) return; pixman_region32_init(&repaint); pixman_region32_intersect(&repaint, &ev->transform.boundingbox, damage); pixman_region32_subtract(&repaint, &repaint, &ev->clip); if (!pixman_region32_not_empty(&repaint)) goto out; if (output->zoom.active) { weston_log("pixman renderer does not support zoom\n"); goto out; } /* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */ if (ev->transform.enabled && ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) { repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER); } else { /* blended region is whole surface minus opaque region: */ pixman_region32_init_rect(&surface_blend, 0, 0, ev->surface->width, ev->surface->height); pixman_region32_subtract(&surface_blend, &surface_blend, &ev->surface->opaque); if (pixman_region32_not_empty(&ev->surface->opaque)) { repaint_region(ev, output, &repaint, &ev->surface->opaque, PIXMAN_OP_SRC); } if (pixman_region32_not_empty(&surface_blend)) { repaint_region(ev, output, &repaint, &surface_blend, PIXMAN_OP_OVER); } pixman_region32_fini(&surface_blend); } out: pixman_region32_fini(&repaint); }
cairo_int_status_t _cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b) { if (!pixman_region32_subtract (&dst->rgn, &a->rgn, &b->rgn)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_SUCCESS; }
static void subtract(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct region *region = wl_resource_get_user_data(resource); pixman_region32_t operand; pixman_region32_init_rect(&operand, x, y, width, height); pixman_region32_subtract(®ion->region, ®ion->region, &operand); }
/** * cairo_region_subtract: * @dst: a #cairo_region_t * @other: another #cairo_region_t * * Subtracts @other from @dst and places the result in @dst * * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY * * Since: 1.10 **/ cairo_status_t cairo_region_subtract (cairo_region_t *dst, cairo_region_t *other) { if (dst->status) return dst->status; if (other->status) return _cairo_region_set_error (dst, other->status); if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &other->rgn)) return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); return CAIRO_STATUS_SUCCESS; }
static void draw_view(struct weston_view *ev, struct weston_output *output, pixman_region32_t *damage) /* in global coordinates */ { static int zoom_logged = 0; struct pixman_surface_state *ps = get_surface_state(ev->surface); /* repaint bounding region in global coordinates: */ pixman_region32_t repaint; /* No buffer attached */ if (!ps->image) return; pixman_region32_init(&repaint); pixman_region32_intersect(&repaint, &ev->transform.boundingbox, damage); pixman_region32_subtract(&repaint, &repaint, &ev->clip); if (!pixman_region32_not_empty(&repaint)) goto out; if (output->zoom.active && !zoom_logged) { weston_log("pixman renderer does not support zoom\n"); zoom_logged = 1; } if (view_transformation_is_translation(ev)) { /* The simple case: The surface regions opaque, non-opaque, * etc. are convertible to global coordinate space. * There is no need to use a source clip region. * It is possible to paint opaque region as PIXMAN_OP_SRC. * Also the boundingbox is accurate rather than an * approximation. */ draw_view_translated(ev, output, &repaint); } else { /* The complex case: the view transformation does not allow * converting opaque etc. regions into global coordinate space. * Therefore we need source clipping to avoid sampling from * unwanted source image areas, unless the source image is * to be used whole. Source clipping does not work with * PIXMAN_OP_SRC. */ draw_view_source_clipped(ev, output, &repaint); } out: pixman_region32_fini(&repaint); }
/** * cairo_region_xor: * @dst: a #cairo_region_t * @other: another #cairo_region_t * * Computes the exclusive difference of @dst with @other and places the * result in @dst. That is, @dst will be set to contain all areas that * are either in @dst or in @other, but not in both. * * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY * * Since: 1.10 **/ cairo_status_t cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other) { cairo_status_t status = CAIRO_STATUS_SUCCESS; pixman_region32_t tmp; if (dst->status) return dst->status; if (other->status) return _cairo_region_set_error (dst, other->status); pixman_region32_init (&tmp); /* XXX: get an xor function into pixman */ if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) || ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) || ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp)) status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); pixman_region32_fini (&tmp); return status; }
static int headless_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) { struct headless_output *output = (struct headless_output *) output_base; struct weston_compositor *ec = output->base.compositor; ec->renderer->repaint_output(&output->base, damage); pixman_region32_subtract(&ec->primary_plane.damage, &ec->primary_plane.damage, damage); wl_event_source_timer_update(output->finish_frame_timer, 16); return 0; }
static void draw_view_translated(struct weston_view *view, struct weston_output *output, pixman_region32_t *repaint_global) { struct weston_surface *surface = view->surface; /* non-opaque region in surface coordinates: */ pixman_region32_t surface_blend; /* region to be painted in output coordinates: */ pixman_region32_t repaint_output; pixman_region32_init(&repaint_output); /* Blended region is whole surface minus opaque region, * unless surface alpha forces us to blend all. */ pixman_region32_init_rect(&surface_blend, 0, 0, surface->width, surface->height); if (!(view->alpha < 1.0)) { pixman_region32_subtract(&surface_blend, &surface_blend, &surface->opaque); if (pixman_region32_not_empty(&surface->opaque)) { region_intersect_only_translation(&repaint_output, repaint_global, &surface->opaque, view); region_global_to_output(output, &repaint_output); repaint_region(view, output, &repaint_output, NULL, PIXMAN_OP_SRC); } } if (pixman_region32_not_empty(&surface_blend)) { region_intersect_only_translation(&repaint_output, repaint_global, &surface_blend, view); region_global_to_output(output, &repaint_output); repaint_region(view, output, &repaint_output, NULL, PIXMAN_OP_OVER); } pixman_region32_fini(&surface_blend); pixman_region32_fini(&repaint_output); }
static void wayland_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) { struct wayland_output *output = (struct wayland_output *) output_base; struct weston_compositor *ec = output->base.compositor; struct wl_callback *callback; callback = wl_surface_frame(output->parent.surface); wl_callback_add_listener(callback, &frame_listener, output); ec->renderer->repaint_output(&output->base, damage); pixman_region32_subtract(&ec->primary_plane.damage, &ec->primary_plane.damage, damage); }
/** * cairo_region_subtract_rectangle: * @dst: a #cairo_region_t * @rectangle: a #cairo_rectangle_int_t * * Subtracts @rectangle from @dst and places the result in @dst * * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY * * Since: 1.10 **/ cairo_status_t cairo_region_subtract_rectangle (cairo_region_t *dst, const cairo_rectangle_int_t *rectangle) { cairo_status_t status = CAIRO_STATUS_SUCCESS; pixman_region32_t region; if (dst->status) return dst->status; pixman_region32_init_rect (®ion, rectangle->x, rectangle->y, rectangle->width, rectangle->height); if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion)) status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); pixman_region32_fini (®ion); return status; }
int main () { pixman_region32_t r1; pixman_region32_t r2; pixman_region32_t r3; pixman_box32_t boxes[] = { { 10, 10, 20, 20 }, { 30, 30, 30, 40 }, { 50, 45, 60, 44 }, }; pixman_box32_t boxes2[] = { { 2, 6, 7, 6 }, { 4, 1, 6, 7 }, }; pixman_box32_t boxes3[] = { { 2, 6, 7, 6 }, { 4, 1, 6, 1 }, }; int i, j; pixman_box32_t *b; pixman_image_t *image, *fill; pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff }; /* This used to go into an infinite loop before pixman-region.c * was fixed to not use explict "short" variables */ pixman_region32_init_rect (&r1, 0, 0, 20, 64000); pixman_region32_init_rect (&r2, 0, 0, 20, 64000); pixman_region32_init_rect (&r3, 0, 0, 20, 64000); pixman_region32_subtract (&r1, &r2, &r3); /* This would produce a region containing an empty * rectangle in it. Such regions are considered malformed, * but using an empty rectangle for initialization should * work. */ pixman_region32_init_rects (&r1, boxes, 3); b = pixman_region32_rectangles (&r1, &i); assert (i == 1); while (i--) { assert (b[i].x1 < b[i].x2); assert (b[i].y1 < b[i].y2); } /* This would produce a rectangle containing the bounding box * of the two rectangles. The correct result is to eliminate * the broken rectangle. */ pixman_region32_init_rects (&r1, boxes2, 2); b = pixman_region32_rectangles (&r1, &i); assert (i == 1); assert (b[0].x1 == 4); assert (b[0].y1 == 1); assert (b[0].x2 == 6); assert (b[0].y2 == 7); /* This should produce an empty region */ pixman_region32_init_rects (&r1, boxes3, 2); b = pixman_region32_rectangles (&r1, &i); assert (i == 0); fill = pixman_image_create_solid_fill (&white); for (i = 0; i < 100; i++) { int image_size = 128; pixman_region32_init (&r1); /* Add some random rectangles */ for (j = 0; j < 64; j++) pixman_region32_union_rect (&r1, &r1, lcg_rand_n (image_size), lcg_rand_n (image_size), lcg_rand_n (25), lcg_rand_n (25)); /* Clip to image size */ pixman_region32_init_rect (&r2, 0, 0, image_size, image_size); pixman_region32_intersect (&r1, &r1, &r2); pixman_region32_fini (&r2); /* render region to a1 mask */ image = pixman_image_create_bits (PIXMAN_a1, image_size, image_size, NULL, 0); pixman_image_set_clip_region32 (image, &r1); pixman_image_composite32 (PIXMAN_OP_SRC, fill, NULL, image, 0, 0, 0, 0, 0, 0, image_size, image_size); pixman_region32_init_from_image (&r2, image); pixman_image_unref (image); assert (pixman_region32_equal (&r1, &r2)); pixman_region32_fini (&r1); pixman_region32_fini (&r2); } pixman_image_unref (fill); return 0; }
int main () { pixman_region32_t r1; pixman_region32_t r2; pixman_region32_t r3; pixman_box32_t boxes[] = { { 10, 10, 20, 20 }, { 30, 30, 30, 40 }, { 50, 45, 60, 44 }, }; pixman_box32_t boxes2[] = { { 2, 6, 7, 6 }, { 4, 1, 6, 7 }, }; pixman_box32_t boxes3[] = { { 2, 6, 7, 6 }, { 4, 1, 6, 1 }, }; int i; pixman_box32_t *b; /* This used to go into an infinite loop before pixman-region.c * was fixed to not use explict "short" variables */ pixman_region32_init_rect (&r1, 0, 0, 20, 64000); pixman_region32_init_rect (&r2, 0, 0, 20, 64000); pixman_region32_init_rect (&r3, 0, 0, 20, 64000); pixman_region32_subtract (&r1, &r2, &r3); /* This would produce a region containing an empty * rectangle in it. Such regions are considered malformed, * but using an empty rectangle for initialization should * work. */ pixman_region32_init_rects (&r1, boxes, 3); b = pixman_region32_rectangles (&r1, &i); assert (i == 1); while (i--) { assert (b[i].x1 < b[i].x2); assert (b[i].y1 < b[i].y2); } /* This would produce a rectangle containing the bounding box * of the two rectangles. The correct result is to eliminate * the broken rectangle. */ pixman_region32_init_rects (&r1, boxes2, 2); b = pixman_region32_rectangles (&r1, &i); assert (i == 1); assert (b[0].x1 == 4); assert (b[0].y1 == 1); assert (b[0].x2 == 6); assert (b[0].y2 == 7); /* This should produce an empty region */ pixman_region32_init_rects (&r1, boxes3, 2); b = pixman_region32_rectangles (&r1, &i); assert (i == 0); return 0; }
Region& Region::createSubtraction(const Region& a, const Region& b) { pixman_region32_subtract(&m_region, &a.m_region, &b.m_region); return *this; }