summaryrefslogtreecommitdiffstats
path: root/cc/base
diff options
context:
space:
mode:
authordanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-22 01:16:43 +0000
committerdanakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-22 01:21:15 +0000
commitd5467eb7835eccd7b1e1a65096c9b1f37c70fcb2 (patch)
treedb295fcc90bc936cf52818bffd73d7560c80f0f3 /cc/base
parent903cf847d2d66f33e1f2cdab5f45a1b07558fa7a (diff)
downloadchromium_src-d5467eb7835eccd7b1e1a65096c9b1f37c70fcb2.zip
chromium_src-d5467eb7835eccd7b1e1a65096c9b1f37c70fcb2.tar.gz
chromium_src-d5467eb7835eccd7b1e1a65096c9b1f37c70fcb2.tar.bz2
cc: Replace Region with SimpleEnclosedRegion for occlusion tracking
Instead of using an arbitrary Region, which is costly (slow), use a new SimpleEnclosedRegion. This class tracks only a single Rect at a given time so it is very fast and small. It tries to get something like the largest rect enclosed in the actual Region (were we to track such a Region) in an online fashion, ie it doesn't remember anything except its current largest possible rect. BUG=405663 Review URL: https://codereview.chromium.org/202523002 Cr-Commit-Position: refs/heads/master@{#291292} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291292 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/base')
-rw-r--r--cc/base/region.cc9
-rw-r--r--cc/base/region.h3
-rw-r--r--cc/base/simple_enclosed_region.cc136
-rw-r--r--cc/base/simple_enclosed_region.h122
-rw-r--r--cc/base/simple_enclosed_region_unittest.cc637
5 files changed, 906 insertions, 1 deletions
diff --git a/cc/base/region.cc b/cc/base/region.cc
index 79c30ec..2484cc2 100644
--- a/cc/base/region.cc
+++ b/cc/base/region.cc
@@ -3,8 +3,10 @@
// found in the LICENSE file.
#include "cc/base/region.h"
+
#include "base/debug/trace_event_argument.h"
#include "base/values.h"
+#include "cc/base/simple_enclosed_region.h"
namespace cc {
@@ -80,6 +82,13 @@ void Region::Subtract(const Region& region) {
skregion_.op(region.skregion_, SkRegion::kDifference_Op);
}
+void Region::Subtract(const SimpleEnclosedRegion& region) {
+ for (size_t i = 0; i < region.GetRegionComplexity(); ++i) {
+ skregion_.op(gfx::RectToSkIRect(region.GetRect(i)),
+ SkRegion::kDifference_Op);
+ }
+}
+
void Region::Union(const gfx::Rect& rect) {
skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kUnion_Op);
}
diff --git a/cc/base/region.h b/cc/base/region.h
index 3ef32db..d78d4cb 100644
--- a/cc/base/region.h
+++ b/cc/base/region.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "third_party/skia/include/core/SkRegion.h"
@@ -22,6 +21,7 @@ class TracedValue;
}
namespace cc {
+class SimpleEnclosedRegion;
class CC_EXPORT Region {
public:
@@ -47,6 +47,7 @@ class CC_EXPORT Region {
void Subtract(const gfx::Rect& rect);
void Subtract(const Region& region);
+ void Subtract(const SimpleEnclosedRegion& region);
void Union(const gfx::Rect& rect);
void Union(const Region& region);
void Intersect(const gfx::Rect& rect);
diff --git a/cc/base/simple_enclosed_region.cc b/cc/base/simple_enclosed_region.cc
new file mode 100644
index 0000000..e2683f3
--- /dev/null
+++ b/cc/base/simple_enclosed_region.cc
@@ -0,0 +1,136 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/base/simple_enclosed_region.h"
+
+#include "base/logging.h"
+#include "cc/base/region.h"
+
+namespace cc {
+
+static bool RectIsLargerArea(const gfx::Rect& a, const gfx::Rect b) {
+ int64 a_area = static_cast<int64>(a.width()) * a.height();
+ int64 b_area = static_cast<int64>(b.width()) * b.height();
+ return a_area > b_area;
+}
+
+SimpleEnclosedRegion::SimpleEnclosedRegion(const Region& region) {
+ for (Region::Iterator it(region); it.has_rect(); it.next())
+ Union(it.rect());
+}
+
+SimpleEnclosedRegion::~SimpleEnclosedRegion() {
+}
+
+void SimpleEnclosedRegion::Subtract(const gfx::Rect& sub_rect) {
+ // We want to keep as much of the current rect as we can, so find the one
+ // largest rectangle inside |rect_| that does not intersect with |sub_rect|.
+ if (!rect_.Intersects(sub_rect))
+ return;
+ if (sub_rect.Contains(rect_)) {
+ rect_ = gfx::Rect();
+ return;
+ }
+
+ int left = rect_.x();
+ int right = rect_.right();
+ int top = rect_.y();
+ int bottom = rect_.bottom();
+
+ int delta_left = sub_rect.x() - left;
+ int delta_right = right - sub_rect.right();
+ int delta_top = sub_rect.y() - top;
+ int delta_bottom = bottom - sub_rect.bottom();
+
+ // The horizontal rect is the larger of the two rectangles above or below
+ // |sub_rect| and inside rect_.
+ int horizontal_top = top;
+ int horizontal_bottom = bottom;
+ if (delta_top > delta_bottom)
+ horizontal_bottom = sub_rect.y();
+ else
+ horizontal_top = sub_rect.bottom();
+ // The vertical rect is the larger of the two rectangles to the left or the
+ // right of |sub_rect| and inside rect_.
+ int vertical_left = left;
+ int vertical_right = right;
+ if (delta_left > delta_right)
+ vertical_right = sub_rect.x();
+ else
+ vertical_left = sub_rect.right();
+
+ rect_.SetRect(
+ left, horizontal_top, right - left, horizontal_bottom - horizontal_top);
+
+ gfx::Rect vertical_rect(
+ vertical_left, top, vertical_right - vertical_left, bottom - top);
+ if (RectIsLargerArea(vertical_rect, rect_))
+ rect_ = vertical_rect;
+}
+
+void SimpleEnclosedRegion::Union(const gfx::Rect& new_rect) {
+ // We want to keep track of a region but bound its complexity at a constant
+ // size. We keep track of the largest rectangle seen by area. If we can add
+ // the |new_rect| to this rectangle then we do that, as that is the cheapest
+ // way to increase the area returned without increasing the complexity.
+ if (new_rect.IsEmpty())
+ return;
+ if (rect_.Contains(new_rect))
+ return;
+ if (new_rect.Contains(rect_)) {
+ rect_ = new_rect;
+ return;
+ }
+
+ int left = rect_.x();
+ int top = rect_.y();
+ int right = rect_.right();
+ int bottom = rect_.bottom();
+
+ int new_left = new_rect.x();
+ int new_top = new_rect.y();
+ int new_right = new_rect.right();
+ int new_bottom = new_rect.bottom();
+
+ // This attempts to expand each edge of |rect_| if the |new_rect| entirely
+ // covers or is adjacent to an entire edge of |rect_|. If this is true for
+ // an edge of |rect_| then it can be expanded out to share that edge with the
+ // same edge of |new_rect|. After, the same thing is done to try expand
+ // |new_rect| relative to |rect_|.
+ if (new_top <= top && new_bottom >= bottom) {
+ if (new_left < left && new_right >= left)
+ left = new_left;
+ if (new_right > right && new_left <= right)
+ right = new_right;
+ } else if (new_left <= left && new_right >= right) {
+ if (new_top < top && new_bottom >= top)
+ top = new_top;
+ if (new_bottom > bottom && new_top <= bottom)
+ bottom = new_bottom;
+ } else if (top <= new_top && bottom >= new_bottom) {
+ if (left < new_left && right >= new_left)
+ new_left = left;
+ if (right > new_right && left <= new_right)
+ new_right = right;
+ } else if (left <= new_left && right >= new_right) {
+ if (top < new_top && bottom >= new_top)
+ new_top = top;
+ if (bottom > new_bottom && top <= new_bottom)
+ new_bottom = bottom;
+ }
+
+ rect_.SetRect(left, top, right - left, bottom - top);
+
+ gfx::Rect adjusted_new_rect(
+ new_left, new_top, new_right - new_left, new_bottom - new_top);
+ if (RectIsLargerArea(adjusted_new_rect, rect_))
+ rect_ = adjusted_new_rect;
+}
+
+gfx::Rect SimpleEnclosedRegion::GetRect(size_t i) const {
+ DCHECK_LT(i, GetRegionComplexity());
+ return rect_;
+}
+
+} // namespace cc
diff --git a/cc/base/simple_enclosed_region.h b/cc/base/simple_enclosed_region.h
new file mode 100644
index 0000000..c9625ba
--- /dev/null
+++ b/cc/base/simple_enclosed_region.h
@@ -0,0 +1,122 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_BASE_SIMPLE_ENCLOSED_REGION_H_
+#define CC_BASE_SIMPLE_ENCLOSED_REGION_H_
+
+#include <string>
+
+#include "cc/base/cc_export.h"
+#include "ui/gfx/rect.h"
+
+namespace cc {
+
+class Region;
+
+// A constant-sized approximation of a Region. The SimpleEnclosedRegion may
+// exclude points in its approximation (may have false negatives) but will never
+// include a point that would not be in the actual Region (no false positives).
+class CC_EXPORT SimpleEnclosedRegion {
+ public:
+ SimpleEnclosedRegion() : rect_() {}
+ SimpleEnclosedRegion(const SimpleEnclosedRegion& region)
+ : rect_(region.rect_) {}
+ explicit SimpleEnclosedRegion(const gfx::Rect& rect) : rect_(rect) {}
+ SimpleEnclosedRegion(int x, int y, int w, int h) : rect_(x, y, w, h) {}
+ SimpleEnclosedRegion(int w, int h) : rect_(w, h) {}
+ explicit SimpleEnclosedRegion(const Region& region);
+ ~SimpleEnclosedRegion();
+
+ const SimpleEnclosedRegion& operator=(const gfx::Rect& rect) {
+ rect_ = rect;
+ return *this;
+ }
+ const SimpleEnclosedRegion& operator=(const SimpleEnclosedRegion& region) {
+ rect_ = region.rect_;
+ return *this;
+ }
+
+ bool IsEmpty() const { return rect_.IsEmpty(); }
+ void Clear() { rect_ = gfx::Rect(); }
+ size_t GetRegionComplexity() const { return rect_.IsEmpty() ? 0 : 1; }
+
+ bool Contains(const gfx::Point& point) const { return rect_.Contains(point); }
+ bool Contains(const gfx::Rect& rect) const { return rect_.Contains(rect); }
+ bool Contains(const SimpleEnclosedRegion& region) const {
+ return rect_.Contains(region.rect_);
+ }
+
+ bool Intersects(const gfx::Rect& rect) const {
+ return rect_.Intersects(rect);
+ }
+ bool Intersects(const SimpleEnclosedRegion& region) const {
+ return rect_.Intersects(region.rect_);
+ }
+
+ void Subtract(const gfx::Rect& sub_rect);
+ void Subtract(const SimpleEnclosedRegion& sub_region) {
+ Subtract(sub_region.rect_);
+ }
+ void Union(const gfx::Rect& new_rect);
+ void Union(const SimpleEnclosedRegion& new_region) {
+ Union(new_region.rect_);
+ }
+ void Intersect(const gfx::Rect& in_rect) { return rect_.Intersect(in_rect); }
+ void Intersect(const SimpleEnclosedRegion& in_region) {
+ Intersect(in_region.rect_);
+ }
+
+ bool Equals(const SimpleEnclosedRegion& other) const {
+ bool both_empty = rect_.IsEmpty() && other.rect_.IsEmpty();
+ return both_empty || rect_ == other.rect_;
+ }
+
+ gfx::Rect bounds() const { return rect_; }
+
+ // The value of |i| must be less than GetRegionComplexity().
+ gfx::Rect GetRect(size_t i) const;
+
+ std::string ToString() const { return rect_.ToString(); }
+
+ private:
+ gfx::Rect rect_;
+};
+
+inline bool operator==(const SimpleEnclosedRegion& a,
+ const SimpleEnclosedRegion& b) {
+ return a.Equals(b);
+}
+
+inline bool operator!=(const SimpleEnclosedRegion& a,
+ const SimpleEnclosedRegion& b) {
+ return !(a == b);
+}
+
+inline SimpleEnclosedRegion SubtractSimpleEnclosedRegions(
+ const SimpleEnclosedRegion& a,
+ const SimpleEnclosedRegion& b) {
+ SimpleEnclosedRegion result = a;
+ result.Subtract(b);
+ return result;
+}
+
+inline SimpleEnclosedRegion IntersectSimpleEnclosedRegions(
+ const SimpleEnclosedRegion& a,
+ const SimpleEnclosedRegion& b) {
+ SimpleEnclosedRegion result = a;
+ result.Intersect(b);
+ return result;
+}
+
+inline SimpleEnclosedRegion UnionSimpleEnclosedRegions(
+ const SimpleEnclosedRegion& a,
+ const SimpleEnclosedRegion& b) {
+ SimpleEnclosedRegion result = a;
+ result.Union(b);
+ return result;
+}
+
+} // namespace cc
+
+#endif // CC_BASE_SIMPLE_ENCLOSED_REGION_H_
diff --git a/cc/base/simple_enclosed_region_unittest.cc b/cc/base/simple_enclosed_region_unittest.cc
new file mode 100644
index 0000000..869da4e
--- /dev/null
+++ b/cc/base/simple_enclosed_region_unittest.cc
@@ -0,0 +1,637 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/base/simple_enclosed_region.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "cc/base/region.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+bool ExpectRegionEq(const gfx::Rect& rect, const SimpleEnclosedRegion& region) {
+ std::vector<gfx::Rect> actual_rects;
+ std::vector<gfx::Rect> expected_rects;
+
+ if (!rect.IsEmpty())
+ expected_rects.push_back(rect);
+
+ for (size_t i = 0; i < region.GetRegionComplexity(); ++i)
+ actual_rects.push_back(region.GetRect(i));
+
+ if (rect.IsEmpty() != region.IsEmpty()) {
+ LOG(ERROR) << "Expected: " << rect.IsEmpty()
+ << " Actual: " << region.IsEmpty();
+ return false;
+ }
+
+ if (expected_rects.size() != actual_rects.size()) {
+ LOG(ERROR) << "Expected: " << expected_rects.size()
+ << " Actual: " << actual_rects.size();
+ return false;
+ }
+
+ std::sort(actual_rects.begin(), actual_rects.end());
+ std::sort(expected_rects.begin(), expected_rects.end());
+
+ for (size_t i = 0; i < expected_rects.size(); ++i) {
+ if (expected_rects[i] != actual_rects[i]) {
+ LOG(ERROR) << "Expected: " << expected_rects[i].ToString()
+ << " Actual: " << actual_rects[i].ToString();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+TEST(SimpleEnclosedRegionTest, Create) {
+ SimpleEnclosedRegion r1;
+ EXPECT_TRUE(r1.IsEmpty());
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(), r1));
+
+ SimpleEnclosedRegion r2(gfx::Rect(2, 3, 4, 5));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 4, 5), r2));
+
+ SimpleEnclosedRegion r3(2, 3, 4, 5);
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 4, 5), r3));
+
+ SimpleEnclosedRegion r4(4, 5);
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(4, 5), r4));
+
+ SimpleEnclosedRegion r5(Region(gfx::Rect(2, 3, 4, 5)));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 4, 5), r5));
+
+ SimpleEnclosedRegion r6(r5);
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 4, 5), r6));
+}
+
+TEST(SimpleEnclosedRegionTest, Assign) {
+ SimpleEnclosedRegion r;
+ EXPECT_TRUE(r.IsEmpty());
+
+ r = gfx::Rect(2, 3, 4, 5);
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 4, 5), r));
+
+ r = SimpleEnclosedRegion(3, 4, 5, 6);
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(3, 4, 5, 6), r));
+}
+
+TEST(SimpleEnclosedRegionTest, Clear) {
+ SimpleEnclosedRegion r(1, 2, 3, 4);
+ EXPECT_FALSE(r.IsEmpty());
+ r.Clear();
+ EXPECT_TRUE(r.IsEmpty());
+}
+
+TEST(SimpleEnclosedRegionTest, GetRegionComplexity) {
+ SimpleEnclosedRegion empty;
+ EXPECT_EQ(0u, empty.GetRegionComplexity());
+
+ SimpleEnclosedRegion stuff;
+ stuff.Union(gfx::Rect(1, 2, 3, 4));
+ EXPECT_EQ(1u, stuff.GetRegionComplexity());
+
+ // The SimpleEnclosedRegion only holds up to 1 rect.
+ stuff.Union(gfx::Rect(5, 6, 7, 8));
+ EXPECT_EQ(1u, stuff.GetRegionComplexity());
+}
+
+TEST(SimpleEnclosedRegionTest, Contains) {
+ SimpleEnclosedRegion r(1, 2, 5, 6);
+
+ EXPECT_FALSE(r.Contains(gfx::Point(0, 2)));
+ EXPECT_FALSE(r.Contains(gfx::Point(1, 1)));
+ EXPECT_TRUE(r.Contains(gfx::Point(1, 2)));
+
+ EXPECT_FALSE(r.Contains(gfx::Point(6, 2)));
+ EXPECT_FALSE(r.Contains(gfx::Point(5, 1)));
+ EXPECT_TRUE(r.Contains(gfx::Point(5, 2)));
+
+ EXPECT_FALSE(r.Contains(gfx::Point(0, 7)));
+ EXPECT_FALSE(r.Contains(gfx::Point(1, 8)));
+ EXPECT_TRUE(r.Contains(gfx::Point(1, 7)));
+
+ EXPECT_FALSE(r.Contains(gfx::Point(6, 7)));
+ EXPECT_FALSE(r.Contains(gfx::Point(5, 8)));
+ EXPECT_TRUE(r.Contains(gfx::Point(5, 7)));
+
+ EXPECT_FALSE(r.Contains(gfx::Rect(0, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(1, 1, 1, 1)));
+ EXPECT_TRUE(r.Contains(gfx::Rect(1, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(0, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Contains(gfx::Rect(6, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(5, 1, 1, 1)));
+ EXPECT_TRUE(r.Contains(gfx::Rect(5, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(5, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Contains(gfx::Rect(0, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(1, 8, 1, 1)));
+ EXPECT_TRUE(r.Contains(gfx::Rect(1, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(0, 7, 2, 2)));
+
+ EXPECT_FALSE(r.Contains(gfx::Rect(6, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(5, 8, 1, 1)));
+ EXPECT_TRUE(r.Contains(gfx::Rect(5, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(gfx::Rect(5, 7, 2, 2)));
+
+ gfx::Rect q(1, 2, 5, 6);
+ EXPECT_TRUE(r.Contains(q)) << q.ToString();
+ q.Inset(-1, 0, 0, 0);
+ EXPECT_FALSE(r.Contains(q)) << q.ToString();
+ q.Inset(1, -1, 0, 0);
+ EXPECT_FALSE(r.Contains(q)) << q.ToString();
+ q.Inset(0, 1, -1, 0);
+ EXPECT_FALSE(r.Contains(q)) << q.ToString();
+ q.Inset(0, 0, 1, -1);
+ EXPECT_FALSE(r.Contains(q)) << q.ToString();
+
+ q.Inset(1, 0, 0, 1);
+ EXPECT_TRUE(r.Contains(q)) << q.ToString();
+ q.Inset(-1, 1, 0, 0);
+ EXPECT_TRUE(r.Contains(q)) << q.ToString();
+ q.Inset(0, -1, 1, 0);
+ EXPECT_TRUE(r.Contains(q)) << q.ToString();
+ q.Inset(0, 0, -1, 1);
+ EXPECT_TRUE(r.Contains(q)) << q.ToString();
+
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(0, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(1, 1, 1, 1)));
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(1, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(0, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(6, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(5, 1, 1, 1)));
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(5, 2, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(5, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(0, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(1, 8, 1, 1)));
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(1, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(0, 7, 2, 2)));
+
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(6, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(5, 8, 1, 1)));
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(5, 7, 1, 1)));
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(5, 7, 2, 2)));
+
+ q = gfx::Rect(1, 2, 5, 6);
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(-1, 0, 0, 0);
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(1, -1, 0, 0);
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, 1, -1, 0);
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, 0, 1, -1);
+ EXPECT_FALSE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+
+ q.Inset(1, 0, 0, 1);
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(-1, 1, 0, 0);
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, -1, 1, 0);
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, 0, -1, 1);
+ EXPECT_TRUE(r.Contains(SimpleEnclosedRegion(q))) << q.ToString();
+}
+
+TEST(SimpleEnclosedRegionTest, Intersects) {
+ SimpleEnclosedRegion r(1, 2, 5, 6);
+
+ EXPECT_FALSE(r.Intersects(gfx::Rect(0, 2, 1, 1)));
+ EXPECT_FALSE(r.Intersects(gfx::Rect(1, 1, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(1, 2, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(0, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Intersects(gfx::Rect(6, 2, 1, 1)));
+ EXPECT_FALSE(r.Intersects(gfx::Rect(5, 1, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(5, 2, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(5, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Intersects(gfx::Rect(0, 7, 1, 1)));
+ EXPECT_FALSE(r.Intersects(gfx::Rect(1, 8, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(1, 7, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(0, 7, 2, 2)));
+
+ EXPECT_FALSE(r.Intersects(gfx::Rect(6, 7, 1, 1)));
+ EXPECT_FALSE(r.Intersects(gfx::Rect(5, 8, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(5, 7, 1, 1)));
+ EXPECT_TRUE(r.Intersects(gfx::Rect(5, 7, 2, 2)));
+
+ gfx::Rect q(1, 2, 5, 6);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+ q.Inset(-1, 0, 0, 0);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+ q.Inset(1, -1, 0, 0);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+ q.Inset(0, 1, -1, 0);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+ q.Inset(0, 0, 1, -1);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+
+ q.Inset(1, 0, 0, 1);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+ q.Inset(-1, 1, 0, 0);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+ q.Inset(0, -1, 1, 0);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+ q.Inset(0, 0, -1, 1);
+ EXPECT_TRUE(r.Intersects(q)) << q.ToString();
+
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(0, 2, 1, 1)));
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(1, 1, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(1, 2, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(0, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(6, 2, 1, 1)));
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(5, 1, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(5, 2, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(5, 1, 2, 2)));
+
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(0, 7, 1, 1)));
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(1, 8, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(1, 7, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(0, 7, 2, 2)));
+
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(6, 7, 1, 1)));
+ EXPECT_FALSE(r.Intersects(SimpleEnclosedRegion(5, 8, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(5, 7, 1, 1)));
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(5, 7, 2, 2)));
+
+ q = gfx::Rect(1, 2, 5, 6);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(-1, 0, 0, 0);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(1, -1, 0, 0);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, 1, -1, 0);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, 0, 1, -1);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+
+ q.Inset(1, 0, 0, 1);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(-1, 1, 0, 0);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, -1, 1, 0);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+ q.Inset(0, 0, -1, 1);
+ EXPECT_TRUE(r.Intersects(SimpleEnclosedRegion(q))) << q.ToString();
+}
+
+TEST(SimpleEnclosedRegionTest, Equals) {
+ SimpleEnclosedRegion r(1, 2, 3, 4);
+ EXPECT_TRUE(r.Equals(SimpleEnclosedRegion(1, 2, 3, 4)));
+ EXPECT_FALSE(r.Equals(SimpleEnclosedRegion(2, 2, 3, 4)));
+ EXPECT_FALSE(r.Equals(SimpleEnclosedRegion(1, 3, 3, 4)));
+ EXPECT_FALSE(r.Equals(SimpleEnclosedRegion(1, 2, 4, 4)));
+ EXPECT_FALSE(r.Equals(SimpleEnclosedRegion(1, 2, 3, 5)));
+ EXPECT_FALSE(r.Equals(SimpleEnclosedRegion(2, 2, 2, 4)));
+ EXPECT_FALSE(r.Equals(SimpleEnclosedRegion(1, 3, 3, 3)));
+}
+
+TEST(SimpleEnclosedRegionTest, Bounds) {
+ SimpleEnclosedRegion r;
+ EXPECT_EQ(gfx::Rect(), r.bounds());
+ r = gfx::Rect(3, 4, 5, 6);
+ EXPECT_EQ(gfx::Rect(3, 4, 5, 6), r.bounds());
+ r.Union(gfx::Rect(1, 2, 12, 13));
+ EXPECT_EQ(gfx::Rect(1, 2, 12, 13), r.bounds());
+}
+
+TEST(SimpleEnclosedRegionTest, GetRect) {
+ SimpleEnclosedRegion r(3, 4, 5, 6);
+ EXPECT_EQ(gfx::Rect(3, 4, 5, 6), r.GetRect(0));
+ r.Union(gfx::Rect(1, 2, 12, 13));
+ EXPECT_EQ(gfx::Rect(1, 2, 12, 13), r.GetRect(0));
+}
+
+TEST(SimpleEnclosedRegionTest, Union) {
+ SimpleEnclosedRegion r;
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(), r));
+
+ // Empty Union anything = anything.
+ r.Union(gfx::Rect(4, 5, 6, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(4, 5, 6, 7), r));
+
+ // Anything Union empty = anything.
+ r.Union(gfx::Rect());
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(4, 5, 6, 7), r));
+
+ // Anything Union contained rect = Anything.
+ r.Union(gfx::Rect(5, 6, 4, 5));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(4, 5, 6, 7), r));
+
+ // Anything Union containing rect = containing rect.
+ r.Union(gfx::Rect(2, 3, 8, 9));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 8, 9), r));
+ r.Union(gfx::Rect(2, 3, 9, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 9, 10), r));
+
+ // Union with a smaller disjoint rect is ignored.
+ r.Union(gfx::Rect(20, 21, 9, 9));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 9, 10), r));
+
+ // Union with a smaller overlapping rect is ignored.
+ r.Union(gfx::Rect(3, 4, 9, 9));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 9, 10), r));
+
+ // Union with an equal sized rect can be either one.
+ r.Union(gfx::Rect(4, 4, 9, 10));
+ EXPECT_EQ(1u, r.GetRegionComplexity());
+ EXPECT_TRUE(r.bounds() == gfx::Rect(2, 3, 9, 10) ||
+ r.bounds() == gfx::Rect(4, 4, 9, 10));
+
+ // Union with a larger disjoint rect is taken.
+ r.Union(gfx::Rect(20, 21, 12, 13));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(20, 21, 12, 13), r));
+
+ // Union with a larger overlapping rect is taken.
+ r.Union(gfx::Rect(19, 19, 12, 14));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(19, 19, 12, 14), r));
+
+ // True also when the rect covers one edge of the existing region.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(12, 7, 9, 16));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(12, 7, 9, 16), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(9, 7, 9, 16));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(9, 7, 9, 16), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(7, 12, 16, 9));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(7, 12, 16, 9), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(7, 9, 16, 9));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(7, 9, 16, 9), r));
+
+ // But if the existing region can be expanded to make a larger rect, then it
+ // will. Union area is 9*12 = 108. By merging, we make a rect with an area of
+ // 10*11 = 110. The resulting rect is expanded as far as possible while
+ // remaining enclosed in the Union.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(12, 9, 9, 12));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 11, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(9, 9, 9, 12));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(9, 10, 11, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(9, 12, 12, 9));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 11), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(9, 9, 12, 9));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 9, 10, 11), r));
+
+ r = gfx::Rect(12, 9, 9, 12);
+ r.Union(gfx::Rect(10, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 11, 10), r));
+
+ r = gfx::Rect(9, 9, 9, 12);
+ r.Union(gfx::Rect(10, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(9, 10, 11, 10), r));
+
+ r = gfx::Rect(9, 12, 12, 9);
+ r.Union(gfx::Rect(10, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 11), r));
+
+ r = gfx::Rect(9, 9, 12, 9);
+ r.Union(gfx::Rect(10, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 9, 10, 11), r));
+}
+
+TEST(SimpleEnclosedRegionTest, Subtract) {
+ SimpleEnclosedRegion r;
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(), r));
+
+ // Empty Subtract anything = empty.
+ r.Subtract(gfx::Rect(4, 5, 6, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(), r));
+
+ // Subtracting an enclosing rect = empty.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(9, 9, 12, 12));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(), r));
+
+ // Subtracting a rect that covers one side of the region will shrink that
+ // side.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(18, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(18, 8, 10, 14));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 18, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 8), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(8, 18, 14, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 8), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(2, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(12, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(2, 8, 10, 14));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(12, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 2, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 12, 10, 8), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(8, 2, 14, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 12, 10, 8), r));
+
+ // Subtracting a rect that does not cover a full side will still shrink that
+ // side.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(18, 12, 10, 8));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(18, 12, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(12, 18, 8, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 8), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(12, 18, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 8), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(2, 12, 10, 8));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(12, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(2, 12, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(12, 10, 8, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(12, 2, 8, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 12, 10, 8), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(12, 2, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 12, 10, 8), r));
+
+ // Subtracting a rect inside the region will make it choose the larger result.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(11, 11, 7, 8));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(18, 10, 2, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(11, 11, 8, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 18, 10, 2), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(12, 11, 7, 8));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 2, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(11, 12, 8, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 2), r));
+
+ // Subtracting a rect that cuts the region in two will choose the larger side.
+ // Here it's the top side.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 14, 10, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(0, 14, 30, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 14, 8, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(0, 14, 18, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(12, 14, 18, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
+
+ // Here it's the bottom side.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 13, 10, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 16, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(0, 13, 30, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 16, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 13, 8, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 16, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(0, 13, 18, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 16, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(12, 13, 18, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 16, 10, 4), r));
+
+ // Here it's the left side.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 10), r));
+
+ // Here it's the right side.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(13, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(16, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(13, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(16, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(13, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(16, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(13, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(16, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(13, 10, 3, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(16, 10, 4, 10), r));
+
+ // Subtracting a rect that leaves three possible choices will choose the
+ // larger.
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 14, 7, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(10, 14, 5, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(15, 10, 5, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(13, 14, 7, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(15, 14, 5, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 5, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 10, 3, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 10, 3, 5));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 15, 10, 5), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 13, 3, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Subtract(gfx::Rect(14, 15, 3, 5));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 5), r));
+}
+
+} // namespace
+} // namespace cc