• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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