summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2011-08-01 22:32:09 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2011-08-11 03:32:14 -0400
commit04bd4bdca622f060d7d39caddeaa495d3e6eb0cb (patch)
treebacdcc38436c85d862b9c3c7ab07bd93a74f9e04
parent795ec5af2fc86fb0ebeca9ce82913d6002267a12 (diff)
Speed up pixman_region{,32}_contains_rectangle()
When someone selects some text in Firefox under a non-composited X server and initiates a drag, a shaped window is created with a complex shape corresponding to the outline of the text. Then, on every mouse movement pixman_region_contains_rectangle() is called many times on that complicated region. And pixman_region_contains_rectangle() is doing a linear scan through the rectangles in the region, although the scan does exit when it finds the first box that can't possibly intersect the passed-in rectangle. This patch changes the loop so that it uses a binary search to skip boxes that don't overlap the current y position. The performance improvement for the text dragging case is easily noticable. V2: Use the binary search for the "getting up to speed or skippping remainder of band" as well.
-rw-r--r--pixman/pixman-region.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/pixman/pixman-region.c b/pixman/pixman-region.c
index 142493b..71995fd 100644
--- a/pixman/pixman-region.c
+++ b/pixman/pixman-region.c
@@ -2086,6 +2086,40 @@ PIXMAN_EXPORT PREFIX (_inverse) (region_type_t *new_reg, /* Destination region
return TRUE;
}
+/* In time O(log n), locate the first box whose y2 is greater than y.
+ * Return @end if no such box exists.
+ */
+static box_type_t *
+find_box_for_y (box_type_t *begin, box_type_t *end, int y)
+{
+ box_type_t *mid;
+
+ if (end == begin)
+ return end;
+
+ if (end - begin == 1)
+ {
+ if (begin->y2 > y)
+ return begin;
+ else
+ return end;
+ }
+
+ mid = begin + (end - begin) / 2;
+ if (mid->y2 > y)
+ {
+ /* If no box is found in [begin, mid], the function
+ * will return @mid, which is then known to be the
+ * correct answer.
+ */
+ return find_box_for_y (begin, mid, y);
+ }
+ else
+ {
+ return find_box_for_y (mid, end, y);
+ }
+}
+
/*
* rect_in(region, rect)
* This routine takes a pointer to a region and a pointer to a box
@@ -2102,7 +2136,6 @@ PIXMAN_EXPORT PREFIX (_inverse) (region_type_t *new_reg, /* Destination region
* partially in the region) or is outside the region (we reached a band
* that doesn't overlap the box at all and part_in is false)
*/
-
pixman_region_overlap_t
PIXMAN_EXPORT PREFIX (_contains_rectangle) (region_type_t * region,
box_type_t * prect)
@@ -2139,12 +2172,15 @@ PIXMAN_EXPORT PREFIX (_contains_rectangle) (region_type_t * region,
/* can stop when both part_out and part_in are TRUE, or we reach prect->y2 */
for (pbox = PIXREGION_BOXPTR (region), pbox_end = pbox + numRects;
- pbox != pbox_end;
- pbox++)
+ pbox != pbox_end;
+ pbox++)
{
-
- if (pbox->y2 <= y)
- continue; /* getting up to speed or skipping remainder of band */
+ /* getting up to speed or skipping remainder of band */
+ if (pbox->y2 <= y)
+ {
+ if ((pbox = find_box_for_y (pbox, pbox_end, y)) == pbox_end)
+ break;
+ }
if (pbox->y1 > y)
{