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