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