mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
0471905a26
Previously our region code was just a simple y,x sorted list of non-intersecting rectangles. This can cause us to have simple regions represented in a complex unoptimizable way. Switching to pixman regions gives us a canonical region implementation. There are some cases when this can cause performance regressions. For example, with the old region code we end up with this region: http://people.mozilla.org/~jmuizelaar/region-pre.html which is represented like this: http://people.mozilla.org/~jmuizelaar/region-post.html with the new code. We call SimplifyOutward(4) on this. With old regions we can't simplify it so we end up taking the bounds and get 1 rect. With the new regions we have only 3 rects to start and so we do nothing. The difference between 3 rects and 1 rect cause D2D to do a PushLayer() instead of a ClipRect() and that seems to be the causes for the regression. --HG-- extra : rebase_source : 65e0d29d67b51a3780448eaecfde33dbcb6b99b1
174 lines
5.4 KiB
C++
174 lines
5.4 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "nsRegion.h"
|
|
|
|
class TestLargestRegion {
|
|
public:
|
|
static void TestSingleRect(nsRect r) {
|
|
nsRegion region(r);
|
|
EXPECT_TRUE(region.GetLargestRectangle().IsEqualInterior(r));
|
|
}
|
|
// Construct a rectangle, remove part of it, then check the remainder
|
|
static void TestNonRectangular() {
|
|
nsRegion r(nsRect(0, 0, 30, 30));
|
|
|
|
const int nTests = 19;
|
|
struct {
|
|
nsRect rect;
|
|
int64_t expectedArea;
|
|
} tests[nTests] = {
|
|
// Remove a 20x10 chunk from the square
|
|
{ nsRect(0, 0, 20, 10), 600 },
|
|
{ nsRect(10, 0, 20, 10), 600 },
|
|
{ nsRect(10, 20, 20, 10), 600 },
|
|
{ nsRect(0, 20, 20, 10), 600 },
|
|
// Remove a 10x20 chunk from the square
|
|
{ nsRect(0, 0, 10, 20), 600 },
|
|
{ nsRect(20, 0, 10, 20), 600 },
|
|
{ nsRect(20, 10, 10, 20), 600 },
|
|
{ nsRect(0, 10, 10, 20), 600 },
|
|
// Remove the center 10x10
|
|
{ nsRect(10, 10, 10, 10), 300 },
|
|
// Remove the middle column
|
|
{ nsRect(10, 0, 10, 30), 300 },
|
|
// Remove the middle row
|
|
{ nsRect(0, 10, 30, 10), 300 },
|
|
// Remove the corners 10x10
|
|
{ nsRect(0, 0, 10, 10), 600 },
|
|
{ nsRect(20, 20, 10, 10), 600 },
|
|
{ nsRect(20, 0, 10, 10), 600 },
|
|
{ nsRect(0, 20, 10, 10), 600 },
|
|
// Remove the corners 20x20
|
|
{ nsRect(0, 0, 20, 20), 300 },
|
|
{ nsRect(10, 10, 20, 20), 300 },
|
|
{ nsRect(10, 0, 20, 20), 300 },
|
|
{ nsRect(0, 10, 20, 20), 300 }
|
|
};
|
|
|
|
for (int32_t i = 0; i < nTests; i++) {
|
|
nsRegion r2;
|
|
r2.Sub(r, tests[i].rect);
|
|
|
|
EXPECT_TRUE(r2.IsComplex()) << "nsRegion code got unexpectedly smarter!";
|
|
|
|
nsRect largest = r2.GetLargestRectangle();
|
|
EXPECT_TRUE(largest.width * largest.height == tests[i].expectedArea) <<
|
|
"Did not successfully find largest rectangle in non-rectangular region on iteration " << i;
|
|
}
|
|
|
|
}
|
|
static void TwoRectTest() {
|
|
nsRegion r(nsRect(0, 0, 100, 100));
|
|
const int nTests = 4;
|
|
struct {
|
|
nsRect rect1, rect2;
|
|
int64_t expectedArea;
|
|
} tests[nTests] = {
|
|
{ nsRect(0, 0, 75, 40), nsRect(0, 60, 75, 40), 2500 },
|
|
{ nsRect(25, 0, 75, 40), nsRect(25, 60, 75, 40), 2500 },
|
|
{ nsRect(25, 0, 75, 40), nsRect(0, 60, 75, 40), 2000 },
|
|
{ nsRect(0, 0, 75, 40), nsRect(25, 60, 75, 40), 2000 },
|
|
};
|
|
for (int32_t i = 0; i < nTests; i++) {
|
|
nsRegion r2;
|
|
|
|
r2.Sub(r, tests[i].rect1);
|
|
r2.Sub(r2, tests[i].rect2);
|
|
|
|
EXPECT_TRUE(r2.IsComplex()) << "nsRegion code got unexpectedly smarter!";
|
|
|
|
nsRect largest = r2.GetLargestRectangle();
|
|
EXPECT_TRUE(largest.width * largest.height == tests[i].expectedArea) <<
|
|
"Did not successfully find largest rectangle in two-rect-subtract region on iteration " << i;
|
|
}
|
|
}
|
|
static void TestContainsSpecifiedRect() {
|
|
nsRegion r(nsRect(0, 0, 100, 100));
|
|
r.Or(r, nsRect(0, 300, 50, 50));
|
|
EXPECT_TRUE(r.GetLargestRectangle(nsRect(0, 300, 10, 10)).IsEqualInterior(nsRect(0, 300, 50, 50))) <<
|
|
"Chose wrong rectangle";
|
|
}
|
|
static void TestContainsSpecifiedOverflowingRect() {
|
|
nsRegion r(nsRect(0, 0, 100, 100));
|
|
r.Or(r, nsRect(0, 300, 50, 50));
|
|
EXPECT_TRUE(r.GetLargestRectangle(nsRect(0, 290, 10, 20)).IsEqualInterior(nsRect(0, 300, 50, 50))) <<
|
|
"Chose wrong rectangle";
|
|
}
|
|
};
|
|
|
|
TEST(Gfx, RegionSingleRect) {
|
|
TestLargestRegion::TestSingleRect(nsRect(0, 52, 720, 480));
|
|
TestLargestRegion::TestSingleRect(nsRect(-20, 40, 50, 20));
|
|
TestLargestRegion::TestSingleRect(nsRect(-20, 40, 10, 8));
|
|
TestLargestRegion::TestSingleRect(nsRect(-20, -40, 10, 8));
|
|
TestLargestRegion::TestSingleRect(nsRect(-10, -10, 20, 20));
|
|
}
|
|
|
|
TEST(Gfx, RegionNonRectangular) {
|
|
TestLargestRegion::TestNonRectangular();
|
|
}
|
|
|
|
TEST(Gfx, RegionTwoRectTest) {
|
|
TestLargestRegion::TwoRectTest();
|
|
}
|
|
|
|
TEST(Gfx, RegionContainsSpecifiedRect) {
|
|
TestLargestRegion::TestContainsSpecifiedRect();
|
|
}
|
|
|
|
TEST(Gfx, RegionTestContainsSpecifiedOverflowingRect) {
|
|
TestLargestRegion::TestContainsSpecifiedOverflowingRect();
|
|
}
|
|
|
|
TEST(Gfx, RegionScaleToInside) {
|
|
{ // no rectangles
|
|
nsRegion r;
|
|
|
|
nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
|
|
nsIntRegion result;
|
|
|
|
EXPECT_TRUE(result.IsEqual(scaled)) <<
|
|
"scaled result incorrect";
|
|
}
|
|
|
|
{ // one rectangle
|
|
nsRegion r(nsRect(0,44760,19096,264));
|
|
|
|
nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
|
|
nsIntRegion result(nsIntRect(0,746,318,4));
|
|
|
|
EXPECT_TRUE(result.IsEqual(scaled)) <<
|
|
"scaled result incorrect";
|
|
}
|
|
|
|
|
|
{ // the first rectangle gets adjusted
|
|
nsRegion r(nsRect(0,44760,19096,264));
|
|
r.Or(r, nsRect(0,45024,19360,1056));
|
|
|
|
nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
|
|
nsIntRegion result(nsIntRect(0,746,318,5));
|
|
result.Or(result, nsIntRect(0,751,322,17));
|
|
|
|
EXPECT_TRUE(result.IsEqual(scaled)) <<
|
|
"scaled result incorrect";
|
|
}
|
|
|
|
{ // the second rectangle gets adjusted
|
|
nsRegion r(nsRect(0,44760,19360,264));
|
|
r.Or(r, nsRect(0,45024,19096,1056));
|
|
|
|
nsIntRegion scaled = r.ScaleToInsidePixels(1, 1, 60);
|
|
nsIntRegion result(nsIntRect(0,746,322,4));
|
|
result.Or(result, nsIntRect(0,750,318,18));
|
|
|
|
EXPECT_TRUE(result.IsEqual(scaled)) <<
|
|
"scaled result incorrect";
|
|
}
|
|
|
|
}
|