cairo_int_status_t _cairo_region_init_boxes (cairo_region_t *region, cairo_box_int_t *boxes, int count) { pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)]; pixman_box32_t *pboxes = stack_pboxes; cairo_int_status_t status = CAIRO_STATUS_SUCCESS; int i; if (count > ARRAY_LENGTH (stack_pboxes)) { pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t)); if (unlikely (pboxes == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } for (i = 0; i < count; i++) { pboxes[i].x1 = boxes[i].p1.x; pboxes[i].y1 = boxes[i].p1.y; pboxes[i].x2 = boxes[i].p2.x; pboxes[i].y2 = boxes[i].p2.y; } if (! pixman_region32_init_rects (®ion->rgn, pboxes, count)) status = _cairo_error (CAIRO_STATUS_NO_MEMORY); if (pboxes != stack_pboxes) free (pboxes); return status; }
/** * cairo_region_create_rectangles: * @rects: an array of @count rectangles * @count: number of rectangles * * Allocates a new region object containing the union of all given @rects. * * Return value: A newly allocated #cairo_region_t. Free with * cairo_region_destroy(). This function always returns a * valid pointer; if memory cannot be allocated, then a special * error object is returned where all operations on the object do nothing. * You can check for this with cairo_region_status(). * * Since: 1.10 **/ cairo_region_t * cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, int count) { pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)]; pixman_box32_t *pboxes = stack_pboxes; cairo_region_t *region; int i; region = _cairo_malloc (sizeof (cairo_region_t)); if (unlikely (region == NULL)) return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); region->status = CAIRO_STATUS_SUCCESS; if (count == 1) { pixman_region32_init_rect (®ion->rgn, rects->x, rects->y, rects->width, rects->height); return region; } if (count > ARRAY_LENGTH (stack_pboxes)) { pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t)); if (unlikely (pboxes == NULL)) { free (region); return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } } for (i = 0; i < count; i++) { pboxes[i].x1 = rects[i].x; pboxes[i].y1 = rects[i].y; pboxes[i].x2 = rects[i].x + rects[i].width; pboxes[i].y2 = rects[i].y + rects[i].height; } i = pixman_region32_init_rects (®ion->rgn, pboxes, count); if (pboxes != stack_pboxes) free (pboxes); if (unlikely (i == 0)) { free (region); return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } return region; }
nsRegion& nsRegion::Transform (const gfx3DMatrix &aTransform) { int n; pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n); for (int i=0; i<n; i++) { nsRect rect = BoxToRect(boxes[i]); boxes[i] = RectToBox(nsIntRegion::ToRect(TransformRect(nsIntRegion::FromRect(rect), aTransform))); } pixman_region32_t region; // This will union all of the rectangles and runs in about O(n lg(n)) pixman_region32_init_rects(®ion, boxes, n); pixman_region32_fini(&mImpl); mImpl = region; return *this; }
void nsRegion::Inflate(const nsMargin& aMargin) { int n; pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n); for (int i=0; i<n; i++) { nsRect rect = BoxToRect(boxes[i]); rect.Inflate(aMargin); boxes[i] = RectToBox(rect); } pixman_region32_t region; // This will union all of the rectangles and runs in about O(n lg(n)) pixman_region32_init_rects(®ion, boxes, n); pixman_region32_fini(&mImpl); mImpl = region; }
nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale) { int n; pixman_box32_t *boxes = pixman_region32_rectangles(&mImpl, &n); for (int i=0; i<n; i++) { nsRect rect = BoxToRect(boxes[i]); rect.ScaleInverseRoundOut(aXScale, aYScale); boxes[i] = RectToBox(rect); } pixman_region32_t region; // This will union all of the rectangles and runs in about O(n lg(n)) pixman_region32_init_rects(®ion, boxes, n); pixman_region32_fini(&mImpl); mImpl = region; return *this; }
cairo_region_t * _cairo_region_create_from_boxes (const cairo_box_t *boxes, int count) { cairo_region_t *region; region = _cairo_malloc (sizeof (cairo_region_t)); if (unlikely (region == NULL)) return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); region->status = CAIRO_STATUS_SUCCESS; if (! pixman_region32_init_rects (®ion->rgn, (pixman_box32_t *)boxes, count)) { free (region); return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); } return region; }
nsIntRegion nsRegion::ToPixels (nscoord aAppUnitsPerPixel, bool aOutsidePixels) const { nsRegion region = *this; int n; pixman_box32_t *boxes = pixman_region32_rectangles(®ion.mImpl, &n); for (int i=0; i<n; i++) { nsRect rect = BoxToRect(boxes[i]); nsIntRect deviceRect; if (aOutsidePixels) deviceRect = rect.ToOutsidePixels(aAppUnitsPerPixel); else deviceRect = rect.ToNearestPixels(aAppUnitsPerPixel); boxes[i] = RectToBox(deviceRect); } nsIntRegion intRegion; pixman_region32_fini(&intRegion.mImpl.mImpl); // This will union all of the rectangles and runs in about O(n lg(n)) pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n); return intRegion; }
nsRegion nsRegion::ConvertAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP) const { if (aFromAPP == aToAPP) { return *this; } nsRegion region = *this; int n; pixman_box32_t *boxes = pixman_region32_rectangles(®ion.mImpl, &n); for (int i=0; i<n; i++) { nsRect rect = BoxToRect(boxes[i]); rect = rect.ConvertAppUnitsRoundIn(aFromAPP, aToAPP); boxes[i] = RectToBox(rect); } pixman_region32_t pixmanRegion; // This will union all of the rectangles and runs in about O(n lg(n)) pixman_region32_init_rects(&pixmanRegion, boxes, n); pixman_region32_fini(®ion.mImpl); region.mImpl = pixmanRegion; return region; }
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; }
nsIntRegion nsRegion::ScaleToInsidePixels (float aScaleX, float aScaleY, nscoord aAppUnitsPerPixel) const { /* When scaling a rect, walk forward through the rect list up until the y value is greater * than the current rect's YMost() value. * * For each rect found, check if the rects have a touching edge (in unscaled coordinates), * and if one edge is entirely contained within the other. * * If it is, then the contained edge can be moved (in scaled pixels) to ensure that no * gap exists. * * Since this could be potentially expensive - O(n^2), we only attempt this algorithm * for the first rect. */ // make a copy of this region so that we can mutate it in place nsRegion region = *this; int n; pixman_box32_t *boxes = pixman_region32_rectangles(®ion.mImpl, &n); nsIntRegion intRegion; if (n) { nsRect first = BoxToRect(boxes[0]); nsIntRect firstDeviceRect = first.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel); for (int i=1; i<n; i++) { nsRect rect = nsRect(boxes[i].x1, boxes[i].y1, boxes[i].x2 - boxes[i].x1, boxes[i].y2 - boxes[i].y1); nsIntRect deviceRect = rect.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel); if (rect.y <= first.YMost()) { if (rect.XMost() == first.x && rect.YMost() <= first.YMost()) { // rect is touching on the left edge of the first rect and contained within // the length of its left edge deviceRect.SetRightEdge(firstDeviceRect.x); } else if (rect.x == first.XMost() && rect.YMost() <= first.YMost()) { // rect is touching on the right edge of the first rect and contained within // the length of its right edge deviceRect.SetLeftEdge(firstDeviceRect.XMost()); } else if (rect.y == first.YMost()) { // The bottom of the first rect is on the same line as the top of rect, but // they aren't necessarily contained. if (rect.x <= first.x && rect.XMost() >= first.XMost()) { // The top of rect contains the bottom of the first rect firstDeviceRect.SetBottomEdge(deviceRect.y); } else if (rect.x >= first.x && rect.XMost() <= first.XMost()) { // The bottom of the first contains the top of rect deviceRect.SetTopEdge(firstDeviceRect.YMost()); } } } boxes[i] = RectToBox(deviceRect); } boxes[0] = RectToBox(firstDeviceRect); pixman_region32_fini(&intRegion.mImpl.mImpl); // This will union all of the rectangles and runs in about O(n lg(n)) pixman_region32_init_rects(&intRegion.mImpl.mImpl, boxes, n); } return intRegion; }