1/* 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org> 4 * Copyright (C) 2008 Apple Inc. All rights reserved. 5 * Copyright (C) 2008 Alp Toker <alp@atoker.com> 6 * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> 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 "SVGElement.h" 28 29#include "CSSCursorImageValue.h" 30#include "DOMImplementation.h" 31#include "Document.h" 32#include "Event.h" 33#include "HTMLNames.h" 34#include "NodeRenderingContext.h" 35#include "RenderObject.h" 36#include "SVGCursorElement.h" 37#include "SVGDocumentExtensions.h" 38#include "SVGElementInstance.h" 39#include "SVGElementRareData.h" 40#include "SVGNames.h" 41#include "SVGSVGElement.h" 42#include "SVGStyledLocatableElement.h" 43#include "SVGTextElement.h" 44#include "ScriptEventListener.h" 45#include "XMLNames.h" 46 47namespace WebCore { 48 49using namespace HTMLNames; 50 51SVGElement::SVGElement(const QualifiedName& tagName, Document* document, ConstructionType constructionType) 52 : StyledElement(tagName, document, constructionType) 53{ 54 setHasCustomStyleCallbacks(); 55} 56 57PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document) 58{ 59 return adoptRef(new SVGElement(tagName, document)); 60} 61 62SVGElement::~SVGElement() 63{ 64 if (!hasSVGRareData()) 65 ASSERT(!SVGElementRareData::rareDataMap().contains(this)); 66 else { 67 ASSERT(document()); 68 SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap(); 69 SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this); 70 ASSERT(it != rareDataMap.end()); 71 72 SVGElementRareData* rareData = it->value; 73 rareData->destroyAnimatedSMILStyleProperties(); 74 if (SVGCursorElement* cursorElement = rareData->cursorElement()) 75 cursorElement->removeClient(this); 76 if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue()) 77 cursorImageValue->removeReferencedElement(this); 78 79 delete rareData; 80 81 it = rareDataMap.find(this); 82 ASSERT(it != rareDataMap.end()); 83 rareDataMap.remove(it); 84 } 85 ASSERT(document()); 86 document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this); 87 document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this); 88} 89 90bool SVGElement::willRecalcStyle(StyleChange change) 91{ 92 if (!hasSVGRareData() || styleChangeType() == SyntheticStyleChange) 93 return true; 94 // If the style changes because of a regular property change (not induced by SMIL animations themselves) 95 // reset the "computed style without SMIL style properties", so the base value change gets reflected. 96 if (change > NoChange || needsStyleRecalc()) 97 svgRareData()->setNeedsOverrideComputedStyleUpdate(); 98 return true; 99} 100 101SVGElementRareData* SVGElement::svgRareData() const 102{ 103 ASSERT(hasSVGRareData()); 104 return SVGElementRareData::rareDataFromMap(this); 105} 106 107SVGElementRareData* SVGElement::ensureSVGRareData() 108{ 109 if (hasSVGRareData()) 110 return svgRareData(); 111 112 ASSERT(!SVGElementRareData::rareDataMap().contains(this)); 113 SVGElementRareData* data = new SVGElementRareData; 114 SVGElementRareData::rareDataMap().set(this, data); 115 setHasSVGRareData(); 116 return data; 117} 118 119bool SVGElement::isOutermostSVGSVGElement() const 120{ 121 if (!hasTagName(SVGNames::svgTag)) 122 return false; 123 124 // If we're living in a shadow tree, we're a <svg> element that got created as replacement 125 // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case 126 // we're always an inner <svg> element. 127 if (isInShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement()) 128 return false; 129 130 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc. 131 if (!parentNode()) 132 return true; 133 134 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element. 135 if (parentNode()->hasTagName(SVGNames::foreignObjectTag)) 136 return true; 137 138 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it 139 return !parentNode()->isSVGElement(); 140} 141 142void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value) 143{ 144 if (error == NoError) 145 return; 146 147 String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\""; 148 SVGDocumentExtensions* extensions = document()->accessSVGExtensions(); 149 150 if (error == NegativeValueForbiddenError) { 151 extensions->reportError("Invalid negative value for " + errorString); 152 return; 153 } 154 155 if (error == ParsingAttributeFailedError) { 156 extensions->reportError("Invalid value for " + errorString); 157 return; 158 } 159 160 ASSERT_NOT_REACHED(); 161} 162 163 164bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const 165{ 166 return DOMImplementation::hasFeature(feature, version); 167} 168 169String SVGElement::xmlbase() const 170{ 171 return fastGetAttribute(XMLNames::baseAttr); 172} 173 174void SVGElement::setXmlbase(const String& value, ExceptionCode&) 175{ 176 setAttribute(XMLNames::baseAttr, value); 177} 178 179void SVGElement::removedFrom(ContainerNode* rootParent) 180{ 181 bool wasInDocument = rootParent->inDocument(); 182 183 StyledElement::removedFrom(rootParent); 184 185 if (wasInDocument) { 186 document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this); 187 document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this); 188 } 189} 190 191SVGSVGElement* SVGElement::ownerSVGElement() const 192{ 193 ContainerNode* n = parentOrShadowHostNode(); 194 while (n) { 195 if (n->hasTagName(SVGNames::svgTag)) 196 return toSVGSVGElement(n); 197 198 n = n->parentOrShadowHostNode(); 199 } 200 201 return 0; 202} 203 204SVGElement* SVGElement::viewportElement() const 205{ 206 // This function needs shadow tree support - as RenderSVGContainer uses this function 207 // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise. 208 ContainerNode* n = parentOrShadowHostNode(); 209 while (n) { 210 if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag)) 211 return toSVGElement(n); 212 213 n = n->parentOrShadowHostNode(); 214 } 215 216 return 0; 217} 218 219SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions() 220{ 221 // This function is provided for use by SVGAnimatedProperty to avoid 222 // global inclusion of Document.h in SVG code. 223 return document() ? document()->accessSVGExtensions() : 0; 224} 225 226void SVGElement::mapInstanceToElement(SVGElementInstance* instance) 227{ 228 ASSERT(instance); 229 230 HashSet<SVGElementInstance*>& instances = ensureSVGRareData()->elementInstances(); 231 ASSERT(!instances.contains(instance)); 232 233 instances.add(instance); 234} 235 236void SVGElement::removeInstanceMapping(SVGElementInstance* instance) 237{ 238 ASSERT(instance); 239 ASSERT(hasSVGRareData()); 240 241 HashSet<SVGElementInstance*>& instances = svgRareData()->elementInstances(); 242 ASSERT(instances.contains(instance)); 243 244 instances.remove(instance); 245} 246 247const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const 248{ 249 if (!hasSVGRareData()) { 250 DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ()); 251 return emptyInstances; 252 } 253 return svgRareData()->elementInstances(); 254} 255 256bool SVGElement::getBoundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy) 257{ 258 if (isStyledLocatable()) { 259 rect = toSVGStyledLocatableElement(this)->getBBox(styleUpdateStrategy); 260 return true; 261 } 262 if (hasTagName(SVGNames::textTag)) { 263 rect = static_cast<SVGTextElement*>(this)->getBBox(styleUpdateStrategy); 264 return true; 265 } 266 return false; 267} 268 269void SVGElement::setCursorElement(SVGCursorElement* cursorElement) 270{ 271 SVGElementRareData* rareData = ensureSVGRareData(); 272 if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) { 273 if (cursorElement == oldCursorElement) 274 return; 275 oldCursorElement->removeReferencedElement(this); 276 } 277 rareData->setCursorElement(cursorElement); 278} 279 280void SVGElement::cursorElementRemoved() 281{ 282 ASSERT(hasSVGRareData()); 283 svgRareData()->setCursorElement(0); 284} 285 286void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue) 287{ 288 SVGElementRareData* rareData = ensureSVGRareData(); 289 if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) { 290 if (cursorImageValue == oldCursorImageValue) 291 return; 292 oldCursorImageValue->removeReferencedElement(this); 293 } 294 rareData->setCursorImageValue(cursorImageValue); 295} 296 297void SVGElement::cursorImageValueRemoved() 298{ 299 ASSERT(hasSVGRareData()); 300 svgRareData()->setCursorImageValue(0); 301} 302 303SVGElement* SVGElement::correspondingElement() 304{ 305 ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot()); 306 return hasSVGRareData() ? svgRareData()->correspondingElement() : 0; 307} 308 309void SVGElement::setCorrespondingElement(SVGElement* correspondingElement) 310{ 311 ensureSVGRareData()->setCorrespondingElement(correspondingElement); 312} 313 314void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 315{ 316 // standard events 317 if (name == onloadAttr) 318 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, name, value)); 319 else if (name == onclickAttr) 320 setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, name, value)); 321 else if (name == onmousedownAttr) 322 setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, name, value)); 323 else if (name == onmouseenterAttr) 324 setAttributeEventListener(eventNames().mouseenterEvent, createAttributeEventListener(this, name, value)); 325 else if (name == onmouseleaveAttr) 326 setAttributeEventListener(eventNames().mouseleaveEvent, createAttributeEventListener(this, name, value)); 327 else if (name == onmousemoveAttr) 328 setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, name, value)); 329 else if (name == onmouseoutAttr) 330 setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, name, value)); 331 else if (name == onmouseoverAttr) 332 setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, name, value)); 333 else if (name == onmouseupAttr) 334 setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, name, value)); 335 else if (name == SVGNames::onfocusinAttr) 336 setAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(this, name, value)); 337 else if (name == SVGNames::onfocusoutAttr) 338 setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, name, value)); 339 else if (name == SVGNames::onactivateAttr) 340 setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, name, value)); 341 else 342 StyledElement::parseAttribute(name, value); 343} 344 345void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes) 346{ 347 localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes); 348} 349 350bool SVGElement::haveLoadedRequiredResources() 351{ 352 Node* child = firstChild(); 353 while (child) { 354 if (child->isSVGElement() && !toSVGElement(child)->haveLoadedRequiredResources()) 355 return false; 356 child = child->nextSibling(); 357 } 358 return true; 359} 360 361static inline void collectInstancesForSVGElement(SVGElement* element, HashSet<SVGElementInstance*>& instances) 362{ 363 ASSERT(element); 364 if (element->containingShadowRoot()) 365 return; 366 367 if (!element->isSVGStyledElement()) 368 return; 369 370 SVGStyledElement* styledElement = toSVGStyledElement(element); 371 ASSERT(!styledElement->instanceUpdatesBlocked()); 372 373 instances = styledElement->instancesForElement(); 374} 375 376bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture) 377{ 378 RefPtr<EventListener> listener = prpListener; 379 380 // Add event listener to regular DOM element 381 if (!Node::addEventListener(eventType, listener, useCapture)) 382 return false; 383 384 // Add event listener to all shadow tree DOM element instances 385 HashSet<SVGElementInstance*> instances; 386 collectInstancesForSVGElement(this, instances); 387 const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); 388 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { 389 ASSERT((*it)->shadowTreeElement()); 390 ASSERT((*it)->correspondingElement() == this); 391 392 bool result = (*it)->shadowTreeElement()->Node::addEventListener(eventType, listener, useCapture); 393 ASSERT_UNUSED(result, result); 394 } 395 396 return true; 397} 398 399bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) 400{ 401 HashSet<SVGElementInstance*> instances; 402 collectInstancesForSVGElement(this, instances); 403 if (instances.isEmpty()) 404 return Node::removeEventListener(eventType, listener, useCapture); 405 406 // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener 407 // object when creating a temporary RegisteredEventListener object used to look up the 408 // event listener in a cache. If we want to be able to call removeEventListener() multiple 409 // times on different nodes, we have to delay its immediate destruction, which would happen 410 // after the first call below. 411 RefPtr<EventListener> protector(listener); 412 413 // Remove event listener from regular DOM element 414 if (!Node::removeEventListener(eventType, listener, useCapture)) 415 return false; 416 417 // Remove event listener from all shadow tree DOM element instances 418 const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); 419 for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { 420 ASSERT((*it)->correspondingElement() == this); 421 422 SVGElement* shadowTreeElement = (*it)->shadowTreeElement(); 423 ASSERT(shadowTreeElement); 424 425 if (shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture)) 426 continue; 427 428 // This case can only be hit for event listeners created from markup 429 ASSERT(listener->wasCreatedFromMarkup()); 430 431 // If the event listener 'listener' has been created from markup and has been fired before 432 // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener 433 // has been created (read: it's not 0 anymore). During shadow tree creation, the event 434 // listener DOM attribute has been cloned, and another event listener has been setup in 435 // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0, 436 // and tryRemoveEventListener() above will fail. Work around that very seldom problem. 437 EventTargetData* data = shadowTreeElement->eventTargetData(); 438 ASSERT(data); 439 440 data->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType); 441 } 442 443 return true; 444} 445 446static bool hasLoadListener(Element* element) 447{ 448 if (element->hasEventListeners(eventNames().loadEvent)) 449 return true; 450 451 for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) { 452 const EventListenerVector& entry = element->getEventListeners(eventNames().loadEvent); 453 for (size_t i = 0; i < entry.size(); ++i) { 454 if (entry[i].useCapture) 455 return true; 456 } 457 } 458 459 return false; 460} 461 462bool SVGElement::shouldMoveToFlowThread(RenderStyle* styleToUse) const 463{ 464 // Allow only svg root elements to be directly collected by a render flow thread. 465 return parentNode() && !parentNode()->isSVGElement() && hasTagName(SVGNames::svgTag) && Element::shouldMoveToFlowThread(styleToUse); 466} 467 468void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents) 469{ 470 RefPtr<SVGElement> currentTarget = this; 471 while (currentTarget && currentTarget->haveLoadedRequiredResources()) { 472 RefPtr<Element> parent; 473 if (sendParentLoadEvents) 474 parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree 475 if (hasLoadListener(currentTarget.get())) 476 currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, false, false)); 477 currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>(); 478 SVGElement* element = toSVGElement(currentTarget.get()); 479 if (!element || !element->isOutermostSVGSVGElement()) 480 continue; 481 482 // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>. 483 // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through 484 // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded. 485 ASSERT(sendParentLoadEvents); 486 487 // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example 488 // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document 489 // to be "ready to render", first. 490 if (!document()->loadEventFinished()) 491 break; 492 } 493} 494 495void SVGElement::sendSVGLoadEventIfPossibleAsynchronously() 496{ 497 svgLoadEventTimer()->startOneShot(0); 498} 499 500void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*) 501{ 502 sendSVGLoadEventIfPossible(); 503} 504 505Timer<SVGElement>* SVGElement::svgLoadEventTimer() 506{ 507 ASSERT_NOT_REACHED(); 508 return 0; 509} 510 511void SVGElement::finishParsingChildren() 512{ 513 StyledElement::finishParsingChildren(); 514 515 // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent. 516 if (isOutermostSVGSVGElement()) 517 return; 518 519 // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>) 520 // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish 521 sendSVGLoadEventIfPossible(); 522} 523 524bool SVGElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const 525{ 526 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, invalidTextContent, ()); 527 528 if (invalidTextContent.isEmpty()) { 529 invalidTextContent.add(SVGNames::textPathTag); 530#if ENABLE(SVG_FONTS) 531 invalidTextContent.add(SVGNames::altGlyphTag); 532#endif 533 invalidTextContent.add(SVGNames::trefTag); 534 invalidTextContent.add(SVGNames::tspanTag); 535 } 536 if (childContext.node()->isSVGElement()) { 537 SVGElement* svgChild = toSVGElement(childContext.node()); 538 if (invalidTextContent.contains(svgChild->tagQName())) 539 return false; 540 541 return svgChild->isValid(); 542 } 543 return false; 544} 545 546void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason) 547{ 548 StyledElement::attributeChanged(name, newValue); 549 550 if (isIdAttributeName(name)) 551 document()->accessSVGExtensions()->rebuildAllElementReferencesForTarget(this); 552 553 // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods), 554 // so we don't want changes to the style attribute to result in extra work here. 555 if (name != HTMLNames::styleAttr) 556 svgAttributeChanged(name); 557} 558 559void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const 560{ 561 if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty) 562 return; 563 564 SVGElement* nonConstThis = const_cast<SVGElement*>(this); 565 if (name == anyQName()) { 566 nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis); 567 elementData()->m_animatedSVGAttributesAreDirty = false; 568 } else 569 nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name); 570} 571 572SVGAttributeToPropertyMap& SVGElement::localAttributeToPropertyMap() 573{ 574 DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, emptyMap, ()); 575 return emptyMap; 576} 577 578void SVGElement::synchronizeRequiredFeatures(SVGElement* contextElement) 579{ 580 ASSERT(contextElement); 581 contextElement->synchronizeRequiredFeatures(); 582} 583 584void SVGElement::synchronizeRequiredExtensions(SVGElement* contextElement) 585{ 586 ASSERT(contextElement); 587 contextElement->synchronizeRequiredExtensions(); 588} 589 590void SVGElement::synchronizeSystemLanguage(SVGElement* contextElement) 591{ 592 ASSERT(contextElement); 593 contextElement->synchronizeSystemLanguage(); 594} 595 596PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer() 597{ 598 if (!correspondingElement()) 599 return document()->ensureStyleResolver()->styleForElement(this); 600 601 RenderStyle* style = 0; 602 if (Element* parent = parentOrShadowHostElement()) { 603 if (RenderObject* renderer = parent->renderer()) 604 style = renderer->style(); 605 } 606 607 return document()->ensureStyleResolver()->styleForElement(correspondingElement(), style, DisallowStyleSharing); 608} 609 610MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const 611{ 612 if (hasSVGRareData()) 613 return svgRareData()->animatedSMILStyleProperties(); 614 return 0; 615} 616 617MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties() 618{ 619 return ensureSVGRareData()->ensureAnimatedSMILStyleProperties(); 620} 621 622void SVGElement::setUseOverrideComputedStyle(bool value) 623{ 624 if (hasSVGRareData()) 625 svgRareData()->setUseOverrideComputedStyle(value); 626} 627 628RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier) 629{ 630 if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle()) 631 return Element::computedStyle(pseudoElementSpecifier); 632 633 RenderStyle* parentStyle = 0; 634 if (Element* parent = parentOrShadowHostElement()) { 635 if (RenderObject* renderer = parent->renderer()) 636 parentStyle = renderer->style(); 637 } 638 639 return svgRareData()->overrideComputedStyle(this, parentStyle); 640} 641 642#ifndef NDEBUG 643bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const 644{ 645 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ()); 646 647 if (animatableAttributes.isEmpty()) { 648 animatableAttributes.add(XLinkNames::hrefAttr); 649 animatableAttributes.add(SVGNames::amplitudeAttr); 650 animatableAttributes.add(SVGNames::azimuthAttr); 651 animatableAttributes.add(SVGNames::baseFrequencyAttr); 652 animatableAttributes.add(SVGNames::biasAttr); 653 animatableAttributes.add(SVGNames::clipPathUnitsAttr); 654 animatableAttributes.add(SVGNames::cxAttr); 655 animatableAttributes.add(SVGNames::cyAttr); 656 animatableAttributes.add(SVGNames::diffuseConstantAttr); 657 animatableAttributes.add(SVGNames::divisorAttr); 658 animatableAttributes.add(SVGNames::dxAttr); 659 animatableAttributes.add(SVGNames::dyAttr); 660 animatableAttributes.add(SVGNames::edgeModeAttr); 661 animatableAttributes.add(SVGNames::elevationAttr); 662 animatableAttributes.add(SVGNames::exponentAttr); 663 animatableAttributes.add(SVGNames::externalResourcesRequiredAttr); 664 animatableAttributes.add(SVGNames::filterResAttr); 665 animatableAttributes.add(SVGNames::filterUnitsAttr); 666 animatableAttributes.add(SVGNames::fxAttr); 667 animatableAttributes.add(SVGNames::fyAttr); 668 animatableAttributes.add(SVGNames::gradientTransformAttr); 669 animatableAttributes.add(SVGNames::gradientUnitsAttr); 670 animatableAttributes.add(SVGNames::heightAttr); 671 animatableAttributes.add(SVGNames::in2Attr); 672 animatableAttributes.add(SVGNames::inAttr); 673 animatableAttributes.add(SVGNames::interceptAttr); 674 animatableAttributes.add(SVGNames::k1Attr); 675 animatableAttributes.add(SVGNames::k2Attr); 676 animatableAttributes.add(SVGNames::k3Attr); 677 animatableAttributes.add(SVGNames::k4Attr); 678 animatableAttributes.add(SVGNames::kernelMatrixAttr); 679 animatableAttributes.add(SVGNames::kernelUnitLengthAttr); 680 animatableAttributes.add(SVGNames::lengthAdjustAttr); 681 animatableAttributes.add(SVGNames::limitingConeAngleAttr); 682 animatableAttributes.add(SVGNames::markerHeightAttr); 683 animatableAttributes.add(SVGNames::markerUnitsAttr); 684 animatableAttributes.add(SVGNames::markerWidthAttr); 685 animatableAttributes.add(SVGNames::maskContentUnitsAttr); 686 animatableAttributes.add(SVGNames::maskUnitsAttr); 687 animatableAttributes.add(SVGNames::methodAttr); 688 animatableAttributes.add(SVGNames::modeAttr); 689 animatableAttributes.add(SVGNames::numOctavesAttr); 690 animatableAttributes.add(SVGNames::offsetAttr); 691 animatableAttributes.add(SVGNames::operatorAttr); 692 animatableAttributes.add(SVGNames::orderAttr); 693 animatableAttributes.add(SVGNames::orientAttr); 694 animatableAttributes.add(SVGNames::pathLengthAttr); 695 animatableAttributes.add(SVGNames::patternContentUnitsAttr); 696 animatableAttributes.add(SVGNames::patternTransformAttr); 697 animatableAttributes.add(SVGNames::patternUnitsAttr); 698 animatableAttributes.add(SVGNames::pointsAtXAttr); 699 animatableAttributes.add(SVGNames::pointsAtYAttr); 700 animatableAttributes.add(SVGNames::pointsAtZAttr); 701 animatableAttributes.add(SVGNames::preserveAlphaAttr); 702 animatableAttributes.add(SVGNames::preserveAspectRatioAttr); 703 animatableAttributes.add(SVGNames::primitiveUnitsAttr); 704 animatableAttributes.add(SVGNames::radiusAttr); 705 animatableAttributes.add(SVGNames::rAttr); 706 animatableAttributes.add(SVGNames::refXAttr); 707 animatableAttributes.add(SVGNames::refYAttr); 708 animatableAttributes.add(SVGNames::resultAttr); 709 animatableAttributes.add(SVGNames::rotateAttr); 710 animatableAttributes.add(SVGNames::rxAttr); 711 animatableAttributes.add(SVGNames::ryAttr); 712 animatableAttributes.add(SVGNames::scaleAttr); 713 animatableAttributes.add(SVGNames::seedAttr); 714 animatableAttributes.add(SVGNames::slopeAttr); 715 animatableAttributes.add(SVGNames::spacingAttr); 716 animatableAttributes.add(SVGNames::specularConstantAttr); 717 animatableAttributes.add(SVGNames::specularExponentAttr); 718 animatableAttributes.add(SVGNames::spreadMethodAttr); 719 animatableAttributes.add(SVGNames::startOffsetAttr); 720 animatableAttributes.add(SVGNames::stdDeviationAttr); 721 animatableAttributes.add(SVGNames::stitchTilesAttr); 722 animatableAttributes.add(SVGNames::surfaceScaleAttr); 723 animatableAttributes.add(SVGNames::tableValuesAttr); 724 animatableAttributes.add(SVGNames::targetAttr); 725 animatableAttributes.add(SVGNames::targetXAttr); 726 animatableAttributes.add(SVGNames::targetYAttr); 727 animatableAttributes.add(SVGNames::transformAttr); 728 animatableAttributes.add(SVGNames::typeAttr); 729 animatableAttributes.add(SVGNames::valuesAttr); 730 animatableAttributes.add(SVGNames::viewBoxAttr); 731 animatableAttributes.add(SVGNames::widthAttr); 732 animatableAttributes.add(SVGNames::x1Attr); 733 animatableAttributes.add(SVGNames::x2Attr); 734 animatableAttributes.add(SVGNames::xAttr); 735 animatableAttributes.add(SVGNames::xChannelSelectorAttr); 736 animatableAttributes.add(SVGNames::y1Attr); 737 animatableAttributes.add(SVGNames::y2Attr); 738 animatableAttributes.add(SVGNames::yAttr); 739 animatableAttributes.add(SVGNames::yChannelSelectorAttr); 740 animatableAttributes.add(SVGNames::zAttr); 741 } 742 743 if (name == classAttr) 744 return isSVGStyledElement(); 745 746 return animatableAttributes.contains(name); 747} 748#endif 749 750} 751 752#endif // ENABLE(SVG) 753