Fix inverse scanconversion -- be sure to keep our calls to SkBlitter in scanline
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 2 Mar 2011 15:58:18 +0000 (15:58 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 2 Mar 2011 15:58:18 +0000 (15:58 +0000)
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

samplecode/SampleComplexClip.cpp
src/core/SkScanPriv.h
src/core/SkScan_AntiPath.cpp
src/core/SkScan_Path.cpp

index c01a9a3..8aee1bf 100644 (file)
@@ -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)) {
index 74c2ee7..e78feed 100644 (file)
@@ -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
 
index fb33ab0..90a1f68 100644 (file)
@@ -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);
+    }
 }
index b1ba7df..c5088a1 100644 (file)
@@ -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);