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