Reland "[svg] Perform colorspace conversions for filter effects"
This reverts commit36acb7b10c
. Reason for revert: artifacts in 1010102 are expected Original change's description: > Revert "[svg] Perform colorspace conversions for filter effects" > > This reverts commita0880eda22
. > > Reason for revert: visual artifacts in 10-bit color depth (10-10-10-2) > > Original change's description: > > [svg] Perform colorspace conversions for filter effects > > > > A filter effect can optionally be specified to operate in either sRGB > > or linearRGB, according to the SVG spec: > > > > https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperties > > > > This CL adds any necessary conversion steps (SkColorFilters) while > > constructing the filter DAG. The default filter effect color space is > > linearRGB. We should now be passing the filters-gauss-* W3C tests. > > > > Specific changes: > > - Tag filter effect results with their colorspace when storing them in > > the filter context map > > - Add an SkColorFolor conversion step as necessary when resolving filter > > effect inputs > > > > Bug: skia:10841 > > Change-Id: Ide12698ea64c4d40f09df93a60718788809086fa > > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/353078 > > Commit-Queue: Tyler Denniston <tdenniston@google.com> > > Reviewed-by: Florin Malita <fmalita@chromium.org> > > TBR=fmalita@chromium.org,tdenniston@google.com > > Change-Id: Id4a33c49643039cfb2d2867a1513e8ee1d7b181a > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: skia:10841 > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/353630 > Reviewed-by: John Stiles <johnstiles@google.com> > Commit-Queue: John Stiles <johnstiles@google.com> TBR=fmalita@chromium.org,tdenniston@google.com,johnstiles@google.com # Not skipping CQ checks because this is a reland. Bug: skia:10841 Change-Id: Id6d9e01d9b18ebfb6f9a6cb74518ad5cd73ea00a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/353777 Reviewed-by: Tyler Denniston <tdenniston@google.com> Commit-Queue: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
parent
bf562de155
commit
8f78d55284
@ -30,17 +30,18 @@ public:
|
|||||||
|
|
||||||
const SkSVGObjectBoundingBoxUnits& primitiveUnits() const { return fPrimitiveUnits; }
|
const SkSVGObjectBoundingBoxUnits& primitiveUnits() const { return fPrimitiveUnits; }
|
||||||
|
|
||||||
void registerResult(const SkSVGStringType&, const sk_sp<SkImageFilter>&, const SkRect&);
|
void registerResult(const SkSVGStringType&, const sk_sp<SkImageFilter>&, const SkRect&, SkSVGColorspace);
|
||||||
|
|
||||||
sk_sp<SkImageFilter> resolveInput(const SkSVGRenderContext&, const SkSVGFeInputType&) const;
|
sk_sp<SkImageFilter> resolveInput(const SkSVGRenderContext&, const SkSVGFeInputType&, SkSVGColorspace) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Result {
|
struct Result {
|
||||||
sk_sp<SkImageFilter> fImageFilter;
|
sk_sp<SkImageFilter> fImageFilter;
|
||||||
SkRect fFilterSubregion;
|
SkRect fFilterSubregion;
|
||||||
|
SkSVGColorspace fColorspace;
|
||||||
};
|
};
|
||||||
|
|
||||||
sk_sp<SkImageFilter> findResultById(const SkSVGStringType&) const;
|
const Result* findResultById(const SkSVGStringType&) const;
|
||||||
|
|
||||||
SkRect fFilterEffectsRegion;
|
SkRect fFilterEffectsRegion;
|
||||||
|
|
||||||
|
@ -84,7 +84,9 @@ SkRect SkSVGFe::resolveFilterSubregion(const SkSVGRenderContext& ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkSVGColorspace SkSVGFe::resolveColorspace(const SkSVGRenderContext& ctx) const {
|
SkSVGColorspace SkSVGFe::resolveColorspace(const SkSVGRenderContext& ctx) const {
|
||||||
return *ctx.presentationContext().fInherited.fColorInterpolationFilters;
|
constexpr SkSVGColorspace kDefaultCS = SkSVGColorspace::kSRGB;
|
||||||
|
const SkSVGColorspace cs = *ctx.presentationContext().fInherited.fColorInterpolationFilters;
|
||||||
|
return cs == SkSVGColorspace::kAuto ? kDefaultCS : cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkSVGFe::applyProperties(SkSVGRenderContext* ctx) const { this->onPrepareToRender(ctx); }
|
void SkSVGFe::applyProperties(SkSVGRenderContext* ctx) const { this->onPrepareToRender(ctx); }
|
||||||
|
@ -91,9 +91,10 @@ SkColorMatrix SkSVGFeColorMatrix::MakeLuminanceToAlpha() {
|
|||||||
|
|
||||||
sk_sp<SkImageFilter> SkSVGFeColorMatrix::onMakeImageFilter(const SkSVGRenderContext& ctx,
|
sk_sp<SkImageFilter> SkSVGFeColorMatrix::onMakeImageFilter(const SkSVGRenderContext& ctx,
|
||||||
const SkSVGFilterContext& fctx) const {
|
const SkSVGFilterContext& fctx) const {
|
||||||
return SkImageFilters::ColorFilter(SkColorFilters::Matrix(makeMatrixForType()),
|
return SkImageFilters::ColorFilter(
|
||||||
fctx.resolveInput(ctx, this->getIn()),
|
SkColorFilters::Matrix(makeMatrixForType()),
|
||||||
this->resolveFilterSubregion(ctx, fctx));
|
fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx)),
|
||||||
|
this->resolveFilterSubregion(ctx, fctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> bool SkSVGAttributeParser::parse(SkSVGFeColorMatrixValues* values) {
|
template <> bool SkSVGAttributeParser::parse(SkSVGFeColorMatrixValues* values) {
|
||||||
|
@ -47,8 +47,9 @@ SkBlendMode SkSVGFeComposite::BlendModeForOperator(SkSVGFeCompositeOperator op)
|
|||||||
sk_sp<SkImageFilter> SkSVGFeComposite::onMakeImageFilter(const SkSVGRenderContext& ctx,
|
sk_sp<SkImageFilter> SkSVGFeComposite::onMakeImageFilter(const SkSVGRenderContext& ctx,
|
||||||
const SkSVGFilterContext& fctx) const {
|
const SkSVGFilterContext& fctx) const {
|
||||||
const SkRect cropRect = this->resolveFilterSubregion(ctx, fctx);
|
const SkRect cropRect = this->resolveFilterSubregion(ctx, fctx);
|
||||||
const sk_sp<SkImageFilter> background = fctx.resolveInput(ctx, fIn2);
|
const SkSVGColorspace colorspace = this->resolveColorspace(ctx);
|
||||||
const sk_sp<SkImageFilter> foreground = fctx.resolveInput(ctx, this->getIn());
|
const sk_sp<SkImageFilter> background = fctx.resolveInput(ctx, fIn2, colorspace);
|
||||||
|
const sk_sp<SkImageFilter> foreground = fctx.resolveInput(ctx, this->getIn(), colorspace);
|
||||||
if (fOperator == SkSVGFeCompositeOperator::kArithmetic) {
|
if (fOperator == SkSVGFeCompositeOperator::kArithmetic) {
|
||||||
constexpr bool enforcePMColor = true;
|
constexpr bool enforcePMColor = true;
|
||||||
return SkImageFilters::Arithmetic(
|
return SkImageFilters::Arithmetic(
|
||||||
|
@ -30,7 +30,7 @@ sk_sp<SkImageFilter> SkSVGFeGaussianBlur::onMakeImageFilter(const SkSVGRenderCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
return SkImageFilters::Blur(sigmaX, sigmaY,
|
return SkImageFilters::Blur(sigmaX, sigmaY,
|
||||||
fctx.resolveInput(ctx, this->getIn()),
|
fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx)),
|
||||||
this->resolveFilterSubregion(ctx, fctx));
|
this->resolveFilterSubregion(ctx, fctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "include/core/SkColorFilter.h"
|
||||||
#include "include/effects/SkImageFilters.h"
|
#include "include/effects/SkImageFilters.h"
|
||||||
#include "modules/svg/include/SkSVGFe.h"
|
#include "modules/svg/include/SkSVGFe.h"
|
||||||
#include "modules/svg/include/SkSVGFilter.h"
|
#include "modules/svg/include/SkSVGFilter.h"
|
||||||
@ -46,6 +47,7 @@ SkRect SkSVGFilter::resolveFilterRegion(const SkSVGRenderContext& ctx) const {
|
|||||||
sk_sp<SkImageFilter> SkSVGFilter::buildFilterDAG(const SkSVGRenderContext& ctx) const {
|
sk_sp<SkImageFilter> SkSVGFilter::buildFilterDAG(const SkSVGRenderContext& ctx) const {
|
||||||
sk_sp<SkImageFilter> filter;
|
sk_sp<SkImageFilter> filter;
|
||||||
SkSVGFilterContext fctx(resolveFilterRegion(ctx), fPrimitiveUnits);
|
SkSVGFilterContext fctx(resolveFilterRegion(ctx), fPrimitiveUnits);
|
||||||
|
SkSVGColorspace cs = SkSVGColorspace::kSRGB;
|
||||||
for (const auto& child : fChildren) {
|
for (const auto& child : fChildren) {
|
||||||
if (!SkSVGFe::IsFilterEffect(child)) {
|
if (!SkSVGFe::IsFilterEffect(child)) {
|
||||||
continue;
|
continue;
|
||||||
@ -62,14 +64,19 @@ sk_sp<SkImageFilter> SkSVGFilter::buildFilterDAG(const SkSVGRenderContext& ctx)
|
|||||||
feNode.applyProperties(&localCtx);
|
feNode.applyProperties(&localCtx);
|
||||||
|
|
||||||
// TODO: there are specific composition rules that need to be followed
|
// TODO: there are specific composition rules that need to be followed
|
||||||
// TODO: perform colorspace conversions depending on 'color-interpolation-filters' setting
|
cs = feNode.resolveColorspace(ctx);
|
||||||
// of the current node and its inputs.
|
|
||||||
filter = feNode.makeImageFilter(localCtx, fctx);
|
filter = feNode.makeImageFilter(localCtx, fctx);
|
||||||
|
|
||||||
if (!feResultType.isEmpty()) {
|
if (!feResultType.isEmpty()) {
|
||||||
fctx.registerResult(feResultType, filter, feNode.resolveFilterSubregion(localCtx, fctx));
|
fctx.registerResult(
|
||||||
|
feResultType, filter, feNode.resolveFilterSubregion(localCtx, fctx), cs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert to final destination colorspace
|
||||||
|
if (cs != SkSVGColorspace::kSRGB) {
|
||||||
|
filter = SkImageFilters::ColorFilter(SkColorFilters::LinearToSRGBGamma(), filter);
|
||||||
|
}
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,33 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "include/core/SkColorFilter.h"
|
||||||
#include "include/effects/SkImageFilters.h"
|
#include "include/effects/SkImageFilters.h"
|
||||||
#include "modules/svg/include/SkSVGFilterContext.h"
|
#include "modules/svg/include/SkSVGFilterContext.h"
|
||||||
#include "modules/svg/include/SkSVGNode.h"
|
#include "modules/svg/include/SkSVGNode.h"
|
||||||
#include "modules/svg/include/SkSVGRenderContext.h"
|
#include "modules/svg/include/SkSVGRenderContext.h"
|
||||||
#include "modules/svg/include/SkSVGTypes.h"
|
#include "modules/svg/include/SkSVGTypes.h"
|
||||||
|
|
||||||
sk_sp<SkImageFilter> SkSVGFilterContext::findResultById(const SkSVGStringType& id) const {
|
namespace {
|
||||||
const Result* res = fResults.find(id);
|
|
||||||
return res ? res->fImageFilter : nullptr;
|
sk_sp<SkImageFilter> ConvertFilterColorspace(sk_sp<SkImageFilter>&& input,
|
||||||
|
SkSVGColorspace src,
|
||||||
|
SkSVGColorspace dst) {
|
||||||
|
if (src == dst) {
|
||||||
|
return std::move(input);
|
||||||
|
} else if (src == SkSVGColorspace::kSRGB && dst == SkSVGColorspace::kLinearRGB) {
|
||||||
|
return SkImageFilters::ColorFilter(SkColorFilters::SRGBToLinearGamma(), input);
|
||||||
|
} else {
|
||||||
|
SkASSERT(src == SkSVGColorspace::kLinearRGB && dst == SkSVGColorspace::kSRGB);
|
||||||
|
return SkImageFilters::ColorFilter(SkColorFilters::LinearToSRGBGamma(), input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const SkSVGFilterContext::Result* SkSVGFilterContext::findResultById(
|
||||||
|
const SkSVGStringType& id) const {
|
||||||
|
return fResults.find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SkRect& SkSVGFilterContext::filterPrimitiveSubregion(const SkSVGFeInputType& input) const {
|
const SkRect& SkSVGFilterContext::filterPrimitiveSubregion(const SkSVGFeInputType& input) const {
|
||||||
@ -25,18 +43,24 @@ const SkRect& SkSVGFilterContext::filterPrimitiveSubregion(const SkSVGFeInputTyp
|
|||||||
|
|
||||||
void SkSVGFilterContext::registerResult(const SkSVGStringType& id,
|
void SkSVGFilterContext::registerResult(const SkSVGStringType& id,
|
||||||
const sk_sp<SkImageFilter>& result,
|
const sk_sp<SkImageFilter>& result,
|
||||||
const SkRect& subregion) {
|
const SkRect& subregion,
|
||||||
|
SkSVGColorspace resultColorspace) {
|
||||||
SkASSERT(!id.isEmpty());
|
SkASSERT(!id.isEmpty());
|
||||||
fResults[id] = {result, subregion};
|
fResults[id] = {result, subregion, resultColorspace};
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<SkImageFilter> SkSVGFilterContext::resolveInput(const SkSVGRenderContext& ctx,
|
sk_sp<SkImageFilter> SkSVGFilterContext::resolveInput(const SkSVGRenderContext& ctx,
|
||||||
const SkSVGFeInputType& inputType) const {
|
const SkSVGFeInputType& inputType,
|
||||||
|
SkSVGColorspace colorspace) const {
|
||||||
|
SkSVGColorspace inputCS = SkSVGColorspace::kSRGB;
|
||||||
|
sk_sp<SkImageFilter> result;
|
||||||
switch (inputType.type()) {
|
switch (inputType.type()) {
|
||||||
case SkSVGFeInputType::Type::kSourceGraphic:
|
case SkSVGFeInputType::Type::kSourceGraphic:
|
||||||
return nullptr;
|
// Do nothing.
|
||||||
|
break;
|
||||||
case SkSVGFeInputType::Type::kFillPaint:
|
case SkSVGFeInputType::Type::kFillPaint:
|
||||||
return SkImageFilters::Paint(*ctx.fillPaint());
|
result = SkImageFilters::Paint(*ctx.fillPaint());
|
||||||
|
break;
|
||||||
case SkSVGFeInputType::Type::kStrokePaint: {
|
case SkSVGFeInputType::Type::kStrokePaint: {
|
||||||
// The paint filter doesn't handle stroke paints properly, so convert to fill for
|
// The paint filter doesn't handle stroke paints properly, so convert to fill for
|
||||||
// simplicity.
|
// simplicity.
|
||||||
@ -44,12 +68,21 @@ sk_sp<SkImageFilter> SkSVGFilterContext::resolveInput(const SkSVGRenderContext&
|
|||||||
// requires some extra work to handle all paint features (gradients, etc).
|
// requires some extra work to handle all paint features (gradients, etc).
|
||||||
SkPaint p = *ctx.strokePaint();
|
SkPaint p = *ctx.strokePaint();
|
||||||
p.setStyle(SkPaint::kFill_Style);
|
p.setStyle(SkPaint::kFill_Style);
|
||||||
return SkImageFilters::Paint(p);
|
result = SkImageFilters::Paint(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SkSVGFeInputType::Type::kFilterPrimitiveReference: {
|
||||||
|
const Result* res = findResultById(inputType.id());
|
||||||
|
if (res) {
|
||||||
|
result = res->fImageFilter;
|
||||||
|
inputCS = res->fColorspace;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case SkSVGFeInputType::Type::kFilterPrimitiveReference:
|
|
||||||
return findResultById(inputType.id());
|
|
||||||
default:
|
default:
|
||||||
SkDebugf("unhandled filter input type %d\n", inputType.type());
|
SkDebugf("unhandled filter input type %d\n", inputType.type());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ConvertFilterColorspace(std::move(result), inputCS, colorspace);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user