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