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