• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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