blob: d9af7d7be39acce26b49d9fa6cf7fb72bd5aaff6 [file] [log] [blame]
/*
* Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2005 Nokia. 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 COMPUTER, INC. ``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 COMPUTER, INC. OR
* 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 "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/gfx/geometry/rect_f.h"
namespace blink {
FloatRect::FloatRect(const IntRect& r)
: location_(r.Location()), size_(r.Size()) {}
FloatRect::FloatRect(const LayoutRect& r)
: location_(r.Location()), size_(r.Size()) {}
FloatRect::FloatRect(const SkRect& r)
: location_(r.fLeft, r.fTop), size_(r.width(), r.height()) {}
void FloatRect::Move(const LayoutSize& delta) {
location_.Move(delta.Width().ToFloat(), delta.Height().ToFloat());
}
void FloatRect::Move(const IntSize& delta) {
location_.Move(delta.Width(), delta.Height());
}
FloatRect FloatRect::NarrowPrecision(double x,
double y,
double width,
double height) {
return FloatRect(clampTo<float>(x), clampTo<float>(y), clampTo<float>(width),
clampTo<float>(height));
}
#if DCHECK_IS_ON()
bool FloatRect::MayNotHaveExactIntRectRepresentation() const {
static const float kMaxExactlyExpressible = 1 << FLT_MANT_DIG;
return fabs(X()) > kMaxExactlyExpressible ||
fabs(Y()) > kMaxExactlyExpressible ||
fabs(Width()) > kMaxExactlyExpressible ||
fabs(Height()) > kMaxExactlyExpressible ||
fabs(MaxX()) > kMaxExactlyExpressible ||
fabs(MaxY()) > kMaxExactlyExpressible;
}
bool FloatRect::EqualWithinEpsilon(const FloatRect& other,
float epsilon) const {
return std::abs(other.X() - X()) <= epsilon &&
std::abs(other.Y() - Y()) <= epsilon &&
std::abs(other.Width() - Width()) <= epsilon &&
std::abs(other.Height() - Height()) <= epsilon;
}
#endif
bool FloatRect::IsExpressibleAsIntRect() const {
return isWithinIntRange(X()) && isWithinIntRange(Y()) &&
isWithinIntRange(Width()) && isWithinIntRange(Height()) &&
isWithinIntRange(MaxX()) && isWithinIntRange(MaxY());
}
void FloatRect::ShiftXEdgeTo(float edge) {
float delta = edge - X();
SetX(edge);
SetWidth(std::max(0.0f, Width() - delta));
}
void FloatRect::ShiftMaxXEdgeTo(float edge) {
float delta = edge - MaxX();
SetWidth(std::max(0.0f, Width() + delta));
}
void FloatRect::ShiftYEdgeTo(float edge) {
float delta = edge - Y();
SetY(edge);
SetHeight(std::max(0.0f, Height() - delta));
}
void FloatRect::ShiftMaxYEdgeTo(float edge) {
float delta = edge - MaxY();
SetHeight(std::max(0.0f, Height() + delta));
}
bool FloatRect::Intersects(const FloatRect& 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 FloatRect::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 FloatRect::Contains(const IntRect& other) const {
return X() <= other.X() && MaxX() >= other.MaxX() && Y() <= other.Y() &&
MaxY() >= other.MaxY();
}
bool FloatRect::Contains(const FloatRect& other) const {
return X() <= other.X() && MaxX() >= other.MaxX() && Y() <= other.Y() &&
MaxY() >= other.MaxY();
}
bool FloatRect::Contains(const FloatPoint& point,
ContainsMode contains_mode) const {
if (contains_mode == kInsideOrOnStroke)
return Contains(point.X(), point.Y());
return X() < point.X() && MaxX() > point.X() && Y() < point.Y() &&
MaxY() > point.Y();
}
void FloatRect::Intersect(const IntRect& other) {
float left = std::max(X(), static_cast<float>(other.X()));
float top = std::max(Y(), static_cast<float>(other.Y()));
float right = std::min(MaxX(), static_cast<float>(other.MaxX()));
float bottom = std::min(MaxY(), static_cast<float>(other.MaxY()));
// Return a clean empty rectangle for non-intersecting cases.
if (left >= right || top >= bottom) {
left = 0;
top = 0;
right = 0;
bottom = 0;
}
SetLocationAndSizeFromEdges(left, top, right, bottom);
}
void FloatRect::Intersect(const FloatRect& other) {
float left = std::max(X(), other.X());
float top = std::max(Y(), other.Y());
float right = std::min(MaxX(), other.MaxX());
float 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;
}
SetLocationAndSizeFromEdges(left, top, right, bottom);
}
bool FloatRect::InclusiveIntersect(const FloatRect& other) {
float left = std::max(X(), other.X());
float top = std::max(Y(), other.Y());
float right = std::min(MaxX(), other.MaxX());
float 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;
SetLocationAndSizeFromEdges(left, top, right, bottom);
return false;
}
SetLocationAndSizeFromEdges(left, top, right, bottom);
return true;
}
void FloatRect::Unite(const FloatRect& other) {
// Handle empty special cases first.
if (other.IsEmpty())
return;
if (IsEmpty()) {
*this = other;
return;
}
UniteEvenIfEmpty(other);
}
void FloatRect::UniteEvenIfEmpty(const FloatRect& other) {
float min_x = std::min(X(), other.X());
float min_y = std::min(Y(), other.Y());
float max_x = std::max(this->MaxX(), other.MaxX());
float max_y = std::max(this->MaxY(), other.MaxY());
SetLocationAndSizeFromEdges(min_x, min_y, max_x, max_y);
}
void FloatRect::UniteIfNonZero(const FloatRect& other) {
// Handle empty special cases first.
if (other.IsZero())
return;
if (IsZero()) {
*this = other;
return;
}
UniteEvenIfEmpty(other);
}
void FloatRect::Extend(const FloatPoint& p) {
float min_x = std::min(X(), p.X());
float min_y = std::min(Y(), p.Y());
float max_x = std::max(this->MaxX(), p.X());
float max_y = std::max(this->MaxY(), p.Y());
SetLocationAndSizeFromEdges(min_x, min_y, max_x, max_y);
}
void FloatRect::Scale(float sx, float sy) {
location_.SetX(X() * sx);
location_.SetY(Y() * sy);
size_.SetWidth(Width() * sx);
size_.SetHeight(Height() * sy);
}
float FloatRect::SquaredDistanceTo(const FloatPoint& point) const {
FloatPoint closest_point;
closest_point.SetX(clampTo<float>(point.X(), X(), MaxX()));
closest_point.SetY(clampTo<float>(point.Y(), Y(), MaxY()));
return (point - closest_point).DiagonalLengthSquared();
}
FloatRect::operator SkRect() const {
return SkRect::MakeXYWH(X(), Y(), Width(), Height());
}
FloatRect::operator gfx::RectF() const {
return gfx::RectF(X(), Y(), Width(), Height());
}
FloatRect UnionRect(const Vector<FloatRect>& rects) {
FloatRect result;
for (const auto& rect : rects)
result.Unite(rect);
return result;
}
IntRect EnclosedIntRect(const FloatRect& rect) {
IntPoint location = CeiledIntPoint(rect.Location());
IntPoint max_point = FlooredIntPoint(rect.MaxXMaxYCorner());
IntSize size(ClampSub(max_point.X(), location.X()),
ClampSub(max_point.Y(), location.Y()));
size.ClampNegativeToZero();
return IntRect(location, size);
}
IntRect RoundedIntRect(const FloatRect& rect) {
return IntRect(RoundedIntPoint(rect.Location()), RoundedIntSize(rect.Size()));
}
FloatRect MapRect(const FloatRect& r,
const FloatRect& src_rect,
const FloatRect& dest_rect) {
if (!src_rect.Width() || !src_rect.Height())
return FloatRect();
float width_scale = dest_rect.Width() / src_rect.Width();
float height_scale = dest_rect.Height() / src_rect.Height();
return FloatRect(dest_rect.X() + (r.X() - src_rect.X()) * width_scale,
dest_rect.Y() + (r.Y() - src_rect.Y()) * height_scale,
r.Width() * width_scale, r.Height() * height_scale);
}
std::ostream& operator<<(std::ostream& ostream, const FloatRect& rect) {
return ostream << rect.ToString();
}
String FloatRect::ToString() const {
return String::Format("%s %s", Location().ToString().Ascii().data(),
Size().ToString().Ascii().data());
}
WTF::TextStream& operator<<(WTF::TextStream& ts, const FloatRect& r) {
ts << "at (" << WTF::TextStream::FormatNumberRespectingIntegers(r.X());
ts << "," << WTF::TextStream::FormatNumberRespectingIntegers(r.Y());
ts << ") size " << WTF::TextStream::FormatNumberRespectingIntegers(r.Width());
ts << "x" << WTF::TextStream::FormatNumberRespectingIntegers(r.Height());
return ts;
}
} // namespace blink