diff options
author | Florin Malita <fmalita@chromium.org> | 2017-10-09 15:14:13 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-10-09 19:36:44 +0000 |
commit | df007e1a7ae808ad41eb2bd01f6a658c5b438285 (patch) | |
tree | 708f8fba7bc23a2e4b8740ade111f4607bead8c1 /experimental/svg/model/SkSVGGradient.cpp | |
parent | 7fc1d12e67d381a401555d5a7a1fa6af1eb8d7d6 (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.cpp | 99 |
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; +} |