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