Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2005 Alexander Kellett <lypanov (at) kde.org>
      5  * Copyright (C) 2009 Dirk Schulze <krit (at) webkit.org>
      6  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  */
     23 
     24 #include "config.h"
     25 
     26 #if ENABLE(SVG)
     27 #include "SVGMaskElement.h"
     28 
     29 #include "Attribute.h"
     30 #include "CSSStyleSelector.h"
     31 #include "RenderSVGResourceMasker.h"
     32 #include "SVGNames.h"
     33 #include "SVGRenderSupport.h"
     34 #include "SVGUnitTypes.h"
     35 
     36 namespace WebCore {
     37 
     38 // Animated property definitions
     39 DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskUnitsAttr, MaskUnits, maskUnits)
     40 DEFINE_ANIMATED_ENUMERATION(SVGMaskElement, SVGNames::maskContentUnitsAttr, MaskContentUnits, maskContentUnits)
     41 DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::xAttr, X, x)
     42 DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::yAttr, Y, y)
     43 DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::widthAttr, Width, width)
     44 DEFINE_ANIMATED_LENGTH(SVGMaskElement, SVGNames::heightAttr, Height, height)
     45 DEFINE_ANIMATED_BOOLEAN(SVGMaskElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
     46 
     47 inline SVGMaskElement::SVGMaskElement(const QualifiedName& tagName, Document* document)
     48     : SVGStyledLocatableElement(tagName, document)
     49     , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
     50     , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
     51     , m_x(LengthModeWidth, "-10%")
     52     , m_y(LengthModeHeight, "-10%")
     53     , m_width(LengthModeWidth, "120%")
     54     , m_height(LengthModeHeight, "120%")
     55 {
     56     // Spec: If the x/y attribute is not specified, the effect is as if a value of "-10%" were specified.
     57     // Spec: If the width/height attribute is not specified, the effect is as if a value of "120%" were specified.
     58 }
     59 
     60 PassRefPtr<SVGMaskElement> SVGMaskElement::create(const QualifiedName& tagName, Document* document)
     61 {
     62     return adoptRef(new SVGMaskElement(tagName, document));
     63 }
     64 
     65 void SVGMaskElement::parseMappedAttribute(Attribute* attr)
     66 {
     67     if (attr->name() == SVGNames::maskUnitsAttr) {
     68         if (attr->value() == "userSpaceOnUse")
     69             setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     70         else if (attr->value() == "objectBoundingBox")
     71             setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     72     } else if (attr->name() == SVGNames::maskContentUnitsAttr) {
     73         if (attr->value() == "userSpaceOnUse")
     74             setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     75         else if (attr->value() == "objectBoundingBox")
     76             setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     77     } else if (attr->name() == SVGNames::xAttr)
     78         setXBaseValue(SVGLength(LengthModeWidth, attr->value()));
     79     else if (attr->name() == SVGNames::yAttr)
     80         setYBaseValue(SVGLength(LengthModeHeight, attr->value()));
     81     else if (attr->name() == SVGNames::widthAttr)
     82         setWidthBaseValue(SVGLength(LengthModeWidth, attr->value()));
     83     else if (attr->name() == SVGNames::heightAttr)
     84         setHeightBaseValue(SVGLength(LengthModeHeight, attr->value()));
     85     else {
     86         if (SVGTests::parseMappedAttribute(attr))
     87             return;
     88         if (SVGLangSpace::parseMappedAttribute(attr))
     89             return;
     90         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
     91             return;
     92         SVGStyledElement::parseMappedAttribute(attr);
     93     }
     94 }
     95 
     96 void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName)
     97 {
     98     SVGStyledElement::svgAttributeChanged(attrName);
     99 
    100     bool invalidateClients = false;
    101     if (attrName == SVGNames::xAttr
    102         || attrName == SVGNames::yAttr
    103         || attrName == SVGNames::widthAttr
    104         || attrName == SVGNames::heightAttr) {
    105         invalidateClients = true;
    106         updateRelativeLengthsInformation();
    107     }
    108 
    109     RenderObject* object = renderer();
    110     if (!object)
    111         return;
    112 
    113     if (invalidateClients
    114         || attrName == SVGNames::maskUnitsAttr
    115         || attrName == SVGNames::maskContentUnitsAttr
    116         || SVGTests::isKnownAttribute(attrName)
    117         || SVGLangSpace::isKnownAttribute(attrName)
    118         || SVGExternalResourcesRequired::isKnownAttribute(attrName)
    119         || SVGStyledElement::isKnownAttribute(attrName))
    120         object->setNeedsLayout(true);
    121 }
    122 
    123 void SVGMaskElement::synchronizeProperty(const QualifiedName& attrName)
    124 {
    125     SVGStyledElement::synchronizeProperty(attrName);
    126 
    127     if (attrName == anyQName()) {
    128         synchronizeMaskUnits();
    129         synchronizeMaskContentUnits();
    130         synchronizeX();
    131         synchronizeY();
    132         synchronizeExternalResourcesRequired();
    133         SVGTests::synchronizeProperties(this, attrName);
    134         return;
    135     }
    136 
    137     if (attrName == SVGNames::maskUnitsAttr)
    138         synchronizeMaskUnits();
    139     else if (attrName == SVGNames::maskContentUnitsAttr)
    140         synchronizeMaskContentUnits();
    141     else if (attrName == SVGNames::xAttr)
    142         synchronizeX();
    143     else if (attrName == SVGNames::yAttr)
    144         synchronizeY();
    145     else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    146         synchronizeExternalResourcesRequired();
    147     else if (SVGTests::isKnownAttribute(attrName))
    148         SVGTests::synchronizeProperties(this, attrName);
    149 }
    150 
    151 AttributeToPropertyTypeMap& SVGMaskElement::attributeToPropertyTypeMap()
    152 {
    153     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
    154     return s_attributeToPropertyTypeMap;
    155 }
    156 
    157 void SVGMaskElement::fillAttributeToPropertyTypeMap()
    158 {
    159     AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
    160 
    161     SVGStyledLocatableElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
    162     attributeToPropertyTypeMap.set(SVGNames::xAttr, AnimatedLength);
    163     attributeToPropertyTypeMap.set(SVGNames::yAttr, AnimatedLength);
    164     attributeToPropertyTypeMap.set(SVGNames::widthAttr, AnimatedLength);
    165     attributeToPropertyTypeMap.set(SVGNames::heightAttr, AnimatedLength);
    166     attributeToPropertyTypeMap.set(SVGNames::maskUnitsAttr, AnimatedEnumeration);
    167     attributeToPropertyTypeMap.set(SVGNames::maskContentUnitsAttr, AnimatedEnumeration);
    168 }
    169 
    170 void SVGMaskElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    171 {
    172     SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    173 
    174     if (changedByParser)
    175         return;
    176 
    177     if (RenderObject* object = renderer())
    178         object->setNeedsLayout(true);
    179 }
    180 
    181 FloatRect SVGMaskElement::maskBoundingBox(const FloatRect& objectBoundingBox) const
    182 {
    183     FloatRect maskBBox;
    184     if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
    185         maskBBox = FloatRect(x().valueAsPercentage() * objectBoundingBox.width() + objectBoundingBox.x(),
    186                              y().valueAsPercentage() * objectBoundingBox.height() + objectBoundingBox.y(),
    187                              width().valueAsPercentage() * objectBoundingBox.width(),
    188                              height().valueAsPercentage() * objectBoundingBox.height());
    189     else
    190         maskBBox = FloatRect(x().value(this),
    191                              y().value(this),
    192                              width().value(this),
    193                              height().value(this));
    194 
    195     return maskBBox;
    196 }
    197 
    198 RenderObject* SVGMaskElement::createRenderer(RenderArena* arena, RenderStyle*)
    199 {
    200     return new (arena) RenderSVGResourceMasker(this);
    201 }
    202 
    203 bool SVGMaskElement::selfHasRelativeLengths() const
    204 {
    205     return x().isRelative()
    206         || y().isRelative()
    207         || width().isRelative()
    208         || height().isRelative();
    209 }
    210 
    211 }
    212 
    213 #endif // ENABLE(SVG)
    214