diff options
Diffstat (limited to 'skia/sgl/SkRegion_path.cpp')
-rw-r--r-- | skia/sgl/SkRegion_path.cpp | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/skia/sgl/SkRegion_path.cpp b/skia/sgl/SkRegion_path.cpp deleted file mode 100644 index d00baf9..0000000 --- a/skia/sgl/SkRegion_path.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/* libs/graphics/sgl/SkRegion_path.cpp -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "SkRegionPriv.h" -#include "SkBlitter.h" -#include "SkScan.h" -#include "SkTDArray.h" -#include "SkPath.h" - -class SkRgnBuilder : public SkBlitter { -public: - virtual ~SkRgnBuilder(); - - // returns true if it could allocate the working storage needed - bool init(int maxHeight, int maxTransitions); - - void done() { - if (fCurrScanline != NULL) { - fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX())); - if (!this->collapsWithPrev()) { // flush the last line - fCurrScanline = fCurrScanline->nextScanline(); - } - } - } - - int computeRunCount() const; - void copyToRect(SkIRect*) const; - void copyToRgn(SkRegion::RunType runs[]) const; - - virtual void blitH(int x, int y, int width); - -#ifdef SK_DEBUG - void dump() const { - SkDebugf("SkRgnBuilder: Top = %d\n", fTop); - const Scanline* line = (Scanline*)fStorage; - while (line < fCurrScanline) { - SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount); - for (int i = 0; i < line->fXCount; i++) { - SkDebugf(" %d", line->firstX()[i]); - } - SkDebugf("\n"); - - line = line->nextScanline(); - } - } -#endif -private: - struct Scanline { - SkRegion::RunType fLastY; - SkRegion::RunType fXCount; - - SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); } - Scanline* nextScanline() const { - return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount); - } - }; - SkRegion::RunType* fStorage; - Scanline* fCurrScanline; - Scanline* fPrevScanline; - // points at next avialable x[] in fCurrScanline - SkRegion::RunType* fCurrXPtr; - SkRegion::RunType fTop; // first Y value - - int fStorageCount; - - bool collapsWithPrev() { - if (fPrevScanline != NULL && - fPrevScanline->fLastY + 1 == fCurrScanline->fLastY && - fPrevScanline->fXCount == fCurrScanline->fXCount && - !memcmp(fPrevScanline->firstX(), - fCurrScanline->firstX(), - fCurrScanline->fXCount * sizeof(SkRegion::RunType))) - { - // update the height of fPrevScanline - fPrevScanline->fLastY = fCurrScanline->fLastY; - return true; - } - return false; - } -}; - -SkRgnBuilder::~SkRgnBuilder() { - sk_free(fStorage); -} - -bool SkRgnBuilder::init(int maxHeight, int maxTransitions) { - if ((maxHeight | maxTransitions) < 0) { - return false; - } - - Sk64 count, size; - - // compute the count with +1 and +3 slop for the working buffer - count.setMul(maxHeight + 1, 3 + maxTransitions); - if (!count.is32() || count.isNeg()) { - return false; - } - fStorageCount = count.get32(); - - size.setMul(fStorageCount, sizeof(SkRegion::RunType)); - if (!size.is32() || size.isNeg()) { - return false; - } - - fStorage = (SkRegion::RunType*)sk_malloc_flags(size.get32(), 0); - if (NULL == fStorage) { - return false; - } - - fCurrScanline = NULL; // signal empty collection - fPrevScanline = NULL; // signal first scanline - return true; -} - -void SkRgnBuilder::blitH(int x, int y, int width) { - if (fCurrScanline == NULL) { // first time - fTop = (SkRegion::RunType)(y); - fCurrScanline = (Scanline*)fStorage; - fCurrScanline->fLastY = (SkRegion::RunType)(y); - fCurrXPtr = fCurrScanline->firstX(); - } else { - SkASSERT(y >= fCurrScanline->fLastY); - - if (y > fCurrScanline->fLastY) { - // if we get here, we're done with fCurrScanline - fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX())); - - int prevLastY = fCurrScanline->fLastY; - if (!this->collapsWithPrev()) { - fPrevScanline = fCurrScanline; - fCurrScanline = fCurrScanline->nextScanline(); - - } - if (y - 1 > prevLastY) { // insert empty run - fCurrScanline->fLastY = (SkRegion::RunType)(y - 1); - fCurrScanline->fXCount = 0; - fCurrScanline = fCurrScanline->nextScanline(); - } - // setup for the new curr line - fCurrScanline->fLastY = (SkRegion::RunType)(y); - fCurrXPtr = fCurrScanline->firstX(); - } - } - // check if we should extend the current run, or add a new one - if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) { - fCurrXPtr[-1] = (SkRegion::RunType)(x + width); - } else { - fCurrXPtr[0] = (SkRegion::RunType)(x); - fCurrXPtr[1] = (SkRegion::RunType)(x + width); - fCurrXPtr += 2; - } - SkASSERT(fCurrXPtr - fStorage < fStorageCount); -} - -int SkRgnBuilder::computeRunCount() const { - if (fCurrScanline == NULL) { - return 0; - } - - const SkRegion::RunType* line = fStorage; - const SkRegion::RunType* stop = (const SkRegion::RunType*)fCurrScanline; - - return 2 + (int)(stop - line); -} - -void SkRgnBuilder::copyToRect(SkIRect* r) const { - SkASSERT(fCurrScanline != NULL); - SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 4); - - const Scanline* line = (const Scanline*)fStorage; - SkASSERT(line->fXCount == 2); - - r->set(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1); -} - -void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const { - SkASSERT(fCurrScanline != NULL); - SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4); - - const Scanline* line = (const Scanline*)fStorage; - const Scanline* stop = fCurrScanline; - - *runs++ = fTop; - do { - *runs++ = (SkRegion::RunType)(line->fLastY + 1); - int count = line->fXCount; - if (count) { - memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType)); - runs += count; - } - *runs++ = SkRegion::kRunTypeSentinel; - line = line->nextScanline(); - } while (line < stop); - SkASSERT(line == stop); - *runs = SkRegion::kRunTypeSentinel; -} - -static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) { - static const uint8_t gPathVerbToInitialLastIndex[] = { - 0, // kMove_Verb - 1, // kLine_Verb - 2, // kQuad_Verb - 3, // kCubic_Verb - 0, // kClose_Verb - 0 // kDone_Verb - }; - - static const uint8_t gPathVerbToMaxEdges[] = { - 0, // kMove_Verb - 1, // kLine_Verb - 2, // kQuad_VerbB - 3, // kCubic_Verb - 0, // kClose_Verb - 0 // kDone_Verb - }; - - SkPath::Iter iter(path, true); - SkPoint pts[4]; - SkPath::Verb verb; - - int maxEdges = 0; - SkScalar top = SkIntToScalar(SK_MaxS16); - SkScalar bot = SkIntToScalar(SK_MinS16); - - while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { - maxEdges += gPathVerbToMaxEdges[verb]; - - int lastIndex = gPathVerbToInitialLastIndex[verb]; - if (lastIndex > 0) { - for (int i = 1; i <= lastIndex; i++) { - if (top > pts[i].fY) { - top = pts[i].fY; - } else if (bot < pts[i].fY) { - bot = pts[i].fY; - } - } - } else if (SkPath::kMove_Verb == verb) { - if (top > pts[0].fY) { - top = pts[0].fY; - } else if (bot < pts[0].fY) { - bot = pts[0].fY; - } - } - } - SkASSERT(top <= bot); - - *itop = SkScalarRound(top); - *ibot = SkScalarRound(bot); - return maxEdges; -} - -bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) { - SkDEBUGCODE(this->validate();) - - if (clip.isEmpty()) { - return this->setEmpty(); - } - - if (path.isEmpty()) { - if (path.isInverseFillType()) { - return this->set(clip); - } else { - return this->setEmpty(); - } - } - - // compute worst-case rgn-size for the path - int pathTop, pathBot; - int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot); - int clipTop, clipBot; - int clipTransitions; - - clipTransitions = clip.count_runtype_values(&clipTop, &clipBot); - - int top = SkMax32(pathTop, clipTop); - int bot = SkMin32(pathBot, clipBot); - - if (top >= bot) - return this->setEmpty(); - - SkRgnBuilder builder; - - if (!builder.init(bot - top, SkMax32(pathTransitions, clipTransitions))) { - // can't allocate working space, so return false - return this->setEmpty(); - } - - SkScan::FillPath(path, clip, &builder); - builder.done(); - - int count = builder.computeRunCount(); - if (count == 0) { - return this->setEmpty(); - } else if (count == kRectRegionRuns) { - builder.copyToRect(&fBounds); - this->setRect(fBounds); - } else { - SkRegion tmp; - - tmp.fRunHead = RunHead::Alloc(count); - builder.copyToRgn(tmp.fRunHead->writable_runs()); - ComputeRunBounds(tmp.fRunHead->readonly_runs(), count, &tmp.fBounds); - this->swap(tmp); - } - SkDEBUGCODE(this->validate();) - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////// - -struct Edge { - enum { - kY0Link = 0x01, - kY1Link = 0x02, - - kCompleteLink = (kY0Link | kY1Link) - }; - - SkRegion::RunType fX; - SkRegion::RunType fY0, fY1; - uint8_t fFlags; - Edge* fNext; - - void set(int x, int y0, int y1) { - SkASSERT(y0 != y1); - - fX = (SkRegion::RunType)(x); - fY0 = (SkRegion::RunType)(y0); - fY1 = (SkRegion::RunType)(y1); - fFlags = 0; - SkDEBUGCODE(fNext = NULL;) - } - - int top() const { - return SkFastMin32(fY0, fY1); - } -}; - -static void find_link(Edge* base, Edge* stop) { - SkASSERT(base < stop); - - if (base->fFlags == Edge::kCompleteLink) { - SkASSERT(base->fNext); - return; - } - - SkASSERT(base + 1 < stop); - - int y0 = base->fY0; - int y1 = base->fY1; - - Edge* e = base; - if ((base->fFlags & Edge::kY0Link) == 0) { - for (;;) { - e += 1; - if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) { - SkASSERT(NULL == e->fNext); - e->fNext = base; - e->fFlags = SkToU8(e->fFlags | Edge::kY1Link); - break; - } - } - } - - e = base; - if ((base->fFlags & Edge::kY1Link) == 0) { - for (;;) { - e += 1; - if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) { - SkASSERT(NULL == base->fNext); - base->fNext = e; - e->fFlags = SkToU8(e->fFlags | Edge::kY0Link); - break; - } - } - } - - base->fFlags = Edge::kCompleteLink; -} - -static int extract_path(Edge* edge, Edge* stop, SkPath* path) { - while (0 == edge->fFlags) { - edge++; // skip over "used" edges - } - - SkASSERT(edge < stop); - - Edge* base = edge; - Edge* prev = edge; - edge = edge->fNext; - SkASSERT(edge != base); - - int count = 1; - path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0)); - prev->fFlags = 0; - do { - if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear - path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V - path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0)); // H - } - prev = edge; - edge = edge->fNext; - count += 1; - prev->fFlags = 0; - } while (edge != base); - path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1)); // V - path->close(); - return count; -} - -#include "SkTSearch.h" - -static int EdgeProc(const Edge* a, const Edge* b) { - return (a->fX == b->fX) ? a->top() - b->top() : a->fX - b->fX; -} - -bool SkRegion::getBoundaryPath(SkPath* path) const { - if (this->isEmpty()) { - return false; - } - - const SkIRect& bounds = this->getBounds(); - - if (this->isRect()) { - SkRect r; - r.set(bounds); // this converts the ints to scalars - path->addRect(r); - return true; - } - - SkRegion::Iterator iter(*this); - SkTDArray<Edge> edges; - - for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) { - Edge* edge = edges.append(2); - edge[0].set(r.fLeft, r.fBottom, r.fTop); - edge[1].set(r.fRight, r.fTop, r.fBottom); - } - SkQSort(edges.begin(), edges.count(), sizeof(Edge), (SkQSortCompareProc)EdgeProc); - - int count = edges.count(); - Edge* start = edges.begin(); - Edge* stop = start + count; - Edge* e; - - for (e = start; e != stop; e++) { - find_link(e, stop); - } - -#ifdef SK_DEBUG - for (e = start; e != stop; e++) { - SkASSERT(e->fNext != NULL); - SkASSERT(e->fFlags == Edge::kCompleteLink); - } -#endif - - path->incReserve(count << 1); - do { - SkASSERT(count > 1); - count -= extract_path(start, stop, path); - } while (count > 0); - - return true; -} - |