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 #if ENABLE(SVG)
     25 #include "SVGPatternElement.h"
     26 
     27 #include "AffineTransform.h"
     28 #include "Attribute.h"
     29 #include "Document.h"
     30 #include "FloatConversion.h"
     31 #include "GraphicsContext.h"
     32 #include "ImageBuffer.h"
     33 #include "PatternAttributes.h"
     34 #include "RenderSVGContainer.h"
     35 #include "RenderSVGResourcePattern.h"
     36 #include "SVGNames.h"
     37 #include "SVGRenderSupport.h"
     38 #include "SVGSVGElement.h"
     39 #include "SVGStyledTransformableElement.h"
     40 #include "SVGTransformable.h"
     41 #include "SVGUnitTypes.h"
     42 
     43 namespace WebCore {
     44 
     45 // Animated property definitions
     46 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::xAttr, X, x)
     47 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::yAttr, Y, y)
     48 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::widthAttr, Width, width)
     49 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::heightAttr, Height, height)
     50 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternUnitsAttr, PatternUnits, patternUnits)
     51 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternContentUnitsAttr, PatternContentUnits, patternContentUnits)
     52 DEFINE_ANIMATED_TRANSFORM_LIST(SVGPatternElement, SVGNames::patternTransformAttr, PatternTransform, patternTransform)
     53 DEFINE_ANIMATED_STRING(SVGPatternElement, XLinkNames::hrefAttr, Href, href)
     54 DEFINE_ANIMATED_BOOLEAN(SVGPatternElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     55 DEFINE_ANIMATED_RECT(SVGPatternElement, SVGNames::viewBoxAttr, ViewBox, viewBox)
     56 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGPatternElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio)
     57 
     58 inline SVGPatternElement::SVGPatternElement(const QualifiedName& tagName, Document* document)
     59     : SVGStyledElement(tagName, document)
     60     , m_x(LengthModeWidth)
     61     , m_y(LengthModeHeight)
     62     , m_width(LengthModeWidth)
     63     , m_height(LengthModeHeight)
     64     , m_patternUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
     65     , m_patternContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
     66 {
     67 }
     68 
     69 PassRefPtr<SVGPatternElement> SVGPatternElement::create(const QualifiedName& tagName, Document* document)
     70 {
     71     return adoptRef(new SVGPatternElement(tagName, document));
     72 }
     73 
     74 void SVGPatternElement::parseMappedAttribute(Attribute* attr)
     75 {
     76     if (attr->name() == SVGNames::patternUnitsAttr) {
     77         if (attr->value() == "userSpaceOnUse")
     78             setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     79         else if (attr->value() == "objectBoundingBox")
     80             setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     81     } else if (attr->name() == SVGNames::patternContentUnitsAttr) {
     82         if (attr->value() == "userSpaceOnUse")
     83             setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     84         else if (attr->value() == "objectBoundingBox")
     85             setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     86     } else if (attr->name() == SVGNames::patternTransformAttr) {
     87         SVGTransformList newList;
     88         if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
     89             newList.clear();
     90 
     91         detachAnimatedPatternTransformListWrappers(newList.size());
     92         setPatternTransformBaseValue(newList);
     93     } else if (attr->name() == SVGNames::xAttr)
     94         setXBaseValue(SVGLength(LengthModeWidth, attr->value()));
     95     else if (attr->name() == SVGNames::yAttr)
     96         setYBaseValue(SVGLength(LengthModeHeight, attr->value()));
     97     else if (attr->name() == SVGNames::widthAttr) {
     98         setWidthBaseValue(SVGLength(LengthModeWidth, attr->value()));
     99         if (widthBaseValue().value(this) < 0.0)
    100             document()->accessSVGExtensions()->reportError("A negative value for pattern attribute <width> is not allowed");
    101     } else if (attr->name() == SVGNames::heightAttr) {
    102         setHeightBaseValue(SVGLength(LengthModeHeight, attr->value()));
    103         if (heightBaseValue().value(this) < 0.0)
    104             document()->accessSVGExtensions()->reportError("A negative value for pattern attribute <height> is not allowed");
    105     } else {
    106         if (SVGURIReference::parseMappedAttribute(attr))
    107             return;
    108         if (SVGTests::parseMappedAttribute(attr))
    109             return;
    110         if (SVGLangSpace::parseMappedAttribute(attr))
    111             return;
    112         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
    113             return;
    114         if (SVGFitToViewBox::parseMappedAttribute(document(), attr))
    115             return;
    116 
    117         SVGStyledElement::parseMappedAttribute(attr);
    118     }
    119 }
    120 
    121 void SVGPatternElement::svgAttributeChanged(const QualifiedName& attrName)
    122 {
    123     SVGStyledElement::svgAttributeChanged(attrName);
    124 
    125     bool invalidateClients = false;
    126     if (attrName == SVGNames::xAttr
    127         || attrName == SVGNames::yAttr
    128         || attrName == SVGNames::widthAttr
    129         || attrName == SVGNames::heightAttr) {
    130         invalidateClients = true;
    131         updateRelativeLengthsInformation();
    132     }
    133 
    134     RenderObject* object = renderer();
    135     if (!object)
    136         return;
    137 
    138     if (invalidateClients
    139         || attrName == SVGNames::patternUnitsAttr
    140         || attrName == SVGNames::patternContentUnitsAttr
    141         || attrName == SVGNames::patternTransformAttr
    142         || SVGURIReference::isKnownAttribute(attrName)
    143         || SVGTests::isKnownAttribute(attrName)
    144         || SVGLangSpace::isKnownAttribute(attrName)
    145         || SVGExternalResourcesRequired::isKnownAttribute(attrName)
    146         || SVGFitToViewBox::isKnownAttribute(attrName)
    147         || SVGStyledElement::isKnownAttribute(attrName))
    148         object->setNeedsLayout(true);
    149 }
    150 
    151 void SVGPatternElement::synchronizeProperty(const QualifiedName& attrName)
    152 {
    153     SVGStyledElement::synchronizeProperty(attrName);
    154 
    155     if (attrName == anyQName()) {
    156         synchronizePatternUnits();
    157         synchronizePatternContentUnits();
    158         synchronizePatternTransform();
    159         synchronizeX();
    160         synchronizeY();
    161         synchronizeWidth();
    162         synchronizeHeight();
    163         synchronizeExternalResourcesRequired();
    164         synchronizeViewBox();
    165         synchronizePreserveAspectRatio();
    166         synchronizeHref();
    167         SVGTests::synchronizeProperties(this, attrName);
    168         return;
    169     }
    170 
    171     if (attrName == SVGNames::patternUnitsAttr)
    172         synchronizePatternUnits();
    173     else if (attrName == SVGNames::patternContentUnitsAttr)
    174         synchronizePatternContentUnits();
    175     else if (attrName == SVGNames::patternTransformAttr)
    176         synchronizePatternTransform();
    177     else if (attrName == SVGNames::xAttr)
    178         synchronizeX();
    179     else if (attrName == SVGNames::yAttr)
    180         synchronizeY();
    181     else if (attrName == SVGNames::widthAttr)
    182         synchronizeWidth();
    183     else if (attrName == SVGNames::heightAttr)
    184         synchronizeHeight();
    185     else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    186         synchronizeExternalResourcesRequired();
    187     else if (attrName == SVGNames::viewBoxAttr)
    188         synchronizeViewBox();
    189     else if (attrName == SVGNames::preserveAspectRatioAttr)
    190         synchronizePreserveAspectRatio();
    191     else if (SVGURIReference::isKnownAttribute(attrName))
    192         synchronizeHref();
    193     else if (SVGTests::isKnownAttribute(attrName))
    194         SVGTests::synchronizeProperties(this, attrName);
    195 }
    196 
    197 AttributeToPropertyTypeMap& SVGPatternElement::attributeToPropertyTypeMap()
    198 {
    199     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
    200     return s_attributeToPropertyTypeMap;
    201 }
    202 
    203 void SVGPatternElement::fillAttributeToPropertyTypeMap()
    204 {
    205     AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
    206 
    207     SVGStyledElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
    208     attributeToPropertyTypeMap.set(SVGNames::xAttr, AnimatedLength);
    209     attributeToPropertyTypeMap.set(SVGNames::yAttr, AnimatedLength);
    210     attributeToPropertyTypeMap.set(SVGNames::widthAttr, AnimatedLength);
    211     attributeToPropertyTypeMap.set(SVGNames::heightAttr, AnimatedLength);
    212     attributeToPropertyTypeMap.set(SVGNames::patternUnitsAttr, AnimatedEnumeration);
    213     attributeToPropertyTypeMap.set(SVGNames::patternContentUnitsAttr, AnimatedEnumeration);
    214     attributeToPropertyTypeMap.set(SVGNames::patternTransformAttr, AnimatedTransformList);
    215     attributeToPropertyTypeMap.set(XLinkNames::hrefAttr, AnimatedString);
    216     attributeToPropertyTypeMap.set(SVGNames::viewBoxAttr, AnimatedRect);
    217     attributeToPropertyTypeMap.set(SVGNames::preserveAspectRatioAttr, AnimatedPreserveAspectRatio);
    218 }
    219 
    220 void SVGPatternElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    221 {
    222     SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    223 
    224     if (changedByParser)
    225         return;
    226 
    227     if (RenderObject* object = renderer())
    228         object->setNeedsLayout(true);
    229 }
    230 
    231 RenderObject* SVGPatternElement::createRenderer(RenderArena* arena, RenderStyle*)
    232 {
    233     return new (arena) RenderSVGResourcePattern(this);
    234 }
    235 
    236 void SVGPatternElement::collectPatternAttributes(PatternAttributes& attributes) const
    237 {
    238     HashSet<const SVGPatternElement*> processedPatterns;
    239 
    240     const SVGPatternElement* current = this;
    241     while (current) {
    242         if (!attributes.hasX() && current->hasAttribute(SVGNames::xAttr))
    243             attributes.setX(current->x());
    244 
    245         if (!attributes.hasY() && current->hasAttribute(SVGNames::yAttr))
    246             attributes.setY(current->y());
    247 
    248         if (!attributes.hasWidth() && current->hasAttribute(SVGNames::widthAttr))
    249             attributes.setWidth(current->width());
    250 
    251         if (!attributes.hasHeight() && current->hasAttribute(SVGNames::heightAttr))
    252             attributes.setHeight(current->height());
    253 
    254         if (!attributes.hasViewBox() && current->hasAttribute(SVGNames::viewBoxAttr))
    255             attributes.setViewBox(current->viewBox());
    256 
    257         if (!attributes.hasPreserveAspectRatio() && current->hasAttribute(SVGNames::preserveAspectRatioAttr))
    258             attributes.setPreserveAspectRatio(current->preserveAspectRatio());
    259 
    260         if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::patternUnitsAttr))
    261             attributes.setBoundingBoxMode(current->patternUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
    262 
    263         if (!attributes.hasBoundingBoxModeContent() && current->hasAttribute(SVGNames::patternContentUnitsAttr))
    264             attributes.setBoundingBoxModeContent(current->patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
    265 
    266         if (!attributes.hasPatternTransform() && current->hasAttribute(SVGNames::patternTransformAttr)) {
    267             AffineTransform transform;
    268             current->patternTransform().concatenate(transform);
    269             attributes.setPatternTransform(transform);
    270         }
    271 
    272         if (!attributes.hasPatternContentElement() && current->hasChildNodes())
    273             attributes.setPatternContentElement(current);
    274 
    275         processedPatterns.add(current);
    276 
    277         // Respect xlink:href, take attributes from referenced element
    278         Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
    279         if (refNode && refNode->hasTagName(SVGNames::patternTag)) {
    280             current = static_cast<const SVGPatternElement*>(const_cast<const Node*>(refNode));
    281 
    282             // Cycle detection
    283             if (processedPatterns.contains(current)) {
    284                 current = 0;
    285                 break;
    286             }
    287         } else
    288             current = 0;
    289     }
    290 }
    291 
    292 bool SVGPatternElement::selfHasRelativeLengths() const
    293 {
    294     return x().isRelative()
    295         || y().isRelative()
    296         || width().isRelative()
    297         || height().isRelative();
    298 }
    299 
    300 }
    301 
    302 #endif // ENABLE(SVG)
    303