1 /* 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org> 4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22 #include "config.h" 23 24 #if ENABLE(SVG) 25 #include "SVGMarkerElement.h" 26 27 #include "Attribute.h" 28 #include "RenderSVGResourceMarker.h" 29 #include "SVGFitToViewBox.h" 30 #include "SVGNames.h" 31 #include "SVGSVGElement.h" 32 33 namespace WebCore { 34 35 // Animated property definitions 36 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::refXAttr, RefX, refX) 37 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::refYAttr, RefY, refY) 38 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::markerWidthAttr, MarkerWidth, markerWidth) 39 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::markerHeightAttr, MarkerHeight, markerHeight) 40 DEFINE_ANIMATED_ENUMERATION(SVGMarkerElement, SVGNames::markerUnitsAttr, MarkerUnits, markerUnits) 41 DEFINE_ANIMATED_ENUMERATION_MULTIPLE_WRAPPERS(SVGMarkerElement, SVGNames::orientAttr, orientTypeIdentifier(), OrientType, orientType) 42 DEFINE_ANIMATED_ANGLE_MULTIPLE_WRAPPERS(SVGMarkerElement, SVGNames::orientAttr, orientAngleIdentifier(), OrientAngle, orientAngle) 43 DEFINE_ANIMATED_BOOLEAN(SVGMarkerElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 44 DEFINE_ANIMATED_RECT(SVGMarkerElement, SVGNames::viewBoxAttr, ViewBox, viewBox) 45 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGMarkerElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio) 46 47 inline SVGMarkerElement::SVGMarkerElement(const QualifiedName& tagName, Document* document) 48 : SVGStyledElement(tagName, document) 49 , m_refX(LengthModeWidth) 50 , m_refY(LengthModeHeight) 51 , m_markerWidth(LengthModeWidth, "3") 52 , m_markerHeight(LengthModeHeight, "3") 53 , m_markerUnits(SVG_MARKERUNITS_STROKEWIDTH) 54 , m_orientType(SVG_MARKER_ORIENT_ANGLE) 55 { 56 // Spec: If the markerWidth/markerHeight attribute is not specified, the effect is as if a value of "3" were specified. 57 } 58 59 PassRefPtr<SVGMarkerElement> SVGMarkerElement::create(const QualifiedName& tagName, Document* document) 60 { 61 return adoptRef(new SVGMarkerElement(tagName, document)); 62 } 63 64 const AtomicString& SVGMarkerElement::orientTypeIdentifier() 65 { 66 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientType")); 67 return s_identifier; 68 } 69 70 const AtomicString& SVGMarkerElement::orientAngleIdentifier() 71 { 72 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientAngle")); 73 return s_identifier; 74 } 75 76 AffineTransform SVGMarkerElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const 77 { 78 return SVGFitToViewBox::viewBoxToViewTransform(viewBox(), preserveAspectRatio(), viewWidth, viewHeight); 79 } 80 81 void SVGMarkerElement::parseMappedAttribute(Attribute* attr) 82 { 83 if (attr->name() == SVGNames::markerUnitsAttr) { 84 if (attr->value() == "userSpaceOnUse") 85 setMarkerUnitsBaseValue(SVG_MARKERUNITS_USERSPACEONUSE); 86 else if (attr->value() == "strokeWidth") 87 setMarkerUnitsBaseValue(SVG_MARKERUNITS_STROKEWIDTH); 88 } else if (attr->name() == SVGNames::refXAttr) 89 setRefXBaseValue(SVGLength(LengthModeWidth, attr->value())); 90 else if (attr->name() == SVGNames::refYAttr) 91 setRefYBaseValue(SVGLength(LengthModeHeight, attr->value())); 92 else if (attr->name() == SVGNames::markerWidthAttr) 93 setMarkerWidthBaseValue(SVGLength(LengthModeWidth, attr->value())); 94 else if (attr->name() == SVGNames::markerHeightAttr) 95 setMarkerHeightBaseValue(SVGLength(LengthModeHeight, attr->value())); 96 else if (attr->name() == SVGNames::orientAttr) { 97 SVGAngle angle; 98 99 if (attr->value() == "auto") 100 setOrientTypeBaseValue(SVG_MARKER_ORIENT_AUTO); 101 else { 102 ExceptionCode ec = 0; 103 angle.setValueAsString(attr->value(), ec); 104 setOrientTypeBaseValue(SVG_MARKER_ORIENT_ANGLE); 105 } 106 107 setOrientAngleBaseValue(angle); 108 } else { 109 if (SVGLangSpace::parseMappedAttribute(attr)) 110 return; 111 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) 112 return; 113 if (SVGFitToViewBox::parseMappedAttribute(document(), attr)) 114 return; 115 116 SVGStyledElement::parseMappedAttribute(attr); 117 } 118 } 119 120 void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName) 121 { 122 SVGStyledElement::svgAttributeChanged(attrName); 123 124 bool invalidateClients = false; 125 if (attrName == SVGNames::refXAttr 126 || attrName == SVGNames::refYAttr 127 || attrName == SVGNames::markerWidthAttr 128 || attrName == SVGNames::markerHeightAttr) { 129 invalidateClients = true; 130 updateRelativeLengthsInformation(); 131 } 132 133 RenderObject* object = renderer(); 134 if (!object) 135 return; 136 137 if (invalidateClients 138 || attrName == SVGNames::markerUnitsAttr 139 || attrName == SVGNames::orientAttr 140 || SVGLangSpace::isKnownAttribute(attrName) 141 || SVGExternalResourcesRequired::isKnownAttribute(attrName) 142 || SVGFitToViewBox::isKnownAttribute(attrName) 143 || SVGStyledElement::isKnownAttribute(attrName)) 144 object->setNeedsLayout(true); 145 } 146 147 void SVGMarkerElement::synchronizeProperty(const QualifiedName& attrName) 148 { 149 SVGStyledElement::synchronizeProperty(attrName); 150 151 if (attrName == anyQName()) { 152 synchronizeMarkerUnits(); 153 synchronizeRefX(); 154 synchronizeRefY(); 155 synchronizeMarkerWidth(); 156 synchronizeMarkerHeight(); 157 synchronizeOrientAngle(); 158 synchronizeOrientType(); 159 synchronizeExternalResourcesRequired(); 160 synchronizeViewBox(); 161 synchronizePreserveAspectRatio(); 162 return; 163 } 164 165 if (attrName == SVGNames::markerUnitsAttr) 166 synchronizeMarkerUnits(); 167 else if (attrName == SVGNames::refXAttr) 168 synchronizeRefX(); 169 else if (attrName == SVGNames::refYAttr) 170 synchronizeRefY(); 171 else if (attrName == SVGNames::markerWidthAttr) 172 synchronizeMarkerWidth(); 173 else if (attrName == SVGNames::markerHeightAttr) 174 synchronizeMarkerHeight(); 175 else if (attrName == SVGNames::orientAttr) { 176 synchronizeOrientAngle(); 177 synchronizeOrientType(); 178 } else if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) 179 synchronizeExternalResourcesRequired(); 180 else if (SVGFitToViewBox::isKnownAttribute(attrName)) { 181 synchronizeViewBox(); 182 synchronizePreserveAspectRatio(); 183 } 184 } 185 186 AttributeToPropertyTypeMap& SVGMarkerElement::attributeToPropertyTypeMap() 187 { 188 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 189 return s_attributeToPropertyTypeMap; 190 } 191 192 void SVGMarkerElement::fillAttributeToPropertyTypeMap() 193 { 194 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap(); 195 196 SVGStyledElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap); 197 attributeToPropertyTypeMap.set(SVGNames::refXAttr, AnimatedLength); 198 attributeToPropertyTypeMap.set(SVGNames::refYAttr, AnimatedLength); 199 attributeToPropertyTypeMap.set(SVGNames::markerWidthAttr, AnimatedLength); 200 attributeToPropertyTypeMap.set(SVGNames::markerHeightAttr, AnimatedLength); 201 attributeToPropertyTypeMap.set(SVGNames::markerUnitsAttr, AnimatedEnumeration); 202 attributeToPropertyTypeMap.set(SVGNames::orientAttr, AnimatedAngle); 203 attributeToPropertyTypeMap.set(SVGNames::viewBoxAttr, AnimatedRect); 204 } 205 206 void SVGMarkerElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 207 { 208 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 209 210 if (changedByParser) 211 return; 212 213 if (RenderObject* object = renderer()) 214 object->setNeedsLayout(true); 215 } 216 217 void SVGMarkerElement::setOrientToAuto() 218 { 219 setOrientTypeBaseValue(SVG_MARKER_ORIENT_AUTO); 220 setOrientAngleBaseValue(SVGAngle()); 221 222 if (RenderObject* object = renderer()) 223 object->setNeedsLayout(true); 224 } 225 226 void SVGMarkerElement::setOrientToAngle(const SVGAngle& angle) 227 { 228 setOrientTypeBaseValue(SVG_MARKER_ORIENT_ANGLE); 229 setOrientAngleBaseValue(angle); 230 231 if (RenderObject* object = renderer()) 232 object->setNeedsLayout(true); 233 } 234 235 RenderObject* SVGMarkerElement::createRenderer(RenderArena* arena, RenderStyle*) 236 { 237 return new (arena) RenderSVGResourceMarker(this); 238 } 239 240 bool SVGMarkerElement::selfHasRelativeLengths() const 241 { 242 return refX().isRelative() 243 || refY().isRelative() 244 || markerWidth().isRelative() 245 || markerHeight().isRelative(); 246 } 247 248 } 249 250 #endif 251