blob: 3ae91cf0716b3fca4032b6b9cd31ddaffab8b0ef [file] [log] [blame]
/*
* Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "platform/geometry/IntRect.h"
#include "platform/geometry/FloatRect.h"
#include "platform/geometry/LayoutRect.h"
#include "platform/wtf/CheckedNumeric.h"
#include "platform/wtf/Vector.h"
#include "platform/wtf/text/WTFString.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/gfx/geometry/rect.h"
#include <algorithm>
namespace blink {
IntRect::IntRect(const FloatRect& r)
: location_(clampTo<int>(r.X()), clampTo<int>(r.Y())),
size_(clampTo<int>(r.Width()), clampTo<int>(r.Height())) {}
IntRect::IntRect(const LayoutRect& r)
: location_(r.X().ToInt(), r.Y().ToInt()),
size_(r.Width().ToInt(), r.Height().ToInt()) {}
void IntRect::ShiftXEdgeTo(int edge) {
int delta = edge - X();
SetX(edge);
SetWidth(std::max(0, Width() - delta));
}
void IntRect::ShiftMaxXEdgeTo(int edge) {
int delta = edge - MaxX();
SetWidth(std::max(0, Width() + delta));
}
void IntRect::ShiftYEdgeTo(int edge) {
int delta = edge - Y();
SetY(edge);
SetHeight(std::max(0, Height() - delta));
}
void IntRect::ShiftMaxYEdgeTo(int edge) {
int delta = edge - MaxY();
SetHeight(std::max(0, Height() + delta));
}
bool IntRect::Intersects(const IntRect& other) const {
// Checking emptiness handles negative widths as well as zero.
return !IsEmpty() && !other.IsEmpty() && X() < other.MaxX() &&
other.X() < MaxX() && Y() < other.MaxY() && other.Y() < MaxY();
}
bool IntRect::Contains(const IntRect& other) const {
return X() <= other.X() && MaxX() >= other.MaxX() && Y() <= other.Y() &&
MaxY() >= other.MaxY();
}
void IntRect::Intersect(const IntRect& other) {
int left = std::max(X(), other.X());
int top = std::max(Y(), other.Y());
int right = std::min(MaxX(), other.MaxX());
int bottom = std::min(MaxY(), other.MaxY());
// Return a clean empty rectangle for non-intersecting cases.
if (left >= right || top >= bottom) {
left = 0;
top = 0;
right = 0;
bottom = 0;
}
location_.SetX(left);
location_.SetY(top);
size_.SetWidth(right - left);
size_.SetHeight(bottom - top);
}
void IntRect::Unite(const IntRect& other) {
// Handle empty special cases first.
if (other.IsEmpty())
return;
if (IsEmpty()) {
*this = other;
return;
}
UniteEvenIfEmpty(other);
}
void IntRect::UniteIfNonZero(const IntRect& other) {
// Handle empty special cases first.
if (!other.Width() && !other.Height())
return;
if (!Width() && !Height()) {
*this = other;
return;
}
UniteEvenIfEmpty(other);
}
void IntRect::UniteEvenIfEmpty(const IntRect& other) {
int left = std::min(X(), other.X());
int top = std::min(Y(), other.Y());
int right = std::max(MaxX(), other.MaxX());
int bottom = std::max(MaxY(), other.MaxY());
location_.SetX(left);
location_.SetY(top);
size_.SetWidth(right - left);
size_.SetHeight(bottom - top);
}
void IntRect::Scale(float s) {
location_.SetX((int)(X() * s));
location_.SetY((int)(Y() * s));
size_.SetWidth((int)(Width() * s));
size_.SetHeight((int)(Height() * s));
}
static inline int DistanceToInterval(int pos, int start, int end) {
if (pos < start)
return start - pos;
if (pos > end)
return end - pos;
return 0;
}
IntSize IntRect::DifferenceToPoint(const IntPoint& point) const {
int xdistance = DistanceToInterval(point.X(), X(), MaxX());
int ydistance = DistanceToInterval(point.Y(), Y(), MaxY());
return IntSize(xdistance, ydistance);
}
IntRect::operator SkIRect() const {
SkIRect rect = {X(), Y(), MaxX(), MaxY()};
return rect;
}
IntRect::operator SkRect() const {
SkRect rect;
rect.set(SkIntToScalar(X()), SkIntToScalar(Y()), SkIntToScalar(MaxX()),
SkIntToScalar(MaxY()));
return rect;
}
IntRect::operator gfx::Rect() const {
return gfx::Rect(X(), Y(), Width(), Height());
}
IntRect UnionRect(const Vector<IntRect>& rects) {
IntRect result;
size_t count = rects.size();
for (size_t i = 0; i < count; ++i)
result.Unite(rects[i]);
return result;
}
IntRect UnionRectEvenIfEmpty(const Vector<IntRect>& rects) {
size_t count = rects.size();
if (!count)
return IntRect();
IntRect result = rects[0];
for (size_t i = 1; i < count; ++i)
result.UniteEvenIfEmpty(rects[i]);
return result;
}
std::ostream& operator<<(std::ostream& ostream, const IntRect& rect) {
return ostream << rect.ToString();
}
String IntRect::ToString() const {
return String::Format("%s %s", Location().ToString().Ascii().data(),
Size().ToString().Ascii().data());
}
bool IntRect::IsValid() const {
CheckedNumeric<int> max = location_.X();
max += size_.Width();
if (!max.IsValid())
return false;
max = location_.Y();
max += size_.Height();
return max.IsValid();
}
} // namespace blink