1 /* 2 * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2008 Eric Seidel <eric (at) webkit.org> 5 * Copyright (C) 2008 Dirk Schulze <krit (at) webkit.org> 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 */ 23 24 #include "config.h" 25 26 #include "core/svg/SVGLinearGradientElement.h" 27 28 #include "core/rendering/svg/RenderSVGResourceLinearGradient.h" 29 #include "core/svg/LinearGradientAttributes.h" 30 #include "core/svg/SVGElementInstance.h" 31 #include "core/svg/SVGLength.h" 32 #include "core/svg/SVGTransformList.h" 33 34 namespace WebCore { 35 36 // Animated property definitions 37 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x1Attr, X1, x1) 38 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y1Attr, Y1, y1) 39 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x2Attr, X2, x2) 40 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y2Attr, Y2, y2) 41 42 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGLinearGradientElement) 43 REGISTER_LOCAL_ANIMATED_PROPERTY(x1) 44 REGISTER_LOCAL_ANIMATED_PROPERTY(y1) 45 REGISTER_LOCAL_ANIMATED_PROPERTY(x2) 46 REGISTER_LOCAL_ANIMATED_PROPERTY(y2) 47 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGradientElement) 48 END_REGISTER_ANIMATED_PROPERTIES 49 50 inline SVGLinearGradientElement::SVGLinearGradientElement(Document& document) 51 : SVGGradientElement(SVGNames::linearGradientTag, document) 52 , m_x1(LengthModeWidth) 53 , m_y1(LengthModeHeight) 54 , m_x2(LengthModeWidth, "100%") 55 , m_y2(LengthModeHeight) 56 { 57 // Spec: If the x2 attribute is not specified, the effect is as if a value of "100%" were specified. 58 ScriptWrappable::init(this); 59 registerAnimatedPropertiesForSVGLinearGradientElement(); 60 } 61 62 PassRefPtr<SVGLinearGradientElement> SVGLinearGradientElement::create(Document& document) 63 { 64 return adoptRef(new SVGLinearGradientElement(document)); 65 } 66 67 bool SVGLinearGradientElement::isSupportedAttribute(const QualifiedName& attrName) 68 { 69 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 70 if (supportedAttributes.isEmpty()) { 71 supportedAttributes.add(SVGNames::x1Attr); 72 supportedAttributes.add(SVGNames::x2Attr); 73 supportedAttributes.add(SVGNames::y1Attr); 74 supportedAttributes.add(SVGNames::y2Attr); 75 } 76 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 77 } 78 79 void SVGLinearGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 80 { 81 SVGParsingError parseError = NoError; 82 83 if (!isSupportedAttribute(name)) 84 SVGGradientElement::parseAttribute(name, value); 85 else if (name == SVGNames::x1Attr) 86 setX1BaseValue(SVGLength::construct(LengthModeWidth, value, parseError)); 87 else if (name == SVGNames::y1Attr) 88 setY1BaseValue(SVGLength::construct(LengthModeHeight, value, parseError)); 89 else if (name == SVGNames::x2Attr) 90 setX2BaseValue(SVGLength::construct(LengthModeWidth, value, parseError)); 91 else if (name == SVGNames::y2Attr) 92 setY2BaseValue(SVGLength::construct(LengthModeHeight, value, parseError)); 93 else 94 ASSERT_NOT_REACHED(); 95 96 reportAttributeParsingError(parseError, name, value); 97 } 98 99 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName& attrName) 100 { 101 if (!isSupportedAttribute(attrName)) { 102 SVGGradientElement::svgAttributeChanged(attrName); 103 return; 104 } 105 106 SVGElementInstance::InvalidationGuard invalidationGuard(this); 107 108 updateRelativeLengthsInformation(); 109 110 RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); 111 if (renderer) 112 renderer->invalidateCacheAndMarkForLayout(); 113 } 114 115 RenderObject* SVGLinearGradientElement::createRenderer(RenderStyle*) 116 { 117 return new RenderSVGResourceLinearGradient(this); 118 } 119 120 bool SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttributes& attributes) 121 { 122 HashSet<SVGGradientElement*> processedGradients; 123 124 bool isLinear = true; 125 SVGGradientElement* current = this; 126 127 while (current) { 128 if (!current->renderer()) 129 return false; 130 131 if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr)) 132 attributes.setSpreadMethod(current->spreadMethodCurrentValue()); 133 134 if (!attributes.hasGradientUnits() && current->hasAttribute(SVGNames::gradientUnitsAttr)) 135 attributes.setGradientUnits(current->gradientUnitsCurrentValue()); 136 137 if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) { 138 AffineTransform transform; 139 current->gradientTransformCurrentValue().concatenate(transform); 140 attributes.setGradientTransform(transform); 141 } 142 143 if (!attributes.hasStops()) { 144 const Vector<Gradient::ColorStop>& stops(current->buildStops()); 145 if (!stops.isEmpty()) 146 attributes.setStops(stops); 147 } 148 149 if (isLinear) { 150 SVGLinearGradientElement* linear = toSVGLinearGradientElement(current); 151 152 if (!attributes.hasX1() && current->hasAttribute(SVGNames::x1Attr)) 153 attributes.setX1(linear->x1CurrentValue()); 154 155 if (!attributes.hasY1() && current->hasAttribute(SVGNames::y1Attr)) 156 attributes.setY1(linear->y1CurrentValue()); 157 158 if (!attributes.hasX2() && current->hasAttribute(SVGNames::x2Attr)) 159 attributes.setX2(linear->x2CurrentValue()); 160 161 if (!attributes.hasY2() && current->hasAttribute(SVGNames::y2Attr)) 162 attributes.setY2(linear->y2CurrentValue()); 163 } 164 165 processedGradients.add(current); 166 167 // Respect xlink:href, take attributes from referenced element 168 Node* refNode = SVGURIReference::targetElementFromIRIString(current->hrefCurrentValue(), document()); 169 if (refNode && (refNode->hasTagName(SVGNames::linearGradientTag) || refNode->hasTagName(SVGNames::radialGradientTag))) { 170 current = toSVGGradientElement(refNode); 171 172 // Cycle detection 173 if (processedGradients.contains(current)) { 174 current = 0; 175 break; 176 } 177 178 isLinear = current->hasTagName(SVGNames::linearGradientTag); 179 } else 180 current = 0; 181 } 182 183 return true; 184 } 185 186 bool SVGLinearGradientElement::selfHasRelativeLengths() const 187 { 188 return x1CurrentValue().isRelative() 189 || y1CurrentValue().isRelative() 190 || x2CurrentValue().isRelative() 191 || y2CurrentValue().isRelative(); 192 } 193 194 } 195