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