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