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 #if ENABLE(SVG) 27 #include "SVGLinearGradientElement.h" 28 29 #include "Attribute.h" 30 #include "Document.h" 31 #include "FloatPoint.h" 32 #include "LinearGradientAttributes.h" 33 #include "RenderSVGResourceLinearGradient.h" 34 #include "SVGLength.h" 35 #include "SVGNames.h" 36 #include "SVGTransform.h" 37 #include "SVGTransformList.h" 38 #include "SVGUnitTypes.h" 39 40 namespace WebCore { 41 42 // Animated property definitions 43 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x1Attr, X1, x1) 44 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y1Attr, Y1, y1) 45 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x2Attr, X2, x2) 46 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y2Attr, Y2, y2) 47 48 inline SVGLinearGradientElement::SVGLinearGradientElement(const QualifiedName& tagName, Document* document) 49 : SVGGradientElement(tagName, document) 50 , m_x1(LengthModeWidth) 51 , m_y1(LengthModeHeight) 52 , m_x2(LengthModeWidth, "100%") 53 , m_y2(LengthModeHeight) 54 { 55 // Spec: If the x2 attribute is not specified, the effect is as if a value of "100%" were specified. 56 } 57 58 PassRefPtr<SVGLinearGradientElement> SVGLinearGradientElement::create(const QualifiedName& tagName, Document* document) 59 { 60 return adoptRef(new SVGLinearGradientElement(tagName, document)); 61 } 62 63 void SVGLinearGradientElement::parseMappedAttribute(Attribute* attr) 64 { 65 if (attr->name() == SVGNames::x1Attr) 66 setX1BaseValue(SVGLength(LengthModeWidth, attr->value())); 67 else if (attr->name() == SVGNames::y1Attr) 68 setY1BaseValue(SVGLength(LengthModeHeight, attr->value())); 69 else if (attr->name() == SVGNames::x2Attr) 70 setX2BaseValue(SVGLength(LengthModeWidth, attr->value())); 71 else if (attr->name() == SVGNames::y2Attr) 72 setY2BaseValue(SVGLength(LengthModeHeight, attr->value())); 73 else 74 SVGGradientElement::parseMappedAttribute(attr); 75 } 76 77 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName& attrName) 78 { 79 SVGGradientElement::svgAttributeChanged(attrName); 80 81 if (attrName == SVGNames::x1Attr 82 || attrName == SVGNames::y1Attr 83 || attrName == SVGNames::x2Attr 84 || attrName == SVGNames::y2Attr) { 85 updateRelativeLengthsInformation(); 86 87 RenderObject* object = renderer(); 88 if (!object) 89 return; 90 91 object->setNeedsLayout(true); 92 } 93 } 94 95 void SVGLinearGradientElement::synchronizeProperty(const QualifiedName& attrName) 96 { 97 SVGGradientElement::synchronizeProperty(attrName); 98 99 if (attrName == anyQName()) { 100 synchronizeX1(); 101 synchronizeY1(); 102 synchronizeX2(); 103 synchronizeY2(); 104 return; 105 } 106 107 if (attrName == SVGNames::x1Attr) 108 synchronizeX1(); 109 else if (attrName == SVGNames::y1Attr) 110 synchronizeY1(); 111 else if (attrName == SVGNames::x2Attr) 112 synchronizeX2(); 113 else if (attrName == SVGNames::y2Attr) 114 synchronizeY2(); 115 } 116 117 AttributeToPropertyTypeMap& SVGLinearGradientElement::attributeToPropertyTypeMap() 118 { 119 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 120 return s_attributeToPropertyTypeMap; 121 } 122 123 void SVGLinearGradientElement::fillAttributeToPropertyTypeMap() 124 { 125 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap(); 126 127 SVGGradientElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap); 128 attributeToPropertyTypeMap.set(SVGNames::x1Attr, AnimatedLength); 129 attributeToPropertyTypeMap.set(SVGNames::y1Attr, AnimatedLength); 130 attributeToPropertyTypeMap.set(SVGNames::x2Attr, AnimatedLength); 131 attributeToPropertyTypeMap.set(SVGNames::y2Attr, AnimatedLength); 132 } 133 134 RenderObject* SVGLinearGradientElement::createRenderer(RenderArena* arena, RenderStyle*) 135 { 136 return new (arena) RenderSVGResourceLinearGradient(this); 137 } 138 139 void SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttributes& attributes) 140 { 141 HashSet<SVGGradientElement*> processedGradients; 142 143 bool isLinear = true; 144 SVGGradientElement* current = this; 145 146 while (current) { 147 if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr)) 148 attributes.setSpreadMethod((GradientSpreadMethod) current->spreadMethod()); 149 150 if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr)) 151 attributes.setBoundingBoxMode(current->gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); 152 153 if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) { 154 AffineTransform transform; 155 current->gradientTransform().concatenate(transform); 156 attributes.setGradientTransform(transform); 157 } 158 159 if (!attributes.hasStops()) { 160 const Vector<Gradient::ColorStop>& stops(current->buildStops()); 161 if (!stops.isEmpty()) 162 attributes.setStops(stops); 163 } 164 165 if (isLinear) { 166 SVGLinearGradientElement* linear = static_cast<SVGLinearGradientElement*>(current); 167 168 if (!attributes.hasX1() && current->hasAttribute(SVGNames::x1Attr)) 169 attributes.setX1(linear->x1()); 170 171 if (!attributes.hasY1() && current->hasAttribute(SVGNames::y1Attr)) 172 attributes.setY1(linear->y1()); 173 174 if (!attributes.hasX2() && current->hasAttribute(SVGNames::x2Attr)) 175 attributes.setX2(linear->x2()); 176 177 if (!attributes.hasY2() && current->hasAttribute(SVGNames::y2Attr)) 178 attributes.setY2(linear->y2()); 179 } 180 181 processedGradients.add(current); 182 183 // Respect xlink:href, take attributes from referenced element 184 Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href())); 185 if (refNode && (refNode->hasTagName(SVGNames::linearGradientTag) || refNode->hasTagName(SVGNames::radialGradientTag))) { 186 current = static_cast<SVGGradientElement*>(refNode); 187 188 // Cycle detection 189 if (processedGradients.contains(current)) { 190 current = 0; 191 break; 192 } 193 194 isLinear = current->hasTagName(SVGNames::linearGradientTag); 195 } else 196 current = 0; 197 } 198 } 199 200 void SVGLinearGradientElement::calculateStartEndPoints(const LinearGradientAttributes& attributes, FloatPoint& startPoint, FloatPoint& endPoint) 201 { 202 // Determine gradient start/end points 203 if (attributes.boundingBoxMode()) { 204 startPoint = FloatPoint(attributes.x1().valueAsPercentage(), attributes.y1().valueAsPercentage()); 205 endPoint = FloatPoint(attributes.x2().valueAsPercentage(), attributes.y2().valueAsPercentage()); 206 } else { 207 startPoint = FloatPoint(attributes.x1().value(this), attributes.y1().value(this)); 208 endPoint = FloatPoint(attributes.x2().value(this), attributes.y2().value(this)); 209 } 210 } 211 212 bool SVGLinearGradientElement::selfHasRelativeLengths() const 213 { 214 return x1().isRelative() 215 || y1().isRelative() 216 || x2().isRelative() 217 || y2().isRelative(); 218 } 219 220 } 221 222 #endif // ENABLE(SVG) 223