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 "core/SVGNames.h" 27 #include "core/rendering/svg/RenderSVGResourceMarker.h" 28 #include "core/svg/SVGAngleTearOff.h" 29 30 namespace blink { 31 32 template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGMarkerUnitsType>() 33 { 34 DEFINE_STATIC_LOCAL(SVGEnumerationStringEntries, entries, ()); 35 if (entries.isEmpty()) { 36 entries.append(std::make_pair(SVGMarkerUnitsUserSpaceOnUse, "userSpaceOnUse")); 37 entries.append(std::make_pair(SVGMarkerUnitsStrokeWidth, "strokeWidth")); 38 } 39 return entries; 40 } 41 42 43 inline SVGMarkerElement::SVGMarkerElement(Document& document) 44 : SVGElement(SVGNames::markerTag, document) 45 , SVGFitToViewBox(this) 46 , m_refX(SVGAnimatedLength::create(this, SVGNames::refXAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths)) 47 , m_refY(SVGAnimatedLength::create(this, SVGNames::refXAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths)) 48 , m_markerWidth(SVGAnimatedLength::create(this, SVGNames::markerWidthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths)) 49 , m_markerHeight(SVGAnimatedLength::create(this, SVGNames::markerHeightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths)) 50 , m_orientAngle(SVGAnimatedAngle::create(this)) 51 , m_markerUnits(SVGAnimatedEnumeration<SVGMarkerUnitsType>::create(this, SVGNames::markerUnitsAttr, SVGMarkerUnitsStrokeWidth)) 52 { 53 // Spec: If the markerWidth/markerHeight attribute is not specified, the effect is as if a value of "3" were specified. 54 m_markerWidth->setDefaultValueAsString("3"); 55 m_markerHeight->setDefaultValueAsString("3"); 56 57 addToPropertyMap(m_refX); 58 addToPropertyMap(m_refY); 59 addToPropertyMap(m_markerWidth); 60 addToPropertyMap(m_markerHeight); 61 addToPropertyMap(m_orientAngle); 62 addToPropertyMap(m_markerUnits); 63 } 64 65 DEFINE_NODE_FACTORY(SVGMarkerElement) 66 67 AffineTransform SVGMarkerElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const 68 { 69 return SVGFitToViewBox::viewBoxToViewTransform(viewBox()->currentValue()->value(), preserveAspectRatio()->currentValue(), viewWidth, viewHeight); 70 } 71 72 bool SVGMarkerElement::isSupportedAttribute(const QualifiedName& attrName) 73 { 74 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 75 if (supportedAttributes.isEmpty()) { 76 SVGFitToViewBox::addSupportedAttributes(supportedAttributes); 77 supportedAttributes.add(SVGNames::markerUnitsAttr); 78 supportedAttributes.add(SVGNames::refXAttr); 79 supportedAttributes.add(SVGNames::refYAttr); 80 supportedAttributes.add(SVGNames::markerWidthAttr); 81 supportedAttributes.add(SVGNames::markerHeightAttr); 82 supportedAttributes.add(SVGNames::orientAttr); 83 } 84 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 85 } 86 87 void SVGMarkerElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 88 { 89 SVGParsingError parseError = NoError; 90 91 if (!isSupportedAttribute(name)) 92 SVGElement::parseAttribute(name, value); 93 else if (name == SVGNames::markerUnitsAttr) 94 m_markerUnits->setBaseValueAsString(value, parseError); 95 else if (name == SVGNames::refXAttr) 96 m_refX->setBaseValueAsString(value, parseError); 97 else if (name == SVGNames::refYAttr) 98 m_refY->setBaseValueAsString(value, parseError); 99 else if (name == SVGNames::markerWidthAttr) 100 m_markerWidth->setBaseValueAsString(value, parseError); 101 else if (name == SVGNames::markerHeightAttr) 102 m_markerHeight->setBaseValueAsString(value, parseError); 103 else if (name == SVGNames::orientAttr) 104 m_orientAngle->setBaseValueAsString(value, parseError); 105 else if (SVGFitToViewBox::parseAttribute(name, value, document(), parseError)) { 106 } else 107 ASSERT_NOT_REACHED(); 108 109 reportAttributeParsingError(parseError, name, value); 110 } 111 112 void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName) 113 { 114 if (!isSupportedAttribute(attrName)) { 115 SVGElement::svgAttributeChanged(attrName); 116 return; 117 } 118 119 SVGElement::InvalidationGuard invalidationGuard(this); 120 121 if (attrName == SVGNames::refXAttr 122 || attrName == SVGNames::refYAttr 123 || attrName == SVGNames::markerWidthAttr 124 || attrName == SVGNames::markerHeightAttr) 125 updateRelativeLengthsInformation(); 126 127 RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); 128 if (renderer) 129 renderer->invalidateCacheAndMarkForLayout(); 130 } 131 132 void SVGMarkerElement::childrenChanged(const ChildrenChange& change) 133 { 134 SVGElement::childrenChanged(change); 135 136 if (change.byParser) 137 return; 138 139 if (RenderObject* object = renderer()) 140 object->setNeedsLayoutAndFullPaintInvalidation(); 141 } 142 143 void SVGMarkerElement::setOrientToAuto() 144 { 145 m_orientAngle->baseValue()->orientType()->setEnumValue(SVGMarkerOrientAuto); 146 invalidateSVGAttributes(); 147 svgAttributeChanged(SVGNames::orientAttr); 148 } 149 150 void SVGMarkerElement::setOrientToAngle(PassRefPtr<SVGAngleTearOff> angle) 151 { 152 ASSERT(angle); 153 RefPtr<SVGAngle> target = angle->target(); 154 m_orientAngle->baseValue()->newValueSpecifiedUnits(target->unitType(), target->valueInSpecifiedUnits()); 155 invalidateSVGAttributes(); 156 svgAttributeChanged(SVGNames::orientAttr); 157 } 158 159 RenderObject* SVGMarkerElement::createRenderer(RenderStyle*) 160 { 161 return new RenderSVGResourceMarker(this); 162 } 163 164 bool SVGMarkerElement::selfHasRelativeLengths() const 165 { 166 return m_refX->currentValue()->isRelative() 167 || m_refY->currentValue()->isRelative() 168 || m_markerWidth->currentValue()->isRelative() 169 || m_markerHeight->currentValue()->isRelative(); 170 } 171 172 } // namespace blink 173