1/*
2 * Copyright (c) 2012, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#pragma once
32
33#include "FloatRect.h"
34#include "IntRect.h"
35#include "LayoutPoint.h"
36#include "LengthBox.h"
37#include <wtf/Forward.h>
38
39namespace WTF {
40class TextStream;
41}
42
43namespace WebCore {
44
45class LayoutRect {
46public:
47 LayoutRect() { }
48 LayoutRect(const LayoutPoint& location, const LayoutSize& size)
49 : m_location(location), m_size(size) { }
50 LayoutRect(LayoutUnit x, LayoutUnit y, LayoutUnit width, LayoutUnit height)
51 : m_location(LayoutPoint(x, y)), m_size(LayoutSize(width, height)) { }
52 LayoutRect(const LayoutPoint& topLeft, const LayoutPoint& bottomRight)
53 : m_location(topLeft), m_size(LayoutSize(bottomRight.x() - topLeft.x(), bottomRight.y() - topLeft.y())) { }
54 LayoutRect(const FloatPoint& location, const FloatSize& size)
55 : m_location(location), m_size(size) { }
56 LayoutRect(const IntRect& rect) : m_location(rect.location()), m_size(rect.size()) { }
57
58 WEBCORE_EXPORT explicit LayoutRect(const FloatRect&); // don't do this implicitly since it's lossy
59
60 LayoutPoint location() const { return m_location; }
61 LayoutSize size() const { return m_size; }
62
63 void setLocation(const LayoutPoint& location) { m_location = location; }
64 void setSize(const LayoutSize& size) { m_size = size; }
65
66 LayoutUnit x() const { return m_location.x(); }
67 LayoutUnit y() const { return m_location.y(); }
68 LayoutUnit maxX() const { return x() + width(); }
69 LayoutUnit maxY() const { return y() + height(); }
70 LayoutUnit width() const { return m_size.width(); }
71 LayoutUnit height() const { return m_size.height(); }
72
73 void setX(LayoutUnit x) { m_location.setX(x); }
74 void setY(LayoutUnit y) { m_location.setY(y); }
75 void setWidth(LayoutUnit width) { m_size.setWidth(width); }
76 void setHeight(LayoutUnit height) { m_size.setHeight(height); }
77
78 bool isEmpty() const { return m_size.isEmpty(); }
79
80 // NOTE: The result is rounded to integer values, and thus may be not the exact
81 // center point.
82 LayoutPoint center() const { return LayoutPoint(x() + width() / 2, y() + height() / 2); }
83
84 void move(const LayoutSize& size) { m_location += size; }
85 void moveBy(const LayoutPoint& offset) { m_location.move(offset.x(), offset.y()); }
86 void move(LayoutUnit dx, LayoutUnit dy) { m_location.move(dx, dy); }
87
88 void expand(const LayoutSize& size) { m_size += size; }
89 void expand(const LayoutBoxExtent& box)
90 {
91 m_location.move(-box.left(), -box.top());
92 m_size.expand(box.left() + box.right(), box.top() + box.bottom());
93 }
94 void expand(LayoutUnit dw, LayoutUnit dh) { m_size.expand(dw, dh); }
95 void contract(const LayoutSize& size) { m_size -= size; }
96 void contract(const LayoutBoxExtent& box)
97 {
98 m_location.move(box.left(), box.top());
99 m_size.shrink(box.left() + box.right(), box.top() + box.bottom());
100 }
101 void contract(LayoutUnit dw, LayoutUnit dh) { m_size.expand(-dw, -dh); }
102
103 void shiftXEdgeTo(LayoutUnit edge)
104 {
105 LayoutUnit delta = edge - x();
106 setX(edge);
107 setWidth(std::max<LayoutUnit>(0, width() - delta));
108 }
109 void shiftMaxXEdgeTo(LayoutUnit edge)
110 {
111 LayoutUnit delta = edge - maxX();
112 setWidth(std::max<LayoutUnit>(0, width() + delta));
113 }
114 void shiftYEdgeTo(LayoutUnit edge)
115 {
116 LayoutUnit delta = edge - y();
117 setY(edge);
118 setHeight(std::max<LayoutUnit>(0, height() - delta));
119 }
120 void shiftMaxYEdgeTo(LayoutUnit edge)
121 {
122 LayoutUnit delta = edge - maxY();
123 setHeight(std::max<LayoutUnit>(0, height() + delta));
124 }
125
126 LayoutPoint minXMinYCorner() const { return m_location; } // typically topLeft
127 LayoutPoint maxXMinYCorner() const { return LayoutPoint(m_location.x() + m_size.width(), m_location.y()); } // typically topRight
128 LayoutPoint minXMaxYCorner() const { return LayoutPoint(m_location.x(), m_location.y() + m_size.height()); } // typically bottomLeft
129 LayoutPoint maxXMaxYCorner() const { return LayoutPoint(m_location.x() + m_size.width(), m_location.y() + m_size.height()); } // typically bottomRight
130 bool isMaxXMaxYRepresentable() const
131 {
132 FloatRect rect = *this;
133 float maxX = rect.maxX();
134 float maxY = rect.maxY();
135 return maxX > LayoutUnit::nearlyMin() && maxX < LayoutUnit::nearlyMax() && maxY > LayoutUnit::nearlyMin() && maxY < LayoutUnit::nearlyMax();
136 }
137
138 bool intersects(const LayoutRect&) const;
139 WEBCORE_EXPORT bool contains(const LayoutRect&) const;
140
141 // This checks to see if the rect contains x,y in the traditional sense.
142 // Equivalent to checking if the rect contains a 1x1 rect below and to the right of (px,py).
143 bool contains(LayoutUnit px, LayoutUnit py) const
144 { return px >= x() && px < maxX() && py >= y() && py < maxY(); }
145 bool contains(const LayoutPoint& point) const { return contains(point.x(), point.y()); }
146
147 void intersect(const LayoutRect&);
148 bool edgeInclusiveIntersect(const LayoutRect&);
149 WEBCORE_EXPORT void unite(const LayoutRect&);
150 void uniteIfNonZero(const LayoutRect&);
151 bool checkedUnite(const LayoutRect&);
152
153 void inflateX(LayoutUnit dx)
154 {
155 m_location.setX(m_location.x() - dx);
156 m_size.setWidth(m_size.width() + dx + dx);
157 }
158 void inflateY(LayoutUnit dy)
159 {
160 m_location.setY(m_location.y() - dy);
161 m_size.setHeight(m_size.height() + dy + dy);
162 }
163 void inflate(LayoutUnit d) { inflateX(d); inflateY(d); }
164 void inflate(LayoutSize size) { inflateX(size.width()); inflateY(size.height()); }
165 WEBCORE_EXPORT void scale(float);
166 void scale(float xScale, float yScale);
167
168 LayoutRect transposedRect() const { return LayoutRect(m_location.transposedPoint(), m_size.transposedSize()); }
169 bool isInfinite() const;
170
171 static LayoutRect infiniteRect()
172 {
173 // Return a rect that is slightly smaller than the true max rect to allow pixelSnapping to round up to the nearest IntRect without overflowing.
174 return LayoutRect(LayoutUnit::nearlyMin() / 2, LayoutUnit::nearlyMin() / 2, LayoutUnit::nearlyMax(), LayoutUnit::nearlyMax());
175 }
176
177 operator FloatRect() const { return FloatRect(m_location, m_size); }
178
179private:
180 LayoutPoint m_location;
181 LayoutSize m_size;
182};
183
184inline LayoutRect intersection(const LayoutRect& a, const LayoutRect& b)
185{
186 LayoutRect c = a;
187 c.intersect(b);
188 return c;
189}
190
191inline LayoutRect unionRect(const LayoutRect& a, const LayoutRect& b)
192{
193 LayoutRect c = a;
194 c.unite(b);
195 return c;
196}
197
198LayoutRect unionRect(const Vector<LayoutRect>&);
199
200inline bool operator==(const LayoutRect& a, const LayoutRect& b)
201{
202 return a.location() == b.location() && a.size() == b.size();
203}
204
205inline bool operator!=(const LayoutRect& a, const LayoutRect& b)
206{
207 return a.location() != b.location() || a.size() != b.size();
208}
209
210inline bool LayoutRect::isInfinite() const
211{
212 return *this == LayoutRect::infiniteRect();
213}
214
215// Integral snapping functions.
216inline IntRect snappedIntRect(const LayoutRect& rect)
217{
218 return IntRect(roundedIntPoint(rect.location()), snappedIntSize(rect.size(), rect.location()));
219}
220
221inline IntRect snappedIntRect(LayoutUnit left, LayoutUnit top, LayoutUnit width, LayoutUnit height)
222{
223 return IntRect(IntPoint(left.round(), top.round()), snappedIntSize(LayoutSize(width, height), LayoutPoint(left, top)));
224}
225
226inline IntRect snappedIntRect(LayoutPoint location, LayoutSize size)
227{
228 return IntRect(roundedIntPoint(location), snappedIntSize(size, location));
229}
230
231WEBCORE_EXPORT IntRect enclosingIntRect(const LayoutRect&);
232WEBCORE_EXPORT LayoutRect enclosingLayoutRect(const FloatRect&);
233
234// Device pixel snapping functions.
235inline FloatRect snapRectToDevicePixels(const LayoutRect& rect, float pixelSnappingFactor)
236{
237 return FloatRect(FloatPoint(roundToDevicePixel(rect.x(), pixelSnappingFactor), roundToDevicePixel(rect.y(), pixelSnappingFactor)), snapSizeToDevicePixel(rect.size(), rect.location(), pixelSnappingFactor));
238}
239
240inline FloatRect snapRectToDevicePixels(LayoutUnit x, LayoutUnit y, LayoutUnit width, LayoutUnit height, float pixelSnappingFactor)
241{
242 return snapRectToDevicePixels(LayoutRect(x, y, width, height), pixelSnappingFactor);
243}
244
245// FIXME: This needs to take vertical centering into account too.
246inline FloatRect snapRectToDevicePixelsWithWritingDirection(const LayoutRect& rect, float deviceScaleFactor, bool ltr)
247{
248 if (!ltr) {
249 FloatPoint snappedTopRight = roundPointToDevicePixels(rect.maxXMinYCorner(), deviceScaleFactor, ltr);
250 FloatSize snappedSize = snapSizeToDevicePixel(rect.size(), rect.maxXMinYCorner(), deviceScaleFactor);
251 return FloatRect(snappedTopRight.x() - snappedSize.width(), snappedTopRight.y(), snappedSize.width(), snappedSize.height());
252 }
253 return snapRectToDevicePixels(rect, deviceScaleFactor);
254}
255
256FloatRect encloseRectToDevicePixels(const LayoutRect&, float pixelSnappingFactor);
257
258WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const LayoutRect&);
259
260} // namespace WebCore
261
262