SkRegion_path.cpp revision fbfcd5602128ec010c82cb733c9cdc0a3254f9f3
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegionPriv.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScan.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTDArray.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkRgnBuilder : public SkBlitter {
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual ~SkRgnBuilder();
19fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // returns true if it could allocate the working storage needed
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool init(int maxHeight, int maxTransitions);
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void done() {
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fCurrScanline != NULL) {
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!this->collapsWithPrev()) { // flush the last line
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline = fCurrScanline->nextScanline();
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int     computeRunCount() const;
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void    copyToRect(SkIRect*) const;
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void    copyToRgn(SkRegion::RunType runs[]) const;
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitH(int x, int y, int width);
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void dump() const {
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const Scanline* line = (Scanline*)fStorage;
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while (line < fCurrScanline) {
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (int i = 0; i < line->fXCount; i++) {
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkDebugf(" %d", line->firstX()[i]);
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDebugf("\n");
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            line = line->nextScanline();
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
549c36a76102453db964cb6e51078a3d74d4126b2creed@google.com    /*
559c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  Scanline mimics a row in the region, nearly. A row in a region is:
569c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *      [Bottom IntervalCount [L R]... Sentinel]
579c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  while a Scanline is
589c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *      [LastY XCount [L R]... uninitialized]
599c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  The two are the same length (which is good), but we have to transmute
609c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  the scanline a little when we convert it to a region-row.
619c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *
629c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  Potentially we could recode this to exactly match the row format, in
639c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  which case copyToRgn() could be a single memcpy. Not sure that is worth
649c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     *  the effort.
659c36a76102453db964cb6e51078a3d74d4126b2creed@google.com     */
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    struct Scanline {
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRegion::RunType fLastY;
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRegion::RunType fXCount;
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); }
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Scanline* nextScanline() const {
729c36a76102453db964cb6e51078a3d74d4126b2creed@google.com            // add final +1 for the x-sentinel
739c36a76102453db964cb6e51078a3d74d4126b2creed@google.com            return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount + 1);
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType*  fStorage;
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Scanline*           fCurrScanline;
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Scanline*           fPrevScanline;
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  points at next avialable x[] in fCurrScanline
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType*  fCurrXPtr;
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType   fTop;           // first Y value
82fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int fStorageCount;
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool collapsWithPrev() {
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fPrevScanline != NULL &&
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPrevScanline->fXCount == fCurrScanline->fXCount &&
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            !memcmp(fPrevScanline->firstX(),
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    fCurrScanline->firstX(),
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    fCurrScanline->fXCount * sizeof(SkRegion::RunType)))
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        {
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // update the height of fPrevScanline
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fPrevScanline->fLastY = fCurrScanline->fLastY;
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return true;
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkRgnBuilder::~SkRgnBuilder() {
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sk_free(fStorage);
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkRgnBuilder::init(int maxHeight, int maxTransitions) {
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((maxHeight | maxTransitions) < 0) {
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Sk64 count, size;
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // compute the count with +1 and +3 slop for the working buffer
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    count.setMul(maxHeight + 1, 3 + maxTransitions);
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!count.is32() || count.isNeg()) {
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fStorageCount = count.get32();
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size.setMul(fStorageCount, sizeof(SkRegion::RunType));
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!size.is32() || size.isNeg()) {
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fStorage = (SkRegion::RunType*)sk_malloc_flags(size.get32(), 0);
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (NULL == fStorage) {
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fCurrScanline = NULL;    // signal empty collection
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fPrevScanline = NULL;    // signal first scanline
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkRgnBuilder::blitH(int x, int y, int width) {
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fCurrScanline == NULL) {  // first time
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fTop = (SkRegion::RunType)(y);
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrScanline = (Scanline*)fStorage;
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrScanline->fLastY = (SkRegion::RunType)(y);
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr = fCurrScanline->firstX();
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(y >= fCurrScanline->fLastY);
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (y > fCurrScanline->fLastY) {
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // if we get here, we're done with fCurrScanline
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int prevLastY = fCurrScanline->fLastY;
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!this->collapsWithPrev()) {
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fPrevScanline = fCurrScanline;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline = fCurrScanline->nextScanline();
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (y - 1 > prevLastY) {  // insert empty run
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline->fLastY = (SkRegion::RunType)(y - 1);
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline->fXCount = 0;
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fCurrScanline = fCurrScanline->nextScanline();
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // setup for the new curr line
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrScanline->fLastY = (SkRegion::RunType)(y);
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fCurrXPtr = fCurrScanline->firstX();
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  check if we should extend the current run, or add a new one
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) {
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr[-1] = (SkRegion::RunType)(x + width);
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr[0] = (SkRegion::RunType)(x);
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr[1] = (SkRegion::RunType)(x + width);
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrXPtr += 2;
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fCurrXPtr - fStorage < fStorageCount);
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkRgnBuilder::computeRunCount() const {
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fCurrScanline == NULL) {
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkRegion::RunType*  line = fStorage;
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkRegion::RunType*  stop = (const SkRegion::RunType*)fCurrScanline;
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return 2 + (int)(stop - line);
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkRgnBuilder::copyToRect(SkIRect* r) const {
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fCurrScanline != NULL);
1879c36a76102453db964cb6e51078a3d74d4126b2creed@google.com    // A rect's scanline is [bottom intervals left right sentinel] == 5
1889c36a76102453db964cb6e51078a3d74d4126b2creed@google.com    SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 5);
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Scanline* line = (const Scanline*)fStorage;
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(line->fXCount == 2);
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r->set(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fCurrScanline != NULL);
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4);
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Scanline* line = (const Scanline*)fStorage;
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const Scanline* stop = fCurrScanline;
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *runs++ = fTop;
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *runs++ = (SkRegion::RunType)(line->fLastY + 1);
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int count = line->fXCount;
2079c36a76102453db964cb6e51078a3d74d4126b2creed@google.com        *runs++ = count >> 1;   // intervalCount
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (count) {
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            runs += count;
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *runs++ = SkRegion::kRunTypeSentinel;
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        line = line->nextScanline();
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (line < stop);
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(line == stop);
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *runs = SkRegion::kRunTypeSentinel;
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static const uint8_t gPathVerbToInitialLastIndex[] = {
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kMove_Verb
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        1,  //  kLine_Verb
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        2,  //  kQuad_Verb
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        3,  //  kCubic_Verb
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kClose_Verb
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0   //  kDone_Verb
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    static const uint8_t gPathVerbToMaxEdges[] = {
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kMove_Verb
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        1,  //  kLine_Verb
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        2,  //  kQuad_VerbB
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        3,  //  kCubic_Verb
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0,  //  kClose_Verb
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        0   //  kDone_Verb
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Iter    iter(path, true);
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPoint         pts[4];
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath::Verb    verb;
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int maxEdges = 0;
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar    top = SkIntToScalar(SK_MaxS16);
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar    bot = SkIntToScalar(SK_MinS16);
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2464a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.com    while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        maxEdges += gPathVerbToMaxEdges[verb];
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int lastIndex = gPathVerbToInitialLastIndex[verb];
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (lastIndex > 0) {
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (int i = 1; i <= lastIndex; i++) {
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (top > pts[i].fY) {
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    top = pts[i].fY;
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                } else if (bot < pts[i].fY) {
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    bot = pts[i].fY;
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else if (SkPath::kMove_Verb == verb) {
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (top > pts[0].fY) {
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                top = pts[0].fY;
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else if (bot < pts[0].fY) {
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                bot = pts[0].fY;
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(top <= bot);
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *itop = SkScalarRound(top);
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *ibot = SkScalarRound(bot);
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return maxEdges;
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(this->validate();)
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clip.isEmpty()) {
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->setEmpty();
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (path.isEmpty()) {
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (path.isInverseFillType()) {
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return this->set(clip);
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return this->setEmpty();
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  compute worst-case rgn-size for the path
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int pathTop, pathBot;
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int clipTop, clipBot;
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int clipTransitions;
293fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int top = SkMax32(pathTop, clipTop);
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int bot = SkMin32(pathBot, clipBot);
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (top >= bot)
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->setEmpty();
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRgnBuilder builder;
303fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!builder.init(bot - top, SkMax32(pathTransitions, clipTransitions))) {
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // can't allocate working space, so return false
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->setEmpty();
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScan::FillPath(path, clip, &builder);
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    builder.done();
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = builder.computeRunCount();
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count == 0) {
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return this->setEmpty();
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else if (count == kRectRegionRuns) {
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        builder.copyToRect(&fBounds);
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->setRect(fBounds);
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
3199c36a76102453db964cb6e51078a3d74d4126b2creed@google.com        SkRegion tmp;
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        tmp.fRunHead = RunHead::Alloc(count);
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        builder.copyToRgn(tmp.fRunHead->writable_runs());
3239c36a76102453db964cb6e51078a3d74d4126b2creed@google.com        tmp.fRunHead->computeRunBounds(&tmp.fBounds);
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->swap(tmp);
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(this->validate();)
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////////////////////////
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////////////////////////
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct Edge {
3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum {
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kY0Link = 0x01,
3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kY1Link = 0x02,
337fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kCompleteLink = (kY0Link | kY1Link)
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType fX;
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::RunType fY0, fY1;
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t fFlags;
3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge*   fNext;
345fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void set(int x, int y0, int y1) {
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(y0 != y1);
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fX = (SkRegion::RunType)(x);
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fY0 = (SkRegion::RunType)(y0);
3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fY1 = (SkRegion::RunType)(y1);
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fFlags = 0;
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDEBUGCODE(fNext = NULL;)
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
355fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int top() const {
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return SkFastMin32(fY0, fY1);
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void find_link(Edge* base, Edge* stop) {
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(base < stop);
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (base->fFlags == Edge::kCompleteLink) {
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(base->fNext);
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(base + 1 < stop);
3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int y0 = base->fY0;
3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int y1 = base->fY1;
3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* e = base;
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((base->fFlags & Edge::kY0Link) == 0) {
3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (;;) {
3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            e += 1;
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) {
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(NULL == e->fNext);
3808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                e->fNext = base;
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                e->fFlags = SkToU8(e->fFlags | Edge::kY1Link);
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
386fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    e = base;
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((base->fFlags & Edge::kY1Link) == 0) {
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (;;) {
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            e += 1;
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) {
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(NULL == base->fNext);
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                base->fNext = e;
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                e->fFlags = SkToU8(e->fFlags | Edge::kY0Link);
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
399fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    base->fFlags = Edge::kCompleteLink;
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int extract_path(Edge* edge, Edge* stop, SkPath* path) {
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (0 == edge->fFlags) {
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge++; // skip over "used" edges
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(edge < stop);
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* base = edge;
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* prev = edge;
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    edge = edge->fNext;
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(edge != base);
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = 1;
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0));
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    prev->fFlags = 0;
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0));    // H
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev = edge;
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge = edge->fNext;
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count += 1;
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        prev->fFlags = 0;
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (edge != base);
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->close();
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return count;
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTSearch.h"
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int EdgeProc(const Edge* a, const Edge* b) {
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (a->fX == b->fX) ? a->top() - b->top() : a->fX - b->fX;
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkRegion::getBoundaryPath(SkPath* path) const {
440d5d9dadcdd5fdbc8a17f3f398e3199b9d12c8d70tomhudson@google.com    // path could safely be NULL if we're empty, but the caller shouldn't
441d5d9dadcdd5fdbc8a17f3f398e3199b9d12c8d70tomhudson@google.com    // *know* that
442d5d9dadcdd5fdbc8a17f3f398e3199b9d12c8d70tomhudson@google.com    SkASSERT(path);
443d5d9dadcdd5fdbc8a17f3f398e3199b9d12c8d70tomhudson@google.com
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->isEmpty()) {
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkIRect& bounds = this->getBounds();
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (this->isRect()) {
451fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        SkRect  r;
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        r.set(bounds);      // this converts the ints to scalars
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path->addRect(r);
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRegion::Iterator  iter(*this);
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkTDArray<Edge>     edges;
459fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) {
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Edge* edge = edges.append(2);
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge[0].set(r.fLeft, r.fBottom, r.fTop);
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge[1].set(r.fRight, r.fTop, r.fBottom);
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
465c7a67cb57e43f8e140c7bd21318b5ad3e2db6b2freed@google.com    qsort(edges.begin(), edges.count(), sizeof(Edge), SkCastForQSort(EdgeProc));
466fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = edges.count();
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* start = edges.begin();
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* stop = start + count;
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Edge* e;
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (e = start; e != stop; e++) {
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        find_link(e, stop);
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (e = start; e != stop; e++) {
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(e->fNext != NULL);
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(e->fFlags == Edge::kCompleteLink);
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    path->incReserve(count << 1);
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(count > 1);
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        count -= extract_path(start, stop, path);
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (count > 0);
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
492