aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-25 13:34:40 +0000
committerGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-25 13:34:40 +0000
commit45a75fb4d0ca5daa0ac5e634238970306e3b5838 (patch)
tree20ec83c238e15edc4e76f57b54030cb671abf864
parent32c1b66a2c4f26935ba59f3afe3e81600fade78d (diff)
path ops : make it real
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
-rw-r--r--gm/pathopsskpclip.cpp73
-rw-r--r--gyp/core.gyp2
-rw-r--r--gyp/core.gypi57
-rw-r--r--gyp/gmslides.gypi4
-rw-r--r--gyp/pathops_unittest.gyp1
-rw-r--r--gyp/tests.gyp2
-rw-r--r--include/core/SkCanvas.h9
-rw-r--r--src/core/SkCanvas.cpp31
8 files changed, 174 insertions, 5 deletions
diff --git a/gm/pathopsskpclip.cpp b/gm/pathopsskpclip.cpp
new file mode 100644
index 0000000000..b85b294fef
--- /dev/null
+++ b/gm/pathopsskpclip.cpp
@@ -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);
+
+}
diff --git a/gyp/core.gyp b/gyp/core.gyp
index 0a38ede481..7d9c9d774c 100644
--- a/gyp/core.gyp
+++ b/gyp/core.gyp
@@ -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',
],
diff --git a/gyp/core.gypi b/gyp/core.gypi
index c694091e7d..4dbbdd677f 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -302,6 +302,63 @@
'<(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',
],
}
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 4386d64006..c46c53412e 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -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',
diff --git a/gyp/pathops_unittest.gyp b/gyp/pathops_unittest.gyp
index 2cb81724f0..d3a1eabbf2 100644
--- a/gyp/pathops_unittest.gyp
+++ b/gyp/pathops_unittest.gyp
@@ -18,7 +18,6 @@
'../tools/',
],
'includes': [
- 'pathops.gypi',
'pathops_unittest.gypi',
],
'sources': [
diff --git a/gyp/tests.gyp b/gyp/tests.gyp
index ef6994ef4d..8e82d1bda0 100644
--- a/gyp/tests.gyp
+++ b/gyp/tests.gyp
@@ -11,13 +11,13 @@
'../src/core',
'../src/effects',
'../src/lazy',
+ '../src/pathops',
'../src/pdf',
'../src/pipe/utils',
'../src/utils',
'../tools/',
],
'includes': [
- 'pathops.gypi',
'pathops_unittest.gypi',
],
'sources': [
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 930bdb6fbc..2bf5a54a51 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -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) {
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 1dc4fad320..d200ba3088 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -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);
}