1 /*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkRect.h"
9
10 #include "include/private/SkMalloc.h"
11 #include "src/core/SkRectPriv.h"
12
dump(std::string & desc,int depth) const13 void SkIRect::dump(std::string& desc, int depth) const {
14 std::string split(depth, '\t');
15 desc += split + "\n SkIRect:{ \n";
16 desc += split + "\t fLeft:" + std::to_string(fLeft) + "\n";
17 desc += split + "\t fTop:" + std::to_string(fTop) + "\n";
18 desc += split + "\t fRight:" + std::to_string(fRight) + "\n";
19 desc += split + "\t fBottom:" + std::to_string(fBottom) + "\n";
20 desc += split + "}\n";
21 }
22
intersect(const SkIRect & a,const SkIRect & b)23 bool SkIRect::intersect(const SkIRect& a, const SkIRect& b) {
24 SkIRect tmp = {
25 std::max(a.fLeft, b.fLeft),
26 std::max(a.fTop, b.fTop),
27 std::min(a.fRight, b.fRight),
28 std::min(a.fBottom, b.fBottom)
29 };
30 if (tmp.isEmpty()) {
31 return false;
32 }
33 *this = tmp;
34 return true;
35 }
36
join(const SkIRect & r)37 void SkIRect::join(const SkIRect& r) {
38 // do nothing if the params are empty
39 if (r.fLeft >= r.fRight || r.fTop >= r.fBottom) {
40 return;
41 }
42
43 // if we are empty, just assign
44 if (fLeft >= fRight || fTop >= fBottom) {
45 *this = r;
46 } else {
47 if (r.fLeft < fLeft) fLeft = r.fLeft;
48 if (r.fTop < fTop) fTop = r.fTop;
49 if (r.fRight > fRight) fRight = r.fRight;
50 if (r.fBottom > fBottom) fBottom = r.fBottom;
51 }
52 }
53
54 /////////////////////////////////////////////////////////////////////////////
55
toQuad(SkPoint quad[4]) const56 void SkRect::toQuad(SkPoint quad[4]) const {
57 SkASSERT(quad);
58
59 quad[0].set(fLeft, fTop);
60 quad[1].set(fRight, fTop);
61 quad[2].set(fRight, fBottom);
62 quad[3].set(fLeft, fBottom);
63 }
64
65 #include "include/private/SkNx.h"
66
setBoundsCheck(const SkPoint pts[],int count)67 bool SkRect::setBoundsCheck(const SkPoint pts[], int count) {
68 SkASSERT((pts && count > 0) || count == 0);
69
70 if (count <= 0) {
71 this->setEmpty();
72 return true;
73 }
74
75 Sk4s min, max;
76 if (count & 1) {
77 min = max = Sk4s(pts->fX, pts->fY,
78 pts->fX, pts->fY);
79 pts += 1;
80 count -= 1;
81 } else {
82 min = max = Sk4s::Load(pts);
83 pts += 2;
84 count -= 2;
85 }
86
87 Sk4s accum = min * 0;
88 while (count) {
89 Sk4s xy = Sk4s::Load(pts);
90 accum = accum * xy;
91 min = Sk4s::Min(min, xy);
92 max = Sk4s::Max(max, xy);
93 pts += 2;
94 count -= 2;
95 }
96
97 bool all_finite = (accum * 0 == 0).allTrue();
98 if (all_finite) {
99 this->setLTRB(std::min(min[0], min[2]), std::min(min[1], min[3]),
100 std::max(max[0], max[2]), std::max(max[1], max[3]));
101 } else {
102 this->setEmpty();
103 }
104 return all_finite;
105 }
106
setBoundsNoCheck(const SkPoint pts[],int count)107 void SkRect::setBoundsNoCheck(const SkPoint pts[], int count) {
108 if (!this->setBoundsCheck(pts, count)) {
109 this->setLTRB(SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN);
110 }
111 }
112
113 #define CHECK_INTERSECT(al, at, ar, ab, bl, bt, br, bb) \
114 SkScalar L = std::max(al, bl); \
115 SkScalar R = std::min(ar, br); \
116 SkScalar T = std::max(at, bt); \
117 SkScalar B = std::min(ab, bb); \
118 do { if (!(L < R && T < B)) return false; } while (0)
119 // do the !(opposite) check so we return false if either arg is NaN
120
intersect(const SkRect & r)121 bool SkRect::intersect(const SkRect& r) {
122 CHECK_INTERSECT(r.fLeft, r.fTop, r.fRight, r.fBottom, fLeft, fTop, fRight, fBottom);
123 this->setLTRB(L, T, R, B);
124 return true;
125 }
126
intersect(const SkRect & a,const SkRect & b)127 bool SkRect::intersect(const SkRect& a, const SkRect& b) {
128 CHECK_INTERSECT(a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom);
129 this->setLTRB(L, T, R, B);
130 return true;
131 }
132
join(const SkRect & r)133 void SkRect::join(const SkRect& r) {
134 if (r.isEmpty()) {
135 return;
136 }
137
138 if (this->isEmpty()) {
139 *this = r;
140 } else {
141 fLeft = std::min(fLeft, r.fLeft);
142 fTop = std::min(fTop, r.fTop);
143 fRight = std::max(fRight, r.fRight);
144 fBottom = std::max(fBottom, r.fBottom);
145 }
146 }
147
148 ////////////////////////////////////////////////////////////////////////////////////////////////
149
150 #include "include/core/SkString.h"
151 #include "src/core/SkStringUtils.h"
152
set_scalar(SkString * storage,SkScalar value,SkScalarAsStringType asType)153 static const char* set_scalar(SkString* storage, SkScalar value, SkScalarAsStringType asType) {
154 storage->reset();
155 SkAppendScalar(storage, value, asType);
156 return storage->c_str();
157 }
158
dump(bool asHex) const159 void SkRect::dump(bool asHex) const {
160 SkScalarAsStringType asType = asHex ? kHex_SkScalarAsStringType : kDec_SkScalarAsStringType;
161
162 SkString line;
163 if (asHex) {
164 SkString tmp;
165 line.printf( "SkRect::MakeLTRB(%s, /* %f */\n", set_scalar(&tmp, fLeft, asType), fLeft);
166 line.appendf(" %s, /* %f */\n", set_scalar(&tmp, fTop, asType), fTop);
167 line.appendf(" %s, /* %f */\n", set_scalar(&tmp, fRight, asType), fRight);
168 line.appendf(" %s /* %f */);", set_scalar(&tmp, fBottom, asType), fBottom);
169 } else {
170 SkString strL, strT, strR, strB;
171 SkAppendScalarDec(&strL, fLeft);
172 SkAppendScalarDec(&strT, fTop);
173 SkAppendScalarDec(&strR, fRight);
174 SkAppendScalarDec(&strB, fBottom);
175 line.printf("SkRect::MakeLTRB(%s, %s, %s, %s);",
176 strL.c_str(), strT.c_str(), strR.c_str(), strB.c_str());
177 }
178 SkDebugf("%s\n", line.c_str());
179 }
180
dump(std::string & desc,int depth) const181 void SkRect::dump(std::string& desc, int depth) const {
182 std::string split(depth, '\t');
183 desc += split + "\n SkRect:{ \n";
184 desc += split + "\t fLeft:" + std::to_string(fLeft) + "\n";
185 desc += split + "\t fTop:" + std::to_string(fTop) + "\n";
186 desc += split + "\t fRight:" + std::to_string(fRight) + "\n";
187 desc += split + "\t fBottom:" + std::to_string(fBottom) + "\n";
188 desc += split + "}\n";
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////////////////////
192
193 template<typename R>
subtract(const R & a,const R & b,R * out)194 static bool subtract(const R& a, const R& b, R* out) {
195 if (a.isEmpty() || b.isEmpty() || !R::Intersects(a, b)) {
196 // Either already empty, or subtracting the empty rect, or there's no intersection, so
197 // in all cases the answer is A.
198 *out = a;
199 return true;
200 }
201
202 // 4 rectangles to consider. If the edge in A is contained in B, the resulting difference can
203 // be represented exactly as a rectangle. Otherwise the difference is the largest subrectangle
204 // that is disjoint from B:
205 // 1. Left part of A: (A.left, A.top, B.left, A.bottom)
206 // 2. Right part of A: (B.right, A.top, A.right, A.bottom)
207 // 3. Top part of A: (A.left, A.top, A.right, B.top)
208 // 4. Bottom part of A: (A.left, B.bottom, A.right, A.bottom)
209 //
210 // Depending on how B intersects A, there will be 1 to 4 positive areas:
211 // - 4 occur when A contains B
212 // - 3 occur when B intersects a single edge
213 // - 2 occur when B intersects at a corner, or spans two opposing edges
214 // - 1 occurs when B spans two opposing edges and contains a 3rd, resulting in an exact rect
215 // - 0 occurs when B contains A, resulting in the empty rect
216 //
217 // Compute the relative areas of the 4 rects described above. Since each subrectangle shares
218 // either the width or height of A, we only have to divide by the other dimension, which avoids
219 // overflow on int32 types, and even if the float relative areas overflow to infinity, the
220 // comparisons work out correctly and (one of) the infinitely large subrects will be chosen.
221 float aHeight = (float) a.height();
222 float aWidth = (float) a.width();
223 float leftArea = 0.f, rightArea = 0.f, topArea = 0.f, bottomArea = 0.f;
224 int positiveCount = 0;
225 if (b.fLeft > a.fLeft) {
226 leftArea = (b.fLeft - a.fLeft) / aWidth;
227 positiveCount++;
228 }
229 if (a.fRight > b.fRight) {
230 rightArea = (a.fRight - b.fRight) / aWidth;
231 positiveCount++;
232 }
233 if (b.fTop > a.fTop) {
234 topArea = (b.fTop - a.fTop) / aHeight;
235 positiveCount++;
236 }
237 if (a.fBottom > b.fBottom) {
238 bottomArea = (a.fBottom - b.fBottom) / aHeight;
239 positiveCount++;
240 }
241
242 if (positiveCount == 0) {
243 SkASSERT(b.contains(a));
244 *out = R::MakeEmpty();
245 return true;
246 }
247
248 *out = a;
249 if (leftArea > rightArea && leftArea > topArea && leftArea > bottomArea) {
250 // Left chunk of A, so the new right edge is B's left edge
251 out->fRight = b.fLeft;
252 } else if (rightArea > topArea && rightArea > bottomArea) {
253 // Right chunk of A, so the new left edge is B's right edge
254 out->fLeft = b.fRight;
255 } else if (topArea > bottomArea) {
256 // Top chunk of A, so the new bottom edge is B's top edge
257 out->fBottom = b.fTop;
258 } else {
259 // Bottom chunk of A, so the new top edge is B's bottom edge
260 SkASSERT(bottomArea > 0.f);
261 out->fTop = b.fBottom;
262 }
263
264 // If we have 1 valid area, the disjoint shape is representable as a rectangle.
265 SkASSERT(!R::Intersects(*out, b));
266 return positiveCount == 1;
267 }
268
Subtract(const SkRect & a,const SkRect & b,SkRect * out)269 bool SkRectPriv::Subtract(const SkRect& a, const SkRect& b, SkRect* out) {
270 return subtract<SkRect>(a, b, out);
271 }
272
Subtract(const SkIRect & a,const SkIRect & b,SkIRect * out)273 bool SkRectPriv::Subtract(const SkIRect& a, const SkIRect& b, SkIRect* out) {
274 return subtract<SkIRect>(a, b, out);
275 }
276