aboutsummaryrefslogtreecommitdiff
path: root/pixman/pixman/pixman-region.c
diff options
context:
space:
mode:
Diffstat (limited to 'pixman/pixman/pixman-region.c')
-rw-r--r--pixman/pixman/pixman-region.c354
1 files changed, 282 insertions, 72 deletions
diff --git a/pixman/pixman/pixman-region.c b/pixman/pixman/pixman-region.c
index 9f7515c78..a6a400581 100644
--- a/pixman/pixman/pixman-region.c
+++ b/pixman/pixman/pixman-region.c
@@ -42,6 +42,25 @@
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
+ * Copyright © 1998 Keith Packard
+ *
+ * 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 Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD 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.
*/
#include <stdlib.h>
@@ -66,63 +85,17 @@
#define GOOD_RECT(rect) ((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2)
#define BAD_RECT(rect) ((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2)
-/* Turn on debugging depending on what type of release this is
- */
-#if (((PIXMAN_VERSION_MICRO % 2) == 0) && ((PIXMAN_VERSION_MINOR % 2) == 1))
-/* This is a development snapshot, so we want self-checking in order to
- * catch as many bugs as possible. However, we don't turn on the asserts
- * because that just leads to the X server crashing which leads to
- * people not running the snapshots.
- */
-# define noFATAL_BUGS
-# define SELF_CHECKS
-#else
-/* This is either a stable release or a random git checkout. We don't
- * want self checks in either case for performance reasons. (Random
- * git checkouts are often used for performance work
- */
-# define noFATAL_BUGS
-# define noSELF_CHECKS
-#endif
-
-#ifndef FATAL_BUGS
-# undef assert
-# undef abort
-# define assert(expr)
-# define abort()
-#endif
-
-#ifdef SELF_CHECKS
-
-static void
-log_region_error (const char *function, const char *message)
-{
- static int n_messages = 0;
-
- if (n_messages < 5)
- {
- fprintf (stderr,
- "*** BUG ***\n"
- "%s: %s\n"
- "Set a breakpoint on 'log_region_error' to debug\n\n",
- function, message);
-
- abort (); /* This is #defined away unless FATAL_BUGS is defined */
-
- n_messages++;
- }
-}
+#ifdef DEBUG
#define GOOD(reg) \
do \
{ \
if (!PREFIX (_selfcheck (reg))) \
- log_region_error (FUNC, "Malformed region " # reg); \
+ _pixman_log_error (FUNC, "Malformed region " # reg); \
} while (0)
#else
-#define log_region_error(function, name)
#define GOOD(reg)
#endif
@@ -284,7 +257,7 @@ alloc_data (size_t n)
} \
ADDRECT (next_rect, nx1, ny1, nx2, ny2); \
region->data->numRects++; \
- assert (region->data->numRects <= region->data->size); \
+ critical_if_fail (region->data->numRects <= region->data->size); \
} while (0)
#define DOWNSIZE(reg, numRects) \
@@ -409,7 +382,7 @@ PREFIX (_init_rect) (region_type_t * region,
if (!GOOD_RECT (&region->extents))
{
if (BAD_RECT (&region->extents))
- log_region_error (FUNC, "Invalid rectangle passed");
+ _pixman_log_error (FUNC, "Invalid rectangle passed");
PREFIX (_init) (region);
return;
}
@@ -423,7 +396,7 @@ PREFIX (_init_with_extents) (region_type_t *region, box_type_t *extents)
if (!GOOD_RECT (extents))
{
if (BAD_RECT (extents))
- log_region_error (FUNC, "Invalid rectangle passed");
+ _pixman_log_error (FUNC, "Invalid rectangle passed");
PREFIX (_init) (region);
return;
}
@@ -601,7 +574,7 @@ pixman_coalesce (region_type_t * region, /* Region to coalesce */
* Figure out how many rectangles are in the band.
*/
numRects = cur_start - prev_start;
- assert (numRects == region->data->numRects - cur_start);
+ critical_if_fail (numRects == region->data->numRects - cur_start);
if (!numRects) return cur_start;
@@ -689,8 +662,8 @@ pixman_region_append_non_o (region_type_t * region,
new_rects = r_end - r;
- assert (y1 < y2);
- assert (new_rects != 0);
+ critical_if_fail (y1 < y2);
+ critical_if_fail (new_rects != 0);
/* Make sure we have enough space for all rectangles to be added */
RECTALLOC (region, new_rects);
@@ -699,7 +672,7 @@ pixman_region_append_non_o (region_type_t * region,
do
{
- assert (r->x1 < r->x2);
+ critical_if_fail (r->x1 < r->x2);
ADDRECT (next_rect, r->x1, y1, r->x2, y2);
r++;
}
@@ -824,8 +797,8 @@ pixman_op (region_type_t * new_reg, /* Place to store result
r2 = PIXREGION_RECTS (reg2);
r2_end = r2 + numRects;
- assert (r1 != r1_end);
- assert (r2 != r2_end);
+ critical_if_fail (r1 != r1_end);
+ critical_if_fail (r2 != r2_end);
old_data = (region_data_type_t *)NULL;
@@ -893,8 +866,8 @@ pixman_op (region_type_t * new_reg, /* Place to store result
* rectangle after the last one in the current band for their
* respective regions.
*/
- assert (r1 != r1_end);
- assert (r2 != r2_end);
+ critical_if_fail (r1 != r1_end);
+ critical_if_fail (r2 != r2_end);
FIND_BAND (r1, r1_band_end, r1_end, r1y1);
FIND_BAND (r2, r2_band_end, r2_end, r2y1);
@@ -1101,7 +1074,7 @@ pixman_set_extents (region_type_t *region)
region->extents.x2 = box_end->x2;
region->extents.y2 = box_end->y2;
- assert (region->extents.y1 < region->extents.y2);
+ critical_if_fail (region->extents.y1 < region->extents.y2);
while (box <= box_end)
{
@@ -1112,7 +1085,7 @@ pixman_set_extents (region_type_t *region)
box++;
}
- assert (region->extents.x1 < region->extents.x2);
+ critical_if_fail (region->extents.x1 < region->extents.x2);
}
/*======================================================================
@@ -1148,8 +1121,8 @@ pixman_region_intersect_o (region_type_t *region,
next_rect = PIXREGION_TOP (region);
- assert (y1 < y2);
- assert (r1 != r1_end && r2 != r2_end);
+ critical_if_fail (y1 < y2);
+ critical_if_fail (r1 != r1_end && r2 != r2_end);
do
{
@@ -1306,8 +1279,8 @@ pixman_region_union_o (region_type_t *region,
int x1; /* left and right side of current union */
int x2;
- assert (y1 < y2);
- assert (r1 != r1_end && r2 != r2_end);
+ critical_if_fail (y1 < y2);
+ critical_if_fail (r1 != r1_end && r2 != r2_end);
next_rect = PIXREGION_TOP (region);
@@ -1377,10 +1350,10 @@ PREFIX (_union_rect) (region_type_t *dest,
if (!GOOD_RECT (&region.extents))
{
if (BAD_RECT (&region.extents))
- log_region_error (FUNC, "Invalid rectangle passed");
+ _pixman_log_error (FUNC, "Invalid rectangle passed");
return PREFIX (_copy) (dest, source);
}
-
+
region.data = NULL;
return PREFIX (_union) (dest, source, &region);
@@ -1870,8 +1843,8 @@ pixman_region_subtract_o (region_type_t * region,
x1 = r1->x1;
- assert (y1 < y2);
- assert (r1 != r1_end && r2 != r2_end);
+ critical_if_fail (y1 < y2);
+ critical_if_fail (r1 != r1_end && r2 != r2_end);
next_rect = PIXREGION_TOP (region);
@@ -1915,7 +1888,7 @@ pixman_region_subtract_o (region_type_t * region,
* Left part of subtrahend covers part of minuend: add uncovered
* part of minuend to region and skip to next subtrahend.
*/
- assert (x1 < r2->x1);
+ critical_if_fail (x1 < r2->x1);
NEWRECT (region, next_rect, x1, y1, r2->x1, y2);
x1 = r2->x2;
@@ -1957,7 +1930,7 @@ pixman_region_subtract_o (region_type_t * region,
*/
while (r1 != r1_end)
{
- assert (x1 < r1->x2);
+ critical_if_fail (x1 < r1->x2);
NEWRECT (region, next_rect, x1, y1, r1->x2, y2);
@@ -2319,7 +2292,7 @@ PREFIX (_reset) (region_type_t *region, box_type_t *box)
{
GOOD (region);
- assert (GOOD_RECT (box));
+ critical_if_fail (GOOD_RECT (box));
region->extents = *box;
@@ -2539,3 +2512,240 @@ PREFIX (_init_rects) (region_type_t *region,
return validate (region, &i);
}
+
+#define READ(_ptr) (*(_ptr))
+
+static inline box_type_t *
+bitmap_addrect (region_type_t *reg,
+ box_type_t *r,
+ box_type_t **first_rect,
+ int rx1, int ry1,
+ int rx2, int ry2)
+{
+ if ((rx1 < rx2) && (ry1 < ry2) &&
+ (!(reg->data->numRects &&
+ ((r-1)->y1 == ry1) && ((r-1)->y2 == ry2) &&
+ ((r-1)->x1 <= rx1) && ((r-1)->x2 >= rx2))))
+ {
+ if (!reg->data ||
+ reg->data->numRects == reg->data->size)
+ {
+ if (!pixman_rect_alloc (reg, 1))
+ return NULL;
+ *first_rect = PIXREGION_BOXPTR(reg);
+ r = *first_rect + reg->data->numRects;
+ }
+ r->x1 = rx1;
+ r->y1 = ry1;
+ r->x2 = rx2;
+ r->y2 = ry2;
+ reg->data->numRects++;
+ if (r->x1 < reg->extents.x1)
+ reg->extents.x1 = r->x1;
+ if (r->x2 > reg->extents.x2)
+ reg->extents.x2 = r->x2;
+ r++;
+ }
+ return r;
+}
+
+/* Convert bitmap clip mask into clipping region.
+ * First, goes through each line and makes boxes by noting the transitions
+ * from 0 to 1 and 1 to 0.
+ * Then it coalesces the current line with the previous if they have boxes
+ * at the same X coordinates.
+ * Stride is in number of uint32_t per line.
+ */
+PIXMAN_EXPORT void
+PREFIX (_init_from_image) (region_type_t *region,
+ pixman_image_t *image)
+{
+ uint32_t mask0 = 0xffffffff & ~SCREEN_SHIFT_RIGHT(0xffffffff, 1);
+ box_type_t *first_rect, *rects, *prect_line_start;
+ box_type_t *old_rect, *new_rect;
+ uint32_t *pw, w, *pw_line, *pw_line_end;
+ int irect_prev_start, irect_line_start;
+ int h, base, rx1 = 0, crects;
+ int ib;
+ pixman_bool_t in_box, same;
+ int width, height, stride;
+
+ PREFIX(_init) (region);
+
+ return_if_fail (image->type == BITS);
+ return_if_fail (image->bits.format == PIXMAN_a1);
+
+ pw_line = pixman_image_get_data (image);
+ width = pixman_image_get_width (image);
+ height = pixman_image_get_height (image);
+ stride = pixman_image_get_stride (image) / 4;
+
+ first_rect = PIXREGION_BOXPTR(region);
+ rects = first_rect;
+
+ region->extents.x1 = width - 1;
+ region->extents.x2 = 0;
+ irect_prev_start = -1;
+ for (h = 0; h < height; h++)
+ {
+ pw = pw_line;
+ pw_line += stride;
+ irect_line_start = rects - first_rect;
+
+ /* If the Screen left most bit of the word is set, we're starting in
+ * a box */
+ if (READ(pw) & mask0)
+ {
+ in_box = TRUE;
+ rx1 = 0;
+ }
+ else
+ {
+ in_box = FALSE;
+ }
+
+ /* Process all words which are fully in the pixmap */
+ pw_line_end = pw + (width >> 5);
+ for (base = 0; pw < pw_line_end; base += 32)
+ {
+ w = READ(pw++);
+ if (in_box)
+ {
+ if (!~w)
+ continue;
+ }
+ else
+ {
+ if (!w)
+ continue;
+ }
+ for (ib = 0; ib < 32; ib++)
+ {
+ /* If the Screen left most bit of the word is set, we're
+ * starting a box */
+ if (w & mask0)
+ {
+ if (!in_box)
+ {
+ rx1 = base + ib;
+ /* start new box */
+ in_box = TRUE;
+ }
+ }
+ else
+ {
+ if (in_box)
+ {
+ /* end box */
+ rects = bitmap_addrect (region, rects, &first_rect,
+ rx1, h, base + ib, h + 1);
+ if (rects == NULL)
+ goto error;
+ in_box = FALSE;
+ }
+ }
+ /* Shift the word VISUALLY left one. */
+ w = SCREEN_SHIFT_LEFT(w, 1);
+ }
+ }
+
+ if (width & 31)
+ {
+ /* Process final partial word on line */
+ w = READ(pw++);
+ for (ib = 0; ib < (width & 31); ib++)
+ {
+ /* If the Screen left most bit of the word is set, we're
+ * starting a box */
+ if (w & mask0)
+ {
+ if (!in_box)
+ {
+ rx1 = base + ib;
+ /* start new box */
+ in_box = TRUE;
+ }
+ }
+ else
+ {
+ if (in_box)
+ {
+ /* end box */
+ rects = bitmap_addrect(region, rects, &first_rect,
+ rx1, h, base + ib, h + 1);
+ if (rects == NULL)
+ goto error;
+ in_box = FALSE;
+ }
+ }
+ /* Shift the word VISUALLY left one. */
+ w = SCREEN_SHIFT_LEFT(w, 1);
+ }
+ }
+ /* If scanline ended with last bit set, end the box */
+ if (in_box)
+ {
+ rects = bitmap_addrect(region, rects, &first_rect,
+ rx1, h, base + (width & 31), h + 1);
+ if (rects == NULL)
+ goto error;
+ }
+ /* if all rectangles on this line have the same x-coords as
+ * those on the previous line, then add 1 to all the previous y2s and
+ * throw away all the rectangles from this line
+ */
+ same = FALSE;
+ if (irect_prev_start != -1)
+ {
+ crects = irect_line_start - irect_prev_start;
+ if (crects != 0 &&
+ crects == ((rects - first_rect) - irect_line_start))
+ {
+ old_rect = first_rect + irect_prev_start;
+ new_rect = prect_line_start = first_rect + irect_line_start;
+ same = TRUE;
+ while (old_rect < prect_line_start)
+ {
+ if ((old_rect->x1 != new_rect->x1) ||
+ (old_rect->x2 != new_rect->x2))
+ {
+ same = FALSE;
+ break;
+ }
+ old_rect++;
+ new_rect++;
+ }
+ if (same)
+ {
+ old_rect = first_rect + irect_prev_start;
+ while (old_rect < prect_line_start)
+ {
+ old_rect->y2 += 1;
+ old_rect++;
+ }
+ rects -= crects;
+ region->data->numRects -= crects;
+ }
+ }
+ }
+ if(!same)
+ irect_prev_start = irect_line_start;
+ }
+ if (!region->data->numRects)
+ {
+ region->extents.x1 = region->extents.x2 = 0;
+ }
+ else
+ {
+ region->extents.y1 = PIXREGION_BOXPTR(region)->y1;
+ region->extents.y2 = PIXREGION_END(region)->y2;
+ if (region->data->numRects == 1)
+ {
+ free (region->data);
+ region->data = NULL;
+ }
+ }
+
+ error:
+ return;
+}