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/SVGRadialGradientElement.h" 27 28 #include "core/rendering/svg/RenderSVGResourceRadialGradient.h" 29 #include "core/svg/RadialGradientAttributes.h" 30 #include "core/svg/SVGTransformList.h" 31 32 namespace blink { 33 34 inline SVGRadialGradientElement::SVGRadialGradientElement(Document& document) 35 : SVGGradientElement(SVGNames::radialGradientTag, document) 36 , m_cx(SVGAnimatedLength::create(this, SVGNames::cxAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths)) 37 , m_cy(SVGAnimatedLength::create(this, SVGNames::cyAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths)) 38 , m_r(SVGAnimatedLength::create(this, SVGNames::rAttr, SVGLength::create(LengthModeOther), ForbidNegativeLengths)) 39 , m_fx(SVGAnimatedLength::create(this, SVGNames::fxAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths)) 40 , m_fy(SVGAnimatedLength::create(this, SVGNames::fyAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths)) 41 , m_fr(SVGAnimatedLength::create(this, SVGNames::frAttr, SVGLength::create(LengthModeOther), ForbidNegativeLengths)) 42 { 43 // Spec: If the cx/cy/r attribute is not specified, the effect is as if a value of "50%" were specified. 44 m_cx->setDefaultValueAsString("50%"); 45 m_cy->setDefaultValueAsString("50%"); 46 m_r->setDefaultValueAsString("50%"); 47 48 // SVG2-Draft Spec: If the fr attributed is not specified, the effect is as if a value of "0%" were specified. 49 m_fr->setDefaultValueAsString("0%"); 50 51 addToPropertyMap(m_cx); 52 addToPropertyMap(m_cy); 53 addToPropertyMap(m_r); 54 addToPropertyMap(m_fx); 55 addToPropertyMap(m_fy); 56 addToPropertyMap(m_fr); 57 } 58 59 DEFINE_NODE_FACTORY(SVGRadialGradientElement) 60 61 bool SVGRadialGradientElement::isSupportedAttribute(const QualifiedName& attrName) 62 { 63 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 64 if (supportedAttributes.isEmpty()) { 65 supportedAttributes.add(SVGNames::cxAttr); 66 supportedAttributes.add(SVGNames::cyAttr); 67 supportedAttributes.add(SVGNames::fxAttr); 68 supportedAttributes.add(SVGNames::fyAttr); 69 supportedAttributes.add(SVGNames::rAttr); 70 supportedAttributes.add(SVGNames::frAttr); 71 } 72 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 73 } 74 75 void SVGRadialGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 76 { 77 SVGParsingError parseError = NoError; 78 79 if (!isSupportedAttribute(name)) 80 SVGGradientElement::parseAttribute(name, value); 81 else if (name == SVGNames::cxAttr) 82 m_cx->setBaseValueAsString(value, parseError); 83 else if (name == SVGNames::cyAttr) 84 m_cy->setBaseValueAsString(value, parseError); 85 else if (name == SVGNames::rAttr) 86 m_r->setBaseValueAsString(value, parseError); 87 else if (name == SVGNames::fxAttr) 88 m_fx->setBaseValueAsString(value, parseError); 89 else if (name == SVGNames::fyAttr) 90 m_fy->setBaseValueAsString(value, parseError); 91 else if (name == SVGNames::frAttr) 92 m_fr->setBaseValueAsString(value, parseError); 93 else 94 ASSERT_NOT_REACHED(); 95 96 reportAttributeParsingError(parseError, name, value); 97 } 98 99 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName) 100 { 101 if (!isSupportedAttribute(attrName)) { 102 SVGGradientElement::svgAttributeChanged(attrName); 103 return; 104 } 105 106 SVGElement::InvalidationGuard invalidationGuard(this); 107 108 updateRelativeLengthsInformation(); 109 110 RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); 111 if (renderer) 112 renderer->invalidateCacheAndMarkForLayout(); 113 } 114 115 RenderObject* SVGRadialGradientElement::createRenderer(RenderStyle*) 116 { 117 return new RenderSVGResourceRadialGradient(this); 118 } 119 120 static void setGradientAttributes(SVGGradientElement* element, RadialGradientAttributes& attributes, bool isRadial = true) 121 { 122 if (!attributes.hasSpreadMethod() && element->spreadMethod()->isSpecified()) 123 attributes.setSpreadMethod(element->spreadMethod()->currentValue()->enumValue()); 124 125 if (!attributes.hasGradientUnits() && element->gradientUnits()->isSpecified()) 126 attributes.setGradientUnits(element->gradientUnits()->currentValue()->enumValue()); 127 128 if (!attributes.hasGradientTransform() && element->gradientTransform()->isSpecified()) { 129 AffineTransform transform; 130 element->gradientTransform()->currentValue()->concatenate(transform); 131 attributes.setGradientTransform(transform); 132 } 133 134 if (!attributes.hasStops()) { 135 const Vector<Gradient::ColorStop>& stops(element->buildStops()); 136 if (!stops.isEmpty()) 137 attributes.setStops(stops); 138 } 139 140 if (isRadial) { 141 SVGRadialGradientElement* radial = toSVGRadialGradientElement(element); 142 143 if (!attributes.hasCx() && radial->cx()->isSpecified()) 144 attributes.setCx(radial->cx()->currentValue()); 145 146 if (!attributes.hasCy() && radial->cy()->isSpecified()) 147 attributes.setCy(radial->cy()->currentValue()); 148 149 if (!attributes.hasR() && radial->r()->isSpecified()) 150 attributes.setR(radial->r()->currentValue()); 151 152 if (!attributes.hasFx() && radial->fx()->isSpecified()) 153 attributes.setFx(radial->fx()->currentValue()); 154 155 if (!attributes.hasFy() && radial->fy()->isSpecified()) 156 attributes.setFy(radial->fy()->currentValue()); 157 158 if (!attributes.hasFr() && radial->fr()->isSpecified()) 159 attributes.setFr(radial->fr()->currentValue()); 160 } 161 } 162 163 bool SVGRadialGradientElement::collectGradientAttributes(RadialGradientAttributes& attributes) 164 { 165 if (!renderer()) 166 return false; 167 168 WillBeHeapHashSet<RawPtrWillBeMember<SVGGradientElement> > processedGradients; 169 SVGGradientElement* current = this; 170 171 setGradientAttributes(current, attributes); 172 processedGradients.add(current); 173 174 while (true) { 175 // Respect xlink:href, take attributes from referenced element 176 Node* refNode = SVGURIReference::targetElementFromIRIString(current->href()->currentValue()->value(), treeScope()); 177 if (refNode && isSVGGradientElement(*refNode)) { 178 current = toSVGGradientElement(refNode); 179 180 // Cycle detection 181 if (processedGradients.contains(current)) 182 break; 183 184 if (!current->renderer()) 185 return false; 186 187 setGradientAttributes(current, attributes, isSVGRadialGradientElement(*current)); 188 processedGradients.add(current); 189 } else { 190 break; 191 } 192 } 193 194 // Handle default values for fx/fy 195 if (!attributes.hasFx()) 196 attributes.setFx(attributes.cx()); 197 198 if (!attributes.hasFy()) 199 attributes.setFy(attributes.cy()); 200 201 return true; 202 } 203 204 bool SVGRadialGradientElement::selfHasRelativeLengths() const 205 { 206 return m_cx->currentValue()->isRelative() 207 || m_cy->currentValue()->isRelative() 208 || m_r->currentValue()->isRelative() 209 || m_fx->currentValue()->isRelative() 210 || m_fy->currentValue()->isRelative() 211 || m_fr->currentValue()->isRelative(); 212 } 213 214 } // namespace blink 215