aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg/model/SkSVGGradient.cpp
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/SkSVGGradient.cpp
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/SkSVGGradient.cpp')
-rw-r--r--experimental/svg/model/SkSVGGradient.cpp99
1 files changed, 99 insertions, 0 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;
+}