| /* | |
| * Copyright 2020 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "modules/svg/include/SkSVGFeDisplacementMap.h" | |
| #include "include/core/SkImageFilter.h" | |
| #include "include/core/SkM44.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/effects/SkImageFilters.h" | |
| #include "modules/svg/include/SkSVGAttributeParser.h" | |
| #include "modules/svg/include/SkSVGFilterContext.h" | |
| #include "modules/svg/include/SkSVGRenderContext.h" | |
| #include <tuple> | |
| bool SkSVGFeDisplacementMap::parseAndSetAttribute(const char* name, const char* value) { | |
| return INHERITED::parseAndSetAttribute(name, value) || | |
| this->setIn2(SkSVGAttributeParser::parse<SkSVGFeInputType>("in2", name, value)) || | |
| this->setXChannelSelector( | |
| SkSVGAttributeParser::parse<SkSVGFeDisplacementMap::ChannelSelector>( | |
| "xChannelSelector", name, value)) || | |
| this->setYChannelSelector( | |
| SkSVGAttributeParser::parse<SkSVGFeDisplacementMap::ChannelSelector>( | |
| "yChannelSelector", name, value)) || | |
| this->setScale(SkSVGAttributeParser::parse<SkSVGNumberType>("scale", name, value)); | |
| } | |
| sk_sp<SkImageFilter> SkSVGFeDisplacementMap::onMakeImageFilter( | |
| const SkSVGRenderContext& ctx, const SkSVGFilterContext& fctx) const { | |
| const SkRect cropRect = this->resolveFilterSubregion(ctx, fctx); | |
| const SkSVGColorspace colorspace = this->resolveColorspace(ctx, fctx); | |
| // According to spec https://www.w3.org/TR/SVG11/filters.html#feDisplacementMapElement, | |
| // the 'in' source image must remain in its current colorspace. | |
| sk_sp<SkImageFilter> in = fctx.resolveInput(ctx, this->getIn()); | |
| sk_sp<SkImageFilter> in2 = fctx.resolveInput(ctx, this->getIn2(), colorspace); | |
| SkScalar scale = fScale; | |
| if (fctx.primitiveUnits().type() == SkSVGObjectBoundingBoxUnits::Type::kObjectBoundingBox) { | |
| const auto obbt = ctx.transformForCurrentOBB(fctx.primitiveUnits()); | |
| scale = SkSVGLengthContext({obbt.scale.x, obbt.scale.y}) | |
| .resolve(SkSVGLength(scale, SkSVGLength::Unit::kPercentage), | |
| SkSVGLengthContext::LengthType::kOther); | |
| } | |
| return SkImageFilters::DisplacementMap( | |
| fXChannelSelector, fYChannelSelector, scale, in2, in, cropRect); | |
| } | |
| SkSVGColorspace SkSVGFeDisplacementMap::resolveColorspace(const SkSVGRenderContext& ctx, | |
| const SkSVGFilterContext& fctx) const { | |
| // According to spec https://www.w3.org/TR/SVG11/filters.html#feDisplacementMapElement, | |
| // the 'in' source image must remain in its current colorspace, which means the colorspace of | |
| // this FE node is the same as the input. | |
| return fctx.resolveInputColorspace(ctx, this->getIn()); | |
| } | |
| template <> | |
| bool SkSVGAttributeParser::parse<SkSVGFeDisplacementMap::ChannelSelector>( | |
| SkSVGFeDisplacementMap::ChannelSelector* channel) { | |
| static constexpr std::tuple<const char*, SkSVGFeDisplacementMap::ChannelSelector> gMap[] = { | |
| { "R", SkSVGFeDisplacementMap::ChannelSelector::kR }, | |
| { "G", SkSVGFeDisplacementMap::ChannelSelector::kG }, | |
| { "B", SkSVGFeDisplacementMap::ChannelSelector::kB }, | |
| { "A", SkSVGFeDisplacementMap::ChannelSelector::kA }, | |
| }; | |
| return this->parseEnumMap(gMap, channel) && this->parseEOSToken(); | |
| } |