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 "config.h"
22
23#include "core/svg/SVGFEBlendElement.h"
24
25#include "core/SVGNames.h"
26#include "platform/graphics/filters/FEBlend.h"
27#include "platform/graphics/filters/FilterEffect.h"
28#include "core/svg/graphics/filters/SVGFilterBuilder.h"
29
30namespace blink {
31
32static WebBlendMode toWebBlendMode(SVGFEBlendElement::Mode mode)
33{
34#define MAP_BLEND_MODE(MODENAME)            \
35    case SVGFEBlendElement::Mode##MODENAME: \
36        return WebBlendMode##MODENAME
37
38    switch (mode) {
39        MAP_BLEND_MODE(Normal);
40        MAP_BLEND_MODE(Multiply);
41        MAP_BLEND_MODE(Screen);
42        MAP_BLEND_MODE(Darken);
43        MAP_BLEND_MODE(Lighten);
44        MAP_BLEND_MODE(Overlay);
45        MAP_BLEND_MODE(ColorDodge);
46        MAP_BLEND_MODE(ColorBurn);
47        MAP_BLEND_MODE(HardLight);
48        MAP_BLEND_MODE(SoftLight);
49        MAP_BLEND_MODE(Difference);
50        MAP_BLEND_MODE(Exclusion);
51        MAP_BLEND_MODE(Hue);
52        MAP_BLEND_MODE(Saturation);
53        MAP_BLEND_MODE(Color);
54        MAP_BLEND_MODE(Luminosity);
55    default:
56        ASSERT_NOT_REACHED();
57        return WebBlendModeNormal;
58    }
59#undef MAP_BLEND_MODE
60}
61
62template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGFEBlendElement::Mode>()
63{
64    DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ());
65    if (entries.isEmpty()) {
66        entries.append(std::make_pair(SVGFEBlendElement::ModeNormal, "normal"));
67        entries.append(std::make_pair(SVGFEBlendElement::ModeMultiply, "multiply"));
68        entries.append(std::make_pair(SVGFEBlendElement::ModeScreen, "screen"));
69        entries.append(std::make_pair(SVGFEBlendElement::ModeDarken, "darken"));
70        entries.append(std::make_pair(SVGFEBlendElement::ModeLighten, "lighten"));
71        entries.append(std::make_pair(SVGFEBlendElement::ModeOverlay, "overlay"));
72        entries.append(std::make_pair(SVGFEBlendElement::ModeColorDodge, "color-dodge"));
73        entries.append(std::make_pair(SVGFEBlendElement::ModeColorBurn, "color-burn"));
74        entries.append(std::make_pair(SVGFEBlendElement::ModeHardLight, "hard-light"));
75        entries.append(std::make_pair(SVGFEBlendElement::ModeSoftLight, "soft-light"));
76        entries.append(std::make_pair(SVGFEBlendElement::ModeDifference, "difference"));
77        entries.append(std::make_pair(SVGFEBlendElement::ModeExclusion, "exclusion"));
78        entries.append(std::make_pair(SVGFEBlendElement::ModeHue, "hue"));
79        entries.append(std::make_pair(SVGFEBlendElement::ModeSaturation, "saturation"));
80        entries.append(std::make_pair(SVGFEBlendElement::ModeColor, "color"));
81        entries.append(std::make_pair(SVGFEBlendElement::ModeLuminosity, "luminosity"));
82    }
83    return entries;
84}
85
86template<> unsigned short getMaxExposedEnumValue<SVGFEBlendElement::Mode>()
87{
88    return SVGFEBlendElement::ModeLighten;
89}
90
91inline SVGFEBlendElement::SVGFEBlendElement(Document& document)
92    : SVGFilterPrimitiveStandardAttributes(SVGNames::feBlendTag, document)
93    , m_in1(SVGAnimatedString::create(this, SVGNames::inAttr, SVGString::create()))
94    , m_in2(SVGAnimatedString::create(this, SVGNames::in2Attr, SVGString::create()))
95    , m_mode(SVGAnimatedEnumeration<Mode>::create(this, SVGNames::modeAttr, SVGFEBlendElement::ModeNormal))
96{
97    addToPropertyMap(m_in1);
98    addToPropertyMap(m_in2);
99    addToPropertyMap(m_mode);
100}
101
102DEFINE_NODE_FACTORY(SVGFEBlendElement)
103
104bool SVGFEBlendElement::isSupportedAttribute(const QualifiedName& attrName)
105{
106    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
107    if (supportedAttributes.isEmpty()) {
108        supportedAttributes.add(SVGNames::modeAttr);
109        supportedAttributes.add(SVGNames::inAttr);
110        supportedAttributes.add(SVGNames::in2Attr);
111    }
112    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
113}
114
115void SVGFEBlendElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
116{
117    parseAttributeNew(name, value);
118}
119
120bool SVGFEBlendElement::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName)
121{
122    FEBlend* blend = static_cast<FEBlend*>(effect);
123    if (attrName == SVGNames::modeAttr)
124        return blend->setBlendMode(toWebBlendMode(m_mode->currentValue()->enumValue()));
125
126    ASSERT_NOT_REACHED();
127    return false;
128}
129
130void SVGFEBlendElement::svgAttributeChanged(const QualifiedName& attrName)
131{
132    if (!isSupportedAttribute(attrName)) {
133        SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName);
134        return;
135    }
136
137    SVGElement::InvalidationGuard invalidationGuard(this);
138
139    if (attrName == SVGNames::modeAttr) {
140        primitiveAttributeChanged(attrName);
141        return;
142    }
143
144    if (attrName == SVGNames::inAttr || attrName == SVGNames::in2Attr) {
145        invalidate();
146        return;
147    }
148
149    ASSERT_NOT_REACHED();
150}
151
152PassRefPtr<FilterEffect> SVGFEBlendElement::build(SVGFilterBuilder* filterBuilder, Filter* filter)
153{
154    FilterEffect* input1 = filterBuilder->getEffectById(AtomicString(m_in1->currentValue()->value()));
155    FilterEffect* input2 = filterBuilder->getEffectById(AtomicString(m_in2->currentValue()->value()));
156
157    if (!input1 || !input2)
158        return nullptr;
159
160    RefPtr<FilterEffect> effect = FEBlend::create(filter, toWebBlendMode(m_mode->currentValue()->enumValue()));
161    FilterEffectVector& inputEffects = effect->inputEffects();
162    inputEffects.reserveCapacity(2);
163    inputEffects.append(input1);
164    inputEffects.append(input2);
165    return effect.release();
166}
167
168}
169