diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-03-02 15:58:18 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-03-02 15:58:18 +0000 |
commit | 55b6b58d8f6e7529c9b9cea606a6e3637c8e2e39 (patch) | |
tree | 8c53f352afb649fb8472964b4887636add54e069 | |
parent | 7239aab311e180960e48de8586b03e261741cc14 (diff) |
Fix inverse scanconversion -- be sure to keep our calls to SkBlitter in scanline
order (top to bottom), since the region blitter explicitly requires this.
git-svn-id: http://skia.googlecode.com/svn/trunk@876 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | samplecode/SampleComplexClip.cpp | 12 | ||||
-rw-r--r-- | src/core/SkScanPriv.h | 22 | ||||
-rw-r--r-- | src/core/SkScan_AntiPath.cpp | 42 | ||||
-rw-r--r-- | src/core/SkScan_Path.cpp | 86 |
4 files changed, 88 insertions, 74 deletions
diff --git a/samplecode/SampleComplexClip.cpp b/samplecode/SampleComplexClip.cpp index c01a9a30e7..8aee1bfb6a 100644 --- a/samplecode/SampleComplexClip.cpp +++ b/samplecode/SampleComplexClip.cpp @@ -25,14 +25,14 @@ static const struct { { SkPaint::kStrokeAndFill_Style, SkPaint::kMiter_Join, 10 }, }; -#define TEST_INVERSE 0 +#define TEST_INVERSE 1 class ComplexClipView : public SkView { SkScalar fWidth; public: ComplexClipView() { } - + protected: // overrides from SkEventSink virtual bool onQuery(SkEvent* evt) { @@ -42,11 +42,11 @@ protected: } return this->INHERITED::onQuery(evt); } - + void drawBG(SkCanvas* canvas) { canvas->drawColor(SkColorSetRGB(0xA0,0xDD,0xA0)); } - + virtual void onDraw(SkCanvas* canvas) { SkPath path; path.moveTo(SkIntToScalar(0), SkIntToScalar(50)); @@ -116,8 +116,8 @@ protected: canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4); canvas->save(); - int invALimit = TEST_INVERSE ? 1 : 2; - for (int invA = 0; invALimit < 2; ++invA) { + int invALimit = TEST_INVERSE ? 2 : 1; + for (int invA = 0; invA < invALimit; ++invA) { for (int op = 0; op < SK_ARRAY_COUNT(gOps); ++op) { int idx = invA * SK_ARRAY_COUNT(gOps) + op; if (!(idx % 3)) { diff --git a/src/core/SkScanPriv.h b/src/core/SkScanPriv.h index 74c2ee768e..e78feed6c9 100644 --- a/src/core/SkScanPriv.h +++ b/src/core/SkScanPriv.h @@ -2,16 +2,16 @@ ** ** 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 +** 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 +** 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 +** 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. */ @@ -40,9 +40,9 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter, int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn); -// blit the rects above and below avoid, clipped to clp -void sk_blit_above_and_below(SkBlitter* blitter, const SkIRect& avoid, - const SkRegion& clip); +// blit the rects above and below avoid, clipped to clip +void sk_blit_above(SkBlitter*, const SkIRect& avoid, const SkRegion& clip); +void sk_blit_below(SkBlitter*, const SkIRect& avoid, const SkRegion& clip); #endif diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index fb33ab0fbd..90a1f681a1 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -2,16 +2,16 @@ ** ** 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 +** 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 +** 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 +** 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. */ @@ -56,12 +56,12 @@ protected: BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip) { fRealBlitter = realBlitter; - + // take the union of the ir bounds and clip, since we may be called with an // inverse filltype const int left = SkMin32(ir.fLeft, clip.getBounds().fLeft); const int right = SkMax32(ir.fRight, clip.getBounds().fRight); - + fLeft = left; fSuperLeft = left << SHIFT; fWidth = right - left; @@ -153,7 +153,7 @@ void SuperBlitter::blitH(int x, int y, int width) // int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT); #if 0 - SkAntiRun<SHIFT> arun; + SkAntiRun<SHIFT> arun; arun.set(x, x + width); fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue); #else @@ -215,11 +215,11 @@ public: { int width = bounds.width(); int rb = SkAlign4(width); - + return (width <= MaskSuperBlitter::kMAX_WIDTH) && (rb * bounds.height() <= MaskSuperBlitter::kMAX_STORAGE); } - + private: enum { kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster @@ -242,10 +242,10 @@ MaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, fMask.fBounds = ir; fMask.fRowBytes = ir.width(); fMask.fFormat = SkMask::kA8_Format; - + fClipRect = ir; fClipRect.intersect(clip.getBounds()); - + // For valgrind, write 1 extra byte at the end so we don't read // uninitialized memory. See comment in add_aa_span and fStorage[]. memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1); @@ -292,7 +292,7 @@ static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount, U8CPU void MaskSuperBlitter::blitH(int x, int y, int width) { int iy = (y >> SHIFT); - + SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom); iy -= fMask.fBounds.fTop; // make it relative to 0 @@ -309,7 +309,7 @@ void MaskSuperBlitter::blitH(int x, int y, int width) SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight); } #endif - + x -= (fMask.fBounds.fLeft << SHIFT); // hack, until I figure out why my cubics (I think) go beyond the bounds @@ -397,12 +397,12 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip, } return; } - + // now use the (possibly wrapped) blitter blitter = clipper.getBlitter(); if (path.isInverseFillType()) { - sk_blit_above_and_below(blitter, ir, clip); + sk_blit_above(blitter, ir, clip); } SkIRect superRect, *superClipRect = NULL; @@ -429,4 +429,8 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip, SuperBlitter superBlit(blitter, ir, clip); sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip); } + + if (path.isInverseFillType()) { + sk_blit_below(blitter, ir, clip); + } } diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp index b1ba7dfb13..c5088a1e79 100644 --- a/src/core/SkScan_Path.cpp +++ b/src/core/SkScan_Path.cpp @@ -2,16 +2,16 @@ ** ** 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 +** 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 +** 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 +** 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. */ @@ -75,7 +75,7 @@ static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, cur for (;;) { SkEdge* prev = edge->fPrev; - + // add 1 to curr_y since we may have added new edges (built from curves) // that start on the next scanline SkASSERT(prev && prev->fFirstY <= curr_y + 1); @@ -145,11 +145,11 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, SkFixed prevX = prevHead->fX; validate_edges_for_y(currE, curr_y); - + if (proc) { proc(blitter, curr_y, PREPOST_START); // pre-proc } - + while (currE->fFirstY <= curr_y) { SkASSERT(currE->fLastY >= curr_y); @@ -181,7 +181,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, if (((SkCubicEdge*)currE)->updateCubic()) { SkASSERT(currE->fFirstY == curr_y + 1); - + newX = currE->fX; goto NEXT_X; } @@ -210,7 +210,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, currE = next; SkASSERT(currE); } - + if (proc) { proc(blitter, curr_y, PREPOST_END); // post-proc } @@ -257,7 +257,7 @@ public: } fPrevX = x + width; } - + // we do not expect to get called with these entrypoints virtual void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) { SkASSERT(!"blitAntiH unexpected"); @@ -275,7 +275,7 @@ public: SkASSERT(!"justAnOpaqueColor unexpected"); return NULL; } - + private: SkBlitter* fBlitter; int fFirstX, fLastX, fPrevX; @@ -313,7 +313,7 @@ static int build_edges(SkEdge edge[], const SkPath& path, SkPath::Iter iter(path, true); SkPoint pts[4]; SkPath::Verb verb; - + SkQuadClipper qclipper; if (clipRect) { SkIRect r; @@ -355,7 +355,7 @@ static int build_edges(SkEdge edge[], const SkPath& path, case SkPath::kCubic_Verb: { SkPoint tmp[10]; SkPoint* p = tmp; - int count = SkChopCubicAtYExtrema(pts, tmp); + int count = SkChopCubicAtYExtrema(pts, tmp); SkASSERT(count >= 0 && count <= 2); do { @@ -417,7 +417,7 @@ static int worst_case_edge_count(const SkPath& path, size_t* storage) */ static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) { int ptCount = path.getPoints(NULL, 0); - // worst case is curve, close, curve, close, as that is + // worst case is curve, close, curve, close, as that is // 2 lines per pt, or : pts * 2 // 2 quads + 1 line per 2 pts, or : pts * 3 / 2 // 3 cubics + 1 line per 3 pts : pts * 4 / 3 @@ -442,15 +442,15 @@ extern "C" { static int edge_compare(const void* a, const void* b) { const SkEdge* edgea = *(const SkEdge**)a; const SkEdge* edgeb = *(const SkEdge**)b; - + int valuea = edgea->fFirstY; int valueb = edgeb->fFirstY; - + if (valuea == valueb) { valuea = edgea->fX; valueb = edgeb->fX; } - + // this overflows if valuea >>> valueb or vice-versa // return valuea - valueb; // do perform the slower but safe compares @@ -460,13 +460,13 @@ extern "C" { static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) { qsort(list, count, sizeof(SkEdge*), edge_compare); - + // now make the edges linked in sorted order for (int i = 1; i < count; i++) { list[i - 1]->fNext = list[i]; list[i]->fPrev = list[i - 1]; } - + *last = list[count - 1]; return list[0]; } @@ -483,7 +483,7 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte #ifdef USE_NEW_BUILDER SkEdgeBuilder builder; - + int count = builder.build(path, clipRect, shiftEdgesUp); SkEdge** list = builder.edgeList(); #else @@ -494,7 +494,7 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte { size_t size2; int maxCount2 = worst_case_edge_count(path, &size2); - + SkASSERT(maxCount >= maxCount2 && size >= size2); } #endif @@ -557,20 +557,25 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc); } -void sk_blit_above_and_below(SkBlitter* blitter, const SkIRect& ir, - const SkRegion& clip) { +void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { const SkIRect& cr = clip.getBounds(); SkIRect tmp; - + tmp.fLeft = cr.fLeft; tmp.fRight = cr.fRight; - tmp.fTop = cr.fTop; tmp.fBottom = ir.fTop; if (!tmp.isEmpty()) { blitter->blitRectRegion(tmp, clip); } +} + +void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { + const SkIRect& cr = clip.getBounds(); + SkIRect tmp; + tmp.fLeft = cr.fLeft; + tmp.fRight = cr.fRight; tmp.fTop = ir.fBottom; tmp.fBottom = cr.fBottom; if (!tmp.isEmpty()) { @@ -635,10 +640,15 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& clip, blitter = clipper.getBlitter(); if (blitter) { + // we have to keep our calls to blitter in sorted order, so we + // must blit the above section first, then the middle, then the bottom. if (path.isInverseFillType()) { - sk_blit_above_and_below(blitter, ir, clip); + sk_blit_above(blitter, ir, clip); } sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, 0, clip); + if (path.isInverseFillType()) { + sk_blit_below(blitter, ir, clip); + } } else { // what does it mean to not have a blitter if path.isInverseFillType??? } @@ -649,7 +659,7 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& clip, static int build_tri_edges(SkEdge edge[], const SkPoint pts[], const SkIRect* clipRect, SkEdge* list[]) { SkEdge** start = list; - + if (edge->setLine(pts[0], pts[1], clipRect, 0)) { *list++ = edge; edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); @@ -668,7 +678,7 @@ static int build_tri_edges(SkEdge edge[], const SkPoint pts[], static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect, SkBlitter* blitter, const SkIRect& ir) { SkASSERT(pts && blitter); - + SkEdge edgeStorage[3]; SkEdge* list[3]; @@ -681,18 +691,18 @@ static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect, // this returns the first and last edge after they're sorted into a dlink list SkEdge* edge = sort_edges(list, count, &last); - + headEdge.fPrev = NULL; headEdge.fNext = edge; headEdge.fFirstY = kEDGE_HEAD_Y; headEdge.fX = SK_MinS32; edge->fPrev = &headEdge; - + tailEdge.fPrev = last; tailEdge.fNext = NULL; tailEdge.fFirstY = kEDGE_TAIL_Y; last->fNext = &tailEdge; - + // now edge is the head of the sorted linklist int stop_y = ir.fBottom; if (clipRect && stop_y > clipRect->fBottom) { @@ -710,7 +720,7 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip, if (clip && clip->isEmpty()) { return; } - + SkRect r; SkIRect ir; r.set(pts, 3); @@ -718,9 +728,9 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip, if (ir.isEmpty()) { return; } - + SkScanClipper clipper(blitter, clip, ir); - + blitter = clipper.getBlitter(); if (NULL != blitter) { sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); |