1 /*
2  * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "third_party/blink/renderer/core/svg/svg_fe_blend_element.h"
22 
23 #include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
24 #include "third_party/blink/renderer/core/svg/svg_enumeration_map.h"
25 #include "third_party/blink/renderer/core/svg_names.h"
26 #include "third_party/blink/renderer/platform/graphics/filters/fe_blend.h"
27 #include "third_party/blink/renderer/platform/heap/heap.h"
28 
29 namespace blink {
30 
ToBlendMode(SVGFEBlendElement::Mode mode)31 static BlendMode ToBlendMode(SVGFEBlendElement::Mode mode) {
32 #define MAP_BLEND_MODE(MODENAME)           \
33   case SVGFEBlendElement::kMode##MODENAME: \
34     return BlendMode::k##MODENAME
35 
36   switch (mode) {
37     MAP_BLEND_MODE(Normal);
38     MAP_BLEND_MODE(Multiply);
39     MAP_BLEND_MODE(Screen);
40     MAP_BLEND_MODE(Darken);
41     MAP_BLEND_MODE(Lighten);
42     MAP_BLEND_MODE(Overlay);
43     MAP_BLEND_MODE(ColorDodge);
44     MAP_BLEND_MODE(ColorBurn);
45     MAP_BLEND_MODE(HardLight);
46     MAP_BLEND_MODE(SoftLight);
47     MAP_BLEND_MODE(Difference);
48     MAP_BLEND_MODE(Exclusion);
49     MAP_BLEND_MODE(Hue);
50     MAP_BLEND_MODE(Saturation);
51     MAP_BLEND_MODE(Color);
52     MAP_BLEND_MODE(Luminosity);
53     default:
54       NOTREACHED();
55       return BlendMode::kNormal;
56   }
57 #undef MAP_BLEND_MODE
58 }
59 
60 template <>
GetEnumerationMap()61 const SVGEnumerationMap& GetEnumerationMap<SVGFEBlendElement::Mode>() {
62   static const SVGEnumerationMap::Entry enum_items[] = {
63       {SVGFEBlendElement::kModeNormal, "normal"},
64       {SVGFEBlendElement::kModeMultiply, "multiply"},
65       {SVGFEBlendElement::kModeScreen, "screen"},
66       {SVGFEBlendElement::kModeDarken, "darken"},
67       {SVGFEBlendElement::kModeLighten, "lighten"},
68       {SVGFEBlendElement::kModeOverlay, "overlay"},
69       {SVGFEBlendElement::kModeColorDodge, "color-dodge"},
70       {SVGFEBlendElement::kModeColorBurn, "color-burn"},
71       {SVGFEBlendElement::kModeHardLight, "hard-light"},
72       {SVGFEBlendElement::kModeSoftLight, "soft-light"},
73       {SVGFEBlendElement::kModeDifference, "difference"},
74       {SVGFEBlendElement::kModeExclusion, "exclusion"},
75       {SVGFEBlendElement::kModeHue, "hue"},
76       {SVGFEBlendElement::kModeSaturation, "saturation"},
77       {SVGFEBlendElement::kModeColor, "color"},
78       {SVGFEBlendElement::kModeLuminosity, "luminosity"},
79   };
80   static const SVGEnumerationMap entries(enum_items);
81   return entries;
82 }
83 
SVGFEBlendElement(Document & document)84 SVGFEBlendElement::SVGFEBlendElement(Document& document)
85     : SVGFilterPrimitiveStandardAttributes(svg_names::kFEBlendTag, document),
86       in1_(MakeGarbageCollected<SVGAnimatedString>(this, svg_names::kInAttr)),
87       in2_(MakeGarbageCollected<SVGAnimatedString>(this, svg_names::kIn2Attr)),
88       mode_(MakeGarbageCollected<SVGAnimatedEnumeration<Mode>>(
89           this,
90           svg_names::kModeAttr,
91           SVGFEBlendElement::kModeNormal)) {
92   AddToPropertyMap(in1_);
93   AddToPropertyMap(in2_);
94   AddToPropertyMap(mode_);
95 }
96 
Trace(Visitor * visitor)97 void SVGFEBlendElement::Trace(Visitor* visitor) {
98   visitor->Trace(in1_);
99   visitor->Trace(in2_);
100   visitor->Trace(mode_);
101   SVGFilterPrimitiveStandardAttributes::Trace(visitor);
102 }
103 
SetFilterEffectAttribute(FilterEffect * effect,const QualifiedName & attr_name)104 bool SVGFEBlendElement::SetFilterEffectAttribute(
105     FilterEffect* effect,
106     const QualifiedName& attr_name) {
107   FEBlend* blend = static_cast<FEBlend*>(effect);
108   if (attr_name == svg_names::kModeAttr)
109     return blend->SetBlendMode(ToBlendMode(mode_->CurrentValue()->EnumValue()));
110 
111   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
112       effect, attr_name);
113 }
114 
SvgAttributeChanged(const QualifiedName & attr_name)115 void SVGFEBlendElement::SvgAttributeChanged(const QualifiedName& attr_name) {
116   if (attr_name == svg_names::kModeAttr) {
117     SVGElement::InvalidationGuard invalidation_guard(this);
118     PrimitiveAttributeChanged(attr_name);
119     return;
120   }
121 
122   if (attr_name == svg_names::kInAttr || attr_name == svg_names::kIn2Attr) {
123     SVGElement::InvalidationGuard invalidation_guard(this);
124     Invalidate();
125     return;
126   }
127 
128   SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(attr_name);
129 }
130 
Build(SVGFilterBuilder * filter_builder,Filter * filter)131 FilterEffect* SVGFEBlendElement::Build(SVGFilterBuilder* filter_builder,
132                                        Filter* filter) {
133   FilterEffect* input1 = filter_builder->GetEffectById(
134       AtomicString(in1_->CurrentValue()->Value()));
135   FilterEffect* input2 = filter_builder->GetEffectById(
136       AtomicString(in2_->CurrentValue()->Value()));
137   DCHECK(input1);
138   DCHECK(input2);
139 
140   auto* effect = MakeGarbageCollected<FEBlend>(
141       filter, ToBlendMode(mode_->CurrentValue()->EnumValue()));
142   FilterEffectVector& input_effects = effect->InputEffects();
143   input_effects.ReserveCapacity(2);
144   input_effects.push_back(input1);
145   input_effects.push_back(input2);
146   return effect;
147 }
148 
149 }  // namespace blink
150