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 #include "core/svg/SVGMarkerElement.h" 25 26 #include "SVGNames.h" 27 #include "core/rendering/svg/RenderSVGResourceMarker.h" 28 #include "core/svg/SVGElementInstance.h" 29 #include "core/svg/SVGFitToViewBox.h" 30 31 namespace WebCore { 32 33 // Define custom animated property 'orientType'. 34 const SVGPropertyInfo* SVGMarkerElement::orientTypePropertyInfo() 35 { 36 static const SVGPropertyInfo* s_propertyInfo = 0; 37 if (!s_propertyInfo) { 38 s_propertyInfo = new SVGPropertyInfo(AnimatedEnumeration, 39 PropertyIsReadWrite, 40 SVGNames::orientAttr, 41 orientTypeIdentifier(), 42 &SVGMarkerElement::synchronizeOrientType, 43 &SVGMarkerElement::lookupOrCreateOrientTypeWrapper); 44 } 45 return s_propertyInfo; 46 } 47 48 // Animated property definitions 49 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::refXAttr, RefX, refX) 50 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::refYAttr, RefY, refY) 51 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::markerWidthAttr, MarkerWidth, markerWidth) 52 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::markerHeightAttr, MarkerHeight, markerHeight) 53 DEFINE_ANIMATED_ENUMERATION(SVGMarkerElement, SVGNames::markerUnitsAttr, MarkerUnits, markerUnits, SVGMarkerUnitsType) 54 DEFINE_ANIMATED_ANGLE_AND_ENUMERATION(SVGMarkerElement, SVGNames::orientAttr, orientAngleIdentifier(), OrientAngle, orientAngle) 55 DEFINE_ANIMATED_BOOLEAN(SVGMarkerElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 56 DEFINE_ANIMATED_RECT(SVGMarkerElement, SVGNames::viewBoxAttr, ViewBox, viewBox) 57 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGMarkerElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio) 58 59 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGMarkerElement) 60 REGISTER_LOCAL_ANIMATED_PROPERTY(refX) 61 REGISTER_LOCAL_ANIMATED_PROPERTY(refY) 62 REGISTER_LOCAL_ANIMATED_PROPERTY(markerWidth) 63 REGISTER_LOCAL_ANIMATED_PROPERTY(markerHeight) 64 REGISTER_LOCAL_ANIMATED_PROPERTY(markerUnits) 65 REGISTER_LOCAL_ANIMATED_PROPERTY(orientAngle) 66 REGISTER_LOCAL_ANIMATED_PROPERTY(orientType) 67 REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired) 68 REGISTER_LOCAL_ANIMATED_PROPERTY(viewBox) 69 REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio) 70 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement) 71 END_REGISTER_ANIMATED_PROPERTIES 72 73 inline SVGMarkerElement::SVGMarkerElement(const QualifiedName& tagName, Document* document) 74 : SVGElement(tagName, document) 75 , m_refX(LengthModeWidth) 76 , m_refY(LengthModeHeight) 77 , m_markerWidth(LengthModeWidth, "3") 78 , m_markerHeight(LengthModeHeight, "3") 79 , m_markerUnits(SVGMarkerUnitsStrokeWidth) 80 , m_orientType(SVGMarkerOrientAngle) 81 { 82 // Spec: If the markerWidth/markerHeight attribute is not specified, the effect is as if a value of "3" were specified. 83 ASSERT(hasTagName(SVGNames::markerTag)); 84 ScriptWrappable::init(this); 85 registerAnimatedPropertiesForSVGMarkerElement(); 86 } 87 88 PassRefPtr<SVGMarkerElement> SVGMarkerElement::create(const QualifiedName& tagName, Document* document) 89 { 90 return adoptRef(new SVGMarkerElement(tagName, document)); 91 } 92 93 const AtomicString& SVGMarkerElement::orientTypeIdentifier() 94 { 95 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientType", AtomicString::ConstructFromLiteral)); 96 return s_identifier; 97 } 98 99 const AtomicString& SVGMarkerElement::orientAngleIdentifier() 100 { 101 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientAngle", AtomicString::ConstructFromLiteral)); 102 return s_identifier; 103 } 104 105 AffineTransform SVGMarkerElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const 106 { 107 return SVGFitToViewBox::viewBoxToViewTransform(viewBoxCurrentValue(), preserveAspectRatioCurrentValue(), viewWidth, viewHeight); 108 } 109 110 bool SVGMarkerElement::isSupportedAttribute(const QualifiedName& attrName) 111 { 112 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 113 if (supportedAttributes.isEmpty()) { 114 SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes); 115 SVGFitToViewBox::addSupportedAttributes(supportedAttributes); 116 supportedAttributes.add(SVGNames::markerUnitsAttr); 117 supportedAttributes.add(SVGNames::refXAttr); 118 supportedAttributes.add(SVGNames::refYAttr); 119 supportedAttributes.add(SVGNames::markerWidthAttr); 120 supportedAttributes.add(SVGNames::markerHeightAttr); 121 supportedAttributes.add(SVGNames::orientAttr); 122 } 123 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 124 } 125 126 void SVGMarkerElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 127 { 128 SVGParsingError parseError = NoError; 129 130 if (!isSupportedAttribute(name)) 131 SVGElement::parseAttribute(name, value); 132 else if (name == SVGNames::markerUnitsAttr) { 133 SVGMarkerUnitsType propertyValue = SVGPropertyTraits<SVGMarkerUnitsType>::fromString(value); 134 if (propertyValue > 0) 135 setMarkerUnitsBaseValue(propertyValue); 136 } else if (name == SVGNames::refXAttr) 137 setRefXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError)); 138 else if (name == SVGNames::refYAttr) 139 setRefYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError)); 140 else if (name == SVGNames::markerWidthAttr) 141 setMarkerWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError)); 142 else if (name == SVGNames::markerHeightAttr) 143 setMarkerHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError)); 144 else if (name == SVGNames::orientAttr) { 145 SVGAngle angle; 146 SVGMarkerOrientType orientType = SVGPropertyTraits<SVGMarkerOrientType>::fromString(value, angle); 147 if (orientType > 0) 148 setOrientTypeBaseValue(orientType); 149 if (orientType == SVGMarkerOrientAngle) 150 setOrientAngleBaseValue(angle); 151 } else if (SVGExternalResourcesRequired::parseAttribute(name, value) 152 || SVGFitToViewBox::parseAttribute(this, name, value)) { 153 } else 154 ASSERT_NOT_REACHED(); 155 156 reportAttributeParsingError(parseError, name, value); 157 } 158 159 void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName) 160 { 161 if (!isSupportedAttribute(attrName)) { 162 SVGElement::svgAttributeChanged(attrName); 163 return; 164 } 165 166 SVGElementInstance::InvalidationGuard invalidationGuard(this); 167 168 if (attrName == SVGNames::refXAttr 169 || attrName == SVGNames::refYAttr 170 || attrName == SVGNames::markerWidthAttr 171 || attrName == SVGNames::markerHeightAttr) 172 updateRelativeLengthsInformation(); 173 174 if (RenderObject* object = renderer()) 175 object->setNeedsLayout(); 176 } 177 178 void SVGMarkerElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 179 { 180 SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 181 182 if (changedByParser) 183 return; 184 185 if (RenderObject* object = renderer()) 186 object->setNeedsLayout(); 187 } 188 189 void SVGMarkerElement::setOrientToAuto() 190 { 191 setOrientTypeBaseValue(SVGMarkerOrientAuto); 192 setOrientAngleBaseValue(SVGAngle()); 193 194 // Mark orientAttr dirty - the next XML DOM access of that attribute kicks in synchronization. 195 m_orientAngle.shouldSynchronize = true; 196 m_orientType.shouldSynchronize = true; 197 invalidateSVGAttributes(); 198 svgAttributeChanged(orientAnglePropertyInfo()->attributeName); 199 } 200 201 void SVGMarkerElement::setOrientToAngle(const SVGAngle& angle) 202 { 203 setOrientTypeBaseValue(SVGMarkerOrientAngle); 204 setOrientAngleBaseValue(angle); 205 206 // Mark orientAttr dirty - the next XML DOM access of that attribute kicks in synchronization. 207 m_orientAngle.shouldSynchronize = true; 208 m_orientType.shouldSynchronize = true; 209 invalidateSVGAttributes(); 210 svgAttributeChanged(orientAnglePropertyInfo()->attributeName); 211 } 212 213 RenderObject* SVGMarkerElement::createRenderer(RenderStyle*) 214 { 215 return new RenderSVGResourceMarker(this); 216 } 217 218 bool SVGMarkerElement::selfHasRelativeLengths() const 219 { 220 return refXCurrentValue().isRelative() 221 || refYCurrentValue().isRelative() 222 || markerWidthCurrentValue().isRelative() 223 || markerHeightCurrentValue().isRelative(); 224 } 225 226 void SVGMarkerElement::synchronizeOrientType(SVGElement* contextElement) 227 { 228 ASSERT(contextElement); 229 SVGMarkerElement* ownerType = toSVGMarkerElement(contextElement); 230 if (!ownerType->m_orientType.shouldSynchronize) 231 return; 232 233 // If orient is not auto, the previous call to synchronizeOrientAngle already set the orientAttr to the right angle. 234 if (ownerType->m_orientType.value != SVGMarkerOrientAuto) 235 return; 236 237 DEFINE_STATIC_LOCAL(AtomicString, autoString, ("auto", AtomicString::ConstructFromLiteral)); 238 ownerType->m_orientType.synchronize(ownerType, orientTypePropertyInfo()->attributeName, autoString); 239 } 240 241 PassRefPtr<SVGAnimatedProperty> SVGMarkerElement::lookupOrCreateOrientTypeWrapper(SVGElement* contextElement) 242 { 243 ASSERT(contextElement); 244 SVGMarkerElement* ownerType = toSVGMarkerElement(contextElement); 245 return SVGAnimatedProperty::lookupOrCreateWrapper<SVGMarkerElement, SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType>, SVGMarkerOrientType> 246 (ownerType, orientTypePropertyInfo(), ownerType->m_orientType.value); 247 } 248 249 PassRefPtr<SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType> > SVGMarkerElement::orientType() 250 { 251 m_orientType.shouldSynchronize = true; 252 return static_pointer_cast<SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType> >(lookupOrCreateOrientTypeWrapper(this)); 253 } 254 255 } 256