1 /* 2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis (at) kde.org> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include "config.h" 22 23 #include "core/svg/SVGGraphicsElement.h" 24 25 #include "SVGNames.h" 26 #include "core/platform/graphics/transforms/AffineTransform.h" 27 #include "core/rendering/svg/RenderSVGPath.h" 28 #include "core/rendering/svg/RenderSVGResource.h" 29 #include "core/rendering/svg/SVGPathData.h" 30 #include "core/svg/SVGElementInstance.h" 31 32 namespace WebCore { 33 34 // Animated property definitions 35 DEFINE_ANIMATED_TRANSFORM_LIST(SVGGraphicsElement, SVGNames::transformAttr, Transform, transform) 36 37 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGGraphicsElement) 38 REGISTER_LOCAL_ANIMATED_PROPERTY(transform) 39 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement) 40 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests) 41 END_REGISTER_ANIMATED_PROPERTIES 42 43 SVGGraphicsElement::SVGGraphicsElement(const QualifiedName& tagName, Document* document, ConstructionType constructionType) 44 : SVGElement(tagName, document, constructionType) 45 { 46 registerAnimatedPropertiesForSVGGraphicsElement(); 47 } 48 49 SVGGraphicsElement::~SVGGraphicsElement() 50 { 51 } 52 53 AffineTransform SVGGraphicsElement::getCTM(StyleUpdateStrategy styleUpdateStrategy) 54 { 55 return SVGLocatable::computeCTM(this, SVGLocatable::NearestViewportScope, styleUpdateStrategy); 56 } 57 58 AffineTransform SVGGraphicsElement::getScreenCTM(StyleUpdateStrategy styleUpdateStrategy) 59 { 60 return SVGLocatable::computeCTM(this, SVGLocatable::ScreenScope, styleUpdateStrategy); 61 } 62 63 AffineTransform SVGGraphicsElement::animatedLocalTransform() const 64 { 65 AffineTransform matrix; 66 RenderStyle* style = renderer() ? renderer()->style() : 0; 67 68 // If CSS property was set, use that, otherwise fallback to attribute (if set). 69 if (style && style->hasTransform()) { 70 // Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath. 71 // See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/ 72 TransformationMatrix transform; 73 style->applyTransform(transform, renderer()->objectBoundingBox()); 74 75 // Flatten any 3D transform. 76 matrix = transform.toAffineTransform(); 77 } else { 78 transformCurrentValue().concatenate(matrix); 79 } 80 81 if (m_supplementalTransform) 82 return *m_supplementalTransform * matrix; 83 return matrix; 84 } 85 86 AffineTransform* SVGGraphicsElement::supplementalTransform() 87 { 88 if (!m_supplementalTransform) 89 m_supplementalTransform = adoptPtr(new AffineTransform); 90 return m_supplementalTransform.get(); 91 } 92 93 bool SVGGraphicsElement::isSupportedAttribute(const QualifiedName& attrName) 94 { 95 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 96 if (supportedAttributes.isEmpty()) { 97 SVGTests::addSupportedAttributes(supportedAttributes); 98 supportedAttributes.add(SVGNames::transformAttr); 99 } 100 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 101 } 102 103 void SVGGraphicsElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 104 { 105 if (!isSupportedAttribute(name)) { 106 SVGElement::parseAttribute(name, value); 107 return; 108 } 109 110 if (name == SVGNames::transformAttr) { 111 SVGTransformList newList; 112 newList.parse(value); 113 detachAnimatedTransformListWrappers(newList.size()); 114 setTransformBaseValue(newList); 115 return; 116 } else if (SVGTests::parseAttribute(name, value)) { 117 return; 118 } 119 120 ASSERT_NOT_REACHED(); 121 } 122 123 void SVGGraphicsElement::svgAttributeChanged(const QualifiedName& attrName) 124 { 125 if (!isSupportedAttribute(attrName)) { 126 SVGElement::svgAttributeChanged(attrName); 127 return; 128 } 129 130 SVGElementInstance::InvalidationGuard invalidationGuard(this); 131 132 if (SVGTests::handleAttributeChange(this, attrName)) 133 return; 134 135 RenderObject* object = renderer(); 136 if (!object) 137 return; 138 139 if (attrName == SVGNames::transformAttr) { 140 object->setNeedsTransformUpdate(); 141 RenderSVGResource::markForLayoutAndParentResourceInvalidation(object); 142 return; 143 } 144 145 ASSERT_NOT_REACHED(); 146 } 147 148 SVGElement* SVGGraphicsElement::nearestViewportElement() const 149 { 150 return SVGTransformable::nearestViewportElement(this); 151 } 152 153 SVGElement* SVGGraphicsElement::farthestViewportElement() const 154 { 155 return SVGTransformable::farthestViewportElement(this); 156 } 157 158 SVGRect SVGGraphicsElement::getBBox(StyleUpdateStrategy styleUpdateStrategy) 159 { 160 return SVGTransformable::getBBox(this, styleUpdateStrategy); 161 } 162 163 RenderObject* SVGGraphicsElement::createRenderer(RenderStyle*) 164 { 165 // By default, any subclass is expected to do path-based drawing 166 return new RenderSVGPath(this); 167 } 168 169 void SVGGraphicsElement::toClipPath(Path& path) 170 { 171 updatePathFromGraphicsElement(this, path); 172 // FIXME: How do we know the element has done a layout? 173 path.transform(animatedLocalTransform()); 174 } 175 176 } 177