1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/base/simple_enclosed_region.h"
6
7 #include "base/logging.h"
8 #include "cc/base/region.h"
9
10 namespace cc {
11
RectIsLargerArea(const gfx::Rect & a,const gfx::Rect b)12 static bool RectIsLargerArea(const gfx::Rect& a, const gfx::Rect b) {
13 int64 a_area = static_cast<int64>(a.width()) * a.height();
14 int64 b_area = static_cast<int64>(b.width()) * b.height();
15 return a_area > b_area;
16 }
17
SimpleEnclosedRegion(const Region & region)18 SimpleEnclosedRegion::SimpleEnclosedRegion(const Region& region) {
19 for (Region::Iterator it(region); it.has_rect(); it.next())
20 Union(it.rect());
21 }
22
~SimpleEnclosedRegion()23 SimpleEnclosedRegion::~SimpleEnclosedRegion() {
24 }
25
Subtract(const gfx::Rect & sub_rect)26 void SimpleEnclosedRegion::Subtract(const gfx::Rect& sub_rect) {
27 // We want to keep as much of the current rect as we can, so find the one
28 // largest rectangle inside |rect_| that does not intersect with |sub_rect|.
29 if (!rect_.Intersects(sub_rect))
30 return;
31 if (sub_rect.Contains(rect_)) {
32 rect_ = gfx::Rect();
33 return;
34 }
35
36 int left = rect_.x();
37 int right = rect_.right();
38 int top = rect_.y();
39 int bottom = rect_.bottom();
40
41 int delta_left = sub_rect.x() - left;
42 int delta_right = right - sub_rect.right();
43 int delta_top = sub_rect.y() - top;
44 int delta_bottom = bottom - sub_rect.bottom();
45
46 // The horizontal rect is the larger of the two rectangles above or below
47 // |sub_rect| and inside rect_.
48 int horizontal_top = top;
49 int horizontal_bottom = bottom;
50 if (delta_top > delta_bottom)
51 horizontal_bottom = sub_rect.y();
52 else
53 horizontal_top = sub_rect.bottom();
54 // The vertical rect is the larger of the two rectangles to the left or the
55 // right of |sub_rect| and inside rect_.
56 int vertical_left = left;
57 int vertical_right = right;
58 if (delta_left > delta_right)
59 vertical_right = sub_rect.x();
60 else
61 vertical_left = sub_rect.right();
62
63 rect_.SetRect(
64 left, horizontal_top, right - left, horizontal_bottom - horizontal_top);
65
66 gfx::Rect vertical_rect(
67 vertical_left, top, vertical_right - vertical_left, bottom - top);
68 if (RectIsLargerArea(vertical_rect, rect_))
69 rect_ = vertical_rect;
70 }
71
Union(const gfx::Rect & new_rect)72 void SimpleEnclosedRegion::Union(const gfx::Rect& new_rect) {
73 // We want to keep track of a region but bound its complexity at a constant
74 // size. We keep track of the largest rectangle seen by area. If we can add
75 // the |new_rect| to this rectangle then we do that, as that is the cheapest
76 // way to increase the area returned without increasing the complexity.
77 if (new_rect.IsEmpty())
78 return;
79 if (rect_.Contains(new_rect))
80 return;
81 if (new_rect.Contains(rect_)) {
82 rect_ = new_rect;
83 return;
84 }
85
86 int left = rect_.x();
87 int top = rect_.y();
88 int right = rect_.right();
89 int bottom = rect_.bottom();
90
91 int new_left = new_rect.x();
92 int new_top = new_rect.y();
93 int new_right = new_rect.right();
94 int new_bottom = new_rect.bottom();
95
96 // This attempts to expand each edge of |rect_| if the |new_rect| entirely
97 // covers or is adjacent to an entire edge of |rect_|. If this is true for
98 // an edge of |rect_| then it can be expanded out to share that edge with the
99 // same edge of |new_rect|. After, the same thing is done to try expand
100 // |new_rect| relative to |rect_|.
101 if (new_top <= top && new_bottom >= bottom) {
102 if (new_left < left && new_right >= left)
103 left = new_left;
104 if (new_right > right && new_left <= right)
105 right = new_right;
106 } else if (new_left <= left && new_right >= right) {
107 if (new_top < top && new_bottom >= top)
108 top = new_top;
109 if (new_bottom > bottom && new_top <= bottom)
110 bottom = new_bottom;
111 } else if (top <= new_top && bottom >= new_bottom) {
112 if (left < new_left && right >= new_left)
113 new_left = left;
114 if (right > new_right && left <= new_right)
115 new_right = right;
116 } else if (left <= new_left && right >= new_right) {
117 if (top < new_top && bottom >= new_top)
118 new_top = top;
119 if (bottom > new_bottom && top <= new_bottom)
120 new_bottom = bottom;
121 }
122
123 rect_.SetRect(left, top, right - left, bottom - top);
124
125 gfx::Rect adjusted_new_rect(
126 new_left, new_top, new_right - new_left, new_bottom - new_top);
127 if (RectIsLargerArea(adjusted_new_rect, rect_))
128 rect_ = adjusted_new_rect;
129 }
130
GetRect(size_t i) const131 gfx::Rect SimpleEnclosedRegion::GetRect(size_t i) const {
132 DCHECK_LT(i, GetRegionComplexity());
133 return rect_;
134 }
135
136 } // namespace cc
137