// 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); } 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& rects); CORE_EXPORT PhysicalRect UnionRectEvenIfEmpty(const Vector& 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_