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/SVGLength.h" 31 #include "core/svg/SVGTransformList.h" 32 33 namespace WebCore { 34 35 inline SVGLinearGradientElement::SVGLinearGradientElement(Document& document) 36 : SVGGradientElement(SVGNames::linearGradientTag, document) 37 , m_x1(SVGAnimatedLength::create(this, SVGNames::x1Attr, SVGLength::create(LengthModeWidth), AllowNegativeLengths)) 38 , m_y1(SVGAnimatedLength::create(this, SVGNames::y1Attr, SVGLength::create(LengthModeHeight), AllowNegativeLengths)) 39 , m_x2(SVGAnimatedLength::create(this, SVGNames::x2Attr, SVGLength::create(LengthModeWidth), AllowNegativeLengths)) 40 , m_y2(SVGAnimatedLength::create(this, SVGNames::y2Attr, SVGLength::create(LengthModeHeight), AllowNegativeLengths)) 41 { 42 ScriptWrappable::init(this); 43 44 // Spec: If the x2 attribute is not specified, the effect is as if a value of "100%" were specified. 45 m_x2->setDefaultValueAsString("100%"); 46 47 addToPropertyMap(m_x1); 48 addToPropertyMap(m_y1); 49 addToPropertyMap(m_x2); 50 addToPropertyMap(m_y2); 51 } 52 53 DEFINE_NODE_FACTORY(SVGLinearGradientElement) 54 55 bool SVGLinearGradientElement::isSupportedAttribute(const QualifiedName& attrName) 56 { 57 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 58 if (supportedAttributes.isEmpty()) { 59 supportedAttributes.add(SVGNames::x1Attr); 60 supportedAttributes.add(SVGNames::x2Attr); 61 supportedAttributes.add(SVGNames::y1Attr); 62 supportedAttributes.add(SVGNames::y2Attr); 63 } 64 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 65 } 66 67 void SVGLinearGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 68 { 69 SVGParsingError parseError = NoError; 70 71 if (!isSupportedAttribute(name)) 72 SVGGradientElement::parseAttribute(name, value); 73 else if (name == SVGNames::x1Attr) 74 m_x1->setBaseValueAsString(value, parseError); 75 else if (name == SVGNames::y1Attr) 76 m_y1->setBaseValueAsString(value, parseError); 77 else if (name == SVGNames::x2Attr) 78 m_x2->setBaseValueAsString(value, parseError); 79 else if (name == SVGNames::y2Attr) 80 m_y2->setBaseValueAsString(value, parseError); 81 else 82 ASSERT_NOT_REACHED(); 83 84 reportAttributeParsingError(parseError, name, value); 85 } 86 87 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName& attrName) 88 { 89 if (!isSupportedAttribute(attrName)) { 90 SVGGradientElement::svgAttributeChanged(attrName); 91 return; 92 } 93 94 SVGElement::InvalidationGuard invalidationGuard(this); 95 96 updateRelativeLengthsInformation(); 97 98 RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); 99 if (renderer) 100 renderer->invalidateCacheAndMarkForLayout(); 101 } 102 103 RenderObject* SVGLinearGradientElement::createRenderer(RenderStyle*) 104 { 105 return new RenderSVGResourceLinearGradient(this); 106 } 107 108 static void setGradientAttributes(SVGGradientElement* element, LinearGradientAttributes& attributes, bool isLinear = true) 109 { 110 if (!attributes.hasSpreadMethod() && element->spreadMethod()->isSpecified()) 111 attributes.setSpreadMethod(element->spreadMethod()->currentValue()->enumValue()); 112 113 if (!attributes.hasGradientUnits() && element->gradientUnits()->isSpecified()) 114 attributes.setGradientUnits(element->gradientUnits()->currentValue()->enumValue()); 115 116 if (!attributes.hasGradientTransform() && element->gradientTransform()->isSpecified()) { 117 AffineTransform transform; 118 element->gradientTransform()->currentValue()->concatenate(transform); 119 attributes.setGradientTransform(transform); 120 } 121 122 if (!attributes.hasStops()) { 123 const Vector<Gradient::ColorStop>& stops(element->buildStops()); 124 if (!stops.isEmpty()) 125 attributes.setStops(stops); 126 } 127 128 if (isLinear) { 129 SVGLinearGradientElement* linear = toSVGLinearGradientElement(element); 130 131 if (!attributes.hasX1() && linear->x1()->isSpecified()) 132 attributes.setX1(linear->x1()->currentValue()); 133 134 if (!attributes.hasY1() && linear->y1()->isSpecified()) 135 attributes.setY1(linear->y1()->currentValue()); 136 137 if (!attributes.hasX2() && linear->x2()->isSpecified()) 138 attributes.setX2(linear->x2()->currentValue()); 139 140 if (!attributes.hasY2() && linear->y2()->isSpecified()) 141 attributes.setY2(linear->y2()->currentValue()); 142 } 143 } 144 145 bool SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttributes& attributes) 146 { 147 if (!renderer()) 148 return false; 149 150 HashSet<SVGGradientElement*> processedGradients; 151 SVGGradientElement* current = this; 152 153 setGradientAttributes(current, attributes); 154 processedGradients.add(current); 155 156 while (true) { 157 // Respect xlink:href, take attributes from referenced element 158 Node* refNode = SVGURIReference::targetElementFromIRIString(current->href()->currentValue()->value(), treeScope()); 159 if (refNode && isSVGGradientElement(*refNode)) { 160 current = toSVGGradientElement(refNode); 161 162 // Cycle detection 163 if (processedGradients.contains(current)) 164 return true; 165 166 if (!current->renderer()) 167 return false; 168 169 setGradientAttributes(current, attributes, isSVGLinearGradientElement(*current)); 170 processedGradients.add(current); 171 } else { 172 return true; 173 } 174 } 175 176 ASSERT_NOT_REACHED(); 177 return false; 178 } 179 180 bool SVGLinearGradientElement::selfHasRelativeLengths() const 181 { 182 return m_x1->currentValue()->isRelative() 183 || m_y1->currentValue()->isRelative() 184 || m_x2->currentValue()->isRelative() 185 || m_y2->currentValue()->isRelative(); 186 } 187 188 } 189