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 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/SVGPatternElement.h"
     25 
     26 #include "XLinkNames.h"
     27 #include "core/rendering/svg/RenderSVGResourcePattern.h"
     28 #include "core/svg/PatternAttributes.h"
     29 #include "core/svg/SVGElementInstance.h"
     30 #include "platform/transforms/AffineTransform.h"
     31 
     32 namespace WebCore {
     33 
     34 // Animated property definitions
     35 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::xAttr, X, x)
     36 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::yAttr, Y, y)
     37 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::widthAttr, Width, width)
     38 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::heightAttr, Height, height)
     39 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternUnitsAttr, PatternUnits, patternUnits, SVGUnitTypes::SVGUnitType)
     40 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternContentUnitsAttr, PatternContentUnits, patternContentUnits, SVGUnitTypes::SVGUnitType)
     41 DEFINE_ANIMATED_TRANSFORM_LIST(SVGPatternElement, SVGNames::patternTransformAttr, PatternTransform, patternTransform)
     42 DEFINE_ANIMATED_STRING(SVGPatternElement, XLinkNames::hrefAttr, Href, href)
     43 DEFINE_ANIMATED_BOOLEAN(SVGPatternElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     44 DEFINE_ANIMATED_RECT(SVGPatternElement, SVGNames::viewBoxAttr, ViewBox, viewBox)
     45 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGPatternElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio)
     46 
     47 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGPatternElement)
     48     REGISTER_LOCAL_ANIMATED_PROPERTY(x)
     49     REGISTER_LOCAL_ANIMATED_PROPERTY(y)
     50     REGISTER_LOCAL_ANIMATED_PROPERTY(width)
     51     REGISTER_LOCAL_ANIMATED_PROPERTY(height)
     52     REGISTER_LOCAL_ANIMATED_PROPERTY(patternUnits)
     53     REGISTER_LOCAL_ANIMATED_PROPERTY(patternContentUnits)
     54     REGISTER_LOCAL_ANIMATED_PROPERTY(patternTransform)
     55     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
     56     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
     57     REGISTER_LOCAL_ANIMATED_PROPERTY(viewBox)
     58     REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio)
     59     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
     60     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
     61 END_REGISTER_ANIMATED_PROPERTIES
     62 
     63 inline SVGPatternElement::SVGPatternElement(Document& document)
     64     : SVGElement(SVGNames::patternTag, document)
     65     , m_x(LengthModeWidth)
     66     , m_y(LengthModeHeight)
     67     , m_width(LengthModeWidth)
     68     , m_height(LengthModeHeight)
     69     , m_patternUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
     70     , m_patternContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
     71 {
     72     ScriptWrappable::init(this);
     73     registerAnimatedPropertiesForSVGPatternElement();
     74 }
     75 
     76 PassRefPtr<SVGPatternElement> SVGPatternElement::create(Document& document)
     77 {
     78     return adoptRef(new SVGPatternElement(document));
     79 }
     80 
     81 bool SVGPatternElement::isSupportedAttribute(const QualifiedName& attrName)
     82 {
     83     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
     84     if (supportedAttributes.isEmpty()) {
     85         SVGURIReference::addSupportedAttributes(supportedAttributes);
     86         SVGTests::addSupportedAttributes(supportedAttributes);
     87         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
     88         SVGFitToViewBox::addSupportedAttributes(supportedAttributes);
     89         supportedAttributes.add(SVGNames::patternUnitsAttr);
     90         supportedAttributes.add(SVGNames::patternContentUnitsAttr);
     91         supportedAttributes.add(SVGNames::patternTransformAttr);
     92         supportedAttributes.add(SVGNames::xAttr);
     93         supportedAttributes.add(SVGNames::yAttr);
     94         supportedAttributes.add(SVGNames::widthAttr);
     95         supportedAttributes.add(SVGNames::heightAttr);
     96     }
     97     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
     98 }
     99 
    100 void SVGPatternElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    101 {
    102     SVGParsingError parseError = NoError;
    103 
    104     if (!isSupportedAttribute(name))
    105         SVGElement::parseAttribute(name, value);
    106     else if (name == SVGNames::patternUnitsAttr) {
    107         SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
    108         if (propertyValue > 0)
    109             setPatternUnitsBaseValue(propertyValue);
    110         return;
    111     } else if (name == SVGNames::patternContentUnitsAttr) {
    112         SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
    113         if (propertyValue > 0)
    114             setPatternContentUnitsBaseValue(propertyValue);
    115         return;
    116     } else if (name == SVGNames::patternTransformAttr) {
    117         SVGTransformList newList;
    118         newList.parse(value);
    119         detachAnimatedPatternTransformListWrappers(newList.size());
    120         setPatternTransformBaseValue(newList);
    121         return;
    122     } else if (name == SVGNames::xAttr)
    123         setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
    124     else if (name == SVGNames::yAttr)
    125         setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
    126     else if (name == SVGNames::widthAttr)
    127         setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
    128     else if (name == SVGNames::heightAttr)
    129         setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
    130     else if (SVGURIReference::parseAttribute(name, value)
    131              || SVGTests::parseAttribute(name, value)
    132              || SVGExternalResourcesRequired::parseAttribute(name, value)
    133              || SVGFitToViewBox::parseAttribute(this, name, value)) {
    134     } else
    135         ASSERT_NOT_REACHED();
    136 
    137     reportAttributeParsingError(parseError, name, value);
    138 }
    139 
    140 void SVGPatternElement::svgAttributeChanged(const QualifiedName& attrName)
    141 {
    142     if (!isSupportedAttribute(attrName)) {
    143         SVGElement::svgAttributeChanged(attrName);
    144         return;
    145     }
    146 
    147     SVGElementInstance::InvalidationGuard invalidationGuard(this);
    148 
    149     if (attrName == SVGNames::xAttr
    150         || attrName == SVGNames::yAttr
    151         || attrName == SVGNames::widthAttr
    152         || attrName == SVGNames::heightAttr)
    153         updateRelativeLengthsInformation();
    154 
    155     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
    156     if (renderer)
    157         renderer->invalidateCacheAndMarkForLayout();
    158 }
    159 
    160 void SVGPatternElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    161 {
    162     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    163 
    164     if (changedByParser)
    165         return;
    166 
    167     if (RenderObject* object = renderer())
    168         object->setNeedsLayout();
    169 }
    170 
    171 RenderObject* SVGPatternElement::createRenderer(RenderStyle*)
    172 {
    173     return new RenderSVGResourcePattern(this);
    174 }
    175 
    176 void SVGPatternElement::collectPatternAttributes(PatternAttributes& attributes) const
    177 {
    178     HashSet<const SVGPatternElement*> processedPatterns;
    179 
    180     const SVGPatternElement* current = this;
    181     while (current) {
    182         if (!attributes.hasX() && current->hasAttribute(SVGNames::xAttr))
    183             attributes.setX(current->xCurrentValue());
    184 
    185         if (!attributes.hasY() && current->hasAttribute(SVGNames::yAttr))
    186             attributes.setY(current->yCurrentValue());
    187 
    188         if (!attributes.hasWidth() && current->hasAttribute(SVGNames::widthAttr))
    189             attributes.setWidth(current->widthCurrentValue());
    190 
    191         if (!attributes.hasHeight() && current->hasAttribute(SVGNames::heightAttr))
    192             attributes.setHeight(current->heightCurrentValue());
    193 
    194         if (!attributes.hasViewBox() && current->hasAttribute(SVGNames::viewBoxAttr) && current->viewBoxCurrentValue().isValid())
    195             attributes.setViewBox(current->viewBoxCurrentValue());
    196 
    197         if (!attributes.hasPreserveAspectRatio() && current->hasAttribute(SVGNames::preserveAspectRatioAttr))
    198             attributes.setPreserveAspectRatio(current->preserveAspectRatioCurrentValue());
    199 
    200         if (!attributes.hasPatternUnits() && current->hasAttribute(SVGNames::patternUnitsAttr))
    201             attributes.setPatternUnits(current->patternUnitsCurrentValue());
    202 
    203         if (!attributes.hasPatternContentUnits() && current->hasAttribute(SVGNames::patternContentUnitsAttr))
    204             attributes.setPatternContentUnits(current->patternContentUnitsCurrentValue());
    205 
    206         if (!attributes.hasPatternTransform() && current->hasAttribute(SVGNames::patternTransformAttr)) {
    207             AffineTransform transform;
    208             current->patternTransformCurrentValue().concatenate(transform);
    209             attributes.setPatternTransform(transform);
    210         }
    211 
    212         if (!attributes.hasPatternContentElement() && current->childElementCount())
    213             attributes.setPatternContentElement(current);
    214 
    215         processedPatterns.add(current);
    216 
    217         // Respect xlink:href, take attributes from referenced element
    218         Node* refNode = SVGURIReference::targetElementFromIRIString(current->hrefCurrentValue(), document());
    219         if (refNode && refNode->hasTagName(SVGNames::patternTag)) {
    220             current = toSVGPatternElement(const_cast<const Node*>(refNode));
    221 
    222             // Cycle detection
    223             if (processedPatterns.contains(current)) {
    224                 current = 0;
    225                 break;
    226             }
    227         } else
    228             current = 0;
    229     }
    230 }
    231 
    232 AffineTransform SVGPatternElement::localCoordinateSpaceTransform(SVGElement::CTMScope) const
    233 {
    234     AffineTransform matrix;
    235     patternTransformCurrentValue().concatenate(matrix);
    236     return matrix;
    237 }
    238 
    239 bool SVGPatternElement::selfHasRelativeLengths() const
    240 {
    241     return xCurrentValue().isRelative()
    242         || yCurrentValue().isRelative()
    243         || widthCurrentValue().isRelative()
    244         || heightCurrentValue().isRelative();
    245 }
    246 
    247 }
    248