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 10namespace cc { 11 12static 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 18SimpleEnclosedRegion::SimpleEnclosedRegion(const Region& region) { 19 for (Region::Iterator it(region); it.has_rect(); it.next()) 20 Union(it.rect()); 21} 22 23SimpleEnclosedRegion::~SimpleEnclosedRegion() { 24} 25 26void 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 72void 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 131gfx::Rect SimpleEnclosedRegion::GetRect(size_t i) const { 132 DCHECK_LT(i, GetRegionComplexity()); 133 return rect_; 134} 135 136} // namespace cc 137