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