File indexing completed on 2024-04-28 15:24:35

0001 /*
0002     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
0003                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
0004 
0005     This file is part of the KDE project
0006 
0007     This library is free software; you can redistribute it and/or
0008     modify it under the terms of the GNU Library General Public
0009     License as published by the Free Software Foundation; either
0010     version 2 of the License, or (at your option) any later version.
0011 
0012     This library is distributed in the hope that it will be useful,
0013     but WITHOUT ANY WARRANTY; without even the implied warranty of
0014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015     Library General Public License for more details.
0016 
0017     You should have received a copy of the GNU Library General Public License
0018     along with this library; see the file COPYING.LIB.  If not, write to
0019     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020     Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #if ENABLE(SVG)
0024 #include "SVGMarkerElement.h"
0025 
0026 #include "PlatformString.h"
0027 #include "RenderSVGViewportContainer.h"
0028 #include "SVGAngle.h"
0029 #include "SVGLength.h"
0030 #include "SVGNames.h"
0031 #include "SVGPreserveAspectRatio.h"
0032 #include "SVGSVGElement.h"
0033 
0034 namespace WebCore
0035 {
0036 
0037 SVGMarkerElement::SVGMarkerElement(const QualifiedName &tagName, Document *doc)
0038     : SVGStyledElement(tagName, doc)
0039     , SVGLangSpace()
0040     , SVGExternalResourcesRequired()
0041     , SVGFitToViewBox()
0042     , m_refX(this, LengthModeWidth)
0043     , m_refY(this, LengthModeHeight)
0044     , m_markerWidth(this, LengthModeWidth)
0045     , m_markerHeight(this, LengthModeHeight)
0046     , m_markerUnits(SVG_MARKERUNITS_STROKEWIDTH)
0047     , m_orientType(0)
0048     , m_orientAngle(new SVGAngle())
0049 {
0050     // Spec: If the attribute is not specified, the effect is as if a value of "3" were specified.
0051     setMarkerWidthBaseValue(SVGLength(this, LengthModeWidth, "3"));
0052     setMarkerHeightBaseValue(SVGLength(this, LengthModeHeight, "3"));
0053 }
0054 
0055 SVGMarkerElement::~SVGMarkerElement()
0056 {
0057 }
0058 
0059 ANIMATED_PROPERTY_DEFINITIONS(SVGMarkerElement, SVGLength, Length, length, RefX, refX, SVGNames::refXAttr, m_refX)
0060 ANIMATED_PROPERTY_DEFINITIONS(SVGMarkerElement, SVGLength, Length, length, RefY, refY, SVGNames::refYAttr, m_refY)
0061 ANIMATED_PROPERTY_DEFINITIONS(SVGMarkerElement, int, Enumeration, enumeration, MarkerUnits, markerUnits, SVGNames::markerUnitsAttr, m_markerUnits)
0062 ANIMATED_PROPERTY_DEFINITIONS(SVGMarkerElement, SVGLength, Length, length, MarkerWidth, markerWidth, SVGNames::markerWidthAttr, m_markerWidth)
0063 ANIMATED_PROPERTY_DEFINITIONS(SVGMarkerElement, SVGLength, Length, length, MarkerHeight, markerHeight, SVGNames::markerHeightAttr, m_markerHeight)
0064 ANIMATED_PROPERTY_DEFINITIONS_WITH_CUSTOM_IDENTIFIER(SVGMarkerElement, int, Enumeration, enumeration, OrientType, orientType, SVGNames::orientAttr, "orientType", m_orientType)
0065 ANIMATED_PROPERTY_DEFINITIONS_WITH_CUSTOM_IDENTIFIER(SVGMarkerElement, SVGAngle *, Angle, angle, OrientAngle, orientAngle, SVGNames::orientAttr, "orientAngle", m_orientAngle.get())
0066 
0067 void SVGMarkerElement::parseMappedAttribute(MappedAttribute *attr)
0068 {
0069     if (attr->name() == SVGNames::markerUnitsAttr) {
0070         if (attr->value() == "userSpaceOnUse") {
0071             setMarkerUnitsBaseValue(SVG_MARKERUNITS_USERSPACEONUSE);
0072         }
0073     } else if (attr->name() == SVGNames::refXAttr) {
0074         setRefXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
0075     } else if (attr->name() == SVGNames::refYAttr) {
0076         setRefYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
0077     } else if (attr->name() == SVGNames::markerWidthAttr) {
0078         setMarkerWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
0079     } else if (attr->name() == SVGNames::markerHeightAttr) {
0080         setMarkerHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
0081     } else if (attr->name() == SVGNames::orientAttr) {
0082         if (attr->value() == "auto") {
0083             setOrientToAuto();
0084         } else {
0085             SVGAngle *angle = new SVGAngle();
0086             angle->setValueAsString(attr->value());
0087             setOrientToAngle(angle);
0088         }
0089     } else {
0090         if (SVGLangSpace::parseMappedAttribute(attr)) {
0091             return;
0092         }
0093         if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) {
0094             return;
0095         }
0096         if (SVGFitToViewBox::parseMappedAttribute(attr)) {
0097             return;
0098         }
0099 
0100         SVGStyledElement::parseMappedAttribute(attr);
0101     }
0102 }
0103 
0104 void SVGMarkerElement::svgAttributeChanged(const QualifiedName &attrName)
0105 {
0106     SVGStyledElement::svgAttributeChanged(attrName);
0107 
0108     if (!m_marker) {
0109         return;
0110     }
0111 
0112     if (attrName == SVGNames::markerUnitsAttr || attrName == SVGNames::refXAttr ||
0113             attrName == SVGNames::refYAttr || attrName == SVGNames::markerWidthAttr ||
0114             attrName == SVGNames::markerHeightAttr || attrName == SVGNames::orientAttr ||
0115             SVGLangSpace::isKnownAttribute(attrName) ||
0116             SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
0117             SVGFitToViewBox::isKnownAttribute(attrName) ||
0118             SVGStyledElement::isKnownAttribute(attrName)) {
0119         if (renderer()) {
0120             renderer()->setNeedsLayout(true);
0121         }
0122 
0123         m_marker->invalidate();
0124     }
0125 }
0126 
0127 void SVGMarkerElement::childrenChanged(bool changedByParser, Node *beforeChange, Node *afterChange, int childCountDelta)
0128 {
0129     SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
0130 
0131     if (renderer()) {
0132         renderer()->setNeedsLayout(true);
0133     }
0134 
0135     if (m_marker) {
0136         m_marker->invalidate();
0137     }
0138 }
0139 
0140 void SVGMarkerElement::setOrientToAuto()
0141 {
0142     setOrientTypeBaseValue(SVG_MARKER_ORIENT_AUTO);
0143 }
0144 
0145 void SVGMarkerElement::setOrientToAngle(SVGAngle *angle)
0146 {
0147     setOrientTypeBaseValue(SVG_MARKER_ORIENT_ANGLE);
0148     setOrientAngleBaseValue(angle);
0149 }
0150 
0151 SVGResource *SVGMarkerElement::canvasResource()
0152 {
0153     if (!m_marker) {
0154         m_marker = SVGResourceMarker::create();
0155     }
0156 
0157     m_marker->setMarker(static_cast<RenderSVGViewportContainer *>(renderer()));
0158 
0159     // Spec: If the attribute is not specified, the effect is as if a
0160     // value of "0" were specified.
0161     if (!m_orientType) {
0162         setOrientToAngle(SVGSVGElement::createSVGAngle());
0163     }
0164 
0165     if (orientType() == SVG_MARKER_ORIENT_ANGLE) {
0166         m_marker->setAngle(orientAngle()->value());
0167     } else {
0168         m_marker->setAutoAngle();
0169     }
0170 
0171     m_marker->setRef(refX().value(), refY().value());
0172     m_marker->setUseStrokeWidth(markerUnits() == SVG_MARKERUNITS_STROKEWIDTH);
0173 
0174     return m_marker.get();
0175 }
0176 
0177 RenderObject *SVGMarkerElement::createRenderer(RenderArena *arena, RenderStyle *style)
0178 {
0179     RenderSVGViewportContainer *markerContainer = new(arena) RenderSVGViewportContainer(this);
0180     markerContainer->setDrawsContents(false); // Marker contents will be explicitly drawn.
0181     return markerContainer;
0182 }
0183 
0184 }
0185 
0186 #endif // ENABLE(SVG)