diff options
author | caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-04-25 13:34:40 +0000 |
---|---|---|
committer | caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-04-25 13:34:40 +0000 |
commit | 45a75fb4d0ca5daa0ac5e634238970306e3b5838 (patch) | |
tree | 20ec83c238e15edc4e76f57b54030cb671abf864 | |
parent | 32c1b66a2c4f26935ba59f3afe3e81600fade78d (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.cpp | 73 | ||||
-rw-r--r-- | gyp/core.gyp | 2 | ||||
-rw-r--r-- | gyp/core.gypi | 57 | ||||
-rw-r--r-- | gyp/gmslides.gypi | 4 | ||||
-rw-r--r-- | gyp/pathops_unittest.gyp | 1 | ||||
-rw-r--r-- | gyp/tests.gyp | 2 | ||||
-rw-r--r-- | include/core/SkCanvas.h | 9 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 31 |
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); } |