1 /* 2 Copyright (C) 2006 Apple Computer, Inc. 3 (C) 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 4 5 This file is part of the WebKit project 6 7 This library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Library General Public 9 License as published by the Free Software Foundation; either 10 version 2 of the License, or (at your option) any later version. 11 12 This library is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Library General Public License for more details. 16 17 You should have received a copy of the GNU Library General Public License 18 along with this library; see the file COPYING.LIB. If not, write to 19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 Boston, MA 02110-1301, USA. 21 */ 22 23 #include "config.h" 24 25 #if ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) 26 #include "SVGForeignObjectElement.h" 27 28 #include "CSSPropertyNames.h" 29 #include "MappedAttribute.h" 30 #include "RenderForeignObject.h" 31 #include "SVGLength.h" 32 #include "SVGNames.h" 33 #include <wtf/Assertions.h> 34 35 namespace WebCore { 36 37 SVGForeignObjectElement::SVGForeignObjectElement(const QualifiedName& tagName, Document *doc) 38 : SVGStyledTransformableElement(tagName, doc) 39 , SVGTests() 40 , SVGLangSpace() 41 , SVGExternalResourcesRequired() 42 , m_x(LengthModeWidth) 43 , m_y(LengthModeHeight) 44 , m_width(LengthModeWidth) 45 , m_height(LengthModeHeight) 46 { 47 } 48 49 SVGForeignObjectElement::~SVGForeignObjectElement() 50 { 51 } 52 53 void SVGForeignObjectElement::parseMappedAttribute(MappedAttribute* attr) 54 { 55 const AtomicString& value = attr->value(); 56 if (attr->name() == SVGNames::xAttr) 57 setXBaseValue(SVGLength(LengthModeWidth, value)); 58 else if (attr->name() == SVGNames::yAttr) 59 setYBaseValue(SVGLength(LengthModeHeight, value)); 60 else if (attr->name() == SVGNames::widthAttr) 61 setWidthBaseValue(SVGLength(LengthModeWidth, value)); 62 else if (attr->name() == SVGNames::heightAttr) 63 setHeightBaseValue(SVGLength(LengthModeHeight, value)); 64 else { 65 if (SVGTests::parseMappedAttribute(attr)) 66 return; 67 if (SVGLangSpace::parseMappedAttribute(attr)) 68 return; 69 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) 70 return; 71 SVGStyledTransformableElement::parseMappedAttribute(attr); 72 } 73 } 74 75 // TODO: Move this function in some SVG*Element base class, as SVGSVGElement / SVGImageElement will need the same logic! 76 77 // This function mimics addCSSProperty and StyledElement::attributeChanged. 78 // In HTML code, you'd always call addCSSProperty from your derived parseMappedAttribute() 79 // function - though in SVG code we need to move this logic into svgAttributeChanged, in 80 // order to support SVG DOM changes (which don't use the parseMappedAttribute/attributeChanged). 81 // If we'd ignore SVG DOM, we could use _exactly_ the same logic as HTML. 82 static inline void addCSSPropertyAndNotifyAttributeMap(StyledElement* element, const QualifiedName& name, int cssProperty, const String& value) 83 { 84 ASSERT(element); 85 86 if (!element) 87 return; 88 89 NamedMappedAttrMap* attrs = element->mappedAttributes(); 90 ASSERT(attrs); 91 92 if (!attrs) 93 return; 94 95 Attribute* attr = attrs->getAttributeItem(name); 96 if (!attr || !attr->isMappedAttribute()) 97 return; 98 99 MappedAttribute* mappedAttr = static_cast<MappedAttribute*>(attr); 100 101 // This logic is only meant to be used for entries that have to be parsed and are mapped to eNone. Assert that. 102 MappedAttributeEntry entry; 103 bool needToParse = element->mapToEntry(mappedAttr->name(), entry); 104 105 ASSERT(needToParse); 106 ASSERT(entry == eNone); 107 108 if (!needToParse || entry != eNone) 109 return; 110 111 if (mappedAttr->decl()) { 112 mappedAttr->setDecl(0); 113 attrs->declRemoved(); 114 } 115 116 element->setNeedsStyleRecalc(); 117 element->addCSSProperty(mappedAttr, cssProperty, value); 118 119 if (CSSMappedAttributeDeclaration* decl = mappedAttr->decl()) { 120 // Add the decl to the table in the appropriate spot. 121 element->setMappedAttributeDecl(entry, mappedAttr, decl); 122 123 decl->setMappedState(entry, mappedAttr->name(), mappedAttr->value()); 124 decl->setParent(0); 125 decl->setNode(0); 126 127 attrs->declAdded(); 128 } 129 } 130 131 void SVGForeignObjectElement::svgAttributeChanged(const QualifiedName& attrName) 132 { 133 SVGStyledTransformableElement::svgAttributeChanged(attrName); 134 135 if (attrName == SVGNames::widthAttr) { 136 addCSSPropertyAndNotifyAttributeMap(this, attrName, CSSPropertyWidth, width().valueAsString()); 137 return; 138 } else if (attrName == SVGNames::heightAttr) { 139 addCSSPropertyAndNotifyAttributeMap(this, attrName, CSSPropertyHeight, height().valueAsString()); 140 return; 141 } 142 143 if (!renderer()) 144 return; 145 146 if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || 147 SVGTests::isKnownAttribute(attrName) || 148 SVGLangSpace::isKnownAttribute(attrName) || 149 SVGExternalResourcesRequired::isKnownAttribute(attrName) || 150 SVGStyledTransformableElement::isKnownAttribute(attrName)) 151 renderer()->setNeedsLayout(true); 152 } 153 154 void SVGForeignObjectElement::synchronizeProperty(const QualifiedName& attrName) 155 { 156 SVGStyledTransformableElement::synchronizeProperty(attrName); 157 158 if (attrName == anyQName()) { 159 synchronizeX(); 160 synchronizeY(); 161 synchronizeWidth(); 162 synchronizeHeight(); 163 synchronizeExternalResourcesRequired(); 164 synchronizeHref(); 165 return; 166 } 167 168 if (attrName == SVGNames::xAttr) 169 synchronizeX(); 170 else if (attrName == SVGNames::yAttr) 171 synchronizeY(); 172 else if (attrName == SVGNames::widthAttr) 173 synchronizeWidth(); 174 else if (attrName == SVGNames::heightAttr) 175 synchronizeHeight(); 176 else if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) 177 synchronizeExternalResourcesRequired(); 178 else if (SVGURIReference::isKnownAttribute(attrName)) 179 synchronizeHref(); 180 } 181 182 RenderObject* SVGForeignObjectElement::createRenderer(RenderArena* arena, RenderStyle*) 183 { 184 return new (arena) RenderForeignObject(this); 185 } 186 187 bool SVGForeignObjectElement::childShouldCreateRenderer(Node* child) const 188 { 189 // Skip over SVG rules which disallow non-SVG kids 190 return StyledElement::childShouldCreateRenderer(child); 191 } 192 193 } // namespace WebCore 194 195 #endif // ENABLE(SVG) && ENABLE(SVG_FOREIGN_OBJECT) 196