[svg] Convert stop-color and stop-opacity to presentation attrs

These are somewhat the first presentation attributes of their kind,
in that they are non-inherited but also not applied via canvas layers.

Implementation-wise the main difference is that these attributes are
not propagated through the fInherited field of the render context's
presentation attribute list.

Change-Id: I0909507b0ecbd21732b3f80c46a343f5a0a9bf7a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/340661
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
Tyler Denniston 2020-12-09 14:16:25 -05:00 committed by Skia Commit-Bot
parent 7416571f4e
commit 04e03bc181
11 changed files with 35 additions and 84 deletions

View File

@ -43,8 +43,6 @@ enum class SkSVGAttribute {
kRx, // <ellipse>,<rect>: horizontal (corner) radius
kRy, // <ellipse>,<rect>: vertical (corner) radius
kSpreadMethod,
kStopColor,
kStopOpacity,
kStroke,
kStrokeDashArray,
kStrokeDashOffset,
@ -98,12 +96,12 @@ struct SkSVGPresentationAttributes {
SkSVGProperty<SkSVGFontWeight, true> fFontWeight;
SkSVGProperty<SkSVGTextAnchor, true> fTextAnchor;
// TODO(tdenniston): add SkSVGStopColor
// uninherited
SkSVGProperty<SkSVGNumberType, false> fOpacity;
SkSVGProperty<SkSVGClip , false> fClipPath;
SkSVGProperty<SkSVGFilterType, false> fFilter;
SkSVGProperty<SkSVGColor , false> fStopColor;
SkSVGProperty<SkSVGNumberType, false> fStopOpacity;
};
#endif // SkSVGAttribute_DEFINED

View File

@ -19,7 +19,6 @@ public:
bool parseInteger(SkSVGIntegerType*);
bool parseViewBox(SkSVGViewBoxType*);
bool parsePoints(SkSVGPointsType*);
bool parseStopColor(SkSVGStopColor*);
bool parsePreserveAspectRatio(SkSVGPreserveAspectRatio*);
// TODO: Migrate all parse*() functions to this style (and delete the old version)

View File

@ -121,6 +121,8 @@ public:
SVG_PRES_ATTR(ClipPath , SkSVGClip , false)
SVG_PRES_ATTR(Filter , SkSVGFilterType, false)
SVG_PRES_ATTR(Opacity , SkSVGNumberType, false)
SVG_PRES_ATTR(StopColor , SkSVGColor , false)
SVG_PRES_ATTR(StopOpacity , SkSVGNumberType, false)
protected:
SkSVGNode(SkSVGTag);

View File

@ -21,12 +21,8 @@ public:
}
const SkSVGLength& offset() const { return fOffset; }
const SkSVGStopColor& stopColor() const { return fStopColor; }
const SkSVGNumberType& stopOpacity() const { return fStopOpacity; }
void setOffset(const SkSVGLength&);
void setStopColor(const SkSVGStopColor&);
void setStopOpacity(const SkSVGNumberType&);
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
@ -34,9 +30,7 @@ protected:
private:
SkSVGStop();
SkSVGLength fOffset = SkSVGLength(0 , SkSVGLength::Unit::kPercentage);
SkSVGStopColor fStopColor = SkSVGStopColor(SK_ColorBLACK);
SkSVGNumberType fStopOpacity = SkSVGNumberType(1);
SkSVGLength fOffset = SkSVGLength(0, SkSVGLength::Unit::kPercentage);
using INHERITED = SkSVGHiddenContainer;
};

View File

@ -34,5 +34,8 @@ SkSVGPresentationAttributes SkSVGPresentationAttributes::MakeInitial() {
result.fFontWeight.init(SkSVGFontWeight::Type::kNormal);
result.fTextAnchor.init(SkSVGTextAnchor::Type::kStart);
result.fStopColor.set(SkSVGColor(SK_ColorBLACK));
result.fStopOpacity.set(SkSVGNumberType(1));
return result;
}

View File

@ -604,23 +604,6 @@ bool SkSVGAttributeParser::parse(SkSVGLineJoin* join) {
return parsedValue && this->parseEOSToken();
}
// https://www.w3.org/TR/SVG11/pservers.html#StopElement
bool SkSVGAttributeParser::parseStopColor(SkSVGStopColor* stopColor) {
SkSVGColorType c;
bool parsedValue = false;
if (this->parse(&c)) {
*stopColor = SkSVGStopColor(c);
parsedValue = true;
} else if (this->parseExpectedStringToken("currentColor")) {
*stopColor = SkSVGStopColor(SkSVGStopColor::Type::kCurrentColor);
parsedValue = true;
} else if (this->parseExpectedStringToken("inherit")) {
*stopColor = SkSVGStopColor(SkSVGStopColor::Type::kInherit);
parsedValue = true;
}
return parsedValue && this->parseEOSToken();
}
// https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits
template <>
bool SkSVGAttributeParser::parse(SkSVGObjectBoundingBoxUnits* objectBoundingBoxUnits) {

View File

@ -93,17 +93,6 @@ bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
bool SetNumberAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
auto parseResult = SkSVGAttributeParser::parse<SkSVGNumberType>(stringValue);
if (!parseResult.isValid()) {
return false;
}
node->setAttribute(attr, SkSVGNumberValue(*parseResult));
return true;
}
bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
SkSVGViewBoxType viewBox;
@ -116,18 +105,6 @@ bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
bool SetStopColorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
SkSVGStopColor stopColor;
SkSVGAttributeParser parser(stringValue);
if (!parser.parseStopColor(&stopColor)) {
return false;
}
node->setAttribute(attr, SkSVGStopColorValue(stopColor));
return true;
}
bool SetObjectBoundingBoxUnitsAttribute(const sk_sp<SkSVGNode>& node,
SkSVGAttribute attr,
const char* stringValue) {
@ -259,8 +236,6 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
{ "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
{ "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
{ "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
{ "stop-color" , { SkSVGAttribute::kStopColor , SetStopColorAttribute }},
{ "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
{ "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
{ "text" , { SkSVGAttribute::kText , SetStringAttribute }},
{ "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},

View File

@ -53,25 +53,28 @@ void SkSVGGradient::collectColorStops(const SkSVGRenderContext& ctx,
SkColor SkSVGGradient::resolveStopColor(const SkSVGRenderContext& ctx,
const SkSVGStop& stop) const {
const SkSVGStopColor& stopColor = stop.stopColor();
const auto& stopColor = stop.getStopColor();
const auto& stopOpacity = stop.getStopOpacity();
// Uninherited presentation attrs should have a concrete value at this point.
if (!stopColor.isValue() || !stopOpacity.isValue()) {
SkDebugf("unhandled: stop-color or stop-opacity has no value\n");
return SK_ColorBLACK;
}
SkColor color;
switch (stopColor.type()) {
case SkSVGStopColor::Type::kColor:
color = stopColor.color();
switch (stopColor->type()) {
case SkSVGColor::Type::kColor:
color = stopColor->color();
break;
case SkSVGStopColor::Type::kCurrentColor:
case SkSVGColor::Type::kCurrentColor:
color = *ctx.presentationContext().fInherited.fColor;
break;
case SkSVGStopColor::Type::kICCColor:
case SkSVGColor::Type::kICCColor:
SkDebugf("unimplemented 'icccolor' stop-color type\n");
color = SK_ColorBLACK;
break;
case SkSVGStopColor::Type::kInherit:
SkDebugf("unimplemented 'inherit' stop-color type\n");
color = SK_ColorBLACK;
break;
}
return SkColorSetA(color, SkScalarRoundToInt(stop.stopOpacity() * 255));
return SkColorSetA(color, SkScalarRoundToInt(*stopOpacity * 255));
}
bool SkSVGGradient::onAsPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {

View File

@ -14,7 +14,11 @@
#include "modules/svg/include/SkSVGValue.h"
#include "src/core/SkTLazy.h"
SkSVGNode::SkSVGNode(SkSVGTag t) : fTag(t) { }
SkSVGNode::SkSVGNode(SkSVGTag t) : fTag(t) {
// Uninherited presentation attributes need a non-null default value.
fPresentationAttributes.fStopColor.set(SkSVGColor(SK_ColorBLACK));
fPresentationAttributes.fStopOpacity.set(SkSVGNumberType(1.0f));
}
SkSVGNode::~SkSVGNode() { }
@ -94,6 +98,8 @@ bool SkSVGNode::parseAndSetAttribute(const char* n, const char* v) {
|| PARSE_AND_SET("font-style" , FontStyle)
|| PARSE_AND_SET("font-weight" , FontWeight)
|| PARSE_AND_SET("opacity" , Opacity)
|| PARSE_AND_SET("stop-color" , StopColor)
|| PARSE_AND_SET("stop-opacity" , StopOpacity)
|| PARSE_AND_SET("stroke" , Stroke)
|| PARSE_AND_SET("stroke-dasharray" , StrokeDashArray)
|| PARSE_AND_SET("stroke-dashoffset", StrokeDashOffset)

View File

@ -455,6 +455,12 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
if (attrs.fFilter.isValue()) {
this->applyFilter(*attrs.fFilter);
}
// Remaining uninherited presentation attributes are accessed as SkSVGNode fields, not via
// the render context.
// TODO: resolve these in a pre-render styling pass and assert here that they are values.
// - stop-color
// - stop-opacity
}
void SkSVGRenderContext::applyOpacity(SkScalar opacity, uint32_t flags) {

View File

@ -16,14 +16,6 @@ void SkSVGStop::setOffset(const SkSVGLength& offset) {
fOffset = offset;
}
void SkSVGStop::setStopColor(const SkSVGStopColor& color) {
fStopColor = color;
}
void SkSVGStop::setStopOpacity(const SkSVGNumberType& opacity) {
fStopOpacity = SkTPin<SkScalar>(opacity, 0, 1);
}
void SkSVGStop::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
case SkSVGAttribute::kOffset:
@ -31,16 +23,6 @@ void SkSVGStop::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
this->setOffset(*offset);
}
break;
case SkSVGAttribute::kStopColor:
if (const auto* color = v.as<SkSVGStopColorValue>()) {
this->setStopColor(*color);
}
break;
case SkSVGAttribute::kStopOpacity:
if (const auto* opacity = v.as<SkSVGNumberValue>()) {
this->setStopOpacity(*opacity);
}
break;
default:
this->INHERITED::onSetAttribute(attr, v);
}