path ops : make it real
authorcaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 25 Apr 2013 13:34:40 +0000 (13:34 +0000)
committercaryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 25 Apr 2013 13:34:40 +0000 (13:34 +0000)
Add an option to SkCanvas to turn on path
ops when combining clips.

Allow Op() to use one of the input paths
as an output path.

Fix a bug in Op() when the minuend is empty
and the subtrahend is not (for difference).

Change the build to allow core to depend on pathops.
Review URL: https://codereview.chromium.org/14474002

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

gm/pathopsskpclip.cpp [new file with mode: 0644]
gyp/core.gyp
gyp/core.gypi
gyp/gmslides.gypi
gyp/pathops_unittest.gyp
gyp/tests.gyp
include/core/SkCanvas.h
src/core/SkCanvas.cpp

diff --git a/gm/pathopsskpclip.cpp b/gm/pathopsskpclip.cpp
new file mode 100644 (file)
index 0000000..b85b294
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkClipStack.h"
+#include "SkDevice.h"
+#include "SkPath.h"
+#include "SkPathOps.h"
+#include "SkPicture.h"
+#include "SkRect.h"
+
+namespace skiagm {
+
+class PathOpsSkpClipGM : public GM {
+public:
+    PathOpsSkpClipGM() {
+    }
+
+protected:
+    virtual SkString onShortName() SK_OVERRIDE {
+        return SkString("pathopsskpclip");
+    }
+
+    virtual SkISize onISize() SK_OVERRIDE {
+        return make_isize(1200, 900);
+    }
+
+    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        SkPicture* pict = SkNEW(SkPicture);
+        SkCanvas* rec = pict->beginRecording(1200, 900);
+        SkPath p;
+        SkRect r = {
+            SkIntToScalar(100),
+            SkIntToScalar(200),
+            SkIntToScalar(400),
+            SkIntToScalar(700)
+        };
+        p.addRoundRect(r, SkIntToScalar(50), SkIntToScalar(50));
+        rec->clipPath(p, SkRegion::kIntersect_Op, true);
+        rec->translate(SkIntToScalar(250), SkIntToScalar(250));
+        rec->clipPath(p, SkRegion::kIntersect_Op, true);
+        rec->drawColor(0xffff0000);
+        pict->endRecording();
+
+        canvas->setAllowSimplifyClip(true);
+        canvas->save();
+        canvas->drawPicture(*pict);
+        canvas->restore();
+
+        canvas->setAllowSimplifyClip(false);
+        canvas->save();
+        canvas->translate(SkIntToScalar(1200 / 2), 0);
+        canvas->drawPicture(*pict);
+        canvas->restore();
+        SkSafeUnref(pict);
+    }
+
+private:
+    typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new PathOpsSkpClipGM; }
+static GMRegistry reg(MyFactory);
+
+}
index 0a38ede..7d9c9d7 100644 (file)
@@ -16,6 +16,7 @@
         '../include/config',
         '../include/core',
         '../include/lazy',
+        '../include/pathops',
         '../include/pipe',
         '../include/ports',
         '../include/utils',
@@ -95,6 +96,7 @@
           '../include/config',
           '../include/core',
           '../include/lazy',
+          '../include/pathops',
           '../include/pipe',
           'ext',
         ],
index c694091..4dbbdd6 100644 (file)
         '<(skia_src_path)/lazy/SkPurgeableMemoryBlock.h',
         '<(skia_src_path)/lazy/SkPurgeableMemoryBlock_common.cpp',
         '<(skia_src_path)/lazy/SkPurgeableImageCache.cpp',
+
+        # Path ops
+        '<(skia_include_path)/pathops/SkPathOps.h',
+
+        '<(skia_src_path)/pathops/SkAddIntersections.cpp',
+        '<(skia_src_path)/pathops/SkDCubicIntersection.cpp',
+        '<(skia_src_path)/pathops/SkDCubicLineIntersection.cpp',
+        '<(skia_src_path)/pathops/SkDCubicToQuads.cpp',
+        '<(skia_src_path)/pathops/SkDLineIntersection.cpp',
+        '<(skia_src_path)/pathops/SkDQuadImplicit.cpp',
+        '<(skia_src_path)/pathops/SkDQuadIntersection.cpp',
+        '<(skia_src_path)/pathops/SkDQuadLineIntersection.cpp',
+        '<(skia_src_path)/pathops/SkIntersections.cpp',
+        '<(skia_src_path)/pathops/SkOpAngle.cpp',
+        '<(skia_src_path)/pathops/SkOpContour.cpp',
+        '<(skia_src_path)/pathops/SkOpEdgeBuilder.cpp',
+        '<(skia_src_path)/pathops/SkOpSegment.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsBounds.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsCommon.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsCubic.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsDebug.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsLine.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsOp.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsPoint.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsQuad.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsRect.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsSimplify.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsTriangle.cpp',
+        '<(skia_src_path)/pathops/SkPathOpsTypes.cpp',
+        '<(skia_src_path)/pathops/SkPathWriter.cpp',
+        '<(skia_src_path)/pathops/SkQuarticRoot.cpp',
+        '<(skia_src_path)/pathops/SkReduceOrder.cpp',
+        '<(skia_src_path)/pathops/SkAddIntersections.h',
+        '<(skia_src_path)/pathops/SkDQuadImplicit.h',
+        '<(skia_src_path)/pathops/SkIntersectionHelper.h',
+        '<(skia_src_path)/pathops/SkIntersections.h',
+        '<(skia_src_path)/pathops/SkLineParameters.h',
+        '<(skia_src_path)/pathops/SkOpAngle.h',
+        '<(skia_src_path)/pathops/SkOpContour.h',
+        '<(skia_src_path)/pathops/SkOpEdgeBuilder.h',
+        '<(skia_src_path)/pathops/SkOpSegment.h',
+        '<(skia_src_path)/pathops/SkOpSpan.h',
+        '<(skia_src_path)/pathops/SkPathOpsBounds.h',
+        '<(skia_src_path)/pathops/SkPathOpsCommon.h',
+        '<(skia_src_path)/pathops/SkPathOpsCubic.h',
+        '<(skia_src_path)/pathops/SkPathOpsCurve.h',
+        '<(skia_src_path)/pathops/SkPathOpsDebug.h',
+        '<(skia_src_path)/pathops/SkPathOpsLine.h',
+        '<(skia_src_path)/pathops/SkPathOpsPoint.h',
+        '<(skia_src_path)/pathops/SkPathOpsQuad.h',
+        '<(skia_src_path)/pathops/SkPathOpsRect.h',
+        '<(skia_src_path)/pathops/SkPathOpsSpan.h',
+        '<(skia_src_path)/pathops/SkPathOpsTriangle.h',
+        '<(skia_src_path)/pathops/SkPathOpsTypes.h',
+        '<(skia_src_path)/pathops/SkPathWriter.h',
+        '<(skia_src_path)/pathops/SkQuarticRoot.h',
+        '<(skia_src_path)/pathops/SkReduceOrder.h',
     ],
 }
 
index 4386d64..c46c534 100644 (file)
@@ -1,8 +1,5 @@
 # include this gypi to include all the golden master slides.
 {
-  'includes': [
-    'pathops.gypi',
-  ],
   'sources': [
     '../gm/aaclip.cpp',
     '../gm/aarectmodes.cpp',
@@ -70,6 +67,7 @@
     '../gm/pathfill.cpp',
     '../gm/pathinterior.cpp',
     '../gm/pathopsinverse.cpp',
+    '../gm/pathopsskpclip.cpp',
     '../gm/pathreverse.cpp',
     '../gm/perlinnoise.cpp',
     '../gm/points.cpp',
index 2cb8172..d3a1eab 100644 (file)
@@ -18,7 +18,6 @@
         '../tools/',
       ],
       'includes': [
-        'pathops.gypi',
         'pathops_unittest.gypi',
       ],
       'sources': [
index ef6994e..8e82d1b 100644 (file)
         '../src/core',
         '../src/effects',
         '../src/lazy',
+        '../src/pathops',
         '../src/pdf',
         '../src/pipe/utils',
         '../src/utils',
         '../tools/',
       ],
       'includes': [
-        'pathops.gypi',
         'pathops_unittest.gypi',
       ],
       'sources': [
index 930bdb6..2bf5a54 100644 (file)
@@ -381,6 +381,13 @@ public:
         fAllowSoftClip = allow;
     }
 
+    /** EXPERIMENTAL -- only used for testing
+        Set to simplify clip stack using path ops.
+     */
+    void setAllowSimplifyClip(bool allow) {
+        fAllowSimplifyClip = allow;
+    }
+
     /** Modify the current clip with the specified region. Note that unlike
         clipRect() and clipPath() which transform their arguments by the current
         matrix, clipRegion() assumes its argument is already in device
@@ -1064,6 +1071,7 @@ private:
     mutable SkRectCompareType fLocalBoundsCompareType;
     mutable bool              fLocalBoundsCompareTypeDirty;
     bool fAllowSoftClip;
+    bool fAllowSimplifyClip;
 
     const SkRectCompareType& getLocalClipBoundsCompareType() const {
         if (fLocalBoundsCompareTypeDirty) {
@@ -1074,6 +1082,7 @@ private:
     }
     void computeLocalClipBoundsCompareType() const;
 
+
     class AutoValidateClip : ::SkNoncopyable {
     public:
         explicit AutoValidateClip(SkCanvas* canvas) : fCanvas(canvas) {
index 1dc4fad..d200ba3 100644 (file)
@@ -15,6 +15,7 @@
 #include "SkDrawFilter.h"
 #include "SkDrawLooper.h"
 #include "SkMetaData.h"
+#include "SkPathOps.h"
 #include "SkPicture.h"
 #include "SkRasterClip.h"
 #include "SkRRect.h"
@@ -508,6 +509,7 @@ SkDevice* SkCanvas::init(SkDevice* device) {
     fLocalBoundsCompareType.setEmpty();
     fLocalBoundsCompareTypeDirty = true;
     fAllowSoftClip = true;
+    fAllowSimplifyClip = false;
     fDeviceCMDirty = false;
     fSaveLayerCount = 0;
     fMetaData = NULL;
@@ -1241,6 +1243,35 @@ bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
     // if we called path.swap() we could avoid a deep copy of this path
     fClipStack.clipDevPath(devPath, op, doAA);
 
+    if (fAllowSimplifyClip) {
+        devPath.reset();
+        devPath.setFillType(SkPath::kInverseEvenOdd_FillType);
+        const SkClipStack* clipStack = getClipStack();
+        SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
+        const SkClipStack::Element* element;
+        while ((element = iter.next())) {
+            SkClipStack::Element::Type type = element->getType();
+            if (type == SkClipStack::Element::kEmpty_Type) {
+                continue;
+            }
+            SkPath operand;
+            if (type == SkClipStack::Element::kRect_Type) {
+                operand.addRect(element->getRect());
+            } else if (type == SkClipStack::Element::kPath_Type) {
+                operand = element->getPath();
+            } else {
+                SkDEBUGFAIL("Unexpected type.");
+            }
+            SkRegion::Op elementOp = element->getOp();
+            if (elementOp == SkRegion::kReplace_Op) {
+                devPath = operand;
+            } else {
+                Op(devPath, operand, (SkPathOp) elementOp, &devPath);
+            }
+        }
+        op = SkRegion::kReplace_Op;
+    }
+
     return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
 }