[svg] Add plumbing for color-interpolation-filters property
The default colorspace for filter effects is linear RGB, as specified in https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperties. Currently we perform all filtering in the destination colorspace. This CL adds the new presentation attribute with the default setting (according to the spec) of linear RGB. This CL does not actually implement any colorspace transformations for filters. Bug: skia:10841 Change-Id: Id778ad3fa5cb6e0aed756584a50880edd9d82e2b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/352738 Commit-Queue: Tyler Denniston <tdenniston@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
bd747cb1e7
commit
7bb85dbb5e
@ -16,6 +16,7 @@ class SkSVGRenderContext;
|
||||
enum class SkSVGAttribute {
|
||||
kClipRule,
|
||||
kColor,
|
||||
kColorInterpolationFilters,
|
||||
kCx, // <circle>, <ellipse>, <radialGradient>: center x position
|
||||
kCy, // <circle>, <ellipse>, <radialGradient>: center y position
|
||||
kD,
|
||||
@ -89,6 +90,7 @@ struct SkSVGPresentationAttributes {
|
||||
SkSVGProperty<SkSVGVisibility, true> fVisibility;
|
||||
|
||||
SkSVGProperty<SkSVGColorType , true> fColor;
|
||||
SkSVGProperty<SkSVGColorspace, true> fColorInterpolationFilters;
|
||||
|
||||
SkSVGProperty<SkSVGFontFamily, true> fFontFamily;
|
||||
SkSVGProperty<SkSVGFontStyle , true> fFontStyle;
|
||||
|
@ -29,6 +29,16 @@ public:
|
||||
// https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveSubRegion
|
||||
SkRect resolveFilterSubregion(const SkSVGRenderContext&, const SkSVGFilterContext&) const;
|
||||
|
||||
/**
|
||||
* Resolves the colorspace within which this filter effect should be applied.
|
||||
* Spec: https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperties
|
||||
* 'color-interpolation-filters' property.
|
||||
*/
|
||||
SkSVGColorspace resolveColorspace(const SkSVGRenderContext&) const;
|
||||
|
||||
/** Propagates any inherited presentation attributes in the given context. */
|
||||
void applyProperties(SkSVGRenderContext*) const;
|
||||
|
||||
SVG_ATTR(In, SkSVGFeInputType, SkSVGFeInputType(SkSVGFeInputType::Type::kSourceGraphic))
|
||||
SVG_ATTR(Result, SkSVGStringType, SkSVGStringType())
|
||||
SVG_OPTIONAL_ATTR(X, SkSVGLength)
|
||||
|
@ -101,35 +101,36 @@ public:
|
||||
virtual bool parseAndSetAttribute(const char* name, const char* value);
|
||||
|
||||
// inherited
|
||||
SVG_PRES_ATTR(ClipRule , SkSVGFillRule , true)
|
||||
SVG_PRES_ATTR(Color , SkSVGColorType , true)
|
||||
SVG_PRES_ATTR(FillRule , SkSVGFillRule , true)
|
||||
SVG_PRES_ATTR(Fill , SkSVGPaint , true)
|
||||
SVG_PRES_ATTR(FillOpacity , SkSVGNumberType, true)
|
||||
SVG_PRES_ATTR(FontFamily , SkSVGFontFamily, true)
|
||||
SVG_PRES_ATTR(FontSize , SkSVGFontSize , true)
|
||||
SVG_PRES_ATTR(FontStyle , SkSVGFontStyle , true)
|
||||
SVG_PRES_ATTR(FontWeight , SkSVGFontWeight, true)
|
||||
SVG_PRES_ATTR(Stroke , SkSVGPaint , true)
|
||||
SVG_PRES_ATTR(StrokeDashArray , SkSVGDashArray , true)
|
||||
SVG_PRES_ATTR(StrokeDashOffset, SkSVGLength , true)
|
||||
SVG_PRES_ATTR(StrokeLineCap , SkSVGLineCap , true)
|
||||
SVG_PRES_ATTR(StrokeLineJoin , SkSVGLineJoin , true)
|
||||
SVG_PRES_ATTR(StrokeMiterLimit, SkSVGNumberType, true)
|
||||
SVG_PRES_ATTR(StrokeOpacity , SkSVGNumberType, true)
|
||||
SVG_PRES_ATTR(StrokeWidth , SkSVGLength , true)
|
||||
SVG_PRES_ATTR(TextAnchor , SkSVGTextAnchor, true)
|
||||
SVG_PRES_ATTR(Visibility , SkSVGVisibility, true)
|
||||
SVG_PRES_ATTR(ClipRule , SkSVGFillRule , true)
|
||||
SVG_PRES_ATTR(Color , SkSVGColorType , true)
|
||||
SVG_PRES_ATTR(ColorInterpolationFilters, SkSVGColorspace, true)
|
||||
SVG_PRES_ATTR(FillRule , SkSVGFillRule , true)
|
||||
SVG_PRES_ATTR(Fill , SkSVGPaint , true)
|
||||
SVG_PRES_ATTR(FillOpacity , SkSVGNumberType, true)
|
||||
SVG_PRES_ATTR(FontFamily , SkSVGFontFamily, true)
|
||||
SVG_PRES_ATTR(FontSize , SkSVGFontSize , true)
|
||||
SVG_PRES_ATTR(FontStyle , SkSVGFontStyle , true)
|
||||
SVG_PRES_ATTR(FontWeight , SkSVGFontWeight, true)
|
||||
SVG_PRES_ATTR(Stroke , SkSVGPaint , true)
|
||||
SVG_PRES_ATTR(StrokeDashArray , SkSVGDashArray , true)
|
||||
SVG_PRES_ATTR(StrokeDashOffset , SkSVGLength , true)
|
||||
SVG_PRES_ATTR(StrokeLineCap , SkSVGLineCap , true)
|
||||
SVG_PRES_ATTR(StrokeLineJoin , SkSVGLineJoin , true)
|
||||
SVG_PRES_ATTR(StrokeMiterLimit , SkSVGNumberType, true)
|
||||
SVG_PRES_ATTR(StrokeOpacity , SkSVGNumberType, true)
|
||||
SVG_PRES_ATTR(StrokeWidth , SkSVGLength , true)
|
||||
SVG_PRES_ATTR(TextAnchor , SkSVGTextAnchor, true)
|
||||
SVG_PRES_ATTR(Visibility , SkSVGVisibility, true)
|
||||
|
||||
// not inherited
|
||||
SVG_PRES_ATTR(ClipPath , SkSVGFuncIRI , false)
|
||||
SVG_PRES_ATTR(Mask , SkSVGFuncIRI , false)
|
||||
SVG_PRES_ATTR(Filter , SkSVGFuncIRI , false)
|
||||
SVG_PRES_ATTR(Opacity , SkSVGNumberType, false)
|
||||
SVG_PRES_ATTR(StopColor , SkSVGColor , false)
|
||||
SVG_PRES_ATTR(StopOpacity , SkSVGNumberType, false)
|
||||
SVG_PRES_ATTR(FloodColor , SkSVGColor , false)
|
||||
SVG_PRES_ATTR(FloodOpacity , SkSVGNumberType, false)
|
||||
SVG_PRES_ATTR(ClipPath , SkSVGFuncIRI , false)
|
||||
SVG_PRES_ATTR(Mask , SkSVGFuncIRI , false)
|
||||
SVG_PRES_ATTR(Filter , SkSVGFuncIRI , false)
|
||||
SVG_PRES_ATTR(Opacity , SkSVGNumberType, false)
|
||||
SVG_PRES_ATTR(StopColor , SkSVGColor , false)
|
||||
SVG_PRES_ATTR(StopOpacity , SkSVGNumberType, false)
|
||||
SVG_PRES_ATTR(FloodColor , SkSVGColor , false)
|
||||
SVG_PRES_ATTR(FloodOpacity , SkSVGNumberType, false)
|
||||
|
||||
protected:
|
||||
SkSVGNode(SkSVGTag);
|
||||
|
@ -650,4 +650,10 @@ enum class SkSVGXmlSpace {
|
||||
kPreserve,
|
||||
};
|
||||
|
||||
enum class SkSVGColorspace {
|
||||
kAuto,
|
||||
kSRGB,
|
||||
kLinearRGB,
|
||||
};
|
||||
|
||||
#endif // SkSVGTypes_DEFINED
|
||||
|
@ -27,6 +27,7 @@ SkSVGPresentationAttributes SkSVGPresentationAttributes::MakeInitial() {
|
||||
result.fVisibility.set(SkSVGVisibility(SkSVGVisibility::Type::kVisible));
|
||||
|
||||
result.fColor.set(SkSVGColorType(SK_ColorBLACK));
|
||||
result.fColorInterpolationFilters.set(SkSVGColorspace::kLinearRGB);
|
||||
|
||||
result.fFontFamily.init("Sans");
|
||||
result.fFontStyle.init(SkSVGFontStyle::Type::kNormal);
|
||||
|
@ -927,3 +927,14 @@ template <>
|
||||
bool SkSVGAttributeParser::parse(std::vector<SkSVGNumberType>* numbers) {
|
||||
return this->parseList(numbers);
|
||||
}
|
||||
|
||||
template <>
|
||||
bool SkSVGAttributeParser::parse(SkSVGColorspace* colorspace) {
|
||||
static constexpr std::tuple<const char*, SkSVGColorspace> gColorspaceMap[] = {
|
||||
{ "auto" , SkSVGColorspace::kAuto },
|
||||
{ "sRGB" , SkSVGColorspace::kSRGB },
|
||||
{ "linearRGB", SkSVGColorspace::kLinearRGB },
|
||||
};
|
||||
|
||||
return this->parseEnumMap(gColorspaceMap, colorspace) && this->parseEOSToken();
|
||||
}
|
||||
|
@ -83,6 +83,12 @@ SkRect SkSVGFe::resolveFilterSubregion(const SkSVGRenderContext& ctx,
|
||||
return subregion;
|
||||
}
|
||||
|
||||
SkSVGColorspace SkSVGFe::resolveColorspace(const SkSVGRenderContext& ctx) const {
|
||||
return *ctx.presentationContext().fInherited.fColorInterpolationFilters;
|
||||
}
|
||||
|
||||
void SkSVGFe::applyProperties(SkSVGRenderContext* ctx) const { this->onPrepareToRender(ctx); }
|
||||
|
||||
bool SkSVGFe::parseAndSetAttribute(const char* name, const char* value) {
|
||||
return INHERITED::parseAndSetAttribute(name, value) ||
|
||||
this->setIn(SkSVGAttributeParser::parse<SkSVGFeInputType>("in", name, value)) ||
|
||||
|
@ -54,11 +54,20 @@ sk_sp<SkImageFilter> SkSVGFilter::buildFilterDAG(const SkSVGRenderContext& ctx)
|
||||
const auto& feNode = static_cast<const SkSVGFe&>(*child);
|
||||
const auto& feResultType = feNode.getResult();
|
||||
|
||||
// Propagate any inherited properties that may impact filter effect behavior (e.g.
|
||||
// color-interpolation-filters). We call this explicitly here because the SkSVGFe
|
||||
// nodes do not participate in the normal onRender path, which is when property
|
||||
// propagation currently occurs.
|
||||
SkSVGRenderContext localCtx(ctx);
|
||||
feNode.applyProperties(&localCtx);
|
||||
|
||||
// TODO: there are specific composition rules that need to be followed
|
||||
filter = feNode.makeImageFilter(ctx, fctx);
|
||||
// TODO: perform colorspace conversions depending on 'color-interpolation-filters' setting
|
||||
// of the current node and its inputs.
|
||||
filter = feNode.makeImageFilter(localCtx, fctx);
|
||||
|
||||
if (!feResultType.isEmpty()) {
|
||||
fctx.registerResult(feResultType, filter, feNode.resolveFilterSubregion(ctx, fctx));
|
||||
fctx.registerResult(feResultType, filter, feNode.resolveFilterSubregion(localCtx, fctx));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,33 +88,34 @@ bool SkSVGNode::parseAndSetAttribute(const char* n, const char* v) {
|
||||
SkSVGAttributeParser::parseProperty<decltype(fPresentationAttributes.f##attrName)>( \
|
||||
svgName, n, v))
|
||||
|
||||
return PARSE_AND_SET("clip-path" , ClipPath)
|
||||
|| PARSE_AND_SET("clip-rule" , ClipRule)
|
||||
|| PARSE_AND_SET("color" , Color)
|
||||
|| PARSE_AND_SET("fill" , Fill)
|
||||
|| PARSE_AND_SET("fill-opacity" , FillOpacity)
|
||||
|| PARSE_AND_SET("fill-rule" , FillRule)
|
||||
|| PARSE_AND_SET("filter" , Filter)
|
||||
|| PARSE_AND_SET("flood-color" , FloodColor)
|
||||
|| PARSE_AND_SET("flood-opacity" , FloodOpacity)
|
||||
|| PARSE_AND_SET("font-family" , FontFamily)
|
||||
|| PARSE_AND_SET("font-size" , FontSize)
|
||||
|| PARSE_AND_SET("font-style" , FontStyle)
|
||||
|| PARSE_AND_SET("font-weight" , FontWeight)
|
||||
|| PARSE_AND_SET("mask" , Mask)
|
||||
|| 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)
|
||||
|| PARSE_AND_SET("stroke-linecap" , StrokeLineCap)
|
||||
|| PARSE_AND_SET("stroke-linejoin" , StrokeLineJoin)
|
||||
|| PARSE_AND_SET("stroke-miterlimit", StrokeMiterLimit)
|
||||
|| PARSE_AND_SET("stroke-opacity" , StrokeOpacity)
|
||||
|| PARSE_AND_SET("stroke-width" , StrokeWidth)
|
||||
|| PARSE_AND_SET("text-anchor" , TextAnchor)
|
||||
|| PARSE_AND_SET("visibility" , Visibility);
|
||||
return PARSE_AND_SET( "clip-path" , ClipPath)
|
||||
|| PARSE_AND_SET("clip-rule" , ClipRule)
|
||||
|| PARSE_AND_SET("color" , Color)
|
||||
|| PARSE_AND_SET("color-interpolation-filters", ColorInterpolationFilters)
|
||||
|| PARSE_AND_SET("fill" , Fill)
|
||||
|| PARSE_AND_SET("fill-opacity" , FillOpacity)
|
||||
|| PARSE_AND_SET("fill-rule" , FillRule)
|
||||
|| PARSE_AND_SET("filter" , Filter)
|
||||
|| PARSE_AND_SET("flood-color" , FloodColor)
|
||||
|| PARSE_AND_SET("flood-opacity" , FloodOpacity)
|
||||
|| PARSE_AND_SET("font-family" , FontFamily)
|
||||
|| PARSE_AND_SET("font-size" , FontSize)
|
||||
|| PARSE_AND_SET("font-style" , FontStyle)
|
||||
|| PARSE_AND_SET("font-weight" , FontWeight)
|
||||
|| PARSE_AND_SET("mask" , Mask)
|
||||
|| 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)
|
||||
|| PARSE_AND_SET("stroke-linecap" , StrokeLineCap)
|
||||
|| PARSE_AND_SET("stroke-linejoin" , StrokeLineJoin)
|
||||
|| PARSE_AND_SET("stroke-miterlimit" , StrokeMiterLimit)
|
||||
|| PARSE_AND_SET("stroke-opacity" , StrokeOpacity)
|
||||
|| PARSE_AND_SET("stroke-width" , StrokeWidth)
|
||||
|| PARSE_AND_SET("text-anchor" , TextAnchor)
|
||||
|| PARSE_AND_SET("visibility" , Visibility);
|
||||
|
||||
#undef PARSE_AND_SET
|
||||
}
|
||||
|
@ -261,6 +261,13 @@ void commitToPaint<SkSVGAttribute::kColor>(const SkSVGPresentationAttributes&,
|
||||
// Not part of the SkPaint state; applied via 'currentColor' color value
|
||||
}
|
||||
|
||||
template <>
|
||||
void commitToPaint<SkSVGAttribute::kColorInterpolationFilters>(const SkSVGPresentationAttributes&,
|
||||
const SkSVGRenderContext&,
|
||||
SkSVGPresentationContext*) {
|
||||
// Not part of the SkPaint state; applied at render time.
|
||||
}
|
||||
|
||||
template <>
|
||||
void commitToPaint<SkSVGAttribute::kFontFamily>(const SkSVGPresentationAttributes&,
|
||||
const SkSVGRenderContext&,
|
||||
@ -406,6 +413,7 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
|
||||
ApplyLazyInheritedAttribute(TextAnchor);
|
||||
ApplyLazyInheritedAttribute(Visibility);
|
||||
ApplyLazyInheritedAttribute(Color);
|
||||
ApplyLazyInheritedAttribute(ColorInterpolationFilters);
|
||||
|
||||
// Local 'color' attribute: update paints for attributes that are set to 'currentColor'.
|
||||
if (attrs.fColor.isValue()) {
|
||||
|
Loading…
Reference in New Issue
Block a user