new scanconversion technique
authorreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 18 Nov 2009 16:09:51 +0000 (16:09 +0000)
committerreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 18 Nov 2009 16:09:51 +0000 (16:09 +0000)
This technique geometrically clips all segments against the clip bounds,
ensuring that we never send a value to the edgelist that might overflow in
fixedpoint.

Current disabled in SkScan_Path.cpp by a #define. There are a few minor pixel
differences between this and the old technique, as found by the gm tool, so
at the moment this new code is off by default.

git-svn-id: http://skia.googlecode.com/svn/trunk@432 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkEdgeClipper.h [new file with mode: 0644]
include/core/SkGeometry.h
samplecode/SampleLineClipper.cpp
src/core/SkEdgeBuilder.cpp [new file with mode: 0644]
src/core/SkEdgeBuilder.h [new file with mode: 0644]
src/core/SkEdgeClipper.cpp [new file with mode: 0644]
src/core/SkQuadClipper.cpp
src/core/SkScan_Path.cpp
src/core/core_files.mk
xcode/core/core.xcodeproj/project.pbxproj

diff --git a/include/core/SkEdgeClipper.h b/include/core/SkEdgeClipper.h
new file mode 100644 (file)
index 0000000..6720b9c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#ifndef SkEdgeClipper_DEFINED
+#define SkEdgeClipper_DEFINED
+
+#include "SkPath.h"
+
+/** This is basically an iterator. It is initialized with an edge and a clip,
+    and then next() is called until it returns kDone_Verb.
+ */
+class SkEdgeClipper {
+public:
+    bool clipQuad(const SkPoint pts[3], const SkRect& clip);
+    bool clipCubic(const SkPoint pts[4], const SkRect& clip);
+
+    SkPath::Verb next(SkPoint pts[]);
+    
+private:
+    SkPoint*        fCurrPoint;
+    SkPath::Verb*   fCurrVerb;
+    
+    enum {
+        kMaxVerbs = 13,
+        kMaxPoints = 32
+    };
+    SkPoint         fPoints[kMaxPoints];
+    SkPath::Verb    fVerbs[kMaxVerbs];
+
+    void clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip);
+    void clipMonoCubic(const SkPoint srcPts[4], const SkRect& clip);
+    void appendVLine(SkScalar x, SkScalar y0, SkScalar y1, bool reverse);
+    void appendQuad(const SkPoint pts[3], bool reverse);
+    void appendCubic(const SkPoint pts[4], bool reverse);
+};
+
+#ifdef SK_DEBUG
+    void sk_assert_monotonic_x(const SkPoint pts[], int count);
+    void sk_assert_monotonic_y(const SkPoint pts[], int count);
+#else
+    #define sk_assert_monotonic_x(pts, count)
+    #define sk_assert_monotonic_y(pts, count)
+#endif
+
+#endif
index 920afb0a877e6fa8ebe256dceaf31cd1a7673ec0..853a7c34a501da737d8fce8589ce6a9575f7e389 100644 (file)
@@ -57,8 +57,8 @@ int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValues[1]);
 /** Given 3 points on a quadratic bezier, chop it into 1, 2 beziers such that
     the resulting beziers are monotonic in Y. This is called by the scan converter.
     Depending on what is returned, dst[] is treated as follows
-    1   dst[0..2] is the original quad
-    2   dst[0..2] and dst[2..4] are the two new quads
+    0   dst[0..2] is the original quad
+    1   dst[0..2] and dst[2..4] are the two new quads
 */
 int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5]);
 int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5]);
@@ -110,12 +110,13 @@ int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar
 /** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that
     the resulting beziers are monotonic in Y. This is called by the scan converter.
     Depending on what is returned, dst[] is treated as follows
-    1   dst[0..3] is the original cubic
-    2   dst[0..3] and dst[3..6] are the two new cubics
-    3   dst[0..3], dst[3..6], dst[6..9] are the three new cubics
+    0   dst[0..3] is the original cubic
+    1   dst[0..3] and dst[3..6] are the two new cubics
+    2   dst[0..3], dst[3..6], dst[6..9] are the three new cubics
     If dst == null, it is ignored and only the count is returned.
 */
 int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]);
+int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10]);
 
 /** Given a cubic bezier, return 0, 1, or 2 t-values that represent the
     inflection points.
index 8ebe95105b428acc4f3cb8e326ecd7b05c75269a..bb3e3409162e3fb713c2af7b056fe3e7efa9d230 100644 (file)
@@ -15,7 +15,7 @@
 #include "SkRandom.h"
 
 #include "SkLineClipper.h"
-#include "SkQuadClipper.h"
+#include "SkEdgeClipper.h"
 
 static void drawQuad(SkCanvas* canvas, const SkPoint pts[3], const SkPaint& p) {
     SkPath path;
@@ -63,7 +63,7 @@ static void quad_clipper(const SkPoint src[], const SkRect& clip,
                          SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
     drawQuad(canvas, src, p1);
     
-    SkQuadClipper2 clipper;
+    SkEdgeClipper clipper;
     if (clipper.clipQuad(src, clip)) {
         SkPoint pts[3];
         SkPath::Verb verb;
@@ -88,7 +88,7 @@ static void cubic_clipper(const SkPoint src[], const SkRect& clip,
                        SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
     drawCubic(canvas, src, p1);
     
-    SkQuadClipper2 clipper;
+    SkEdgeClipper clipper;
     if (clipper.clipCubic(src, clip)) {
         SkPoint pts[4];
         SkPath::Verb verb;
diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp
new file mode 100644 (file)
index 0000000..0f88488
--- /dev/null
@@ -0,0 +1,154 @@
+#include "SkEdgeBuilder.h"
+#include "SkPath.h"
+#include "SkEdge.h"
+#include "SkEdgeClipper.h"
+#include "SkLineClipper.h"
+#include "SkGeometry.h"
+
+SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {}
+
+template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) {
+    return static_cast<T*>(alloc.allocThrow(sizeof(T)));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkEdgeBuilder::addLine(const SkPoint pts[]) {
+    SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
+    if (edge->setLine(pts[0], pts[1], NULL, fShiftUp)) {
+        fList.push(edge);
+    } else {
+        // TODO: unallocate edge from storage...
+    }
+}
+
+void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
+    SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc);
+    if (edge->setQuadratic(pts, fShiftUp)) {
+        fList.push(edge);
+    } else {
+        // TODO: unallocate edge from storage...
+    }
+}
+
+void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
+    SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc);
+    if (edge->setCubic(pts, NULL, fShiftUp)) {
+        fList.push(edge);
+    } else {
+        // TODO: unallocate edge from storage...
+    }
+}
+
+void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) {
+    SkPoint      pts[4];
+    SkPath::Verb verb;
+
+    while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
+        switch (verb) {
+            case SkPath::kLine_Verb:
+                this->addLine(pts);
+                break;
+            case SkPath::kQuad_Verb:
+                this->addQuad(pts);
+                break;
+            case SkPath::kCubic_Verb:
+                this->addCubic(pts);
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
+    dst->set(SkIntToScalar(src.fLeft >> shift),
+             SkIntToScalar(src.fTop >> shift),
+             SkIntToScalar(src.fRight >> shift),
+             SkIntToScalar(src.fBottom >> shift));
+}
+
+int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
+                         int shiftUp) {
+    fAlloc.reset();
+    fList.reset();
+    fShiftUp = shiftUp;
+
+    SkPath::Iter    iter(path, true);
+    SkPoint         pts[4];
+    SkPath::Verb    verb;
+
+    if (iclip) {
+        SkRect clip;
+        setShiftedClip(&clip, *iclip, shiftUp);
+        SkEdgeClipper clipper;
+
+        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+            switch (verb) {
+                case SkPath::kMove_Verb:
+                case SkPath::kClose_Verb:
+                    // we ignore these, and just get the whole segment from
+                    // the corresponding line/quad/cubic verbs
+                    break;
+                case SkPath::kLine_Verb: {
+                    SkPoint lines[SkLineClipper::kMaxPoints];
+                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
+                    for (int i = 0; i < lineCount; i++) {
+                        this->addLine(&lines[i]);
+                    }
+                    break;
+                }
+                case SkPath::kQuad_Verb:
+                    if (clipper.clipQuad(pts, clip)) {
+                        this->addClipper(&clipper);
+                    }
+                    break;
+                case SkPath::kCubic_Verb:
+                    if (clipper.clipCubic(pts, clip)) {
+                        this->addClipper(&clipper);
+                    }
+                    break;
+                default:
+                    SkASSERT(!"unexpected verb");
+                    break;
+            }
+        }
+    } else {
+        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+            switch (verb) {
+                case SkPath::kMove_Verb:
+                case SkPath::kClose_Verb:
+                    // we ignore these, and just get the whole segment from
+                    // the corresponding line/quad/cubic verbs
+                    break;
+                case SkPath::kLine_Verb:
+                    this->addLine(pts);
+                    break;
+                case SkPath::kQuad_Verb: {
+                    SkPoint monoX[5];
+                    int n = SkChopQuadAtYExtrema(pts, monoX);
+                    for (int i = 0; i <= n; i++) {
+                        this->addQuad(&monoX[i * 2]);
+                    }
+                    break;
+                }
+                case SkPath::kCubic_Verb: {
+                    SkPoint monoY[10];
+                    int n = SkChopCubicAtYExtrema(pts, monoY);
+                    for (int i = 0; i <= n; i++) {
+                        this->addCubic(&monoY[i * 3]);
+                    }
+                    break;
+                }
+                default:
+                    SkASSERT(!"unexpected verb");
+                    break;
+            }
+        }
+    }
+    return fList.count();
+}
+
+
diff --git a/src/core/SkEdgeBuilder.h b/src/core/SkEdgeBuilder.h
new file mode 100644 (file)
index 0000000..e9ed519
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SkEdgeBuilder_DEFINED
+#define SkEdgeBuilder_DEFINED
+
+#include "SkChunkAlloc.h"
+#include "SkRect.h"
+#include "SkTDArray.h"
+
+class SkEdge;
+class SkEdgeClipper;
+class SkPath;
+
+class SkEdgeBuilder {
+public:
+    SkEdgeBuilder();
+    
+    int build(const SkPath& path, const SkIRect* clip, int shiftUp);
+
+    SkEdge** edgeList() { return fList.begin(); }
+
+private:
+    SkChunkAlloc        fAlloc;
+    SkTDArray<SkEdge*>  fList;
+    int                 fShiftUp;
+
+    void addLine(const SkPoint pts[]);
+    void addQuad(const SkPoint pts[]);
+    void addCubic(const SkPoint pts[]);
+    void addClipper(SkEdgeClipper*);
+};
+
+#endif
diff --git a/src/core/SkEdgeClipper.cpp b/src/core/SkEdgeClipper.cpp
new file mode 100644 (file)
index 0000000..7ad845d
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2009 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 "SkEdgeClipper.h"
+#include "SkGeometry.h"
+
+static bool quick_reject(const SkRect& bounds, const SkRect& clip) {
+    return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
+}
+
+static inline void clamp_le(SkScalar& value, SkScalar max) {
+    if (value > max) {
+        value = max;
+    }
+}
+
+static inline void clamp_ge(SkScalar& value, SkScalar min) {
+    if (value < min) {
+        value = min;
+    }
+}
+
+/*  src[] must be monotonic in Y. This routine copies src into dst, and sorts
+ it to be increasing in Y. If it had to reverse the order of the points,
+ it returns true, otherwise it returns false
+ */
+static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
+    // we need the data to be monotonically increasing in Y
+    if (src[0].fY > src[count - 1].fY) {
+        for (int i = 0; i < count; i++) {
+            dst[i] = src[count - i - 1];
+        }
+        return true;
+    } else {
+        memcpy(dst, src, count * sizeof(SkPoint));
+        return false;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
+                           SkScalar target, SkScalar* t) {
+    /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
+     *  We solve for t, using quadratic equation, hence we have to rearrange
+     * our cooefficents to look like At^2 + Bt + C
+     */
+    SkScalar A = c0 - c1 - c1 + c2;
+    SkScalar B = 2*(c1 - c0);
+    SkScalar C = c0 - target;
+    
+    SkScalar roots[2];  // we only expect one, but make room for 2 for safety
+    int count = SkFindUnitQuadRoots(A, B, C, roots);
+    if (count) {
+        *t = roots[0];
+        return true;
+    }
+    return false;
+}
+
+static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
+    return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
+}
+
+static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
+    return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
+}
+
+// Modify pts[] in place so that it is clipped in Y to the clip rect
+static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
+    SkScalar t;
+    SkPoint tmp[5]; // for SkChopQuadAt
+
+    // are we partially above
+    if (pts[0].fY < clip.fTop) {
+        if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
+            // take the 2nd chopped quad
+            SkChopQuadAt(pts, tmp, t);
+            clamp_ge(tmp[2].fY, clip.fTop);
+            clamp_ge(tmp[3].fY, clip.fTop);
+            pts[0] = tmp[2];
+            pts[1] = tmp[3];
+        } else {
+            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
+            // so we just clamp against the top
+            for (int i = 0; i < 3; i++) {
+                if (pts[i].fY < clip.fTop) {
+                    pts[i].fY = clip.fTop;
+                }
+            }
+        }
+    }
+    
+    // are we partially below
+    if (pts[2].fY > clip.fBottom) {
+        if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
+            SkChopQuadAt(pts, tmp, t);
+            clamp_le(tmp[1].fY, clip.fBottom);
+            clamp_le(tmp[2].fY, clip.fBottom);
+            pts[1] = tmp[1];
+            pts[2] = tmp[2];
+        } else {
+            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
+            // so we just clamp against the bottom
+            for (int i = 0; i < 3; i++) {
+                if (pts[i].fY > clip.fBottom) {
+                    pts[i].fY = clip.fBottom;
+                }
+            }
+        }
+    }
+}
+
+// srcPts[] must be monotonic in X and Y
+void SkEdgeClipper::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
+    SkPoint pts[3];
+    bool reverse = sort_increasing_Y(pts, srcPts, 3);
+
+    // are we completely above or below
+    if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
+        return;
+    }
+    
+    // Now chop so that pts is contained within clip in Y
+    chop_quad_in_Y(pts, clip);
+
+    if (pts[0].fX > pts[2].fX) {
+        SkTSwap<SkPoint>(pts[0], pts[2]);
+        reverse = !reverse;
+    }
+    SkASSERT(pts[0].fX <= pts[1].fX);
+    SkASSERT(pts[1].fX <= pts[2].fX);
+
+    // Now chop in X has needed, and record the segments
+
+    if (pts[2].fX <= clip.fLeft) {  // wholly to the left
+        this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
+        return;
+    }
+    if (pts[0].fX >= clip.fRight) {  // wholly to the right
+        this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
+        return;
+    }
+
+    SkScalar t;
+    SkPoint tmp[5]; // for SkChopQuadAt
+
+    // are we partially to the left
+    if (pts[0].fX < clip.fLeft) {
+        if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
+            SkChopQuadAt(pts, tmp, t);
+            this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
+            clamp_ge(tmp[2].fX, clip.fLeft);
+            clamp_ge(tmp[3].fX, clip.fLeft);
+            pts[0] = tmp[2];
+            pts[1] = tmp[3];
+        } else {
+            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
+            // so we just clamp against the left
+            this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
+        }
+    }
+    
+    // are we partially to the right
+    if (pts[2].fX > clip.fRight) {
+        if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
+            SkChopQuadAt(pts, tmp, t);
+            clamp_le(tmp[1].fX, clip.fRight);
+            clamp_le(tmp[2].fX, clip.fRight);
+            this->appendQuad(tmp, reverse);
+            this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
+        } else {
+            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
+            // so we just clamp against the right
+            this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
+        }
+    } else {    // wholly inside the clip
+        this->appendQuad(pts, reverse);
+    }
+}
+
+bool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
+    fCurrPoint = fPoints;
+    fCurrVerb = fVerbs;
+
+    SkRect  bounds;
+    bounds.set(srcPts, 3);
+    
+    if (!quick_reject(bounds, clip)) {
+        SkPoint monoY[5];
+        int countY = SkChopQuadAtYExtrema(srcPts, monoY);
+        for (int y = 0; y <= countY; y++) {
+            SkPoint monoX[5];
+            int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
+            for (int x = 0; x <= countX; x++) {
+                this->clipMonoQuad(&monoX[x * 2], clip);
+                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
+                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
+            }
+        }
+    }
+
+    *fCurrVerb = SkPath::kDone_Verb;
+    fCurrPoint = fPoints;
+    fCurrVerb = fVerbs;
+    return SkPath::kDone_Verb != fVerbs[0];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
+                                 SkScalar D, SkScalar t) {
+    return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
+}
+
+/*  Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
+    t value such that cubic(t) = target
+ */
+static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
+                           SkScalar target, SkScalar* t) {
+ //   SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
+    SkASSERT(c0 < target && target < c3);
+
+    SkScalar D = c0;
+    SkScalar A = c3 + 3*(c1 - c2) - c0;
+    SkScalar B = 3*(c2 - c1 - c1 + c0);
+    SkScalar C = 3*(c1 - c0);
+
+    SkScalar minT = 0;
+    SkScalar maxT = SK_Scalar1;
+    for (int i = 0; i < 8; i++) {
+        SkScalar mid = SkScalarAve(minT, maxT);
+        SkScalar coord = eval_cubic_coeff(A, B, C, D, mid);
+        if (coord < target) {
+            minT = mid;
+        } else {
+            maxT = mid;
+        }
+    }
+    *t = SkScalarAve(minT, maxT);
+    return true;
+}
+
+static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) {
+    return chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, t);
+}
+
+static bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) {
+    return chopMonoCubicAt(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, x, t);
+}
+
+// Modify pts[] in place so that it is clipped in Y to the clip rect
+static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
+    SkScalar t;
+    SkPoint tmp[7]; // for SkChopCubicAt
+    
+    // are we partially above
+    if (pts[0].fY < clip.fTop) {
+        if (chopMonoCubicAtY(pts, clip.fTop, &t)) {
+            SkChopCubicAt(pts, tmp, t);
+            clamp_ge(tmp[3].fY, clip.fTop);
+            clamp_ge(tmp[4].fY, clip.fTop);
+            clamp_ge(tmp[5].fY, clip.fTop);
+            pts[0] = tmp[3];
+            pts[1] = tmp[4];
+            pts[2] = tmp[5];
+        } else {
+            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
+            // so we just clamp against the top
+            for (int i = 0; i < 4; i++) {
+                clamp_ge(pts[i].fY, clip.fTop);
+            }
+        }
+    }
+    
+    // are we partially below
+    if (pts[3].fY > clip.fBottom) {
+        if (chopMonoCubicAtY(pts, clip.fBottom, &t)) {
+            SkChopCubicAt(pts, tmp, t);
+            clamp_le(tmp[1].fY, clip.fBottom);
+            clamp_le(tmp[2].fY, clip.fBottom);
+            clamp_le(tmp[3].fY, clip.fBottom);
+            pts[1] = tmp[1];
+            pts[2] = tmp[2];
+            pts[3] = tmp[3];
+        } else {
+            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
+            // so we just clamp against the bottom
+            for (int i = 0; i < 4; i++) {
+                clamp_le(pts[i].fY, clip.fBottom);
+            }
+        }
+    }
+}
+
+// srcPts[] must be monotonic in X and Y
+void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
+    SkPoint pts[4];
+    bool reverse = sort_increasing_Y(pts, src, 4);
+    
+    // are we completely above or below
+    if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
+        return;
+    }
+    
+    // Now chop so that pts is contained within clip in Y
+    chop_cubic_in_Y(pts, clip);
+    
+    if (pts[0].fX > pts[3].fX) {
+        SkTSwap<SkPoint>(pts[0], pts[3]);
+        SkTSwap<SkPoint>(pts[1], pts[2]);
+        reverse = !reverse;
+    }
+    
+    // Now chop in X has needed, and record the segments
+    
+    if (pts[3].fX <= clip.fLeft) {  // wholly to the left
+        this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
+        return;
+    }
+    if (pts[0].fX >= clip.fRight) {  // wholly to the right
+        this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
+        return;
+    }
+    
+    SkScalar t;
+    SkPoint tmp[7];
+    
+    // are we partially to the left
+    if (pts[0].fX < clip.fLeft) {
+        if (chopMonoCubicAtX(pts, clip.fLeft, &t)) {
+            SkChopCubicAt(pts, tmp, t);
+            this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
+            clamp_ge(tmp[3].fX, clip.fLeft);
+            clamp_ge(tmp[4].fX, clip.fLeft);
+            clamp_ge(tmp[5].fX, clip.fLeft);
+            pts[0] = tmp[3];
+            pts[1] = tmp[4];
+            pts[2] = tmp[5];
+        } else {
+            // if chopMonocubicAtY failed, then we may have hit inexact numerics
+            // so we just clamp against the left
+            this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
+        }
+    }
+    
+    // are we partially to the right
+    if (pts[3].fX > clip.fRight) {
+        if (chopMonoCubicAtX(pts, clip.fRight, &t)) {
+            SkChopCubicAt(pts, tmp, t);
+            clamp_le(tmp[1].fX, clip.fRight);
+            clamp_le(tmp[2].fX, clip.fRight);
+            clamp_le(tmp[3].fX, clip.fRight);
+            this->appendCubic(tmp, reverse);
+            this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
+        } else {
+            // if chopMonoCubicAtX failed, then we may have hit inexact numerics
+            // so we just clamp against the right
+            this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
+        }
+    } else {    // wholly inside the clip
+        this->appendCubic(pts, reverse);
+    }
+}
+
+bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
+    fCurrPoint = fPoints;
+    fCurrVerb = fVerbs;
+    
+    SkRect  bounds;
+    bounds.set(srcPts, 4);
+    
+    if (!quick_reject(bounds, clip)) {
+        SkPoint monoY[10];
+        int countY = SkChopCubicAtYExtrema(srcPts, monoY);
+        for (int y = 0; y <= countY; y++) {
+        //    sk_assert_monotonic_y(&monoY[y * 3], 4);
+            SkPoint monoX[10];
+            int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
+            for (int x = 0; x <= countX; x++) {
+            //    sk_assert_monotonic_y(&monoX[x * 3], 4);
+            //    sk_assert_monotonic_x(&monoX[x * 3], 4);
+                this->clipMonoCubic(&monoX[x * 3], clip);
+                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
+                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
+            }
+        }
+    }
+    
+    *fCurrVerb = SkPath::kDone_Verb;
+    fCurrPoint = fPoints;
+    fCurrVerb = fVerbs;
+    return SkPath::kDone_Verb != fVerbs[0];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkEdgeClipper::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
+                                bool reverse) {
+    *fCurrVerb++ = SkPath::kLine_Verb;
+    
+    if (reverse) {
+        SkTSwap<SkScalar>(y0, y1);
+    }
+    fCurrPoint[0].set(x, y0);
+    fCurrPoint[1].set(x, y1);
+    fCurrPoint += 2;
+}
+
+void SkEdgeClipper::appendQuad(const SkPoint pts[3], bool reverse) {
+    *fCurrVerb++ = SkPath::kQuad_Verb;
+    
+    if (reverse) {
+        fCurrPoint[0] = pts[2];
+        fCurrPoint[2] = pts[0];
+    } else {
+        fCurrPoint[0] = pts[0];
+        fCurrPoint[2] = pts[2];
+    }
+    fCurrPoint[1] = pts[1];
+    fCurrPoint += 3;
+}
+
+void SkEdgeClipper::appendCubic(const SkPoint pts[4], bool reverse) {
+    *fCurrVerb++ = SkPath::kCubic_Verb;
+    
+    if (reverse) {
+        for (int i = 0; i < 4; i++) {
+            fCurrPoint[i] = pts[3 - i];
+        }
+    } else {
+        memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
+    }
+    fCurrPoint += 4;
+}
+
+SkPath::Verb SkEdgeClipper::next(SkPoint pts[]) {
+    SkPath::Verb verb = *fCurrVerb;
+
+    switch (verb) {
+        case SkPath::kLine_Verb:
+            memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
+            fCurrPoint += 2;
+            fCurrVerb += 1;
+            break;
+        case SkPath::kQuad_Verb:
+            memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
+            fCurrPoint += 3;
+            fCurrVerb += 1;
+            break;
+        case SkPath::kCubic_Verb:
+            memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
+            fCurrPoint += 4;
+            fCurrVerb += 1;
+            break;
+        case SkPath::kDone_Verb:
+            break;
+        default:
+            SkASSERT(!"unexpected verb in quadclippper2 iter");
+            break;
+    }
+    return verb;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+static void assert_monotonic(const SkScalar coord[], int count) {
+    if (coord[0] > coord[(count - 1) * 2]) {
+        for (int i = 1; i < count; i++) {
+            SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
+        }
+    } else if (coord[0] < coord[(count - 1) * 2]) {
+        for (int i = 1; i < count; i++) {
+            SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
+        }
+    } else {
+        for (int i = 1; i < count; i++) {
+            SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
+        }
+    }
+}
+
+void sk_assert_monotonic_y(const SkPoint pts[], int count) {
+    if (count > 1) {
+        assert_monotonic(&pts[0].fY, count);
+    }
+}
+
+void sk_assert_monotonic_x(const SkPoint pts[], int count) {
+    if (count > 1) {
+        assert_monotonic(&pts[0].fX, count);
+    }
+}
+#endif
index 684d400064600ad4fbaf044513527e5b35628b22..dff18330920dc98f5cf91af65c92c4258e6d1b06 100644 (file)
 #include "SkQuadClipper.h"
 #include "SkGeometry.h"
 
-static bool quick_reject(const SkRect& bounds, const SkRect& clip) {
-    return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
-}
-
 static inline void clamp_le(SkScalar& value, SkScalar max) {
     if (value > max) {
         value = max;
@@ -33,23 +29,6 @@ static inline void clamp_ge(SkScalar& value, SkScalar min) {
     }
 }
 
-/*  src[] must be monotonic in Y. This routine copies src into dst, and sorts
- it to be increasing in Y. If it had to reverse the order of the points,
- it returns true, otherwise it returns false
- */
-static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
-    // we need the data to be monotonically increasing in Y
-    if (src[0].fY > src[count - 1].fY) {
-        for (int i = 0; i < count; i++) {
-            dst[i] = src[count - i - 1];
-        }
-        return true;
-    } else {
-        memcpy(dst, src, count * sizeof(SkPoint));
-        return false;
-    }
-}
-
 SkQuadClipper::SkQuadClipper() {}
 
 void SkQuadClipper::setClip(const SkIRect& clip) {
@@ -82,409 +61,8 @@ static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
     return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
 }
 
-static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
-    return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
-}
-
-// Modify pts[] in place so that it is clipped in Y to the clip rect
-static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
-    SkScalar t;
-    SkPoint tmp[5]; // for SkChopQuadAt
-
-    // are we partially above
-    if (pts[0].fY < clip.fTop) {
-        if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
-            // take the 2nd chopped quad
-            SkChopQuadAt(pts, tmp, t);
-            clamp_ge(tmp[2].fY, clip.fTop);
-            clamp_ge(tmp[3].fY, clip.fTop);
-            pts[0] = tmp[2];
-            pts[1] = tmp[3];
-        } else {
-            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
-            // so we just clamp against the top
-            for (int i = 0; i < 3; i++) {
-                if (pts[i].fY < clip.fTop) {
-                    pts[i].fY = clip.fTop;
-                }
-            }
-        }
-    }
-    
-    // are we partially below
-    if (pts[2].fY > clip.fBottom) {
-        if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
-            SkChopQuadAt(pts, tmp, t);
-            clamp_le(tmp[1].fY, clip.fBottom);
-            clamp_le(tmp[2].fY, clip.fBottom);
-            pts[1] = tmp[1];
-            pts[2] = tmp[2];
-        } else {
-            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
-            // so we just clamp against the bottom
-            for (int i = 0; i < 3; i++) {
-                if (pts[i].fY > clip.fBottom) {
-                    pts[i].fY = clip.fBottom;
-                }
-            }
-        }
-    }
-}
-
-// srcPts[] must be monotonic in X and Y
-void SkQuadClipper2::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
-    SkPoint pts[3];
-    bool reverse = sort_increasing_Y(pts, srcPts, 3);
-
-    // are we completely above or below
-    if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
-        return;
-    }
-    
-    // Now chop so that pts is contained within clip in Y
-    chop_quad_in_Y(pts, clip);
-
-    if (pts[0].fX > pts[2].fX) {
-        SkTSwap<SkPoint>(pts[0], pts[2]);
-        reverse = !reverse;
-    }
-    SkASSERT(pts[0].fX <= pts[1].fX);
-    SkASSERT(pts[1].fX <= pts[2].fX);
-
-    // Now chop in X has needed, and record the segments
-
-    if (pts[2].fX <= clip.fLeft) {  // wholly to the left
-        this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
-        return;
-    }
-    if (pts[0].fX >= clip.fRight) {  // wholly to the right
-        this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
-        return;
-    }
-
-    SkScalar t;
-    SkPoint tmp[5]; // for SkChopQuadAt
-
-    // are we partially to the left
-    if (pts[0].fX < clip.fLeft) {
-        if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
-            SkChopQuadAt(pts, tmp, t);
-            this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
-            clamp_ge(tmp[2].fX, clip.fLeft);
-            clamp_ge(tmp[3].fX, clip.fLeft);
-            pts[0] = tmp[2];
-            pts[1] = tmp[3];
-        } else {
-            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
-            // so we just clamp against the left
-            this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
-        }
-    }
-    
-    // are we partially to the right
-    if (pts[2].fX > clip.fRight) {
-        if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
-            SkChopQuadAt(pts, tmp, t);
-            clamp_le(tmp[1].fX, clip.fRight);
-            clamp_le(tmp[2].fX, clip.fRight);
-            this->appendQuad(tmp, reverse);
-            this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
-        } else {
-            // if chopMonoQuadAtY failed, then we may have hit inexact numerics
-            // so we just clamp against the right
-            this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
-        }
-    } else {    // wholly inside the clip
-        this->appendQuad(pts, reverse);
-    }
-}
-
-bool SkQuadClipper2::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
-    fCurrPoint = fPoints;
-    fCurrVerb = fVerbs;
-
-    SkRect  bounds;
-    bounds.set(srcPts, 3);
-    
-    if (!quick_reject(bounds, clip)) {
-        SkPoint monoY[5];
-        int countY = SkChopQuadAtYExtrema(srcPts, monoY);
-        for (int y = 0; y <= countY; y++) {
-            SkPoint monoX[5];
-            int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
-            for (int x = 0; x <= countX; x++) {
-                this->clipMonoQuad(&monoX[x * 2], clip);
-                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
-                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
-            }
-        }
-    }
-
-    *fCurrVerb = SkPath::kDone_Verb;
-    fCurrPoint = fPoints;
-    fCurrVerb = fVerbs;
-    return SkPath::kDone_Verb != fVerbs[0];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
-                                 SkScalar D, SkScalar t) {
-    return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
-}
-
-/*  Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
-    t value such that cubic(t) = target
- */
-static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
-                           SkScalar target, SkScalar* t) {
- //   SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
-    SkASSERT(c0 < target && target < c3);
-
-    SkScalar D = c0;
-    SkScalar A = c3 + 3*(c1 - c2) - c0;
-    SkScalar B = 3*(c2 - c1 - c1 + c0);
-    SkScalar C = 3*(c1 - c0);
-
-    SkScalar minT = 0;
-    SkScalar maxT = SK_Scalar1;
-    for (int i = 0; i < 8; i++) {
-        SkScalar mid = SkScalarAve(minT, maxT);
-        SkScalar coord = eval_cubic_coeff(A, B, C, D, mid);
-        if (coord < target) {
-            minT = mid;
-        } else {
-            maxT = mid;
-        }
-    }
-    *t = SkScalarAve(minT, maxT);
-    return true;
-}
-
-static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) {
-    return chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, t);
-}
-
-static bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) {
-    return chopMonoCubicAt(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, x, t);
-}
-
-// Modify pts[] in place so that it is clipped in Y to the clip rect
-static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
-    SkScalar t;
-    SkPoint tmp[7]; // for SkChopCubicAt
-    
-    // are we partially above
-    if (pts[0].fY < clip.fTop) {
-        if (chopMonoCubicAtY(pts, clip.fTop, &t)) {
-            SkChopCubicAt(pts, tmp, t);
-            clamp_ge(tmp[3].fY, clip.fTop);
-            clamp_ge(tmp[4].fY, clip.fTop);
-            clamp_ge(tmp[5].fY, clip.fTop);
-            pts[0] = tmp[3];
-            pts[1] = tmp[4];
-            pts[2] = tmp[5];
-        } else {
-            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
-            // so we just clamp against the top
-            for (int i = 0; i < 4; i++) {
-                clamp_ge(pts[i].fY, clip.fTop);
-            }
-        }
-    }
-    
-    // are we partially below
-    if (pts[3].fY > clip.fBottom) {
-        if (chopMonoCubicAtY(pts, clip.fBottom, &t)) {
-            SkChopCubicAt(pts, tmp, t);
-            clamp_le(tmp[1].fY, clip.fBottom);
-            clamp_le(tmp[2].fY, clip.fBottom);
-            clamp_le(tmp[3].fY, clip.fBottom);
-            pts[1] = tmp[1];
-            pts[2] = tmp[2];
-            pts[3] = tmp[3];
-        } else {
-            // if chopMonoCubicAtY failed, then we may have hit inexact numerics
-            // so we just clamp against the bottom
-            for (int i = 0; i < 4; i++) {
-                clamp_le(pts[i].fY, clip.fBottom);
-            }
-        }
-    }
-}
-
-// srcPts[] must be monotonic in X and Y
-void SkQuadClipper2::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
-    SkPoint pts[4];
-    bool reverse = sort_increasing_Y(pts, src, 4);
-    
-    // are we completely above or below
-    if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
-        return;
-    }
-    
-    // Now chop so that pts is contained within clip in Y
-    chop_cubic_in_Y(pts, clip);
-    
-    if (pts[0].fX > pts[3].fX) {
-        SkTSwap<SkPoint>(pts[0], pts[3]);
-        SkTSwap<SkPoint>(pts[1], pts[2]);
-        reverse = !reverse;
-    }
-    
-    // Now chop in X has needed, and record the segments
-    
-    if (pts[3].fX <= clip.fLeft) {  // wholly to the left
-        this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
-        return;
-    }
-    if (pts[0].fX >= clip.fRight) {  // wholly to the right
-        this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
-        return;
-    }
-    
-    SkScalar t;
-    SkPoint tmp[7];
-    
-    // are we partially to the left
-    if (pts[0].fX < clip.fLeft) {
-        if (chopMonoCubicAtX(pts, clip.fLeft, &t)) {
-            SkChopCubicAt(pts, tmp, t);
-            this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
-            clamp_ge(tmp[3].fX, clip.fLeft);
-            clamp_ge(tmp[4].fX, clip.fLeft);
-            clamp_ge(tmp[5].fX, clip.fLeft);
-            pts[0] = tmp[3];
-            pts[1] = tmp[4];
-            pts[2] = tmp[5];
-        } else {
-            // if chopMonocubicAtY failed, then we may have hit inexact numerics
-            // so we just clamp against the left
-            this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
-        }
-    }
-    
-    // are we partially to the right
-    if (pts[3].fX > clip.fRight) {
-        if (chopMonoCubicAtX(pts, clip.fRight, &t)) {
-            SkChopCubicAt(pts, tmp, t);
-            clamp_le(tmp[1].fX, clip.fRight);
-            clamp_le(tmp[2].fX, clip.fRight);
-            clamp_le(tmp[3].fX, clip.fRight);
-            this->appendCubic(tmp, reverse);
-            this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
-        } else {
-            // if chopMonoCubicAtX failed, then we may have hit inexact numerics
-            // so we just clamp against the right
-            this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
-        }
-    } else {    // wholly inside the clip
-        this->appendCubic(pts, reverse);
-    }
-}
-
-bool SkQuadClipper2::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
-    fCurrPoint = fPoints;
-    fCurrVerb = fVerbs;
-    
-    SkRect  bounds;
-    bounds.set(srcPts, 4);
-    
-    if (!quick_reject(bounds, clip)) {
-        SkPoint monoY[10];
-        int countY = SkChopCubicAtYExtrema(srcPts, monoY);
-        for (int y = 0; y <= countY; y++) {
-        //    sk_assert_monotonic_y(&monoY[y * 3], 4);
-            SkPoint monoX[10];
-            int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
-            for (int x = 0; x <= countX; x++) {
-            //    sk_assert_monotonic_y(&monoX[x * 3], 4);
-            //    sk_assert_monotonic_x(&monoX[x * 3], 4);
-                this->clipMonoCubic(&monoX[x * 3], clip);
-                SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
-                SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
-            }
-        }
-    }
-    
-    *fCurrVerb = SkPath::kDone_Verb;
-    fCurrPoint = fPoints;
-    fCurrVerb = fVerbs;
-    return SkPath::kDone_Verb != fVerbs[0];
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkQuadClipper2::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
-                                 bool reverse) {
-    *fCurrVerb++ = SkPath::kLine_Verb;
-
-    if (reverse) {
-        SkTSwap<SkScalar>(y0, y1);
-    }
-    fCurrPoint[0].set(x, y0);
-    fCurrPoint[1].set(x, y1);
-    fCurrPoint += 2;
-}
-
-void SkQuadClipper2::appendQuad(const SkPoint pts[3], bool reverse) {
-    *fCurrVerb++ = SkPath::kQuad_Verb;
-    
-    if (reverse) {
-        fCurrPoint[0] = pts[2];
-        fCurrPoint[2] = pts[0];
-    } else {
-        fCurrPoint[0] = pts[0];
-        fCurrPoint[2] = pts[2];
-    }
-    fCurrPoint[1] = pts[1];
-    fCurrPoint += 3;
-}
-
-void SkQuadClipper2::appendCubic(const SkPoint pts[4], bool reverse) {
-    *fCurrVerb++ = SkPath::kCubic_Verb;
-    
-    if (reverse) {
-        for (int i = 0; i < 4; i++) {
-            fCurrPoint[i] = pts[3 - i];
-        }
-    } else {
-        memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
-    }
-    fCurrPoint += 4;
-}
-
-SkPath::Verb SkQuadClipper2::next(SkPoint pts[]) {
-    SkPath::Verb verb = *fCurrVerb;
-
-    switch (verb) {
-        case SkPath::kLine_Verb:
-            memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
-            fCurrPoint += 2;
-            fCurrVerb += 1;
-            break;
-        case SkPath::kQuad_Verb:
-            memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
-            fCurrPoint += 3;
-            fCurrVerb += 1;
-            break;
-        case SkPath::kCubic_Verb:
-            memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
-            fCurrPoint += 4;
-            fCurrVerb += 1;
-            break;
-        case SkPath::kDone_Verb:
-            break;
-        default:
-            SkASSERT(!"unexpected verb in quadclippper2 iter");
-            break;
-    }
-    return verb;
-}
-
-//////////
-//////////
-
 /*  If we somehow returned the fact that we had to flip the pts in Y, we could
  communicate that to setQuadratic, and then avoid having to flip it back
  here (only to have setQuadratic do the flip again)
@@ -554,34 +132,3 @@ bool SkQuadClipper::clipQuad(const SkPoint srcPts[3], SkPoint dst[3]) {
     return true;
 }
 
-///////////////////////////
-
-#ifdef SK_DEBUG
-static void assert_monotonic(const SkScalar coord[], int count) {
-    if (coord[0] > coord[(count - 1) * 2]) {
-        for (int i = 1; i < count; i++) {
-            SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
-        }
-    } else if (coord[0] < coord[(count - 1) * 2]) {
-        for (int i = 1; i < count; i++) {
-            SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
-        }
-    } else {
-        for (int i = 1; i < count; i++) {
-            SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
-        }
-    }
-}
-
-void sk_assert_monotonic_y(const SkPoint pts[], int count) {
-    if (count > 1) {
-        assert_monotonic(&pts[0].fY, count);
-    }
-}
-
-void sk_assert_monotonic_x(const SkPoint pts[], int count) {
-    if (count > 1) {
-        assert_monotonic(&pts[0].fX, count);
-    }
-}
-#endif
index 6d052258bb563c1728b9ebb338d55579899d44bf..368951214d75e439f9bbf37309c5f8620879ab35 100644 (file)
@@ -24,6 +24,8 @@
 #include "SkRegion.h"
 #include "SkTemplates.h"
 
+//#define USE_NEW_BUILDER
+
 #define kEDGE_HEAD_Y    SK_MinS32
 #define kEDGE_TAIL_Y    SK_MaxS32
 
@@ -301,6 +303,9 @@ static inline bool line_too_big(const SkPoint pts[2])
             SkScalarAbs(dy) > SkIntToScalar(511);
 }
 
+#ifdef USE_NEW_BUILDER
+#include "SkEdgeBuilder.h"
+#else
 static int build_edges(SkEdge edge[], const SkPath& path,
                        const SkIRect* clipRect, SkEdge* list[], int shiftUp) {
     SkEdge**        start = list;
@@ -428,6 +433,7 @@ static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) {
     *storage = quadSize;
     return edgeCount;
 }
+#endif
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -474,6 +480,12 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
 {
     SkASSERT(&path && blitter);
 
+#ifdef USE_NEW_BUILDER
+    SkEdgeBuilder   builder;
+    
+    int count = builder.build(path, clipRect, shiftEdgesUp);
+    SkEdge**    list = builder.edgeList();
+#else
     size_t  size;
     int     maxCount = cheap_worst_case_edge_count(path, &size);
 
@@ -488,17 +500,19 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
 
     SkAutoMalloc    memory(maxCount * sizeof(SkEdge*) + size);
     SkEdge**        list = (SkEdge**)memory.get();
-    SkEdge*         edge = (SkEdge*)(list + maxCount);
-    int             count = build_edges(edge, path, clipRect, list, shiftEdgesUp);
-    SkEdge          headEdge, tailEdge, *last;
-
+    SkEdge*         initialEdge = (SkEdge*)(list + maxCount);
+    int             count = build_edges(initialEdge, path, clipRect, list,
+                                        shiftEdgesUp);
     SkASSERT(count <= maxCount);
+#endif
+
     if (count < 2) {
         return;
     }
 
+    SkEdge headEdge, tailEdge, *last;
     // this returns the first and last edge after they're sorted into a dlink list
-    edge = sort_edges(list, count, &last);
+    SkEdge* edge = sort_edges(list, count, &last);
 
     headEdge.fPrev = NULL;
     headEdge.fNext = edge;
index 553706d6ec2025b05f634dcda2ab0275ee4f241f..c36f11a2cde28358819235557a2db801ce149317 100644 (file)
@@ -34,6 +34,8 @@ SOURCE := \
     SkDither.cpp \
     SkDraw.cpp \
     SkEdge.cpp \
+    SkEdgeBuilder.cpp \
+    SkEdgeClipper.cpp \
     SkFilterProc.cpp \
     SkFlattenable.cpp \
     SkFloat.cpp \
@@ -43,6 +45,7 @@ SOURCE := \
     SkGlobals.cpp \
     SkGlyphCache.cpp \
     SkGraphics.cpp \
+    SkLineClipper.cpp \
     SkMMapStream.cpp \
     SkMask.cpp \
     SkMaskFilter.cpp \
index 6256cca1a6171b5614ecbc6b78e16ad793798233..0f5cfcd1b36a056ef80647662ecb0ba5e8291524 100644 (file)
@@ -33,7 +33,6 @@
                005F25820EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F25090EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h */; };
                005F25830EF94F7900582A90 /* SkBitmapShaderTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F250A0EF94F7900582A90 /* SkBitmapShaderTemplate.h */; };
                005F25840EF94F7900582A90 /* SkBlitBWMaskTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F250B0EF94F7900582A90 /* SkBlitBWMaskTemplate.h */; };
-               005F25850EF94F7900582A90 /* SkBlitRow.h in Headers */ = {isa = PBXBuildFile; fileRef = 005F250C0EF94F7900582A90 /* SkBlitRow.h */; };
                005F25860EF94F7900582A90 /* SkBlitRow_D16.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F250D0EF94F7900582A90 /* SkBlitRow_D16.cpp */; };
                005F25870EF94F7900582A90 /* SkBlitRow_D4444.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F250E0EF94F7900582A90 /* SkBlitRow_D4444.cpp */; };
                005F25880EF94F7900582A90 /* SkBlitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F250F0EF94F7900582A90 /* SkBlitter.cpp */; };
                005F26960EF955D400582A90 /* SkComposeShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 005F26950EF955D400582A90 /* SkComposeShader.cpp */; };
                007C786A0F3B4D5F0004B142 /* SkQuadClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 007C78690F3B4D5F0004B142 /* SkQuadClipper.cpp */; };
                0096586E0FC7205100C3AE15 /* SkShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0096586D0FC7205100C3AE15 /* SkShape.cpp */; };
-               009CC7920F5DAF4B002185BE /* SkCubicClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009CC7910F5DAF4B002185BE /* SkCubicClipper.cpp */; };
+               00F043FC10B445F50049C54C /* SkEdgeBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00F043F910B445F50049C54C /* SkEdgeBuilder.cpp */; };
+               00F043FD10B445F50049C54C /* SkEdgeClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00F043FA10B445F50049C54C /* SkEdgeClipper.cpp */; };
+               00F043FE10B445F50049C54C /* SkLineClipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00F043FB10B445F50049C54C /* SkLineClipper.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
                005F25090EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBitmapShader16BilerpTemplate.h; path = ../../src/core/SkBitmapShader16BilerpTemplate.h; sourceTree = SOURCE_ROOT; };
                005F250A0EF94F7900582A90 /* SkBitmapShaderTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBitmapShaderTemplate.h; path = ../../src/core/SkBitmapShaderTemplate.h; sourceTree = SOURCE_ROOT; };
                005F250B0EF94F7900582A90 /* SkBlitBWMaskTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBlitBWMaskTemplate.h; path = ../../src/core/SkBlitBWMaskTemplate.h; sourceTree = SOURCE_ROOT; };
-               005F250C0EF94F7900582A90 /* SkBlitRow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkBlitRow.h; path = ../../src/core/SkBlitRow.h; sourceTree = SOURCE_ROOT; };
                005F250D0EF94F7900582A90 /* SkBlitRow_D16.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkBlitRow_D16.cpp; path = ../../src/core/SkBlitRow_D16.cpp; sourceTree = SOURCE_ROOT; };
                005F250E0EF94F7900582A90 /* SkBlitRow_D4444.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkBlitRow_D4444.cpp; path = ../../src/core/SkBlitRow_D4444.cpp; sourceTree = SOURCE_ROOT; };
                005F250F0EF94F7900582A90 /* SkBlitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkBlitter.cpp; path = ../../src/core/SkBlitter.cpp; sourceTree = SOURCE_ROOT; };
                005F26950EF955D400582A90 /* SkComposeShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkComposeShader.cpp; path = ../../src/core/SkComposeShader.cpp; sourceTree = SOURCE_ROOT; };
                007C78690F3B4D5F0004B142 /* SkQuadClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkQuadClipper.cpp; path = ../../src/core/SkQuadClipper.cpp; sourceTree = SOURCE_ROOT; };
                0096586D0FC7205100C3AE15 /* SkShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkShape.cpp; path = ../../src/core/SkShape.cpp; sourceTree = SOURCE_ROOT; };
-               009CC7910F5DAF4B002185BE /* SkCubicClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkCubicClipper.cpp; path = ../../src/core/SkCubicClipper.cpp; sourceTree = SOURCE_ROOT; };
+               00F043F910B445F50049C54C /* SkEdgeBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkEdgeBuilder.cpp; path = ../../src/core/SkEdgeBuilder.cpp; sourceTree = SOURCE_ROOT; };
+               00F043FA10B445F50049C54C /* SkEdgeClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkEdgeClipper.cpp; path = ../../src/core/SkEdgeClipper.cpp; sourceTree = SOURCE_ROOT; };
+               00F043FB10B445F50049C54C /* SkLineClipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkLineClipper.cpp; path = ../../src/core/SkLineClipper.cpp; sourceTree = SOURCE_ROOT; };
                D2AAC046055464E500DB518D /* libcore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcore.a; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
                08FB7795FE84155DC02AAC07 /* src */ = {
                        isa = PBXGroup;
                        children = (
+                               00F043F910B445F50049C54C /* SkEdgeBuilder.cpp */,
+                               00F043FA10B445F50049C54C /* SkEdgeClipper.cpp */,
+                               00F043FB10B445F50049C54C /* SkLineClipper.cpp */,
                                00244E0F106A6DEA00B8F4D8 /* SkBlitRow_D32.cpp */,
                                00554E0C102733D300C9C8ED /* SkBitmapProcState_opts_none.cpp */,
                                002B342710213340000F04C6 /* SkBlitRow_opts_none.cpp */,
                                005DC79A10179AE000F00DFB /* SkFontHost.cpp */,
                                005DC79810179ACD00F00DFB /* SkBlitter_ARGB32_Subpixel.cpp */,
-                               009CC7910F5DAF4B002185BE /* SkCubicClipper.cpp */,
                                007C78690F3B4D5F0004B142 /* SkQuadClipper.cpp */,
                                002884D40EFAB8F80083E387 /* SkStream.cpp */,
                                002884C70EFAB8B90083E387 /* SkMMapStream.cpp */,
                                005F25090EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h */,
                                005F250A0EF94F7900582A90 /* SkBitmapShaderTemplate.h */,
                                005F250B0EF94F7900582A90 /* SkBlitBWMaskTemplate.h */,
-                               005F250C0EF94F7900582A90 /* SkBlitRow.h */,
                                005F250D0EF94F7900582A90 /* SkBlitRow_D16.cpp */,
                                005F250E0EF94F7900582A90 /* SkBlitRow_D4444.cpp */,
                                005F250F0EF94F7900582A90 /* SkBlitter.cpp */,
                                005F25820EF94F7900582A90 /* SkBitmapShader16BilerpTemplate.h in Headers */,
                                005F25830EF94F7900582A90 /* SkBitmapShaderTemplate.h in Headers */,
                                005F25840EF94F7900582A90 /* SkBlitBWMaskTemplate.h in Headers */,
-                               005F25850EF94F7900582A90 /* SkBlitRow.h in Headers */,
                                005F25970EF94F7900582A90 /* SkCordic.h in Headers */,
                                005F25980EF94F7900582A90 /* SkCoreBlitters.h in Headers */,
                                005F259F0EF94F7900582A90 /* SkDrawProcs.h in Headers */,
                                002884C80EFAB8B90083E387 /* SkMMapStream.cpp in Sources */,
                                002884D50EFAB8F80083E387 /* SkStream.cpp in Sources */,
                                007C786A0F3B4D5F0004B142 /* SkQuadClipper.cpp in Sources */,
-                               009CC7920F5DAF4B002185BE /* SkCubicClipper.cpp in Sources */,
                                0096586E0FC7205100C3AE15 /* SkShape.cpp in Sources */,
                                005DC79910179ACD00F00DFB /* SkBlitter_ARGB32_Subpixel.cpp in Sources */,
                                005DC79B10179AE000F00DFB /* SkFontHost.cpp in Sources */,
                                002B342810213340000F04C6 /* SkBlitRow_opts_none.cpp in Sources */,
                                00554E0D102733D300C9C8ED /* SkBitmapProcState_opts_none.cpp in Sources */,
                                00244E10106A6DEA00B8F4D8 /* SkBlitRow_D32.cpp in Sources */,
+                               00F043FC10B445F50049C54C /* SkEdgeBuilder.cpp in Sources */,
+                               00F043FD10B445F50049C54C /* SkEdgeClipper.cpp in Sources */,
+                               00F043FE10B445F50049C54C /* SkLineClipper.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };