Home | History | Annotate | Download | only in svg
      1 /*
      2     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3                   2004, 2005, 2006, 2007 Rob Buis <buis (at) 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 
     35 namespace WebCore {
     36 
     37 char SVGOrientTypeAttrIdentifier[] = "SVGOrientTypeAttr";
     38 char SVGOrientAngleAttrIdentifier[] = "SVGOrientAngleAttr";
     39 
     40 SVGMarkerElement::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 
     55 SVGMarkerElement::~SVGMarkerElement()
     56 {
     57 }
     58 
     59 AffineTransform SVGMarkerElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
     60 {
     61     return SVGFitToViewBox::viewBoxToViewTransform(viewBox(), preserveAspectRatio(), viewWidth, viewHeight);
     62 }
     63 
     64 void 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 
    102 void 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 
    123 void 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 
    162 void 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 
    175 void 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 
    189 void 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 
    203 SVGResource* 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 
    222 RenderObject* 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