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