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 | #include "config.h" |
32 | #include "LayoutRect.h" |
33 | |
34 | #include <algorithm> |
35 | #include <wtf/text/TextStream.h> |
36 | |
37 | namespace WebCore { |
38 | |
39 | LayoutRect::LayoutRect(const FloatRect& r) |
40 | : m_location(LayoutPoint(r.location())) |
41 | , m_size(LayoutSize(r.size())) |
42 | { |
43 | } |
44 | |
45 | bool LayoutRect::intersects(const LayoutRect& other) const |
46 | { |
47 | // Checking emptiness handles negative widths as well as zero. |
48 | return !isEmpty() && !other.isEmpty() |
49 | && x() < other.maxX() && other.x() < maxX() |
50 | && y() < other.maxY() && other.y() < maxY(); |
51 | } |
52 | |
53 | bool LayoutRect::contains(const LayoutRect& other) const |
54 | { |
55 | return x() <= other.x() && maxX() >= other.maxX() |
56 | && y() <= other.y() && maxY() >= other.maxY(); |
57 | } |
58 | |
59 | void LayoutRect::intersect(const LayoutRect& other) |
60 | { |
61 | LayoutPoint newLocation(std::max(x(), other.x()), std::max(y(), other.y())); |
62 | LayoutPoint newMaxPoint(std::min(maxX(), other.maxX()), std::min(maxY(), other.maxY())); |
63 | |
64 | // Return a clean empty rectangle for non-intersecting cases. |
65 | if (newLocation.x() >= newMaxPoint.x() || newLocation.y() >= newMaxPoint.y()) { |
66 | newLocation = LayoutPoint(0, 0); |
67 | newMaxPoint = LayoutPoint(0, 0); |
68 | } |
69 | |
70 | m_location = newLocation; |
71 | m_size = newMaxPoint - newLocation; |
72 | } |
73 | |
74 | bool LayoutRect::edgeInclusiveIntersect(const LayoutRect& other) |
75 | { |
76 | LayoutPoint newLocation(std::max(x(), other.x()), std::max(y(), other.y())); |
77 | LayoutPoint newMaxPoint(std::min(maxX(), other.maxX()), std::min(maxY(), other.maxY())); |
78 | |
79 | bool intersects = true; |
80 | |
81 | // Return a clean empty rectangle for non-intersecting cases. |
82 | if (newLocation.x() > newMaxPoint.x() || newLocation.y() > newMaxPoint.y()) { |
83 | newLocation = { }; |
84 | newMaxPoint = { }; |
85 | intersects = false; |
86 | } |
87 | |
88 | m_location = newLocation; |
89 | m_size = newMaxPoint - newLocation; |
90 | return intersects; |
91 | } |
92 | |
93 | void LayoutRect::unite(const LayoutRect& other) |
94 | { |
95 | // Handle empty special cases first. |
96 | if (other.isEmpty()) |
97 | return; |
98 | if (isEmpty()) { |
99 | *this = other; |
100 | return; |
101 | } |
102 | |
103 | LayoutPoint newLocation(std::min(x(), other.x()), std::min(y(), other.y())); |
104 | LayoutPoint newMaxPoint(std::max(maxX(), other.maxX()), std::max(maxY(), other.maxY())); |
105 | |
106 | m_location = newLocation; |
107 | m_size = newMaxPoint - newLocation; |
108 | } |
109 | |
110 | bool LayoutRect::checkedUnite(const LayoutRect& other) |
111 | { |
112 | if (other.isEmpty()) |
113 | return true; |
114 | if (isEmpty()) { |
115 | *this = other; |
116 | return true; |
117 | } |
118 | if (!isMaxXMaxYRepresentable() || !other.isMaxXMaxYRepresentable()) |
119 | return false; |
120 | FloatPoint topLeft = FloatPoint(std::min<float>(x(), other.x()), std::min<float>(y(), other.y())); |
121 | FloatPoint bottomRight = FloatPoint(std::max<float>(maxX(), other.maxX()), std::max<float>(maxY(), other.maxY())); |
122 | FloatSize size = bottomRight - topLeft; |
123 | |
124 | if (size.width() >= LayoutUnit::nearlyMax() || size.height() >= LayoutUnit::nearlyMax()) |
125 | return false; |
126 | m_location = LayoutPoint(topLeft); |
127 | m_size = LayoutSize(size); |
128 | return true; |
129 | } |
130 | |
131 | void LayoutRect::uniteIfNonZero(const LayoutRect& other) |
132 | { |
133 | // Handle empty special cases first. |
134 | if (!other.width() && !other.height()) |
135 | return; |
136 | if (!width() && !height()) { |
137 | *this = other; |
138 | return; |
139 | } |
140 | |
141 | LayoutPoint newLocation(std::min(x(), other.x()), std::min(y(), other.y())); |
142 | LayoutPoint newMaxPoint(std::max(maxX(), other.maxX()), std::max(maxY(), other.maxY())); |
143 | |
144 | m_location = newLocation; |
145 | m_size = newMaxPoint - newLocation; |
146 | } |
147 | |
148 | void LayoutRect::scale(float scaleValue) |
149 | { |
150 | scale(scaleValue, scaleValue); |
151 | } |
152 | |
153 | void LayoutRect::scale(float xScale, float yScale) |
154 | { |
155 | if (isInfinite()) |
156 | return; |
157 | m_location.scale(xScale, yScale); |
158 | m_size.scale(xScale, yScale); |
159 | } |
160 | |
161 | LayoutRect unionRect(const Vector<LayoutRect>& rects) |
162 | { |
163 | LayoutRect result; |
164 | |
165 | size_t count = rects.size(); |
166 | for (size_t i = 0; i < count; ++i) |
167 | result.unite(rects[i]); |
168 | |
169 | return result; |
170 | } |
171 | |
172 | IntRect enclosingIntRect(const LayoutRect& rect) |
173 | { |
174 | // Empty rects with fractional x, y values turn into non-empty rects when converting to enclosing. |
175 | // We need to ensure that empty rects stay empty after the conversion, because the selection code expects them to be empty. |
176 | IntPoint location = flooredIntPoint(rect.minXMinYCorner()); |
177 | IntPoint maxPoint = IntPoint(rect.width() ? rect.maxX().ceil() : location.x(), rect.height() ? rect.maxY().ceil() : location.y()); |
178 | return IntRect(location, maxPoint - location); |
179 | } |
180 | |
181 | LayoutRect enclosingLayoutRect(const FloatRect& rect) |
182 | { |
183 | LayoutPoint location = flooredLayoutPoint(rect.minXMinYCorner()); |
184 | LayoutPoint maxPoint = ceiledLayoutPoint(rect.maxXMaxYCorner()); |
185 | |
186 | return LayoutRect(location, maxPoint - location); |
187 | } |
188 | |
189 | FloatRect encloseRectToDevicePixels(const LayoutRect& rect, float pixelSnappingFactor) |
190 | { |
191 | FloatPoint location = floorPointToDevicePixels(rect.minXMinYCorner(), pixelSnappingFactor); |
192 | FloatPoint maxPoint = ceilPointToDevicePixels(rect.maxXMaxYCorner(), pixelSnappingFactor); |
193 | |
194 | return FloatRect(location, maxPoint - location); |
195 | } |
196 | |
197 | TextStream& operator<<(TextStream& ts, const LayoutRect& r) |
198 | { |
199 | if (ts.hasFormattingFlag(TextStream::Formatting::LayoutUnitsAsIntegers)) |
200 | return ts << snappedIntRect(r); |
201 | |
202 | return ts << FloatRect(r); |
203 | } |
204 | |
205 | } // namespace WebCore |
206 | |