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 | |
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')
-rw-r--r-- | experimental/svg/model/SkSVGGradient.cpp | 99 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGGradient.h | 49 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGLinearGradient.cpp | 83 | ||||
-rw-r--r-- | experimental/svg/model/SkSVGLinearGradient.h | 22 |
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 |