aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-01-03 23:37:54 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-04 15:22:59 +0000
commite6345d90f8f9d975128de9890d26b1af1fedc524 (patch)
tree549f9ca28b341150208c3e38a779c5bc607bc60b
parent9d44081e00f67361414935b82332df5754bddcaf (diff)
[skotty,sksg] Add support for geometry merge
TBR= Change-Id: Ia5edbfeae61779ead6031f6dd4e33794b3eefdc0 Reviewed-on: https://skia-review.googlesource.com/90382 Reviewed-by: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@chromium.org>
-rw-r--r--BUILD.gn1
-rw-r--r--experimental/skotty/Skotty.cpp59
-rw-r--r--experimental/sksg/SkSGGeometryNode.cpp7
-rw-r--r--experimental/sksg/SkSGGeometryNode.h5
-rw-r--r--experimental/sksg/SkSGNode.h1
-rw-r--r--experimental/sksg/geometry/SkSGMerge.cpp81
-rw-r--r--experimental/sksg/geometry/SkSGMerge.h61
-rw-r--r--experimental/sksg/geometry/SkSGPath.cpp4
-rw-r--r--experimental/sksg/geometry/SkSGPath.h1
-rw-r--r--experimental/sksg/geometry/SkSGRect.cpp13
-rw-r--r--experimental/sksg/geometry/SkSGRect.h2
11 files changed, 222 insertions, 13 deletions
diff --git a/BUILD.gn b/BUILD.gn
index 8344b542b6..fe58f50e1a 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1384,6 +1384,7 @@ if (skia_enable_tools) {
"experimental/sksg/SkSGPaintNode.cpp",
"experimental/sksg/SkSGRenderNode.cpp",
"experimental/sksg/effects/SkSGTransform.cpp",
+ "experimental/sksg/geometry/SkSGMerge.cpp",
"experimental/sksg/geometry/SkSGPath.cpp",
"experimental/sksg/geometry/SkSGRect.cpp",
"experimental/sksg/paint/SkSGColor.cpp",
diff --git a/experimental/skotty/Skotty.cpp b/experimental/skotty/Skotty.cpp
index f2006bac0b..47ff828183 100644
--- a/experimental/skotty/Skotty.cpp
+++ b/experimental/skotty/Skotty.cpp
@@ -20,6 +20,7 @@
#include "SkSGDraw.h"
#include "SkSGInvalidationController.h"
#include "SkSGGroup.h"
+#include "SkSGMerge.h"
#include "SkSGPath.h"
#include "SkSGRect.h"
#include "SkSGTransform.h"
@@ -28,6 +29,8 @@
#include "SkTHash.h"
#include <cmath>
+#include <vector>
+
#include "stdlib.h"
namespace skotty {
@@ -223,6 +226,26 @@ sk_sp<sksg::PaintNode> AttachStrokePaint(const Json::Value& jstroke, AttachConte
return stroke_node;
}
+std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
+ const Json::Value& jmerge, AttachContext* ctx, std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
+ std::vector<sk_sp<sksg::GeometryNode>> merged;
+
+ static constexpr sksg::Merge::Mode gModes[] = {
+ sksg::Merge::Mode::kMerge, // "mm": 1
+ sksg::Merge::Mode::kUnion, // "mm": 2
+ sksg::Merge::Mode::kDifference, // "mm": 3
+ sksg::Merge::Mode::kIntersect, // "mm": 4
+ sksg::Merge::Mode::kXOR , // "mm": 5
+ };
+
+ const auto mode = gModes[SkTPin<int>(ParseInt(jmerge["mm"], 1) - 1, 0, SK_ARRAY_COUNT(gModes))];
+ merged.push_back(sksg::Merge::Make(std::move(geos), mode));
+
+ LOG("** Attached merge path effect, mode: %d\n", mode);
+
+ return merged;
+}
+
using GeometryAttacherT = sk_sp<sksg::GeometryNode> (*)(const Json::Value&, AttachContext*);
static constexpr GeometryAttacherT gGeometryAttachers[] = {
AttachPathGeometry,
@@ -246,8 +269,17 @@ static constexpr TransformAttacherT gTransformAttachers[] = {
AttachTransform,
};
+using GeometryEffectAttacherT =
+ std::vector<sk_sp<sksg::GeometryNode>> (*)(const Json::Value&,
+ AttachContext*,
+ std::vector<sk_sp<sksg::GeometryNode>>&&);
+static constexpr GeometryEffectAttacherT gGeometryEffectAttachers[] = {
+ AttachMergeGeometryEffect,
+};
+
enum class ShapeType {
kGeometry,
+ kGeometryEffect,
kPaint,
kGroup,
kTransform,
@@ -261,12 +293,13 @@ struct ShapeInfo {
const ShapeInfo* FindShapeInfo(const Json::Value& shape) {
static constexpr ShapeInfo gShapeInfo[] = {
- { "fl", ShapeType::kPaint , 0 }, // fill -> AttachFillPaint
- { "gr", ShapeType::kGroup , 0 }, // group -> AttachShapeGroup
- { "rc", ShapeType::kGeometry , 1 }, // shape -> AttachRRectGeometry
- { "sh", ShapeType::kGeometry , 0 }, // shape -> AttachPathGeometry
- { "st", ShapeType::kPaint , 1 }, // stroke -> AttachStrokePaint
- { "tr", ShapeType::kTransform, 0 }, // transform -> AttachTransform
+ { "fl", ShapeType::kPaint , 0 }, // fill -> AttachFillPaint
+ { "gr", ShapeType::kGroup , 0 }, // group -> AttachShapeGroup
+ { "mm", ShapeType::kGeometryEffect, 0 }, // merge -> AttachMergeGeometryEffect
+ { "rc", ShapeType::kGeometry , 1 }, // shape -> AttachRRectGeometry
+ { "sh", ShapeType::kGeometry , 0 }, // shape -> AttachPathGeometry
+ { "st", ShapeType::kPaint , 1 }, // stroke -> AttachStrokePaint
+ { "tr", ShapeType::kTransform , 0 }, // transform -> AttachTransform
};
if (!shape.isObject())
@@ -313,8 +346,8 @@ sk_sp<sksg::RenderNode> AttachShape(const Json::Value& shapeArray, AttachContext
sk_sp<sksg::Group> shape_group = sksg::Group::Make();
sk_sp<sksg::RenderNode> xformed_group = shape_group;
- SkSTArray<16, sk_sp<sksg::GeometryNode>, true> geos;
- SkSTArray<16, sk_sp<sksg::RenderNode> , true> draws;
+ std::vector<sk_sp<sksg::GeometryNode>> geos;
+ std::vector<sk_sp<sksg::RenderNode>> draws;
for (const auto& s : shapeArray) {
const auto* info = FindShapeInfo(s);
@@ -330,6 +363,10 @@ sk_sp<sksg::RenderNode> AttachShape(const Json::Value& shapeArray, AttachContext
geos.push_back(std::move(geo));
}
} break;
+ case ShapeType::kGeometryEffect: {
+ SkASSERT(info->fAttacherIndex < SK_ARRAY_COUNT(gGeometryEffectAttachers));
+ geos = gGeometryEffectAttachers[info->fAttacherIndex](s, ctx, std::move(geos));
+ } break;
case ShapeType::kPaint: {
SkASSERT(info->fAttacherIndex < SK_ARRAY_COUNT(gPaintAttachers));
if (auto paint = gPaintAttachers[info->fAttacherIndex](s, ctx)) {
@@ -356,11 +393,11 @@ sk_sp<sksg::RenderNode> AttachShape(const Json::Value& shapeArray, AttachContext
return nullptr;
}
- for (int i = draws.count() - 1; i >= 0; --i) {
- shape_group->addChild(std::move(draws[i]));
+ for (auto draw = draws.rbegin(); draw != draws.rend(); ++draw) {
+ shape_group->addChild(std::move(*draw));
}
- LOG("** Attached shape: %d draws.\n", draws.count());
+ LOG("** Attached shape: %zd draws.\n", draws.size());
return xformed_group;
}
diff --git a/experimental/sksg/SkSGGeometryNode.cpp b/experimental/sksg/SkSGGeometryNode.cpp
index 6ac7eda6a4..cbc0d558e2 100644
--- a/experimental/sksg/SkSGGeometryNode.cpp
+++ b/experimental/sksg/SkSGGeometryNode.cpp
@@ -7,6 +7,8 @@
#include "SkSGGeometryNode.h"
+#include "SkPath.h"
+
namespace sksg {
void GeometryNode::draw(SkCanvas* canvas, const SkPaint& paint) const {
@@ -14,4 +16,9 @@ void GeometryNode::draw(SkCanvas* canvas, const SkPaint& paint) const {
this->onDraw(canvas, paint);
}
+SkPath GeometryNode::asPath() const {
+ SkASSERT(!this->hasInval());
+ return this->onAsPath();
+}
+
} // namespace sksg
diff --git a/experimental/sksg/SkSGGeometryNode.h b/experimental/sksg/SkSGGeometryNode.h
index a43937510f..a898b06519 100644
--- a/experimental/sksg/SkSGGeometryNode.h
+++ b/experimental/sksg/SkSGGeometryNode.h
@@ -12,6 +12,7 @@
class SkCanvas;
class SkPaint;
+class SkPath;
namespace sksg {
@@ -25,14 +26,14 @@ class GeometryNode : public Node {
public:
void draw(SkCanvas*, const SkPaint&) const;
- // SkPath asPath() const; // unused for now
+ SkPath asPath() const;
protected:
GeometryNode() = default;
virtual void onDraw(SkCanvas*, const SkPaint&) const = 0;
- // virtual SkPath onAsPath() const = 0; // unused for now
+ virtual SkPath onAsPath() const = 0;
private:
friend class Draw; // wants to know the cached bounds.
diff --git a/experimental/sksg/SkSGNode.h b/experimental/sksg/SkSGNode.h
index bc5970a3d9..7758eca4c5 100644
--- a/experimental/sksg/SkSGNode.h
+++ b/experimental/sksg/SkSGNode.h
@@ -55,6 +55,7 @@ private:
friend class Draw;
friend class EffectNode;
friend class Group;
+ friend class Merge;
friend class Stroke;
template <typename Func>
diff --git a/experimental/sksg/geometry/SkSGMerge.cpp b/experimental/sksg/geometry/SkSGMerge.cpp
new file mode 100644
index 0000000000..a9f06d464f
--- /dev/null
+++ b/experimental/sksg/geometry/SkSGMerge.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSGMerge.h"
+
+#include "SkCanvas.h"
+#include "SkPathOps.h"
+
+namespace sksg {
+
+Merge::Merge(std::vector<sk_sp<GeometryNode>>&& geos, Mode mode)
+ : fGeos(std::move(geos))
+ , fMode(mode) {
+ for (const auto& geo : fGeos) {
+ geo->addInvalReceiver(this);
+ }
+}
+
+Merge::~Merge() {
+ for (const auto& geo : fGeos) {
+ geo->removeInvalReceiver(this);
+ }
+}
+
+void Merge::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
+ SkASSERT(!this->hasInval());
+ canvas->drawPath(fMerged, paint);
+}
+
+SkPath Merge::onAsPath() const {
+ return fMerged;
+}
+
+static SkPathOp mode_to_op(Merge::Mode mode) {
+ switch (mode) {
+ case Merge::Mode::kUnion:
+ return kUnion_SkPathOp;
+ case Merge::Mode::kIntersect:
+ return kIntersect_SkPathOp;
+ case Merge::Mode::kDifference:
+ return kDifference_SkPathOp;
+ case Merge::Mode::kReverseDifference:
+ return kReverseDifference_SkPathOp;
+ case Merge::Mode::kXOR:
+ return kXOR_SkPathOp;
+ default:
+ break;
+ }
+
+ return kUnion_SkPathOp;
+}
+
+SkRect Merge::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
+ SkASSERT(this->hasInval());
+
+ const auto op = mode_to_op(fMode);
+ SkOpBuilder builder;
+
+ fMerged.reset();
+
+ for (const auto& geo : fGeos) {
+ geo->revalidate(ic, ctm);
+ if (fMode == Mode::kMerge) {
+ fMerged.addPath(geo->asPath());
+ } else {
+ builder.add(geo->asPath(), geo == fGeos.front() ? kUnion_SkPathOp : op);
+ }
+ }
+
+ if (fMode != Mode::kMerge) {
+ builder.resolve(&fMerged);
+ }
+
+ return fMerged.computeTightBounds();
+}
+
+} // namespace skotty
diff --git a/experimental/sksg/geometry/SkSGMerge.h b/experimental/sksg/geometry/SkSGMerge.h
new file mode 100644
index 0000000000..b0cb40de9c
--- /dev/null
+++ b/experimental/sksg/geometry/SkSGMerge.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSGMerge_DEFINED
+#define SkSGMerge_DEFINED
+
+#include "SkSGGeometryNode.h"
+
+#include "SkPath.h"
+
+#include <vector>
+
+class SkCanvas;
+class SkPaint;
+
+namespace sksg {
+
+/**
+ * Concrete Geometry node, combining other geometries based on Mode.
+ */
+class Merge final : public GeometryNode {
+public:
+ enum class Mode {
+ // Append path mode.
+ kMerge,
+
+ // SkPathOp ops.
+ kUnion,
+ kIntersect,
+ kDifference,
+ kReverseDifference,
+ kXOR,
+ };
+
+ static sk_sp<Merge> Make(std::vector<sk_sp<GeometryNode>>&& geos, Mode mode) {
+ return sk_sp<Merge>(new Merge(std::move(geos), mode));
+ }
+
+ ~Merge() override;
+
+protected:
+ void onDraw(SkCanvas*, const SkPaint&) const override;
+
+ SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
+ SkPath onAsPath() const override;
+
+private:
+ Merge(std::vector<sk_sp<GeometryNode>>&& geos, Mode);
+
+ std::vector<sk_sp<GeometryNode>> fGeos;
+ SkPath fMerged;
+ Mode fMode;
+};
+
+} // namespace sksg
+
+#endif // SkSGMerge_DEFINED
diff --git a/experimental/sksg/geometry/SkSGPath.cpp b/experimental/sksg/geometry/SkSGPath.cpp
index 9b7b0427ea..a04dcf60cc 100644
--- a/experimental/sksg/geometry/SkSGPath.cpp
+++ b/experimental/sksg/geometry/SkSGPath.cpp
@@ -24,4 +24,8 @@ SkRect Path::onRevalidate(InvalidationController*, const SkMatrix&) {
return fPath.computeTightBounds();
}
+SkPath Path::onAsPath() const {
+ return fPath;
+}
+
} // namespace sksg
diff --git a/experimental/sksg/geometry/SkSGPath.h b/experimental/sksg/geometry/SkSGPath.h
index 52212cfc82..18caa10f2a 100644
--- a/experimental/sksg/geometry/SkSGPath.h
+++ b/experimental/sksg/geometry/SkSGPath.h
@@ -31,6 +31,7 @@ protected:
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
+ SkPath onAsPath() const override;
private:
explicit Path(const SkPath&);
diff --git a/experimental/sksg/geometry/SkSGRect.cpp b/experimental/sksg/geometry/SkSGRect.cpp
index a49fcf1315..c2ac384bef 100644
--- a/experimental/sksg/geometry/SkSGRect.cpp
+++ b/experimental/sksg/geometry/SkSGRect.cpp
@@ -9,6 +9,7 @@
#include "SkCanvas.h"
#include "SkPaint.h"
+#include "SkPath.h"
namespace sksg {
@@ -24,6 +25,12 @@ SkRect Rect::onRevalidate(InvalidationController*, const SkMatrix&) {
return fRect;
}
+SkPath Rect::onAsPath() const {
+ SkPath path;
+ path.addRect(fRect);
+ return path;
+}
+
RRect::RRect(const SkRRect& rr) : fRRect(rr) {}
void RRect::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
@@ -36,4 +43,10 @@ SkRect RRect::onRevalidate(InvalidationController*, const SkMatrix&) {
return fRRect.getBounds();
}
+SkPath RRect::onAsPath() const {
+ SkPath path;
+ path.addRRect(fRRect);
+ return path;
+}
+
} // namespace sksg
diff --git a/experimental/sksg/geometry/SkSGRect.h b/experimental/sksg/geometry/SkSGRect.h
index 108b1b2186..ad27910da9 100644
--- a/experimental/sksg/geometry/SkSGRect.h
+++ b/experimental/sksg/geometry/SkSGRect.h
@@ -35,6 +35,7 @@ protected:
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
+ SkPath onAsPath() const override;
private:
explicit Rect(const SkRect&);
@@ -56,6 +57,7 @@ protected:
void onDraw(SkCanvas*, const SkPaint&) const override;
SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
+ SkPath onAsPath() const override;
private:
explicit RRect(const SkRRect&);