/* * 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(x), clampTo(y), clampTo(width), clampTo(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(other.X())); float top = std::max(Y(), static_cast(other.Y())); float right = std::min(MaxX(), static_cast(other.MaxX())); float bottom = std::min(MaxY(), static_cast(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(point.X(), X(), MaxX())); closest_point.SetY(clampTo(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& 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