/src/skia/src/core/SkRect.cpp
Line | Count | Source (jump to first uncovered line) |
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/core/SkM44.h" |
11 | | #include "include/private/base/SkDebug.h" |
12 | | #include "include/private/base/SkTPin.h" |
13 | | #include "src/core/SkRectPriv.h" |
14 | | |
15 | | class SkMatrix; |
16 | | |
17 | 10.6G | bool SkIRect::intersect(const SkIRect& a, const SkIRect& b) { |
18 | 10.6G | SkIRect tmp = { |
19 | 10.6G | std::max(a.fLeft, b.fLeft), |
20 | 10.6G | std::max(a.fTop, b.fTop), |
21 | 10.6G | std::min(a.fRight, b.fRight), |
22 | 10.6G | std::min(a.fBottom, b.fBottom) |
23 | 10.6G | }; |
24 | 10.6G | if (tmp.isEmpty()) { |
25 | 10.5G | return false; |
26 | 10.5G | } |
27 | 96.5M | *this = tmp; |
28 | 96.5M | return true; |
29 | 10.6G | } |
30 | | |
31 | 898k | void SkIRect::join(const SkIRect& r) { |
32 | | // do nothing if the params are empty |
33 | 898k | if (r.fLeft >= r.fRight || r.fTop >= r.fBottom) { |
34 | 408k | return; |
35 | 408k | } |
36 | | |
37 | | // if we are empty, just assign |
38 | 490k | if (fLeft >= fRight || fTop >= fBottom) { |
39 | 32.5k | *this = r; |
40 | 457k | } else { |
41 | 457k | if (r.fLeft < fLeft) fLeft = r.fLeft; |
42 | 457k | if (r.fTop < fTop) fTop = r.fTop; |
43 | 457k | if (r.fRight > fRight) fRight = r.fRight; |
44 | 457k | if (r.fBottom > fBottom) fBottom = r.fBottom; |
45 | 457k | } |
46 | 490k | } |
47 | | |
48 | | ///////////////////////////////////////////////////////////////////////////// |
49 | | |
50 | 89.6k | void SkRect::toQuad(SkPoint quad[4]) const { |
51 | 89.6k | SkASSERT(quad); |
52 | | |
53 | 89.6k | quad[0].set(fLeft, fTop); |
54 | 89.6k | quad[1].set(fRight, fTop); |
55 | 89.6k | quad[2].set(fRight, fBottom); |
56 | 89.6k | quad[3].set(fLeft, fBottom); |
57 | 89.6k | } |
58 | | |
59 | | #include "src/base/SkVx.h" |
60 | | |
61 | 145M | bool SkRect::setBoundsCheck(const SkPoint pts[], int count) { |
62 | 145M | SkASSERT((pts && count > 0) || count == 0); |
63 | | |
64 | 145M | if (count <= 0) { |
65 | 156k | this->setEmpty(); |
66 | 156k | return true; |
67 | 156k | } |
68 | | |
69 | 145M | skvx::float4 min, max; |
70 | 145M | if (count & 1) { |
71 | 122M | min = max = skvx::float2::Load(pts).xyxy(); |
72 | 122M | pts += 1; |
73 | 122M | count -= 1; |
74 | 122M | } else { |
75 | 22.2M | min = max = skvx::float4::Load(pts); |
76 | 22.2M | pts += 2; |
77 | 22.2M | count -= 2; |
78 | 22.2M | } |
79 | | |
80 | 145M | skvx::float4 accum = min * 0; |
81 | 437M | while (count) { |
82 | 292M | skvx::float4 xy = skvx::float4::Load(pts); |
83 | 292M | accum = accum * xy; |
84 | 292M | min = skvx::min(min, xy); |
85 | 292M | max = skvx::max(max, xy); |
86 | 292M | pts += 2; |
87 | 292M | count -= 2; |
88 | 292M | } |
89 | | |
90 | 145M | const bool all_finite = all(accum * 0 == 0); |
91 | 145M | if (all_finite) { |
92 | 144M | this->setLTRB(std::min(min[0], min[2]), std::min(min[1], min[3]), |
93 | 144M | std::max(max[0], max[2]), std::max(max[1], max[3])); |
94 | 144M | } else { |
95 | 94.1k | this->setEmpty(); |
96 | 94.1k | } |
97 | 145M | return all_finite; |
98 | 145M | } SkRect::setBoundsCheck(SkPoint const*, int) Line | Count | Source | 61 | 145M | bool SkRect::setBoundsCheck(const SkPoint pts[], int count) { | 62 | 145M | SkASSERT((pts && count > 0) || count == 0); | 63 | | | 64 | 145M | if (count <= 0) { | 65 | 156k | this->setEmpty(); | 66 | 156k | return true; | 67 | 156k | } | 68 | | | 69 | 145M | skvx::float4 min, max; | 70 | 145M | if (count & 1) { | 71 | 122M | min = max = skvx::float2::Load(pts).xyxy(); | 72 | 122M | pts += 1; | 73 | 122M | count -= 1; | 74 | 122M | } else { | 75 | 22.2M | min = max = skvx::float4::Load(pts); | 76 | 22.2M | pts += 2; | 77 | 22.2M | count -= 2; | 78 | 22.2M | } | 79 | | | 80 | 145M | skvx::float4 accum = min * 0; | 81 | 437M | while (count) { | 82 | 292M | skvx::float4 xy = skvx::float4::Load(pts); | 83 | 292M | accum = accum * xy; | 84 | 292M | min = skvx::min(min, xy); | 85 | 292M | max = skvx::max(max, xy); | 86 | 292M | pts += 2; | 87 | 292M | count -= 2; | 88 | 292M | } | 89 | | | 90 | 145M | const bool all_finite = all(accum * 0 == 0); | 91 | 145M | if (all_finite) { | 92 | 144M | this->setLTRB(std::min(min[0], min[2]), std::min(min[1], min[3]), | 93 | 144M | std::max(max[0], max[2]), std::max(max[1], max[3])); | 94 | 144M | } else { | 95 | 94.1k | this->setEmpty(); | 96 | 94.1k | } | 97 | 145M | return all_finite; | 98 | 145M | } |
SkRect::setBoundsCheck(SkPoint const*, int) Line | Count | Source | 61 | 4 | bool SkRect::setBoundsCheck(const SkPoint pts[], int count) { | 62 | 4 | SkASSERT((pts && count > 0) || count == 0); | 63 | | | 64 | 4 | if (count <= 0) { | 65 | 0 | this->setEmpty(); | 66 | 0 | return true; | 67 | 0 | } | 68 | | | 69 | 4 | skvx::float4 min, max; | 70 | 4 | if (count & 1) { | 71 | 0 | min = max = skvx::float2::Load(pts).xyxy(); | 72 | 0 | pts += 1; | 73 | 0 | count -= 1; | 74 | 4 | } else { | 75 | 4 | min = max = skvx::float4::Load(pts); | 76 | 4 | pts += 2; | 77 | 4 | count -= 2; | 78 | 4 | } | 79 | | | 80 | 4 | skvx::float4 accum = min * 0; | 81 | 8 | while (count) { | 82 | 4 | skvx::float4 xy = skvx::float4::Load(pts); | 83 | 4 | accum = accum * xy; | 84 | 4 | min = skvx::min(min, xy); | 85 | 4 | max = skvx::max(max, xy); | 86 | 4 | pts += 2; | 87 | 4 | count -= 2; | 88 | 4 | } | 89 | | | 90 | 4 | const bool all_finite = all(accum * 0 == 0); | 91 | 4 | if (all_finite) { | 92 | 4 | this->setLTRB(std::min(min[0], min[2]), std::min(min[1], min[3]), | 93 | 4 | std::max(max[0], max[2]), std::max(max[1], max[3])); | 94 | 4 | } else { | 95 | 0 | this->setEmpty(); | 96 | 0 | } | 97 | 4 | return all_finite; | 98 | 4 | } |
|
99 | | |
100 | 73.0k | void SkRect::setBoundsNoCheck(const SkPoint pts[], int count) { |
101 | 73.0k | if (!this->setBoundsCheck(pts, count)) { |
102 | 3.36k | this->setLTRB(SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN); |
103 | 3.36k | } |
104 | 73.0k | } |
105 | | |
106 | | #define CHECK_INTERSECT(al, at, ar, ab, bl, bt, br, bb) \ |
107 | 13.8M | float L = std::max(al, bl); \ |
108 | 13.8M | float R = std::min(ar, br); \ |
109 | 13.8M | float T = std::max(at, bt); \ |
110 | 13.8M | float B = std::min(ab, bb); \ |
111 | 13.8M | do { if (!(L < R && T < B)) return false; } while (0) |
112 | | // do the !(opposite) check so we return false if either arg is NaN |
113 | | |
114 | 13.8M | bool SkRect::intersect(const SkRect& r) { |
115 | 13.8M | CHECK_INTERSECT(r.fLeft, r.fTop, r.fRight, r.fBottom, fLeft, fTop, fRight, fBottom); |
116 | 12.3M | this->setLTRB(L, T, R, B); |
117 | 12.3M | return true; |
118 | 13.8M | } |
119 | | |
120 | 629 | bool SkRect::intersect(const SkRect& a, const SkRect& b) { |
121 | 629 | CHECK_INTERSECT(a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom); |
122 | 487 | this->setLTRB(L, T, R, B); |
123 | 487 | return true; |
124 | 629 | } |
125 | | |
126 | 785k | void SkRect::join(const SkRect& r) { |
127 | 785k | if (r.isEmpty()) { |
128 | 257k | return; |
129 | 257k | } |
130 | | |
131 | 527k | if (this->isEmpty()) { |
132 | 94.3k | *this = r; |
133 | 433k | } else { |
134 | 433k | fLeft = std::min(fLeft, r.fLeft); |
135 | 433k | fTop = std::min(fTop, r.fTop); |
136 | 433k | fRight = std::max(fRight, r.fRight); |
137 | 433k | fBottom = std::max(fBottom, r.fBottom); |
138 | 433k | } |
139 | 527k | } |
140 | | |
141 | | //////////////////////////////////////////////////////////////////////////////////////////////// |
142 | | |
143 | | #include "include/core/SkString.h" |
144 | | #include "src/core/SkStringUtils.h" |
145 | | |
146 | 0 | static const char* set_scalar(SkString* storage, float value, SkScalarAsStringType asType) { |
147 | 0 | storage->reset(); |
148 | 0 | SkAppendScalar(storage, value, asType); |
149 | 0 | return storage->c_str(); |
150 | 0 | } |
151 | | |
152 | 0 | void SkRect::dump(bool asHex) const { |
153 | 0 | SkScalarAsStringType asType = asHex ? kHex_SkScalarAsStringType : kDec_SkScalarAsStringType; |
154 | |
|
155 | 0 | SkString line; |
156 | 0 | if (asHex) { |
157 | 0 | SkString tmp; |
158 | 0 | line.printf( "SkRect::MakeLTRB(%s, /* %f */\n", set_scalar(&tmp, fLeft, asType), fLeft); |
159 | 0 | line.appendf(" %s, /* %f */\n", set_scalar(&tmp, fTop, asType), fTop); |
160 | 0 | line.appendf(" %s, /* %f */\n", set_scalar(&tmp, fRight, asType), fRight); |
161 | 0 | line.appendf(" %s /* %f */);", set_scalar(&tmp, fBottom, asType), fBottom); |
162 | 0 | } else { |
163 | 0 | SkString strL, strT, strR, strB; |
164 | 0 | SkAppendScalarDec(&strL, fLeft); |
165 | 0 | SkAppendScalarDec(&strT, fTop); |
166 | 0 | SkAppendScalarDec(&strR, fRight); |
167 | 0 | SkAppendScalarDec(&strB, fBottom); |
168 | 0 | line.printf("SkRect::MakeLTRB(%s, %s, %s, %s);", |
169 | 0 | strL.c_str(), strT.c_str(), strR.c_str(), strB.c_str()); |
170 | 0 | } |
171 | 0 | SkDebugf("%s\n", line.c_str()); |
172 | 0 | } |
173 | | |
174 | | //////////////////////////////////////////////////////////////////////////////////////////////// |
175 | | |
176 | | template<typename R> |
177 | 37.4k | static bool subtract(const R& a, const R& b, R* out) { |
178 | 37.4k | if (a.isEmpty() || b.isEmpty() || !R::Intersects(a, b)) { |
179 | | // Either already empty, or subtracting the empty rect, or there's no intersection, so |
180 | | // in all cases the answer is A. |
181 | 21.1k | *out = a; |
182 | 21.1k | return true; |
183 | 21.1k | } |
184 | | |
185 | | // 4 rectangles to consider. If the edge in A is contained in B, the resulting difference can |
186 | | // be represented exactly as a rectangle. Otherwise the difference is the largest subrectangle |
187 | | // that is disjoint from B: |
188 | | // 1. Left part of A: (A.left, A.top, B.left, A.bottom) |
189 | | // 2. Right part of A: (B.right, A.top, A.right, A.bottom) |
190 | | // 3. Top part of A: (A.left, A.top, A.right, B.top) |
191 | | // 4. Bottom part of A: (A.left, B.bottom, A.right, A.bottom) |
192 | | // |
193 | | // Depending on how B intersects A, there will be 1 to 4 positive areas: |
194 | | // - 4 occur when A contains B |
195 | | // - 3 occur when B intersects a single edge |
196 | | // - 2 occur when B intersects at a corner, or spans two opposing edges |
197 | | // - 1 occurs when B spans two opposing edges and contains a 3rd, resulting in an exact rect |
198 | | // - 0 occurs when B contains A, resulting in the empty rect |
199 | | // |
200 | | // Compute the relative areas of the 4 rects described above. Since each subrectangle shares |
201 | | // either the width or height of A, we only have to divide by the other dimension, which avoids |
202 | | // overflow on int32 types, and even if the float relative areas overflow to infinity, the |
203 | | // comparisons work out correctly and (one of) the infinitely large subrects will be chosen. |
204 | 16.2k | float aHeight = (float) a.height(); |
205 | 16.2k | float aWidth = (float) a.width(); |
206 | 16.2k | float leftArea = 0.f, rightArea = 0.f, topArea = 0.f, bottomArea = 0.f; |
207 | 16.2k | int positiveCount = 0; |
208 | 16.2k | if (b.fLeft > a.fLeft) { |
209 | 7.51k | leftArea = (b.fLeft - a.fLeft) / aWidth; |
210 | 7.51k | positiveCount++; |
211 | 7.51k | } |
212 | 16.2k | if (a.fRight > b.fRight) { |
213 | 6.00k | rightArea = (a.fRight - b.fRight) / aWidth; |
214 | 6.00k | positiveCount++; |
215 | 6.00k | } |
216 | 16.2k | if (b.fTop > a.fTop) { |
217 | 10.6k | topArea = (b.fTop - a.fTop) / aHeight; |
218 | 10.6k | positiveCount++; |
219 | 10.6k | } |
220 | 16.2k | if (a.fBottom > b.fBottom) { |
221 | 8.51k | bottomArea = (a.fBottom - b.fBottom) / aHeight; |
222 | 8.51k | positiveCount++; |
223 | 8.51k | } |
224 | | |
225 | 16.2k | if (positiveCount == 0) { |
226 | 656 | SkASSERT(b.contains(a)); |
227 | 656 | *out = R::MakeEmpty(); |
228 | 656 | return true; |
229 | 656 | } |
230 | | |
231 | 15.6k | *out = a; |
232 | 15.6k | if (leftArea > rightArea && leftArea > topArea && leftArea > bottomArea) { |
233 | | // Left chunk of A, so the new right edge is B's left edge |
234 | 3.04k | out->fRight = b.fLeft; |
235 | 12.5k | } else if (rightArea > topArea && rightArea > bottomArea) { |
236 | | // Right chunk of A, so the new left edge is B's right edge |
237 | 4.10k | out->fLeft = b.fRight; |
238 | 8.45k | } else if (topArea > bottomArea) { |
239 | | // Top chunk of A, so the new bottom edge is B's top edge |
240 | 2.66k | out->fBottom = b.fTop; |
241 | 5.78k | } else { |
242 | | // Bottom chunk of A, so the new top edge is B's bottom edge |
243 | 5.78k | SkASSERT(bottomArea > 0.f); |
244 | 5.78k | out->fTop = b.fBottom; |
245 | 5.78k | } |
246 | | |
247 | | // If we have 1 valid area, the disjoint shape is representable as a rectangle. |
248 | 15.6k | SkASSERT(!R::Intersects(*out, b)); |
249 | 15.6k | return positiveCount == 1; |
250 | 16.2k | } Unexecuted instantiation: SkRect.cpp:bool subtract<SkRect>(SkRect const&, SkRect const&, SkRect*) SkRect.cpp:bool subtract<SkIRect>(SkIRect const&, SkIRect const&, SkIRect*) Line | Count | Source | 177 | 37.4k | static bool subtract(const R& a, const R& b, R* out) { | 178 | 37.4k | if (a.isEmpty() || b.isEmpty() || !R::Intersects(a, b)) { | 179 | | // Either already empty, or subtracting the empty rect, or there's no intersection, so | 180 | | // in all cases the answer is A. | 181 | 21.1k | *out = a; | 182 | 21.1k | return true; | 183 | 21.1k | } | 184 | | | 185 | | // 4 rectangles to consider. If the edge in A is contained in B, the resulting difference can | 186 | | // be represented exactly as a rectangle. Otherwise the difference is the largest subrectangle | 187 | | // that is disjoint from B: | 188 | | // 1. Left part of A: (A.left, A.top, B.left, A.bottom) | 189 | | // 2. Right part of A: (B.right, A.top, A.right, A.bottom) | 190 | | // 3. Top part of A: (A.left, A.top, A.right, B.top) | 191 | | // 4. Bottom part of A: (A.left, B.bottom, A.right, A.bottom) | 192 | | // | 193 | | // Depending on how B intersects A, there will be 1 to 4 positive areas: | 194 | | // - 4 occur when A contains B | 195 | | // - 3 occur when B intersects a single edge | 196 | | // - 2 occur when B intersects at a corner, or spans two opposing edges | 197 | | // - 1 occurs when B spans two opposing edges and contains a 3rd, resulting in an exact rect | 198 | | // - 0 occurs when B contains A, resulting in the empty rect | 199 | | // | 200 | | // Compute the relative areas of the 4 rects described above. Since each subrectangle shares | 201 | | // either the width or height of A, we only have to divide by the other dimension, which avoids | 202 | | // overflow on int32 types, and even if the float relative areas overflow to infinity, the | 203 | | // comparisons work out correctly and (one of) the infinitely large subrects will be chosen. | 204 | 16.2k | float aHeight = (float) a.height(); | 205 | 16.2k | float aWidth = (float) a.width(); | 206 | 16.2k | float leftArea = 0.f, rightArea = 0.f, topArea = 0.f, bottomArea = 0.f; | 207 | 16.2k | int positiveCount = 0; | 208 | 16.2k | if (b.fLeft > a.fLeft) { | 209 | 7.51k | leftArea = (b.fLeft - a.fLeft) / aWidth; | 210 | 7.51k | positiveCount++; | 211 | 7.51k | } | 212 | 16.2k | if (a.fRight > b.fRight) { | 213 | 6.00k | rightArea = (a.fRight - b.fRight) / aWidth; | 214 | 6.00k | positiveCount++; | 215 | 6.00k | } | 216 | 16.2k | if (b.fTop > a.fTop) { | 217 | 10.6k | topArea = (b.fTop - a.fTop) / aHeight; | 218 | 10.6k | positiveCount++; | 219 | 10.6k | } | 220 | 16.2k | if (a.fBottom > b.fBottom) { | 221 | 8.51k | bottomArea = (a.fBottom - b.fBottom) / aHeight; | 222 | 8.51k | positiveCount++; | 223 | 8.51k | } | 224 | | | 225 | 16.2k | if (positiveCount == 0) { | 226 | 656 | SkASSERT(b.contains(a)); | 227 | 656 | *out = R::MakeEmpty(); | 228 | 656 | return true; | 229 | 656 | } | 230 | | | 231 | 15.6k | *out = a; | 232 | 15.6k | if (leftArea > rightArea && leftArea > topArea && leftArea > bottomArea) { | 233 | | // Left chunk of A, so the new right edge is B's left edge | 234 | 3.04k | out->fRight = b.fLeft; | 235 | 12.5k | } else if (rightArea > topArea && rightArea > bottomArea) { | 236 | | // Right chunk of A, so the new left edge is B's right edge | 237 | 4.10k | out->fLeft = b.fRight; | 238 | 8.45k | } else if (topArea > bottomArea) { | 239 | | // Top chunk of A, so the new bottom edge is B's top edge | 240 | 2.66k | out->fBottom = b.fTop; | 241 | 5.78k | } else { | 242 | | // Bottom chunk of A, so the new top edge is B's bottom edge | 243 | 5.78k | SkASSERT(bottomArea > 0.f); | 244 | 5.78k | out->fTop = b.fBottom; | 245 | 5.78k | } | 246 | | | 247 | | // If we have 1 valid area, the disjoint shape is representable as a rectangle. | 248 | 15.6k | SkASSERT(!R::Intersects(*out, b)); | 249 | 15.6k | return positiveCount == 1; | 250 | 16.2k | } |
Unexecuted instantiation: SkRect.cpp:bool subtract<SkRect>(SkRect const&, SkRect const&, SkRect*) |
251 | | |
252 | 0 | bool SkRectPriv::Subtract(const SkRect& a, const SkRect& b, SkRect* out) { |
253 | 0 | return subtract<SkRect>(a, b, out); |
254 | 0 | } |
255 | | |
256 | 37.4k | bool SkRectPriv::Subtract(const SkIRect& a, const SkIRect& b, SkIRect* out) { |
257 | 37.4k | return subtract<SkIRect>(a, b, out); |
258 | 37.4k | } |
259 | | |
260 | | |
261 | | bool SkRectPriv::QuadContainsRect(const SkMatrix& m, |
262 | | const SkIRect& a, |
263 | | const SkIRect& b, |
264 | 224k | float tol) { |
265 | 224k | return QuadContainsRect(SkM44(m), SkRect::Make(a), SkRect::Make(b), tol); |
266 | 224k | } |
267 | | |
268 | 448k | bool SkRectPriv::QuadContainsRect(const SkM44& m, const SkRect& a, const SkRect& b, float tol) { |
269 | 448k | return all(QuadContainsRectMask(m, a, b, tol)); |
270 | 448k | } |
271 | | |
272 | | skvx::int4 SkRectPriv::QuadContainsRectMask(const SkM44& m, |
273 | | const SkRect& a, |
274 | | const SkRect& b, |
275 | 543k | float tol) { |
276 | 543k | SkDEBUGCODE(SkM44 inverse;) |
277 | 543k | SkASSERT(m.invert(&inverse)); |
278 | | // With empty rectangles, the calculated edges could give surprising results. If 'a' were not |
279 | | // sorted, its normals would point outside the sorted rectangle, so lots of potential rects |
280 | | // would be seen as "contained". If 'a' is all 0s, its edge equations are also (0,0,0) so every |
281 | | // point has a distance of 0, and would be interpreted as inside. |
282 | 543k | if (a.isEmpty()) { |
283 | 44.7k | return skvx::int4(0); // all "false" |
284 | 44.7k | } |
285 | | // However, 'b' is only used to define its 4 corners to check against the transformed edges. |
286 | | // This is valid regardless of b's emptiness or sortedness. |
287 | | |
288 | | // Calculate the 4 homogenous coordinates of 'a' transformed by 'm' where Z=0 and W=1. |
289 | 498k | auto ax = skvx::float4{a.fLeft, a.fRight, a.fRight, a.fLeft}; |
290 | 498k | auto ay = skvx::float4{a.fTop, a.fTop, a.fBottom, a.fBottom}; |
291 | | |
292 | 498k | auto max = m.rc(0,0)*ax + m.rc(0,1)*ay + m.rc(0,3); |
293 | 498k | auto may = m.rc(1,0)*ax + m.rc(1,1)*ay + m.rc(1,3); |
294 | 498k | auto maw = m.rc(3,0)*ax + m.rc(3,1)*ay + m.rc(3,3); |
295 | | |
296 | 498k | if (all(maw < 0.f)) { |
297 | | // If all points of A are mapped to w < 0, then the edge equations end up representing the |
298 | | // convex hull of projected points when A should in fact be considered empty. |
299 | 1.31k | return skvx::int4(0); // all "false" |
300 | 1.31k | } |
301 | | |
302 | | // Cross product of adjacent vertices provides homogenous lines for the 4 sides of the quad |
303 | 497k | auto lA = may*skvx::shuffle<1,2,3,0>(maw) - maw*skvx::shuffle<1,2,3,0>(may); |
304 | 497k | auto lB = maw*skvx::shuffle<1,2,3,0>(max) - max*skvx::shuffle<1,2,3,0>(maw); |
305 | 497k | auto lC = max*skvx::shuffle<1,2,3,0>(may) - may*skvx::shuffle<1,2,3,0>(max); |
306 | | |
307 | | // Before transforming, the corners of 'a' were in CW order, but afterwards they may become CCW, |
308 | | // so the sign corrects the direction of the edge normals to point inwards. |
309 | 497k | float sign = (lA[0]*lB[1] - lB[0]*lA[1]) < 0 ? -1.f : 1.f; |
310 | | |
311 | | // Calculate distance from 'b' to each edge. Since 'b' has presumably been transformed by 'm' |
312 | | // *and* projected, this assumes W = 1. |
313 | 497k | SkRect bInset = b.makeInset(tol, tol); |
314 | 497k | auto d0 = sign * (lA*bInset.fLeft + lB*bInset.fTop + lC); |
315 | 497k | auto d1 = sign * (lA*bInset.fRight + lB*bInset.fTop + lC); |
316 | 497k | auto d2 = sign * (lA*bInset.fRight + lB*bInset.fBottom + lC); |
317 | 497k | auto d3 = sign * (lA*bInset.fLeft + lB*bInset.fBottom + lC); |
318 | | |
319 | | // 'b' is contained in the mapped rectangle if all distances are >= 0 |
320 | 497k | return (d0 >= 0.f) & (d1 >= 0.f) & (d2 >= 0.f) & (d3 >= 0.f); |
321 | 498k | } |
322 | | |
323 | 5.21k | SkIRect SkRectPriv::ClosestDisjointEdge(const SkIRect& src, const SkIRect& dst) { |
324 | 5.21k | if (src.isEmpty() || dst.isEmpty()) { |
325 | 1.06k | return SkIRect::MakeEmpty(); |
326 | 1.06k | } |
327 | | |
328 | 4.15k | int l = src.fLeft; |
329 | 4.15k | int r = src.fRight; |
330 | 4.15k | if (r <= dst.fLeft) { |
331 | | // Select right column of pixels in crop |
332 | 1.18k | l = r - 1; |
333 | 2.96k | } else if (l >= dst.fRight) { |
334 | | // Left column of 'crop' |
335 | 1.35k | r = l + 1; |
336 | 1.60k | } else { |
337 | | // Regular intersection along X axis. |
338 | 1.60k | l = SkTPin(l, dst.fLeft, dst.fRight); |
339 | 1.60k | r = SkTPin(r, dst.fLeft, dst.fRight); |
340 | 1.60k | } |
341 | | |
342 | 4.15k | int t = src.fTop; |
343 | 4.15k | int b = src.fBottom; |
344 | 4.15k | if (b <= dst.fTop) { |
345 | | // Select bottom row of pixels in crop |
346 | 1.20k | t = b - 1; |
347 | 2.94k | } else if (t >= dst.fBottom) { |
348 | | // Top row of 'crop' |
349 | 1.59k | b = t + 1; |
350 | 1.59k | } else { |
351 | 1.35k | t = SkTPin(t, dst.fTop, dst.fBottom); |
352 | 1.35k | b = SkTPin(b, dst.fTop, dst.fBottom); |
353 | 1.35k | } |
354 | | |
355 | 4.15k | return SkIRect::MakeLTRB(l,t,r,b); |
356 | 5.21k | } |