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