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.
5 #include "cc/base/simple_enclosed_region.h"
7 #include "base/logging.h"
8 #include "cc/base/region.h"
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
;
18 SimpleEnclosedRegion::SimpleEnclosedRegion(const Region
& region
) {
19 for (Region::Iterator
it(region
); it
.has_rect(); it
.next())
23 SimpleEnclosedRegion::~SimpleEnclosedRegion() {
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
))
31 if (sub_rect
.Contains(rect_
)) {
37 int right
= rect_
.right();
39 int bottom
= rect_
.bottom();
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();
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();
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();
61 vertical_left
= sub_rect
.right();
64 left
, horizontal_top
, right
- left
, horizontal_bottom
- horizontal_top
);
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
;
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())
79 if (rect_
.Contains(new_rect
))
81 if (new_rect
.Contains(rect_
)) {
88 int right
= rect_
.right();
89 int bottom
= rect_
.bottom();
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();
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
)
104 if (new_right
> right
&& new_left
<= right
)
106 } else if (new_left
<= left
&& new_right
>= right
) {
107 if (new_top
< top
&& new_bottom
>= top
)
109 if (new_bottom
> bottom
&& new_top
<= bottom
)
111 } else if (top
<= new_top
&& bottom
>= new_bottom
) {
112 if (left
< new_left
&& right
>= new_left
)
114 if (right
> new_right
&& left
<= new_right
)
116 } else if (left
<= new_left
&& right
>= new_right
) {
117 if (top
< new_top
&& bottom
>= new_top
)
119 if (bottom
> new_bottom
&& top
<= new_bottom
)
123 rect_
.SetRect(left
, top
, right
- left
, bottom
- top
);
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
;
131 gfx::Rect
SimpleEnclosedRegion::GetRect(size_t i
) const {
132 DCHECK_LT(i
, GetRegionComplexity());