blob: e37c5dbf9ce3e74f053766ad57cdd3e02dfc3d14 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_PHYSICAL_RECT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_PHYSICAL_RECT_H_
#include "base/compiler_specific.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace WTF {
class TextStream;
}
namespace blink {
class ComputedStyle;
struct NGPhysicalBoxStrut;
// PhysicalRect is the position and size of a rect (typically a fragment)
// relative to its parent rect in the physical coordinate system.
// For more information about physical and logical coordinate systems, see:
// https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/core/layout/README.md#coordinate-spaces
struct CORE_EXPORT PhysicalRect {
constexpr PhysicalRect() = default;
constexpr PhysicalRect(const PhysicalOffset& offset, const PhysicalSize& size)
: offset(offset), size(size) {}
// TODO(wangxianzhu): This is temporary for convenience of constructing
// PhysicalRect with LayoutBox::Size(), before we convert LayoutBox::Size() to
// PhysicalSize.
constexpr PhysicalRect(const PhysicalOffset& offset, const LayoutSize& size)
: offset(offset), size(size) {}
constexpr PhysicalRect(LayoutUnit left,
LayoutUnit top,
LayoutUnit width,
LayoutUnit height)
: offset(left, top), size(width, height) {}
// For testing only. It's defined in core/testing/core_unit_test_helpers.h.
inline PhysicalRect(int left, int top, int width, int height);
PhysicalOffset offset;
PhysicalSize size;
constexpr bool IsEmpty() const { return size.IsEmpty(); }
constexpr LayoutUnit X() const { return offset.left; }
constexpr LayoutUnit Y() const { return offset.top; }
constexpr LayoutUnit Width() const { return size.width; }
constexpr LayoutUnit Height() const { return size.height; }
LayoutUnit Right() const { return offset.left + size.width; }
LayoutUnit Bottom() const { return offset.top + size.height; }
void SetX(LayoutUnit x) { offset.left = x; }
void SetY(LayoutUnit y) { offset.top = y; }
void SetWidth(LayoutUnit w) { size.width = w; }
void SetHeight(LayoutUnit h) { size.height = h; }
PhysicalOffset MinXMinYCorner() const { return offset; }
PhysicalOffset MaxXMinYCorner() const {
return {offset.left + size.width, offset.top};
}
PhysicalOffset MinXMaxYCorner() const {
return {offset.left, offset.top + size.height};
}
PhysicalOffset MaxXMaxYCorner() const {
return {offset.left + size.width, offset.top + size.height};
}
constexpr bool operator==(const PhysicalRect& other) const {
return offset == other.offset && size == other.size;
}
bool operator!=(const PhysicalRect& other) const { return !(*this == other); }
// Returns the distance to |target| in horizontal and vertical directions.
// Each distance is zero if |this| contains |target| in that direction.
PhysicalSize DistanceAsSize(PhysicalOffset target) const;
bool Contains(const PhysicalRect&) const;
bool Contains(LayoutUnit px, LayoutUnit py) const {
return px >= offset.left && px < Right() && py >= offset.top &&
py < Bottom();
}
bool Contains(const PhysicalOffset& point) const {
return Contains(point.left, point.top);
}
WARN_UNUSED_RESULT bool Intersects(const PhysicalRect&) const;
WARN_UNUSED_RESULT bool IntersectsInclusively(const PhysicalRect&) const;
// Whether all edges of the rect are at full-pixel boundaries.
// i.e.: EnclosingIntRect(this)) == this
bool EdgesOnPixelBoundaries() const {
return !offset.left.HasFraction() && !offset.top.HasFraction() &&
!size.width.HasFraction() && !size.height.HasFraction();
}
void Unite(const PhysicalRect&);
void UniteIfNonZero(const PhysicalRect&);
void UniteEvenIfEmpty(const PhysicalRect&);
void Intersect(const PhysicalRect&);
bool InclusiveIntersect(const PhysicalRect&);
void Expand(const NGPhysicalBoxStrut&);
void Expand(const LayoutRectOutsets&);
void ExpandEdges(LayoutUnit top,
LayoutUnit right,
LayoutUnit bottom,
LayoutUnit left) {
offset.top -= top;
offset.left -= left;
size.width += left + right;
size.height += top + bottom;
}
void ExpandEdgesToPixelBoundaries();
void Inflate(LayoutUnit d) { ExpandEdges(d, d, d, d); }
void Contract(const NGPhysicalBoxStrut&);
void Contract(const LayoutRectOutsets&);
void ContractEdges(LayoutUnit top,
LayoutUnit right,
LayoutUnit bottom,
LayoutUnit left) {
ExpandEdges(-top, -right, -bottom, -left);
}
void Move(const PhysicalOffset& o) { offset += o; }
void ShiftLeftEdgeTo(LayoutUnit edge) {
LayoutUnit delta = edge - X();
SetX(edge);
SetWidth((Width() - delta).ClampNegativeToZero());
}
void ShiftRightEdgeTo(LayoutUnit edge) {
LayoutUnit delta = edge - Right();
SetWidth((Width() + delta).ClampNegativeToZero());
}
void ShiftTopEdgeTo(LayoutUnit edge) {
LayoutUnit delta = edge - Y();
SetY(edge);
SetHeight((Height() - delta).ClampNegativeToZero());
}
void ShiftBottomEdgeTo(LayoutUnit edge) {
LayoutUnit delta = edge - Bottom();
SetHeight((Height() + delta).ClampNegativeToZero());
}
// TODO(crbug.com/962299): These functions should upgraded to force correct
// pixel snapping in a type-safe way.
IntPoint PixelSnappedOffset() const { return RoundedIntPoint(offset); }
int PixelSnappedWidth() const {
return SnapSizeToPixel(size.width, offset.left);
}
int PixelSnappedHeight() const {
return SnapSizeToPixel(size.height, offset.top);
}
IntSize PixelSnappedSize() const {
return {PixelSnappedWidth(), PixelSnappedHeight()};
}
PhysicalOffset Center() const {
return offset + PhysicalOffset(size.width / 2, size.height / 2);
}
// Conversions from/to existing code. New code prefers type safety for
// logical/physical distinctions.
constexpr explicit PhysicalRect(const LayoutRect& r)
: offset(r.X(), r.Y()), size(r.Width(), r.Height()) {}
constexpr LayoutRect ToLayoutRect() const {
return LayoutRect(offset.left, offset.top, size.width, size.height);
}
LayoutRect ToLayoutFlippedRect(const ComputedStyle&,
const PhysicalSize&) const;
constexpr explicit operator FloatRect() const {
return FloatRect(offset.left, offset.top, size.width, size.height);
}
static PhysicalRect EnclosingRect(const FloatRect& rect) {
PhysicalOffset offset(LayoutUnit::FromFloatFloor(rect.X()),
LayoutUnit::FromFloatFloor(rect.Y()));
PhysicalSize size(LayoutUnit::FromFloatCeil(rect.MaxX()) - offset.left,
LayoutUnit::FromFloatCeil(rect.MaxY()) - offset.top);
return PhysicalRect(offset, size);
}
// This is faster than EnclosingRect(). Can be used in situation that we
// prefer performance to accuracy and haven't observed problems caused by the
// tiny error (< LayoutUnit::Epsilon()).
static PhysicalRect FastAndLossyFromFloatRect(const FloatRect& rect) {
return PhysicalRect(LayoutUnit(rect.X()), LayoutUnit(rect.Y()),
LayoutUnit(rect.Width()), LayoutUnit(rect.Height()));
}
explicit PhysicalRect(const IntRect& r)
: offset(r.Location()), size(r.Size()) {}
static IntRect InfiniteIntRect() { return LayoutRect::InfiniteIntRect(); }
String ToString() const;
};
inline PhysicalRect UnionRect(const PhysicalRect& a, const PhysicalRect& b) {
auto r = a;
r.Unite(b);
return r;
}
inline PhysicalRect Intersection(const PhysicalRect& a, const PhysicalRect& b) {
auto r = a;
r.Intersect(b);
return r;
}
// TODO(crbug.com/962299): These functions should upgraded to force correct
// pixel snapping in a type-safe way.
inline IntRect EnclosingIntRect(const PhysicalRect& r) {
IntPoint location = FlooredIntPoint(r.offset);
IntPoint max_point = CeiledIntPoint(r.MaxXMaxYCorner());
return IntRect(location, max_point - location);
}
inline IntRect PixelSnappedIntRect(const PhysicalRect& r) {
return {r.PixelSnappedOffset(), r.PixelSnappedSize()};
}
// TODO(wangxianzhu): For temporary conversion from LayoutRect to PhysicalRect,
// where the input will be changed to PhysicalRect soon, to avoid redundant
// PhysicalRect() which can't be discovered by the compiler.
inline PhysicalRect PhysicalRectToBeNoop(const LayoutRect& r) {
return PhysicalRect(r);
}
CORE_EXPORT PhysicalRect UnionRect(const Vector<PhysicalRect>& rects);
CORE_EXPORT PhysicalRect
UnionRectEvenIfEmpty(const Vector<PhysicalRect>& rects);
CORE_EXPORT std::ostream& operator<<(std::ostream&, const PhysicalRect&);
CORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const PhysicalRect&);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_PHYSICAL_RECT_H_