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/SkPath.h" 9cb93a386Sopenharmony_ci#include "include/private/SkTDArray.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 11cb93a386Sopenharmony_ci#include "src/core/SkBlitter.h" 12cb93a386Sopenharmony_ci#include "src/core/SkRegionPriv.h" 13cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h" 14cb93a386Sopenharmony_ci#include "src/core/SkScan.h" 15cb93a386Sopenharmony_ci#include "src/core/SkTSort.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci// The rgnbuilder caller *seems* to pass short counts, possible often seens early failure, so 18cb93a386Sopenharmony_ci// we may not want to promote this to a "std" routine just yet. 19cb93a386Sopenharmony_cistatic bool sk_memeq32(const int32_t* SK_RESTRICT a, const int32_t* SK_RESTRICT b, int count) { 20cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 21cb93a386Sopenharmony_ci if (a[i] != b[i]) { 22cb93a386Sopenharmony_ci return false; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci return true; 26cb93a386Sopenharmony_ci} 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciclass SkRgnBuilder : public SkBlitter { 29cb93a386Sopenharmony_cipublic: 30cb93a386Sopenharmony_ci SkRgnBuilder(); 31cb93a386Sopenharmony_ci ~SkRgnBuilder() override; 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci // returns true if it could allocate the working storage needed 34cb93a386Sopenharmony_ci bool init(int maxHeight, int maxTransitions, bool pathIsInverse); 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci void done() { 37cb93a386Sopenharmony_ci if (fCurrScanline != nullptr) { 38cb93a386Sopenharmony_ci fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX())); 39cb93a386Sopenharmony_ci if (!this->collapsWithPrev()) { // flush the last line 40cb93a386Sopenharmony_ci fCurrScanline = fCurrScanline->nextScanline(); 41cb93a386Sopenharmony_ci } 42cb93a386Sopenharmony_ci } 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci int computeRunCount() const; 46cb93a386Sopenharmony_ci void copyToRect(SkIRect*) const; 47cb93a386Sopenharmony_ci void copyToRgn(SkRegion::RunType runs[]) const; 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci void blitH(int x, int y, int width) override; 50cb93a386Sopenharmony_ci void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override { 51cb93a386Sopenharmony_ci SkDEBUGFAIL("blitAntiH not implemented"); 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci#ifdef SK_DEBUG 55cb93a386Sopenharmony_ci void dump() const { 56cb93a386Sopenharmony_ci SkDebugf("SkRgnBuilder: Top = %d\n", fTop); 57cb93a386Sopenharmony_ci const Scanline* line = (Scanline*)fStorage; 58cb93a386Sopenharmony_ci while (line < fCurrScanline) { 59cb93a386Sopenharmony_ci SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount); 60cb93a386Sopenharmony_ci for (int i = 0; i < line->fXCount; i++) { 61cb93a386Sopenharmony_ci SkDebugf(" %d", line->firstX()[i]); 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci SkDebugf("\n"); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci line = line->nextScanline(); 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci#endif 69cb93a386Sopenharmony_ciprivate: 70cb93a386Sopenharmony_ci /* 71cb93a386Sopenharmony_ci * Scanline mimics a row in the region, nearly. A row in a region is: 72cb93a386Sopenharmony_ci * [Bottom IntervalCount [L R]... Sentinel] 73cb93a386Sopenharmony_ci * while a Scanline is 74cb93a386Sopenharmony_ci * [LastY XCount [L R]... uninitialized] 75cb93a386Sopenharmony_ci * The two are the same length (which is good), but we have to transmute 76cb93a386Sopenharmony_ci * the scanline a little when we convert it to a region-row. 77cb93a386Sopenharmony_ci * 78cb93a386Sopenharmony_ci * Potentially we could recode this to exactly match the row format, in 79cb93a386Sopenharmony_ci * which case copyToRgn() could be a single memcpy. Not sure that is worth 80cb93a386Sopenharmony_ci * the effort. 81cb93a386Sopenharmony_ci */ 82cb93a386Sopenharmony_ci struct Scanline { 83cb93a386Sopenharmony_ci SkRegion::RunType fLastY; 84cb93a386Sopenharmony_ci SkRegion::RunType fXCount; 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); } 87cb93a386Sopenharmony_ci Scanline* nextScanline() const { 88cb93a386Sopenharmony_ci // add final +1 for the x-sentinel 89cb93a386Sopenharmony_ci return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount + 1); 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci }; 92cb93a386Sopenharmony_ci SkRegion::RunType* fStorage; 93cb93a386Sopenharmony_ci Scanline* fCurrScanline; 94cb93a386Sopenharmony_ci Scanline* fPrevScanline; 95cb93a386Sopenharmony_ci // points at next avialable x[] in fCurrScanline 96cb93a386Sopenharmony_ci SkRegion::RunType* fCurrXPtr; 97cb93a386Sopenharmony_ci SkRegion::RunType fTop; // first Y value 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci int fStorageCount; 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci bool collapsWithPrev() { 102cb93a386Sopenharmony_ci if (fPrevScanline != nullptr && 103cb93a386Sopenharmony_ci fPrevScanline->fLastY + 1 == fCurrScanline->fLastY && 104cb93a386Sopenharmony_ci fPrevScanline->fXCount == fCurrScanline->fXCount && 105cb93a386Sopenharmony_ci sk_memeq32(fPrevScanline->firstX(), fCurrScanline->firstX(), fCurrScanline->fXCount)) 106cb93a386Sopenharmony_ci { 107cb93a386Sopenharmony_ci // update the height of fPrevScanline 108cb93a386Sopenharmony_ci fPrevScanline->fLastY = fCurrScanline->fLastY; 109cb93a386Sopenharmony_ci return true; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci return false; 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci}; 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ciSkRgnBuilder::SkRgnBuilder() 116cb93a386Sopenharmony_ci : fStorage(nullptr) { 117cb93a386Sopenharmony_ci} 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ciSkRgnBuilder::~SkRgnBuilder() { 120cb93a386Sopenharmony_ci sk_free(fStorage); 121cb93a386Sopenharmony_ci} 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_cibool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) { 124cb93a386Sopenharmony_ci if ((maxHeight | maxTransitions) < 0) { 125cb93a386Sopenharmony_ci return false; 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci SkSafeMath safe; 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci if (pathIsInverse) { 131cb93a386Sopenharmony_ci // allow for additional X transitions to "invert" each scanline 132cb93a386Sopenharmony_ci // [ L' ... normal transitions ... R' ] 133cb93a386Sopenharmony_ci // 134cb93a386Sopenharmony_ci maxTransitions = safe.addInt(maxTransitions, 2); 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci // compute the count with +1 and +3 slop for the working buffer 138cb93a386Sopenharmony_ci size_t count = safe.mul(safe.addInt(maxHeight, 1), safe.addInt(3, maxTransitions)); 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci if (pathIsInverse) { 141cb93a386Sopenharmony_ci // allow for two "empty" rows for the top and bottom 142cb93a386Sopenharmony_ci // [ Y, 1, L, R, S] == 5 (*2 for top and bottom) 143cb93a386Sopenharmony_ci count = safe.add(count, 10); 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci if (!safe || !SkTFitsIn<int32_t>(count)) { 147cb93a386Sopenharmony_ci return false; 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci fStorageCount = SkToS32(count); 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci fStorage = (SkRegion::RunType*)sk_malloc_canfail(fStorageCount, sizeof(SkRegion::RunType)); 152cb93a386Sopenharmony_ci if (nullptr == fStorage) { 153cb93a386Sopenharmony_ci return false; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci fCurrScanline = nullptr; // signal empty collection 157cb93a386Sopenharmony_ci fPrevScanline = nullptr; // signal first scanline 158cb93a386Sopenharmony_ci return true; 159cb93a386Sopenharmony_ci} 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_civoid SkRgnBuilder::blitH(int x, int y, int width) { 162cb93a386Sopenharmony_ci if (fCurrScanline == nullptr) { // first time 163cb93a386Sopenharmony_ci fTop = (SkRegion::RunType)(y); 164cb93a386Sopenharmony_ci fCurrScanline = (Scanline*)fStorage; 165cb93a386Sopenharmony_ci fCurrScanline->fLastY = (SkRegion::RunType)(y); 166cb93a386Sopenharmony_ci fCurrXPtr = fCurrScanline->firstX(); 167cb93a386Sopenharmony_ci } else { 168cb93a386Sopenharmony_ci SkASSERT(y >= fCurrScanline->fLastY); 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci if (y > fCurrScanline->fLastY) { 171cb93a386Sopenharmony_ci // if we get here, we're done with fCurrScanline 172cb93a386Sopenharmony_ci fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX())); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci int prevLastY = fCurrScanline->fLastY; 175cb93a386Sopenharmony_ci if (!this->collapsWithPrev()) { 176cb93a386Sopenharmony_ci fPrevScanline = fCurrScanline; 177cb93a386Sopenharmony_ci fCurrScanline = fCurrScanline->nextScanline(); 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci if (y - 1 > prevLastY) { // insert empty run 181cb93a386Sopenharmony_ci fCurrScanline->fLastY = (SkRegion::RunType)(y - 1); 182cb93a386Sopenharmony_ci fCurrScanline->fXCount = 0; 183cb93a386Sopenharmony_ci fCurrScanline = fCurrScanline->nextScanline(); 184cb93a386Sopenharmony_ci } 185cb93a386Sopenharmony_ci // setup for the new curr line 186cb93a386Sopenharmony_ci fCurrScanline->fLastY = (SkRegion::RunType)(y); 187cb93a386Sopenharmony_ci fCurrXPtr = fCurrScanline->firstX(); 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci // check if we should extend the current run, or add a new one 191cb93a386Sopenharmony_ci if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) { 192cb93a386Sopenharmony_ci fCurrXPtr[-1] = (SkRegion::RunType)(x + width); 193cb93a386Sopenharmony_ci } else { 194cb93a386Sopenharmony_ci fCurrXPtr[0] = (SkRegion::RunType)(x); 195cb93a386Sopenharmony_ci fCurrXPtr[1] = (SkRegion::RunType)(x + width); 196cb93a386Sopenharmony_ci fCurrXPtr += 2; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci SkASSERT(fCurrXPtr - fStorage < fStorageCount); 199cb93a386Sopenharmony_ci} 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ciint SkRgnBuilder::computeRunCount() const { 202cb93a386Sopenharmony_ci if (fCurrScanline == nullptr) { 203cb93a386Sopenharmony_ci return 0; 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci const SkRegion::RunType* line = fStorage; 207cb93a386Sopenharmony_ci const SkRegion::RunType* stop = (const SkRegion::RunType*)fCurrScanline; 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci return 2 + (int)(stop - line); 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_civoid SkRgnBuilder::copyToRect(SkIRect* r) const { 213cb93a386Sopenharmony_ci SkASSERT(fCurrScanline != nullptr); 214cb93a386Sopenharmony_ci // A rect's scanline is [bottom intervals left right sentinel] == 5 215cb93a386Sopenharmony_ci SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 5); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci const Scanline* line = (const Scanline*)fStorage; 218cb93a386Sopenharmony_ci SkASSERT(line->fXCount == 2); 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci r->setLTRB(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1); 221cb93a386Sopenharmony_ci} 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_civoid SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const { 224cb93a386Sopenharmony_ci SkASSERT(fCurrScanline != nullptr); 225cb93a386Sopenharmony_ci SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci const Scanline* line = (const Scanline*)fStorage; 228cb93a386Sopenharmony_ci const Scanline* stop = fCurrScanline; 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci *runs++ = fTop; 231cb93a386Sopenharmony_ci do { 232cb93a386Sopenharmony_ci *runs++ = (SkRegion::RunType)(line->fLastY + 1); 233cb93a386Sopenharmony_ci int count = line->fXCount; 234cb93a386Sopenharmony_ci *runs++ = count >> 1; // intervalCount 235cb93a386Sopenharmony_ci if (count) { 236cb93a386Sopenharmony_ci memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType)); 237cb93a386Sopenharmony_ci runs += count; 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci *runs++ = SkRegion_kRunTypeSentinel; 240cb93a386Sopenharmony_ci line = line->nextScanline(); 241cb93a386Sopenharmony_ci } while (line < stop); 242cb93a386Sopenharmony_ci SkASSERT(line == stop); 243cb93a386Sopenharmony_ci *runs = SkRegion_kRunTypeSentinel; 244cb93a386Sopenharmony_ci} 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_cistatic unsigned verb_to_initial_last_index(unsigned verb) { 247cb93a386Sopenharmony_ci static const uint8_t gPathVerbToInitialLastIndex[] = { 248cb93a386Sopenharmony_ci 0, // kMove_Verb 249cb93a386Sopenharmony_ci 1, // kLine_Verb 250cb93a386Sopenharmony_ci 2, // kQuad_Verb 251cb93a386Sopenharmony_ci 2, // kConic_Verb 252cb93a386Sopenharmony_ci 3, // kCubic_Verb 253cb93a386Sopenharmony_ci 0, // kClose_Verb 254cb93a386Sopenharmony_ci 0 // kDone_Verb 255cb93a386Sopenharmony_ci }; 256cb93a386Sopenharmony_ci SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToInitialLastIndex)); 257cb93a386Sopenharmony_ci return gPathVerbToInitialLastIndex[verb]; 258cb93a386Sopenharmony_ci} 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_cistatic unsigned verb_to_max_edges(unsigned verb) { 261cb93a386Sopenharmony_ci static const uint8_t gPathVerbToMaxEdges[] = { 262cb93a386Sopenharmony_ci 0, // kMove_Verb 263cb93a386Sopenharmony_ci 1, // kLine_Verb 264cb93a386Sopenharmony_ci 2, // kQuad_VerbB 265cb93a386Sopenharmony_ci 2, // kConic_VerbB 266cb93a386Sopenharmony_ci 3, // kCubic_Verb 267cb93a386Sopenharmony_ci 0, // kClose_Verb 268cb93a386Sopenharmony_ci 0 // kDone_Verb 269cb93a386Sopenharmony_ci }; 270cb93a386Sopenharmony_ci SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToMaxEdges)); 271cb93a386Sopenharmony_ci return gPathVerbToMaxEdges[verb]; 272cb93a386Sopenharmony_ci} 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ci// If returns 0, ignore itop and ibot 275cb93a386Sopenharmony_cistatic int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) { 276cb93a386Sopenharmony_ci SkPath::Iter iter(path, true); 277cb93a386Sopenharmony_ci SkPoint pts[4]; 278cb93a386Sopenharmony_ci SkPath::Verb verb; 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci int maxEdges = 0; 281cb93a386Sopenharmony_ci SkScalar top = SkIntToScalar(SK_MaxS16); 282cb93a386Sopenharmony_ci SkScalar bot = SkIntToScalar(SK_MinS16); 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 285cb93a386Sopenharmony_ci maxEdges += verb_to_max_edges(verb); 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci int lastIndex = verb_to_initial_last_index(verb); 288cb93a386Sopenharmony_ci if (lastIndex > 0) { 289cb93a386Sopenharmony_ci for (int i = 1; i <= lastIndex; i++) { 290cb93a386Sopenharmony_ci if (top > pts[i].fY) { 291cb93a386Sopenharmony_ci top = pts[i].fY; 292cb93a386Sopenharmony_ci } else if (bot < pts[i].fY) { 293cb93a386Sopenharmony_ci bot = pts[i].fY; 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci } 296cb93a386Sopenharmony_ci } else if (SkPath::kMove_Verb == verb) { 297cb93a386Sopenharmony_ci if (top > pts[0].fY) { 298cb93a386Sopenharmony_ci top = pts[0].fY; 299cb93a386Sopenharmony_ci } else if (bot < pts[0].fY) { 300cb93a386Sopenharmony_ci bot = pts[0].fY; 301cb93a386Sopenharmony_ci } 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci if (0 == maxEdges) { 305cb93a386Sopenharmony_ci return 0; // we have only moves+closes 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci SkASSERT(top <= bot); 309cb93a386Sopenharmony_ci *itop = SkScalarRoundToInt(top); 310cb93a386Sopenharmony_ci *ibot = SkScalarRoundToInt(bot); 311cb93a386Sopenharmony_ci return maxEdges; 312cb93a386Sopenharmony_ci} 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_cistatic bool check_inverse_on_empty_return(SkRegion* dst, const SkPath& path, const SkRegion& clip) { 315cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 316cb93a386Sopenharmony_ci return dst->set(clip); 317cb93a386Sopenharmony_ci } else { 318cb93a386Sopenharmony_ci return dst->setEmpty(); 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci} 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_cibool SkRegion::setPath(const SkPath& path, const SkRegion& clip) { 323cb93a386Sopenharmony_ci SkDEBUGCODE(SkRegionPriv::Validate(*this)); 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_ci if (clip.isEmpty() || !path.isFinite() || path.isEmpty()) { 326cb93a386Sopenharmony_ci // This treats non-finite paths as empty as well, so this returns empty or 'clip' if 327cb93a386Sopenharmony_ci // it's inverse-filled. If clip is also empty, path's fill type doesn't really matter 328cb93a386Sopenharmony_ci // and this region ends up empty. 329cb93a386Sopenharmony_ci return check_inverse_on_empty_return(this, path, clip); 330cb93a386Sopenharmony_ci } 331cb93a386Sopenharmony_ci 332cb93a386Sopenharmony_ci // Our builder is very fragile, and can't be called with spans/rects out of Y->X order. 333cb93a386Sopenharmony_ci // To ensure this, we only "fill" clipped to a rect (the clip's bounds), and if the 334cb93a386Sopenharmony_ci // clip is more complex than that, we just post-intersect the result with the clip. 335cb93a386Sopenharmony_ci if (clip.isComplex()) { 336cb93a386Sopenharmony_ci if (!this->setPath(path, SkRegion(clip.getBounds()))) { 337cb93a386Sopenharmony_ci return false; 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci return this->op(clip, kIntersect_Op); 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci // compute worst-case rgn-size for the path 343cb93a386Sopenharmony_ci int pathTop, pathBot; 344cb93a386Sopenharmony_ci int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot); 345cb93a386Sopenharmony_ci if (0 == pathTransitions) { 346cb93a386Sopenharmony_ci return check_inverse_on_empty_return(this, path, clip); 347cb93a386Sopenharmony_ci } 348cb93a386Sopenharmony_ci 349cb93a386Sopenharmony_ci int clipTop, clipBot; 350cb93a386Sopenharmony_ci int clipTransitions = clip.count_runtype_values(&clipTop, &clipBot); 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci int top = std::max(pathTop, clipTop); 353cb93a386Sopenharmony_ci int bot = std::min(pathBot, clipBot); 354cb93a386Sopenharmony_ci if (top >= bot) { 355cb93a386Sopenharmony_ci return check_inverse_on_empty_return(this, path, clip); 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci SkRgnBuilder builder; 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci if (!builder.init(bot - top, 361cb93a386Sopenharmony_ci std::max(pathTransitions, clipTransitions), 362cb93a386Sopenharmony_ci path.isInverseFillType())) { 363cb93a386Sopenharmony_ci // can't allocate working space, so return false 364cb93a386Sopenharmony_ci return this->setEmpty(); 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci SkScan::FillPath(path, clip, &builder); 368cb93a386Sopenharmony_ci builder.done(); 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_ci int count = builder.computeRunCount(); 371cb93a386Sopenharmony_ci if (count == 0) { 372cb93a386Sopenharmony_ci return this->setEmpty(); 373cb93a386Sopenharmony_ci } else if (count == kRectRegionRuns) { 374cb93a386Sopenharmony_ci builder.copyToRect(&fBounds); 375cb93a386Sopenharmony_ci this->setRect(fBounds); 376cb93a386Sopenharmony_ci } else { 377cb93a386Sopenharmony_ci SkRegion tmp; 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci tmp.fRunHead = RunHead::Alloc(count); 380cb93a386Sopenharmony_ci builder.copyToRgn(tmp.fRunHead->writable_runs()); 381cb93a386Sopenharmony_ci tmp.fRunHead->computeRunBounds(&tmp.fBounds); 382cb93a386Sopenharmony_ci this->swap(tmp); 383cb93a386Sopenharmony_ci } 384cb93a386Sopenharmony_ci SkDEBUGCODE(SkRegionPriv::Validate(*this)); 385cb93a386Sopenharmony_ci return true; 386cb93a386Sopenharmony_ci} 387cb93a386Sopenharmony_ci 388cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////// 389cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////// 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_cistruct Edge { 392cb93a386Sopenharmony_ci enum { 393cb93a386Sopenharmony_ci kY0Link = 0x01, 394cb93a386Sopenharmony_ci kY1Link = 0x02, 395cb93a386Sopenharmony_ci 396cb93a386Sopenharmony_ci kCompleteLink = (kY0Link | kY1Link) 397cb93a386Sopenharmony_ci }; 398cb93a386Sopenharmony_ci 399cb93a386Sopenharmony_ci SkRegionPriv::RunType fX; 400cb93a386Sopenharmony_ci SkRegionPriv::RunType fY0, fY1; 401cb93a386Sopenharmony_ci uint8_t fFlags; 402cb93a386Sopenharmony_ci Edge* fNext; 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci void set(int x, int y0, int y1) { 405cb93a386Sopenharmony_ci SkASSERT(y0 != y1); 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci fX = (SkRegionPriv::RunType)(x); 408cb93a386Sopenharmony_ci fY0 = (SkRegionPriv::RunType)(y0); 409cb93a386Sopenharmony_ci fY1 = (SkRegionPriv::RunType)(y1); 410cb93a386Sopenharmony_ci fFlags = 0; 411cb93a386Sopenharmony_ci SkDEBUGCODE(fNext = nullptr;) 412cb93a386Sopenharmony_ci } 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci int top() const { 415cb93a386Sopenharmony_ci return std::min(fY0, fY1); 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci}; 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_cistatic void find_link(Edge* base, Edge* stop) { 420cb93a386Sopenharmony_ci SkASSERT(base < stop); 421cb93a386Sopenharmony_ci 422cb93a386Sopenharmony_ci if (base->fFlags == Edge::kCompleteLink) { 423cb93a386Sopenharmony_ci SkASSERT(base->fNext); 424cb93a386Sopenharmony_ci return; 425cb93a386Sopenharmony_ci } 426cb93a386Sopenharmony_ci 427cb93a386Sopenharmony_ci SkASSERT(base + 1 < stop); 428cb93a386Sopenharmony_ci 429cb93a386Sopenharmony_ci int y0 = base->fY0; 430cb93a386Sopenharmony_ci int y1 = base->fY1; 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci Edge* e = base; 433cb93a386Sopenharmony_ci if ((base->fFlags & Edge::kY0Link) == 0) { 434cb93a386Sopenharmony_ci for (;;) { 435cb93a386Sopenharmony_ci e += 1; 436cb93a386Sopenharmony_ci if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) { 437cb93a386Sopenharmony_ci SkASSERT(nullptr == e->fNext); 438cb93a386Sopenharmony_ci e->fNext = base; 439cb93a386Sopenharmony_ci e->fFlags = SkToU8(e->fFlags | Edge::kY1Link); 440cb93a386Sopenharmony_ci break; 441cb93a386Sopenharmony_ci } 442cb93a386Sopenharmony_ci } 443cb93a386Sopenharmony_ci } 444cb93a386Sopenharmony_ci 445cb93a386Sopenharmony_ci e = base; 446cb93a386Sopenharmony_ci if ((base->fFlags & Edge::kY1Link) == 0) { 447cb93a386Sopenharmony_ci for (;;) { 448cb93a386Sopenharmony_ci e += 1; 449cb93a386Sopenharmony_ci if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) { 450cb93a386Sopenharmony_ci SkASSERT(nullptr == base->fNext); 451cb93a386Sopenharmony_ci base->fNext = e; 452cb93a386Sopenharmony_ci e->fFlags = SkToU8(e->fFlags | Edge::kY0Link); 453cb93a386Sopenharmony_ci break; 454cb93a386Sopenharmony_ci } 455cb93a386Sopenharmony_ci } 456cb93a386Sopenharmony_ci } 457cb93a386Sopenharmony_ci 458cb93a386Sopenharmony_ci base->fFlags = Edge::kCompleteLink; 459cb93a386Sopenharmony_ci} 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_cistatic int extract_path(Edge* edge, Edge* stop, SkPath* path) { 462cb93a386Sopenharmony_ci while (0 == edge->fFlags) { 463cb93a386Sopenharmony_ci edge++; // skip over "used" edges 464cb93a386Sopenharmony_ci } 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_ci SkASSERT(edge < stop); 467cb93a386Sopenharmony_ci 468cb93a386Sopenharmony_ci Edge* base = edge; 469cb93a386Sopenharmony_ci Edge* prev = edge; 470cb93a386Sopenharmony_ci edge = edge->fNext; 471cb93a386Sopenharmony_ci SkASSERT(edge != base); 472cb93a386Sopenharmony_ci 473cb93a386Sopenharmony_ci int count = 1; 474cb93a386Sopenharmony_ci path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0)); 475cb93a386Sopenharmony_ci prev->fFlags = 0; 476cb93a386Sopenharmony_ci do { 477cb93a386Sopenharmony_ci if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear 478cb93a386Sopenharmony_ci path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V 479cb93a386Sopenharmony_ci path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0)); // H 480cb93a386Sopenharmony_ci } 481cb93a386Sopenharmony_ci prev = edge; 482cb93a386Sopenharmony_ci edge = edge->fNext; 483cb93a386Sopenharmony_ci count += 1; 484cb93a386Sopenharmony_ci prev->fFlags = 0; 485cb93a386Sopenharmony_ci } while (edge != base); 486cb93a386Sopenharmony_ci path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V 487cb93a386Sopenharmony_ci path->close(); 488cb93a386Sopenharmony_ci return count; 489cb93a386Sopenharmony_ci} 490cb93a386Sopenharmony_ci 491cb93a386Sopenharmony_cistruct EdgeLT { 492cb93a386Sopenharmony_ci bool operator()(const Edge& a, const Edge& b) const { 493cb93a386Sopenharmony_ci return (a.fX == b.fX) ? a.top() < b.top() : a.fX < b.fX; 494cb93a386Sopenharmony_ci } 495cb93a386Sopenharmony_ci}; 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_cibool SkRegion::getBoundaryPath(SkPath* path) const { 498cb93a386Sopenharmony_ci // path could safely be nullptr if we're empty, but the caller shouldn't 499cb93a386Sopenharmony_ci // *know* that 500cb93a386Sopenharmony_ci SkASSERT(path); 501cb93a386Sopenharmony_ci 502cb93a386Sopenharmony_ci if (this->isEmpty()) { 503cb93a386Sopenharmony_ci return false; 504cb93a386Sopenharmony_ci } 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci const SkIRect& bounds = this->getBounds(); 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci if (this->isRect()) { 509cb93a386Sopenharmony_ci SkRect r; 510cb93a386Sopenharmony_ci r.set(bounds); // this converts the ints to scalars 511cb93a386Sopenharmony_ci path->addRect(r); 512cb93a386Sopenharmony_ci return true; 513cb93a386Sopenharmony_ci } 514cb93a386Sopenharmony_ci 515cb93a386Sopenharmony_ci SkRegion::Iterator iter(*this); 516cb93a386Sopenharmony_ci SkTDArray<Edge> edges; 517cb93a386Sopenharmony_ci 518cb93a386Sopenharmony_ci for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) { 519cb93a386Sopenharmony_ci Edge* edge = edges.append(2); 520cb93a386Sopenharmony_ci edge[0].set(r.fLeft, r.fBottom, r.fTop); 521cb93a386Sopenharmony_ci edge[1].set(r.fRight, r.fTop, r.fBottom); 522cb93a386Sopenharmony_ci } 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ci int count = edges.count(); 525cb93a386Sopenharmony_ci Edge* start = edges.begin(); 526cb93a386Sopenharmony_ci Edge* stop = start + count; 527cb93a386Sopenharmony_ci SkTQSort<Edge>(start, stop, EdgeLT()); 528cb93a386Sopenharmony_ci 529cb93a386Sopenharmony_ci Edge* e; 530cb93a386Sopenharmony_ci for (e = start; e != stop; e++) { 531cb93a386Sopenharmony_ci find_link(e, stop); 532cb93a386Sopenharmony_ci } 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_ci#ifdef SK_DEBUG 535cb93a386Sopenharmony_ci for (e = start; e != stop; e++) { 536cb93a386Sopenharmony_ci SkASSERT(e->fNext != nullptr); 537cb93a386Sopenharmony_ci SkASSERT(e->fFlags == Edge::kCompleteLink); 538cb93a386Sopenharmony_ci } 539cb93a386Sopenharmony_ci#endif 540cb93a386Sopenharmony_ci 541cb93a386Sopenharmony_ci path->incReserve(count << 1); 542cb93a386Sopenharmony_ci do { 543cb93a386Sopenharmony_ci SkASSERT(count > 1); 544cb93a386Sopenharmony_ci count -= extract_path(start, stop, path); 545cb93a386Sopenharmony_ci } while (count > 0); 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci return true; 548cb93a386Sopenharmony_ci} 549