aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg/model
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2017-10-09 15:14:13 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-10-09 19:36:44 +0000
commitdf007e1a7ae808ad41eb2bd01f6a658c5b438285 (patch)
tree708f8fba7bc23a2e4b8740ade111f4607bead8c1 /experimental/svg/model
parent7fc1d12e67d381a401555d5a7a1fa6af1eb8d7d6 (diff)
[SVGDom] Factor out common gradient logic
In preparation of radial gradient support, move common logic into an abstract base class (SkSVGGradient). Change-Id: Ie5361048ca8fddd9070c573c8daef0d0f57dc95e Reviewed-on: https://skia-review.googlesource.com/57108 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'experimental/svg/model')
-rw-r--r--experimental/svg/model/SkSVGGradient.cpp99
-rw-r--r--experimental/svg/model/SkSVGGradient.h49
-rw-r--r--experimental/svg/model/SkSVGLinearGradient.cpp83
-rw-r--r--experimental/svg/model/SkSVGLinearGradient.h22
4 files changed, 159 insertions, 94 deletions
diff --git a/experimental/svg/model/SkSVGGradient.cpp b/experimental/svg/model/SkSVGGradient.cpp
new file mode 100644
index 0000000000..fbd5f77590
--- /dev/null
+++ b/experimental/svg/model/SkSVGGradient.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "SkSVGGradient.h"
+#include "SkSVGRenderContext.h"
+#include "SkSVGStop.h"
+#include "SkSVGValue.h"
+
+void SkSVGGradient::setHref(const SkSVGStringType& href) {
+ fHref = std::move(href);
+}
+
+void SkSVGGradient::setGradientTransform(const SkSVGTransformType& t) {
+ fGradientTransform = t;
+}
+
+void SkSVGGradient::setSpreadMethod(const SkSVGSpreadMethod& spread) {
+ fSpreadMethod = spread;
+}
+
+void SkSVGGradient::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
+ switch (attr) {
+ case SkSVGAttribute::kGradientTransform:
+ if (const auto* t = v.as<SkSVGTransformValue>()) {
+ this->setGradientTransform(*t);
+ }
+ break;
+ case SkSVGAttribute::kHref:
+ if (const auto* href = v.as<SkSVGStringValue>()) {
+ this->setHref(*href);
+ }
+ break;
+ case SkSVGAttribute::kSpreadMethod:
+ if (const auto* spread = v.as<SkSVGSpreadMethodValue>()) {
+ this->setSpreadMethod(*spread);
+ }
+ break;
+ default:
+ this->INHERITED::onSetAttribute(attr, v);
+ }
+}
+
+// https://www.w3.org/TR/SVG/pservers.html#LinearGradientElementHrefAttribute
+void SkSVGGradient::collectColorStops(const SkSVGRenderContext& ctx,
+ StopPositionArray* pos,
+ StopColorArray* colors) const {
+ // Used to resolve percentage offsets.
+ const SkSVGLengthContext ltx(SkSize::Make(1, 1));
+
+ for (const auto& child : fChildren) {
+ if (child->tag() != SkSVGTag::kStop) {
+ continue;
+ }
+
+ const auto& stop = static_cast<const SkSVGStop&>(*child);
+ colors->push_back(SkColorSetA(stop.stopColor(),
+ SkScalarRoundToInt(stop.stopOpacity() * 255)));
+ pos->push_back(SkTPin(ltx.resolve(stop.offset(), SkSVGLengthContext::LengthType::kOther),
+ 0.f, 1.f));
+ }
+
+ SkASSERT(colors->count() == pos->count());
+
+ if (pos->empty() && !fHref.value().isEmpty()) {
+ const auto* ref = ctx.findNodeById(fHref);
+ if (ref && ref->tag() == SkSVGTag::kLinearGradient) {
+ static_cast<const SkSVGGradient*>(ref)->collectColorStops(ctx, pos, colors);
+ }
+ }
+}
+
+bool SkSVGGradient::onAsPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {
+ StopColorArray colors;
+ StopPositionArray pos;
+
+ this->collectColorStops(ctx, &pos, &colors);
+
+ // TODO:
+ // * stop (lazy?) sorting
+ // * href loop detection
+ // * href attribute inheritance (not just color stops)
+ // * objectBoundingBox units support
+
+ static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kPad) ==
+ SkShader::kClamp_TileMode, "SkSVGSpreadMethod::Type is out of sync");
+ static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kRepeat) ==
+ SkShader::kRepeat_TileMode, "SkSVGSpreadMethod::Type is out of sync");
+ static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kReflect) ==
+ SkShader::kMirror_TileMode, "SkSVGSpreadMethod::Type is out of sync");
+ const auto tileMode = static_cast<SkShader::TileMode>(fSpreadMethod.type());
+
+ paint->setShader(this->onMakeShader(ctx, colors.begin(), pos.begin(), colors.count(), tileMode,
+ fGradientTransform.value()));
+ return true;
+}
diff --git a/experimental/svg/model/SkSVGGradient.h b/experimental/svg/model/SkSVGGradient.h
new file mode 100644
index 0000000000..75ffba932d
--- /dev/null
+++ b/experimental/svg/model/SkSVGGradient.h
@@ -0,0 +1,49 @@
+/*
+ * 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 SkSVGGradient_DEFINED
+#define SkSVGGradient_DEFINED
+
+#include "SkShader.h"
+#include "SkSVGHiddenContainer.h"
+#include "SkSVGTypes.h"
+
+class SkMatrix;
+class SkSVGRenderContext;
+
+class SkSVGGradient : public SkSVGHiddenContainer {
+public:
+ ~SkSVGGradient() override = default;
+
+ void setHref(const SkSVGStringType&);
+ void setGradientTransform(const SkSVGTransformType&);
+ void setSpreadMethod(const SkSVGSpreadMethod&);
+
+protected:
+ explicit SkSVGGradient(SkSVGTag t) : INHERITED(t) {}
+
+ void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
+
+ bool onAsPaint(const SkSVGRenderContext&, SkPaint*) const final;
+
+ virtual sk_sp<SkShader> onMakeShader(const SkSVGRenderContext&,
+ const SkColor*, const SkScalar*, int count,
+ SkShader::TileMode, const SkMatrix& localMatrix) const = 0;
+
+private:
+ using StopPositionArray = SkSTArray<2, SkScalar, true>;
+ using StopColorArray = SkSTArray<2, SkColor, true>;
+ void collectColorStops(const SkSVGRenderContext&, StopPositionArray*, StopColorArray*) const;
+
+ SkSVGStringType fHref;
+ SkSVGTransformType fGradientTransform = SkSVGTransformType(SkMatrix::I());
+ SkSVGSpreadMethod fSpreadMethod = SkSVGSpreadMethod(SkSVGSpreadMethod::Type::kPad);
+
+ typedef SkSVGHiddenContainer INHERITED;
+};
+
+#endif // SkSVGGradient_DEFINED
diff --git a/experimental/svg/model/SkSVGLinearGradient.cpp b/experimental/svg/model/SkSVGLinearGradient.cpp
index 4bbed1c354..14939d1371 100644
--- a/experimental/svg/model/SkSVGLinearGradient.cpp
+++ b/experimental/svg/model/SkSVGLinearGradient.cpp
@@ -8,23 +8,10 @@
#include "SkGradientShader.h"
#include "SkSVGLinearGradient.h"
#include "SkSVGRenderContext.h"
-#include "SkSVGStop.h"
#include "SkSVGValue.h"
SkSVGLinearGradient::SkSVGLinearGradient() : INHERITED(SkSVGTag::kLinearGradient) {}
-void SkSVGLinearGradient::setHref(const SkSVGStringType& href) {
- fHref = std::move(href);
-}
-
-void SkSVGLinearGradient::setGradientTransform(const SkSVGTransformType& t) {
- fGradientTransform = t;
-}
-
-void SkSVGLinearGradient::setSpreadMethod(const SkSVGSpreadMethod& spread) {
- fSpreadMethod = spread;
-}
-
void SkSVGLinearGradient::setX1(const SkSVGLength& x1) {
fX1 = x1;
}
@@ -43,21 +30,6 @@ void SkSVGLinearGradient::setY2(const SkSVGLength& y2) {
void SkSVGLinearGradient::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
- case SkSVGAttribute::kGradientTransform:
- if (const auto* t = v.as<SkSVGTransformValue>()) {
- this->setGradientTransform(*t);
- }
- break;
- case SkSVGAttribute::kHref:
- if (const auto* href = v.as<SkSVGStringValue>()) {
- this->setHref(*href);
- }
- break;
- case SkSVGAttribute::kSpreadMethod:
- if (const auto* spread = v.as<SkSVGSpreadMethodValue>()) {
- this->setSpreadMethod(*spread);
- }
- break;
case SkSVGAttribute::kX1:
if (const auto* x1 = v.as<SkSVGLengthValue>()) {
this->setX1(*x1);
@@ -83,36 +55,10 @@ void SkSVGLinearGradient::onSetAttribute(SkSVGAttribute attr, const SkSVGValue&
}
}
-// https://www.w3.org/TR/SVG/pservers.html#LinearGradientElementHrefAttribute
-void SkSVGLinearGradient::collectColorStops(const SkSVGRenderContext& ctx,
- SkSTArray<2, SkScalar, true>* pos,
- SkSTArray<2, SkColor, true>* colors) const {
- // Used to resolve percentage offsets.
- const SkSVGLengthContext ltx(SkSize::Make(1, 1));
-
- for (const auto& child : fChildren) {
- if (child->tag() != SkSVGTag::kStop) {
- continue;
- }
-
- const auto& stop = static_cast<const SkSVGStop&>(*child);
- colors->push_back(SkColorSetA(stop.stopColor(),
- SkScalarRoundToInt(stop.stopOpacity() * 255)));
- pos->push_back(SkTPin(ltx.resolve(stop.offset(), SkSVGLengthContext::LengthType::kOther),
- 0.f, 1.f));
- }
-
- SkASSERT(colors->count() == pos->count());
-
- if (pos->empty() && !fHref.value().isEmpty()) {
- const auto* ref = ctx.findNodeById(fHref);
- if (ref && ref->tag() == SkSVGTag::kLinearGradient) {
- static_cast<const SkSVGLinearGradient*>(ref)->collectColorStops(ctx, pos, colors);
- }
- }
-}
-
-bool SkSVGLinearGradient::onAsPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {
+sk_sp<SkShader> SkSVGLinearGradient::onMakeShader(const SkSVGRenderContext& ctx,
+ const SkColor* colors, const SkScalar* pos,
+ int count, SkShader::TileMode tm,
+ const SkMatrix& localMatrix) const {
const auto& lctx = ctx.lengthContext();
const auto x1 = lctx.resolve(fX1, SkSVGLengthContext::LengthType::kHorizontal);
const auto y1 = lctx.resolve(fY1, SkSVGLengthContext::LengthType::kVertical);
@@ -120,25 +66,6 @@ bool SkSVGLinearGradient::onAsPaint(const SkSVGRenderContext& ctx, SkPaint* pain
const auto y2 = lctx.resolve(fY2, SkSVGLengthContext::LengthType::kVertical);
const SkPoint pts[2] = { {x1, y1}, {x2, y2}};
- SkSTArray<2, SkColor , true> colors;
- SkSTArray<2, SkScalar, true> pos;
-
- this->collectColorStops(ctx, &pos, &colors);
- // TODO:
- // * stop (lazy?) sorting
- // * href loop detection
- // * href attribute inheritance (not just color stops)
- // * objectBoundingBox units support
-
- static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kPad) ==
- SkShader::kClamp_TileMode, "SkSVGSpreadMethod::Type is out of sync");
- static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kRepeat) ==
- SkShader::kRepeat_TileMode, "SkSVGSpreadMethod::Type is out of sync");
- static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kReflect) ==
- SkShader::kMirror_TileMode, "SkSVGSpreadMethod::Type is out of sync");
- const auto tileMode = static_cast<SkShader::TileMode>(fSpreadMethod.type());
- paint->setShader(SkGradientShader::MakeLinear(pts, colors.begin(), pos.begin(), colors.count(),
- tileMode, 0, &fGradientTransform.value()));
- return true;
+ return SkGradientShader::MakeLinear(pts, colors, pos, count, tm, 0, &localMatrix);
}
diff --git a/experimental/svg/model/SkSVGLinearGradient.h b/experimental/svg/model/SkSVGLinearGradient.h
index 4e5905c02d..e878baf67d 100644
--- a/experimental/svg/model/SkSVGLinearGradient.h
+++ b/experimental/svg/model/SkSVGLinearGradient.h
@@ -8,46 +8,36 @@
#ifndef SkSVGLinearGradient_DEFINED
#define SkSVGLinearGradient_DEFINED
-#include "SkSVGHiddenContainer.h"
+#include "SkSVGGradient.h"
#include "SkSVGTypes.h"
-class SkSVGLinearGradient : public SkSVGHiddenContainer {
+class SkSVGLinearGradient final : public SkSVGGradient {
public:
~SkSVGLinearGradient() override = default;
static sk_sp<SkSVGLinearGradient> Make() {
return sk_sp<SkSVGLinearGradient>(new SkSVGLinearGradient());
}
- void setHref(const SkSVGStringType&);
- void setGradientTransform(const SkSVGTransformType&);
- void setSpreadMethod(const SkSVGSpreadMethod&);
void setX1(const SkSVGLength&);
void setY1(const SkSVGLength&);
void setX2(const SkSVGLength&);
void setY2(const SkSVGLength&);
protected:
- bool onAsPaint(const SkSVGRenderContext&, SkPaint*) const override;
-
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
+ sk_sp<SkShader> onMakeShader(const SkSVGRenderContext&,
+ const SkColor*, const SkScalar*, int count,
+ SkShader::TileMode, const SkMatrix&) const override;
private:
SkSVGLinearGradient();
- void collectColorStops(const SkSVGRenderContext&,
- SkSTArray<2, SkScalar, true>*,
- SkSTArray<2, SkColor, true>*) const;
-
SkSVGLength fX1 = SkSVGLength(0 , SkSVGLength::Unit::kPercentage);
SkSVGLength fY1 = SkSVGLength(0 , SkSVGLength::Unit::kPercentage);
SkSVGLength fX2 = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
SkSVGLength fY2 = SkSVGLength(0 , SkSVGLength::Unit::kPercentage);
- SkSVGStringType fHref;
- SkSVGTransformType fGradientTransform = SkSVGTransformType(SkMatrix::I());
- SkSVGSpreadMethod fSpreadMethod = SkSVGSpreadMethod(SkSVGSpreadMethod::Type::kPad);
-
- typedef SkSVGHiddenContainer INHERITED;
+ typedef SkSVGGradient INHERITED;
};
#endif // SkSVGLinearGradient_DEFINED