SkRegion_path.cpp revision 96fcdcc219d2a0d3579719b84b28bede76efba64
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegionPriv.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScan.h"
1160e0fee6d4acff638ccc9670c4055aced529a7a0bungeman#include "SkTSort.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTDArray.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15b8f07988494a62fbe8fba70129b1bb9366e9f6eereed// The rgnbuilder caller *seems* to pass short counts, possible often seens early failure, so
16b8f07988494a62fbe8fba70129b1bb9366e9f6eereed// we may not want to promote this to a "std" routine just yet.
17b8f07988494a62fbe8fba70129b1bb9366e9f6eereedstatic bool sk_memeq32(const int32_t* SK_RESTRICT a, const int32_t* SK_RESTRICT b, int count) {
18b8f07988494a62fbe8fba70129b1bb9366e9f6eereed    for (int i = 0; i < count; ++i) {
19b8f07988494a62fbe8fba70129b1bb9366e9f6eereed        if (a[i] != b[i]) {
20b8f07988494a62fbe8fba70129b1bb9366e9f6eereed            return false;
21b8f07988494a62fbe8fba70129b1bb9366e9f6eereed        }
22b8f07988494a62fbe8fba70129b1bb9366e9f6eereed    }
23b8f07988494a62fbe8fba70129b1bb9366e9f6eereed    return true;
24b8f07988494a62fbe8fba70129b1bb9366e9f6eereed}
25b8f07988494a62fbe8fba70129b1bb9366e9f6eereed
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkRgnBuilder : public SkBlitter {
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
2873be1fc2b02757e3d98621d7cf735591aa6dffdbcommit-bot@chromium.org    SkRgnBuilder();
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual ~SkRgnBuilder();
30fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // returns true if it could allocate the working storage needed
32b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com    bool init(int maxHeight, int maxTransitions, bool pathIsInverse);
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void done() {
3596fcdcc219d2a0d3579719b84b28bede76efba64halcanary        if (fCurrScanline != nullptr) {
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!this->collapsWithPrev()) { // flush the last line
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline = fCurrScanline->nextScanline();
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int     computeRunCount() const;
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void    copyToRect(SkIRect*) const;
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void    copyToRgn(SkRegion::RunType runs[]) const;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void blitH(int x, int y, int width) override;
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void dump() const {
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const Scanline* line = (Scanline*)fStorage;
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while (line < fCurrScanline) {
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (int i = 0; i < line->fXCount; i++) {
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkDebugf(" %d", line->firstX()[i]);
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDebugf("\n");
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            line = line->nextScanline();
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
659c36a76102453db964cb6e51078a3d74d4126b2creed@google.com    /*
669c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  Scanline mimics a row in the region, nearly. A row in a region is:
679c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *      [Bottom IntervalCount [L R]... Sentinel]
689c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  while a Scanline is
699c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *      [LastY XCount [L R]... uninitialized]
709c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  The two are the same length (which is good), but we have to transmute
719c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  the scanline a little when we convert it to a region-row.
729c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *
739c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  Potentially we could recode this to exactly match the row format, in
749c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  which case copyToRgn() could be a single memcpy. Not sure that is worth
759c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  the effort.
769c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     */
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    struct Scanline {
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRegion::RunType fLastY;
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRegion::RunType fXCount;
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); }
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Scanline* nextScanline() const {
839c36a76102453db964cb6e51078a3d74d4126b2creed@google.com            // add final +1 for the x-sentinel
849c36a76102453db964cb6e51078a3d74d4126b2creed@google.com            return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount + 1);
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType*  fStorage;
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Scanline*           fCurrScanline;
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Scanline*           fPrevScanline;
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  points at next avialable x[] in fCurrScanline
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType*  fCurrXPtr;
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType   fTop;           // first Y value
93fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int fStorageCount;
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool collapsWithPrev() {
9796fcdcc219d2a0d3579719b84b28bede76efba64halcanary        if (fPrevScanline != nullptr &&
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPrevScanline->fXCount == fCurrScanline->fXCount &&
100b8f07988494a62fbe8fba70129b1bb9366e9f6eereed            sk_memeq32(fPrevScanline->firstX(), fCurrScanline->firstX(), fCurrScanline->fXCount))
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // update the height of fPrevScanline
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPrevScanline->fLastY = fCurrScanline->fLastY;
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return true;
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11073be1fc2b02757e3d98621d7cf735591aa6dffdbcommit-bot@chromium.orgSkRgnBuilder::SkRgnBuilder()
11196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    : fStorage(nullptr) {
11273be1fc2b02757e3d98621d7cf735591aa6dffdbcommit-bot@chromium.org}
11373be1fc2b02757e3d98621d7cf735591aa6dffdbcommit-bot@chromium.org
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkRgnBuilder::~SkRgnBuilder() {
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sk_free(fStorage);
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
118b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.combool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) {
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((maxHeight | maxTransitions) < 0) {
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
123b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com    if (pathIsInverse) {
124b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com        // allow for additional X transitions to "invert" each scanline
125b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com        // [ L' ... normal transitions ... R' ]
126b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com        //
127b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com        maxTransitions += 2;
128b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com    }
129b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // compute the count with +1 and +3 slop for the working buffer
13157212f9469c8056bab3c85243dbb904e386eab95reed@google.com    int64_t count = sk_64_mul(maxHeight + 1, 3 + maxTransitions);
132b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com
133b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com    if (pathIsInverse) {
134b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com        // allow for two "empty" rows for the top and bottom
135b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com        //      [ Y, 1, L, R, S] == 5 (*2 for top and bottom)
13657212f9469c8056bab3c85243dbb904e386eab95reed@google.com        count += 10;
137b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com    }
138b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com
13957212f9469c8056bab3c85243dbb904e386eab95reed@google.com    if (count < 0 || !sk_64_isS32(count)) {
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14257212f9469c8056bab3c85243dbb904e386eab95reed@google.com    fStorageCount = sk_64_asS32(count);
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14457212f9469c8056bab3c85243dbb904e386eab95reed@google.com    int64_t size = sk_64_mul(fStorageCount, sizeof(SkRegion::RunType));
14557212f9469c8056bab3c85243dbb904e386eab95reed@google.com    if (size < 0 || !sk_64_isS32(size)) {
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
148472629190eb3c8220742c584e19f3a07b2d09c8cskia.committer@gmail.com
14957212f9469c8056bab3c85243dbb904e386eab95reed@google.com    fStorage = (SkRegion::RunType*)sk_malloc_flags(sk_64_asS32(size), 0);
15096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (nullptr == fStorage) {
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
15496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    fCurrScanline = nullptr;    // signal empty collection
15596fcdcc219d2a0d3579719b84b28bede76efba64halcanary    fPrevScanline = nullptr;    // signal first scanline
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkRgnBuilder::blitH(int x, int y, int width) {
16096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (fCurrScanline == nullptr) {  // first time
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fTop = (SkRegion::RunType)(y);
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrScanline = (Scanline*)fStorage;
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrScanline->fLastY = (SkRegion::RunType)(y);
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr = fCurrScanline->firstX();
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(y >= fCurrScanline->fLastY);
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (y > fCurrScanline->fLastY) {
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // if we get here, we're done with fCurrScanline
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int prevLastY = fCurrScanline->fLastY;
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!this->collapsWithPrev()) {
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fPrevScanline = fCurrScanline;
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline = fCurrScanline->nextScanline();
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (y - 1 > prevLastY) {  // insert empty run
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline->fLastY = (SkRegion::RunType)(y - 1);
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline->fXCount = 0;
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline = fCurrScanline->nextScanline();
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // setup for the new curr line
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrScanline->fLastY = (SkRegion::RunType)(y);
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrXPtr = fCurrScanline->firstX();
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  check if we should extend the current run, or add a new one
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) {
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr[-1] = (SkRegion::RunType)(x + width);
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr[0] = (SkRegion::RunType)(x);
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr[1] = (SkRegion::RunType)(x + width);
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr += 2;
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fCurrXPtr - fStorage < fStorageCount);
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkRgnBuilder::computeRunCount() const {
20096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (fCurrScanline == nullptr) {
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkRegion::RunType*  line = fStorage;
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkRegion::RunType*  stop = (const SkRegion::RunType*)fCurrScanline;
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return 2 + (int)(stop - line);
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkRgnBuilder::copyToRect(SkIRect* r) const {
21196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(fCurrScanline != nullptr);
2129c36a76102453db964cb6e51078a3d74d4126b2creed@google.com    // A rect's scanline is [bottom intervals left right sentinel] == 5
2139c36a76102453db964cb6e51078a3d74d4126b2creed@google.com    SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 5);
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Scanline* line = (const Scanline*)fStorage;
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(line->fXCount == 2);
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r->set(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
22296fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkASSERT(fCurrScanline != nullptr);
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4);
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Scanline* line = (const Scanline*)fStorage;
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Scanline* stop = fCurrScanline;
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *runs++ = fTop;
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *runs++ = (SkRegion::RunType)(line->fLastY + 1);
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int count = line->fXCount;
2329c36a76102453db964cb6e51078a3d74d4126b2creed@google.com        *runs++ = count >> 1;   // intervalCount
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (count) {
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            runs += count;
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *runs++ = SkRegion::kRunTypeSentinel;
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        line = line->nextScanline();
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (line < stop);
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(line == stop);
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *runs = SkRegion::kRunTypeSentinel;
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
244277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.comstatic unsigned verb_to_initial_last_index(unsigned verb) {
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static const uint8_t gPathVerbToInitialLastIndex[] = {
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kMove_Verb
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        1,  //  kLine_Verb
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        2,  //  kQuad_Verb
249277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com        2,  //  kConic_Verb
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        3,  //  kCubic_Verb
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kClose_Verb
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0   //  kDone_Verb
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
254277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com    SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToInitialLastIndex));
255277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com    return gPathVerbToInitialLastIndex[verb];
256277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com}
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
258277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.comstatic unsigned verb_to_max_edges(unsigned verb) {
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static const uint8_t gPathVerbToMaxEdges[] = {
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kMove_Verb
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        1,  //  kLine_Verb
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        2,  //  kQuad_VerbB
263277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com        2,  //  kConic_VerbB
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        3,  //  kCubic_Verb
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kClose_Verb
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0   //  kDone_Verb
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
268277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com    SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToMaxEdges));
269277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com    return gPathVerbToMaxEdges[verb];
270277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com}
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
272c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed// If returns 0, ignore itop and ibot
273277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.comstatic int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Iter    iter(path, true);
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint         pts[4];
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Verb    verb;
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int maxEdges = 0;
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar    top = SkIntToScalar(SK_MaxS16);
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar    bot = SkIntToScalar(SK_MinS16);
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2824a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.com    while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
283277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com        maxEdges += verb_to_max_edges(verb);
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
285277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com        int lastIndex = verb_to_initial_last_index(verb);
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (lastIndex > 0) {
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (int i = 1; i <= lastIndex; i++) {
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (top > pts[i].fY) {
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    top = pts[i].fY;
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                } else if (bot < pts[i].fY) {
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    bot = pts[i].fY;
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else if (SkPath::kMove_Verb == verb) {
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (top > pts[0].fY) {
2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                top = pts[0].fY;
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else if (bot < pts[0].fY) {
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bot = pts[0].fY;
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
302c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    if (0 == maxEdges) {
303c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed        return 0;   // we have only moves+closes
304c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    }
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
306c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    SkASSERT(top <= bot);
307e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com    *itop = SkScalarRoundToInt(top);
308e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com    *ibot = SkScalarRoundToInt(bot);
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return maxEdges;
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
312c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freedstatic bool check_inverse_on_empty_return(SkRegion* dst, const SkPath& path, const SkRegion& clip) {
313c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    if (path.isInverseFillType()) {
314c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed        return dst->set(clip);
315c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    } else {
316c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed        return dst->setEmpty();
317c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    }
318c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed}
319c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(this->validate();)
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clip.isEmpty()) {
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->setEmpty();
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (path.isEmpty()) {
328c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed        return check_inverse_on_empty_return(this, path, clip);
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  compute worst-case rgn-size for the path
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int pathTop, pathBot;
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
334c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    if (0 == pathTransitions) {
335c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed        return check_inverse_on_empty_return(this, path, clip);
336c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    }
337fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
338c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    int clipTop, clipBot;
339c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    int clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int top = SkMax32(pathTop, clipTop);
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int bot = SkMin32(pathBot, clipBot);
343c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    if (top >= bot) {
344c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed        return check_inverse_on_empty_return(this, path, clip);
345c1b11f1db69bea8d64ebf656ae92ea9ec6dbb40freed    }
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRgnBuilder builder;
348fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
349b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com    if (!builder.init(bot - top,
350b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com                      SkMax32(pathTransitions, clipTransitions),
351b58ba8912ab1a372eb60ab111f477b915eb3da4dreed@google.com                      path.isInverseFillType())) {
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // can't allocate working space, so return false
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->setEmpty();
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScan::FillPath(path, clip, &builder);
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    builder.done();
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = builder.computeRunCount();
3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count == 0) {
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->setEmpty();
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else if (count == kRectRegionRuns) {
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        builder.copyToRect(&fBounds);
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->setRect(fBounds);
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
3669c36a76102453db964cb6e51078a3d74d4126b2creed@google.com        SkRegion tmp;
3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmp.fRunHead = RunHead::Alloc(count);
3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        builder.copyToRgn(tmp.fRunHead->writable_runs());
3709c36a76102453db964cb6e51078a3d74d4126b2creed@google.com        tmp.fRunHead->computeRunBounds(&tmp.fBounds);
3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->swap(tmp);
3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(this->validate();)
3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////////////////////////
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////////////////////////
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct Edge {
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum {
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kY0Link = 0x01,
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kY1Link = 0x02,
384fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kCompleteLink = (kY0Link | kY1Link)
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType fX;
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType fY0, fY1;
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t fFlags;
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge*   fNext;
392fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void set(int x, int y0, int y1) {
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(y0 != y1);
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fX = (SkRegion::RunType)(x);
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fY0 = (SkRegion::RunType)(y0);
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fY1 = (SkRegion::RunType)(y1);
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fFlags = 0;
40096fcdcc219d2a0d3579719b84b28bede76efba64halcanary        SkDEBUGCODE(fNext = nullptr;)
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
402fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int top() const {
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkFastMin32(fY0, fY1);
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void find_link(Edge* base, Edge* stop) {
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(base < stop);
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (base->fFlags == Edge::kCompleteLink) {
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(base->fNext);
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(base + 1 < stop);
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int y0 = base->fY0;
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int y1 = base->fY1;
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* e = base;
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((base->fFlags & Edge::kY0Link) == 0) {
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (;;) {
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            e += 1;
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) {
42696fcdcc219d2a0d3579719b84b28bede76efba64halcanary                SkASSERT(nullptr == e->fNext);
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                e->fNext = base;
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                e->fFlags = SkToU8(e->fFlags | Edge::kY1Link);
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
433fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    e = base;
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((base->fFlags & Edge::kY1Link) == 0) {
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (;;) {
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            e += 1;
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) {
43996fcdcc219d2a0d3579719b84b28bede76efba64halcanary                SkASSERT(nullptr == base->fNext);
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                base->fNext = e;
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                e->fFlags = SkToU8(e->fFlags | Edge::kY0Link);
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
446fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    base->fFlags = Edge::kCompleteLink;
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int extract_path(Edge* edge, Edge* stop, SkPath* path) {
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (0 == edge->fFlags) {
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge++; // skip over "used" edges
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(edge < stop);
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* base = edge;
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* prev = edge;
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    edge = edge->fNext;
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(edge != base);
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = 1;
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0));
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    prev->fFlags = 0;
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0));    // H
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev = edge;
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge = edge->fNext;
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count += 1;
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev->fFlags = 0;
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (edge != base);
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->close();
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return count;
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
48060e0fee6d4acff638ccc9670c4055aced529a7a0bungemanstruct EdgeLT {
48160e0fee6d4acff638ccc9670c4055aced529a7a0bungeman    bool operator()(const Edge& a, const Edge& b) const {
48260e0fee6d4acff638ccc9670c4055aced529a7a0bungeman        return (a.fX == b.fX) ? a.top() < b.top() : a.fX < b.fX;
48360e0fee6d4acff638ccc9670c4055aced529a7a0bungeman    }
48460e0fee6d4acff638ccc9670c4055aced529a7a0bungeman};
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkRegion::getBoundaryPath(SkPath* path) const {
48796fcdcc219d2a0d3579719b84b28bede76efba64halcanary    // path could safely be nullptr if we're empty, but the caller shouldn't
488d5d9dadcdd5fdbc8a17f3f398e3199b9d12c8d70tomhudson@google.com    // *know* that
489d5d9dadcdd5fdbc8a17f3f398e3199b9d12c8d70tomhudson@google.com    SkASSERT(path);
490d5d9dadcdd5fdbc8a17f3f398e3199b9d12c8d70tomhudson@google.com
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->isEmpty()) {
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkIRect& bounds = this->getBounds();
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->isRect()) {
498fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        SkRect  r;
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        r.set(bounds);      // this converts the ints to scalars
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path->addRect(r);
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Iterator  iter(*this);
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkTDArray<Edge>     edges;
506fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) {
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Edge* edge = edges.append(2);
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge[0].set(r.fLeft, r.fBottom, r.fTop);
5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge[1].set(r.fRight, r.fTop, r.fBottom);
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
512fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = edges.count();
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* start = edges.begin();
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* stop = start + count;
51660e0fee6d4acff638ccc9670c4055aced529a7a0bungeman    SkTQSort<Edge>(start, stop - 1, EdgeLT());
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
51860e0fee6d4acff638ccc9670c4055aced529a7a0bungeman    Edge* e;
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (e = start; e != stop; e++) {
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        find_link(e, stop);
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (e = start; e != stop; e++) {
52596fcdcc219d2a0d3579719b84b28bede76efba64halcanary        SkASSERT(e->fNext != nullptr);
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(e->fFlags == Edge::kCompleteLink);
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->incReserve(count << 1);
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(count > 1);
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count -= extract_path(start, stop, path);
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (count > 0);
5358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
538