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