aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-01-07 08:54:24 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-07 14:30:08 +0000
commit51b8c89b1c2772cf4126ec5c9bfaf4b0dccbd2e3 (patch)
treea8c1883026455186f1f7570a6db14d1e276360e9 /experimental
parent9661b98221146b379189da015103f692a5902c36 (diff)
[skotty,sksg] Initial trim path effect
TBR= Change-Id: I5b612c5aade23f727a3622daeff2534f68e6b66a Reviewed-on: https://skia-review.googlesource.com/91404 Reviewed-by: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'experimental')
-rw-r--r--experimental/skotty/Skotty.cpp47
-rw-r--r--experimental/sksg/SkSGNode.h1
-rw-r--r--experimental/sksg/geometry/SkSGTrimEffect.cpp61
-rw-r--r--experimental/sksg/geometry/SkSGTrimEffect.h53
4 files changed, 161 insertions, 1 deletions
diff --git a/experimental/skotty/Skotty.cpp b/experimental/skotty/Skotty.cpp
index 8c48d1f871..a13a04c03c 100644
--- a/experimental/skotty/Skotty.cpp
+++ b/experimental/skotty/Skotty.cpp
@@ -24,6 +24,7 @@
#include "SkSGPath.h"
#include "SkSGRect.h"
#include "SkSGTransform.h"
+#include "SkSGTrimEffect.h"
#include "SkStream.h"
#include "SkTArray.h"
#include "SkTHash.h"
@@ -308,7 +309,8 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
sksg::Merge::Mode::kXOR , // "mm": 5
};
- const auto mode = gModes[SkTPin<int>(ParseInt(jmerge["mm"], 1) - 1, 0, SK_ARRAY_COUNT(gModes))];
+ const auto mode = gModes[SkTPin<int>(ParseInt(jmerge["mm"], 1) - 1,
+ 0, SK_ARRAY_COUNT(gModes) - 1)];
merged.push_back(sksg::Merge::Make(std::move(geos), mode));
LOG("** Attached merge path effect, mode: %d\n", mode);
@@ -316,6 +318,47 @@ std::vector<sk_sp<sksg::GeometryNode>> AttachMergeGeometryEffect(
return merged;
}
+std::vector<sk_sp<sksg::GeometryNode>> AttachTrimGeometryEffect(
+ const Json::Value& jtrim, AttachContext* ctx, std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
+
+ enum class Mode {
+ kMerged, // "m": 1
+ kSeparate, // "m": 2
+ } gModes[] = { Mode::kMerged, Mode::kSeparate };
+
+ const auto mode = gModes[SkTPin<int>(ParseInt(jtrim["m"], 1) - 1,
+ 0, SK_ARRAY_COUNT(gModes) - 1)];
+
+ std::vector<sk_sp<sksg::GeometryNode>> inputs;
+ if (mode == Mode::kMerged) {
+ inputs.push_back(sksg::Merge::Make(std::move(geos), sksg::Merge::Mode::kMerge));
+ } else {
+ inputs = std::move(geos);
+ }
+
+ std::vector<sk_sp<sksg::GeometryNode>> trimmed;
+ trimmed.reserve(inputs.size());
+ for (const auto& i : inputs) {
+ const auto trim = sksg::TrimEffect::Make(i);
+ trimmed.push_back(trim);
+ AttachProperty<ScalarValue, SkScalar>(jtrim["s"], ctx, trim,
+ [](const sk_sp<sksg::TrimEffect>& node, const SkScalar& s) {
+ node->setStart(s * 0.01f);
+ });
+ AttachProperty<ScalarValue, SkScalar>(jtrim["e"], ctx, trim,
+ [](const sk_sp<sksg::TrimEffect>& node, const SkScalar& e) {
+ node->setEnd(e * 0.01f);
+ });
+ // TODO: "offset" doesn't currently work the same as BM - figure out what's going on.
+ AttachProperty<ScalarValue, SkScalar>(jtrim["o"], ctx, trim,
+ [](const sk_sp<sksg::TrimEffect>& node, const SkScalar& o) {
+ node->setOffset(o * 0.01f);
+ });
+ }
+
+ return trimmed;
+}
+
using GeometryAttacherT = sk_sp<sksg::GeometryNode> (*)(const Json::Value&, AttachContext*);
static constexpr GeometryAttacherT gGeometryAttachers[] = {
AttachPathGeometry,
@@ -341,6 +384,7 @@ using GeometryEffectAttacherT =
std::vector<sk_sp<sksg::GeometryNode>>&&);
static constexpr GeometryEffectAttacherT gGeometryEffectAttachers[] = {
AttachMergeGeometryEffect,
+ AttachTrimGeometryEffect,
};
enum class ShapeType {
@@ -367,6 +411,7 @@ const ShapeInfo* FindShapeInfo(const Json::Value& shape) {
{ "sh", ShapeType::kGeometry , 0 }, // shape -> AttachPathGeometry
{ "sr", ShapeType::kGeometry , 3 }, // polystar -> AttachPolyStarGeometry
{ "st", ShapeType::kPaint , 1 }, // stroke -> AttachStrokePaint
+ { "tm", ShapeType::kGeometryEffect, 1 }, // trim -> AttachTrimGeometryEffect
{ "tr", ShapeType::kTransform , 0 }, // transform -> In-place handler
};
diff --git a/experimental/sksg/SkSGNode.h b/experimental/sksg/SkSGNode.h
index 769e2a4e68..4e1e7b0d2a 100644
--- a/experimental/sksg/SkSGNode.h
+++ b/experimental/sksg/SkSGNode.h
@@ -70,6 +70,7 @@ private:
friend class Merge;
friend class Stroke;
friend class Transform;
+ friend class TrimEffect;
template <typename Func>
void forEachInvalReceiver(Func&&) const;
diff --git a/experimental/sksg/geometry/SkSGTrimEffect.cpp b/experimental/sksg/geometry/SkSGTrimEffect.cpp
new file mode 100644
index 0000000000..4c30389877
--- /dev/null
+++ b/experimental/sksg/geometry/SkSGTrimEffect.cpp
@@ -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.
+ */
+
+#include "SkSGTrimEffect.h"
+
+#include "SkCanvas.h"
+#include "SkDashPathEffect.h"
+#include "SkPathMeasure.h"
+
+namespace sksg {
+
+TrimEffect::TrimEffect(sk_sp<GeometryNode> child)
+ : fChild(std::move(child)) {
+ fChild->addInvalReceiver(this);
+}
+
+TrimEffect::~TrimEffect() {
+ fChild->removeInvalReceiver(this);
+}
+
+// TODO
+// This is a quick hack to get something on the screen. What we really want here is to apply
+// the geometry transformation and cache the result on revalidation. Or an SkTrimPathEffect.
+void TrimEffect::onDraw(SkCanvas* canvas, const SkPaint& paint) const {
+ SkASSERT(!this->hasInval());
+
+ SkASSERT(!paint.getPathEffect());
+
+ const auto path = fChild->asPath();
+ SkScalar pathLen = 0;
+ SkPathMeasure measure(path, false);
+ do {
+ pathLen += measure.getLength();
+ } while (measure.nextContour());
+
+ const auto start = SkScalarPin(fStart , 0, 1) * pathLen,
+ end = SkScalarPin(fEnd , 0, 1) * pathLen,
+ offset = SkScalarPin(fOffset, 0, 1) * pathLen,
+ len = SkTMax<SkScalar>(end - start, 0);
+
+ const SkScalar dashes[4] = { 0, start, len, pathLen - end };
+ SkPaint dashedPaint(paint);
+ dashedPaint.setPathEffect(SkDashPathEffect::Make(dashes, 4, -offset));
+
+ canvas->drawPath(path, dashedPaint);
+}
+
+SkPath TrimEffect::onAsPath() const {
+ return fChild->asPath();
+}
+
+SkRect TrimEffect::onRevalidate(InvalidationController* ic, const SkMatrix& ctm) {
+ SkASSERT(this->hasInval());
+ return fChild->revalidate(ic, ctm);
+}
+
+} // namespace sksg
diff --git a/experimental/sksg/geometry/SkSGTrimEffect.h b/experimental/sksg/geometry/SkSGTrimEffect.h
new file mode 100644
index 0000000000..77da3ab2d0
--- /dev/null
+++ b/experimental/sksg/geometry/SkSGTrimEffect.h
@@ -0,0 +1,53 @@
+/*
+ * 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 SkSGTrimEffect_DEFINED
+#define SkSGTrimEffect_DEFINED
+
+#include "SkSGGeometryNode.h"
+
+#include "SkPath.h"
+
+class SkCanvas;
+class SkPaint;
+
+namespace sksg {
+
+/**
+ * Concrete Geometry node, applying a trim effect to its child.
+ */
+class TrimEffect final : public GeometryNode {
+public:
+ static sk_sp<TrimEffect> Make(sk_sp<GeometryNode> child) {
+ return child ? sk_sp<TrimEffect>(new TrimEffect(std::move(child))) : nullptr;
+ }
+
+ ~TrimEffect() override;
+
+ SG_ATTRIBUTE(Start , SkScalar, fStart )
+ SG_ATTRIBUTE(End , SkScalar, fEnd )
+ SG_ATTRIBUTE(Offset, SkScalar, fOffset)
+
+protected:
+ void onDraw(SkCanvas*, const SkPaint&) const override;
+
+ SkRect onRevalidate(InvalidationController*, const SkMatrix&) override;
+ SkPath onAsPath() const override;
+
+private:
+ explicit TrimEffect(sk_sp<GeometryNode>);
+
+ const sk_sp<GeometryNode> fChild;
+
+ SkScalar fStart = 0, // starting t
+ fEnd = 1, // ending t
+ fOffset = 0; // t offset
+};
+
+} // namespace sksg
+
+#endif // SkSGTrimEffect_DEFINED