[SVGDom] Clipped clipPath support
authorFlorin Malita <fmalita@chromium.org>
Thu, 8 Dec 2016 21:04:24 +0000 (16:04 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Fri, 9 Dec 2016 16:06:25 +0000 (16:06 +0000)
ClipPaths can be clipped too, e.g.:

  <clipPath id="clip1" clip-path="url(#clip2)">...</clipPath>

Since we're not really drawing clips but resolving their geometry,
asPath() needs to take composed clipping into account (and intersect as
needed).

R=reed@google.com,robertphillips@google.com,stephana@google.com

Change-Id: I25959e22fe50f72042147cfe6b416b6b9ac20cd4
Reviewed-on: https://skia-review.googlesource.com/5720
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>

experimental/svg/model/SkSVGNode.cpp
experimental/svg/model/SkSVGRenderContext.cpp
experimental/svg/model/SkSVGRenderContext.h

index ec452ec..0f3743f 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "SkCanvas.h"
 #include "SkMatrix.h"
+#include "SkPathOps.h"
 #include "SkSVGNode.h"
 #include "SkSVGRenderContext.h"
 #include "SkSVGValue.h"
@@ -32,7 +33,18 @@ bool SkSVGNode::asPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {
 
 SkPath SkSVGNode::asPath(const SkSVGRenderContext& ctx) const {
     SkSVGRenderContext localContext(ctx);
-    return this->onPrepareToRender(&localContext) ? this->onAsPath(localContext) : SkPath();
+    if (!this->onPrepareToRender(&localContext)) {
+        return SkPath();
+    }
+
+    SkPath path = this->onAsPath(localContext);
+
+    if (const auto* clipPath = localContext.clipPath()) {
+        // There is a clip-path present on the current node.
+        Op(path, *clipPath, kIntersect_SkPathOp, &path);
+    }
+
+    return path;
 }
 
 bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
index d8307a0..9de605a 100644 (file)
@@ -328,12 +328,20 @@ void SkSVGRenderContext::applyClip(const SkSVGClip& clip) {
 
     const SkPath clipPath = clipNode->asPath(*this);
 
+    // We use the computed clip path in two ways:
+    //
+    //   - apply to the current canvas, for drawing
+    //   - track in the presentation context, for asPath() composition
+    //
+    // TODO: the two uses are exclusive, avoid canvas churn when non needed.
+
     // Only save if needed
     if (fCanvas->getSaveCount() == fCanvasSaveCount) {
         fCanvas->save();
     }
 
     fCanvas->clipPath(clipPath, true);
+    fClipPath.set(clipPath);
 }
 
 const SkPaint* SkSVGRenderContext::fillPaint() const {
index ab046cd..3cd38cb 100644 (file)
@@ -9,6 +9,7 @@
 #define SkSVGRenderContext_DEFINED
 
 #include "SkPaint.h"
+#include "SkPath.h"
 #include "SkRect.h"
 #include "SkSize.h"
 #include "SkSVGAttribute.h"
@@ -79,6 +80,9 @@ public:
     const SkPaint* fillPaint() const;
     const SkPaint* strokePaint() const;
 
+    // The local computed clip path (not inherited).
+    const SkPath* clipPath() const { return fClipPath.getMaybeNull(); }
+
 private:
     // Stack-only
     void* operator new(size_t)                               = delete;
@@ -95,6 +99,9 @@ private:
     // The save count on 'fCanvas' at construction time.
     // A restoreToCount() will be issued on destruction.
     int                                           fCanvasSaveCount;
+
+    // clipPath, if present for the current context (not inherited).
+    SkTLazy<SkPath>                               fClipPath;
 };
 
 #endif // SkSVGRenderContext_DEFINED