1 /* 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2008 Apple Inc. All rights reserved. 5 * Copyright (C) 2008 Alp Toker <alp (at) atoker.com> 6 * Copyright (C) 2009 Cameron McCormack <cam (at) 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 #include "core/svg/SVGElement.h" 27 28 #include "bindings/v8/ScriptEventListener.h" 29 #include "core/HTMLNames.h" 30 #include "core/SVGNames.h" 31 #include "core/XLinkNames.h" 32 #include "core/XMLNames.h" 33 #include "core/css/CSSCursorImageValue.h" 34 #include "core/css/parser/BisonCSSParser.h" 35 #include "core/dom/Document.h" 36 #include "core/dom/ElementTraversal.h" 37 #include "core/dom/shadow/ShadowRoot.h" 38 #include "core/events/Event.h" 39 #include "core/frame/Settings.h" 40 #include "core/html/HTMLElement.h" 41 #include "core/rendering/RenderObject.h" 42 #include "core/rendering/svg/RenderSVGResourceContainer.h" 43 #include "core/svg/SVGCursorElement.h" 44 #include "core/svg/SVGDocumentExtensions.h" 45 #include "core/svg/SVGElementRareData.h" 46 #include "core/svg/SVGGraphicsElement.h" 47 #include "core/svg/SVGSVGElement.h" 48 #include "core/svg/SVGTitleElement.h" 49 #include "core/svg/SVGUseElement.h" 50 51 #include "wtf/TemporaryChange.h" 52 53 namespace WebCore { 54 55 using namespace HTMLNames; 56 using namespace SVGNames; 57 58 void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName) 59 { 60 // FIXME: when CSS supports "transform-origin" the special case for transform_originAttr can be removed. 61 // FIXME: It's not clear the above is strictly true, as -webkit-transform-origin has non-standard behavior. 62 CSSPropertyID propertyId = cssPropertyID(attrName.localName()); 63 if (!propertyId && attrName == transform_originAttr) { 64 propertyId = CSSPropertyWebkitTransformOrigin; // cssPropertyID("-webkit-transform-origin") 65 } else if (propertyId == CSSPropertyTransformOrigin) { 66 propertyId = CSSPropertyWebkitTransformOrigin; 67 } 68 ASSERT(propertyId > 0); 69 propertyNameToIdMap->set(attrName.localName().impl(), propertyId); 70 } 71 72 SVGElement::SVGElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType) 73 : Element(tagName, &document, constructionType) 74 #if ASSERT_ENABLED 75 , m_inRelativeLengthClientsInvalidation(false) 76 #endif 77 // |m_isContextElement| must be initialized before |m_className|, as SVGAnimatedString tear-off c-tor currently set this to true. 78 , m_isContextElement(false) 79 , m_SVGRareData(nullptr) 80 , m_className(SVGAnimatedString::create(this, HTMLNames::classAttr, SVGString::create())) 81 { 82 ScriptWrappable::init(this); 83 addToPropertyMap(m_className); 84 setHasCustomStyleCallbacks(); 85 } 86 87 SVGElement::~SVGElement() 88 { 89 ASSERT(inDocument() || !hasRelativeLengths()); 90 91 // The below teardown is all handled by weak pointer processing in oilpan. 92 #if !ENABLE(OILPAN) 93 if (hasSVGRareData()) { 94 if (SVGCursorElement* cursorElement = svgRareData()->cursorElement()) 95 cursorElement->removeReferencedElement(this); 96 if (CSSCursorImageValue* cursorImageValue = svgRareData()->cursorImageValue()) 97 cursorImageValue->removeReferencedElement(this); 98 // Clear the rare data now so that we are in a consistent state when 99 // calling rebuildAllElementReferencesForTarget() below. 100 m_SVGRareData.clear(); 101 } 102 103 // With Oilpan, either removedFrom has been called or the document is dead 104 // as well and there is no reason to clear out the references. 105 document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this); 106 document().accessSVGExtensions().removeAllElementReferencesForTarget(this); 107 #endif 108 } 109 110 void SVGElement::detach(const AttachContext& context) 111 { 112 Element::detach(context); 113 if (SVGElement* element = correspondingElement()) 114 element->removeInstanceMapping(this); 115 } 116 117 void SVGElement::attach(const AttachContext& context) 118 { 119 Element::attach(context); 120 if (SVGElement* element = correspondingElement()) 121 element->mapInstanceToElement(this); 122 } 123 124 short SVGElement::tabIndex() const 125 { 126 if (supportsFocus()) 127 return Element::tabIndex(); 128 return -1; 129 } 130 131 void SVGElement::willRecalcStyle(StyleRecalcChange change) 132 { 133 if (!hasSVGRareData()) 134 return; 135 // If the style changes because of a regular property change (not induced by SMIL animations themselves) 136 // reset the "computed style without SMIL style properties", so the base value change gets reflected. 137 if (change > NoChange || needsStyleRecalc()) 138 svgRareData()->setNeedsOverrideComputedStyleUpdate(); 139 } 140 141 void SVGElement::buildPendingResourcesIfNeeded() 142 { 143 Document& document = this->document(); 144 if (!needsPendingResourceHandling() || !inDocument() || inUseShadowTree()) 145 return; 146 147 SVGDocumentExtensions& extensions = document.accessSVGExtensions(); 148 AtomicString resourceId = getIdAttribute(); 149 if (!extensions.hasPendingResource(resourceId)) 150 return; 151 152 // Mark pending resources as pending for removal. 153 extensions.markPendingResourcesForRemoval(resourceId); 154 155 // Rebuild pending resources for each client of a pending resource that is being removed. 156 while (Element* clientElement = extensions.removeElementFromPendingResourcesForRemoval(resourceId)) { 157 ASSERT(clientElement->hasPendingResources()); 158 if (clientElement->hasPendingResources()) { 159 // FIXME: Ideally we'd always resolve pending resources async instead of inside 160 // insertedInto and svgAttributeChanged. For now we only do it for <use> since 161 // that would stamp out DOM. 162 if (isSVGUseElement(clientElement)) 163 toSVGUseElement(clientElement)->invalidateShadowTree(); 164 else 165 clientElement->buildPendingResource(); 166 extensions.clearHasPendingResourcesIfPossible(clientElement); 167 } 168 } 169 } 170 171 bool SVGElement::rendererIsNeeded(const RenderStyle& style) 172 { 173 // http://www.w3.org/TR/SVG/extend.html#PrivateData 174 // Prevent anything other than SVG renderers from appearing in our render tree 175 // Spec: SVG allows inclusion of elements from foreign namespaces anywhere 176 // with the SVG content. In general, the SVG user agent will include the unknown 177 // elements in the DOM but will otherwise ignore unknown elements. 178 if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement()) 179 return Element::rendererIsNeeded(style); 180 181 return false; 182 } 183 184 SVGElementRareData* SVGElement::ensureSVGRareData() 185 { 186 if (hasSVGRareData()) 187 return svgRareData(); 188 189 m_SVGRareData = adoptPtrWillBeNoop(new SVGElementRareData(this)); 190 return m_SVGRareData.get(); 191 } 192 193 bool SVGElement::isOutermostSVGSVGElement() const 194 { 195 if (!isSVGSVGElement(*this)) 196 return false; 197 198 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc. 199 if (!parentNode()) 200 return true; 201 202 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element. 203 if (isSVGForeignObjectElement(*parentNode())) 204 return true; 205 206 // If we're living in a shadow tree, we're a <svg> element that got created as replacement 207 // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case 208 // we're always an inner <svg> element. 209 if (inUseShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement()) 210 return false; 211 212 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it 213 return !parentNode()->isSVGElement(); 214 } 215 216 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value) 217 { 218 if (error == NoError) 219 return; 220 221 String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\""; 222 SVGDocumentExtensions& extensions = document().accessSVGExtensions(); 223 224 if (error == NegativeValueForbiddenError) { 225 extensions.reportError("Invalid negative value for " + errorString); 226 return; 227 } 228 229 if (error == ParsingAttributeFailedError) { 230 extensions.reportError("Invalid value for " + errorString); 231 return; 232 } 233 234 ASSERT_NOT_REACHED(); 235 } 236 237 String SVGElement::title() const 238 { 239 // According to spec, we should not return titles when hovering over root <svg> elements (those 240 // <title> elements are the title of the document, not a tooltip) so we instantly return. 241 if (isOutermostSVGSVGElement()) 242 return String(); 243 244 if (inUseShadowTree()) { 245 String useTitle(shadowHost()->title()); 246 if (!useTitle.isEmpty()) 247 return useTitle; 248 } 249 250 // If we aren't an instance in a <use> or the <use> title was not found, then find the first 251 // <title> child of this element. 252 // If a title child was found, return the text contents. 253 if (Element* titleElement = Traversal<SVGTitleElement>::firstChild(*this)) 254 return titleElement->innerText(); 255 256 // Otherwise return a null/empty string. 257 return String(); 258 } 259 260 bool SVGElement::instanceUpdatesBlocked() const 261 { 262 return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked(); 263 } 264 265 void SVGElement::setInstanceUpdatesBlocked(bool value) 266 { 267 if (hasSVGRareData()) 268 svgRareData()->setInstanceUpdatesBlocked(value); 269 } 270 271 AffineTransform SVGElement::localCoordinateSpaceTransform(CTMScope) const 272 { 273 // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement) 274 return AffineTransform(); 275 } 276 277 const AtomicString& SVGElement::xmlbase() const 278 { 279 return fastGetAttribute(XMLNames::baseAttr); 280 } 281 282 void SVGElement::setXMLbase(const AtomicString& value) 283 { 284 setAttribute(XMLNames::baseAttr, value); 285 } 286 287 const AtomicString& SVGElement::xmllang() const 288 { 289 return fastGetAttribute(XMLNames::langAttr); 290 } 291 292 void SVGElement::setXMLlang(const AtomicString& value) 293 { 294 setAttribute(XMLNames::langAttr, value); 295 } 296 297 const AtomicString& SVGElement::xmlspace() const 298 { 299 return fastGetAttribute(XMLNames::spaceAttr); 300 } 301 302 void SVGElement::setXMLspace(const AtomicString& value) 303 { 304 setAttribute(XMLNames::spaceAttr, value); 305 } 306 307 Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent) 308 { 309 Element::insertedInto(rootParent); 310 updateRelativeLengthsInformation(); 311 buildPendingResourcesIfNeeded(); 312 return InsertionDone; 313 } 314 315 void SVGElement::removedFrom(ContainerNode* rootParent) 316 { 317 bool wasInDocument = rootParent->inDocument(); 318 319 if (wasInDocument && hasRelativeLengths()) { 320 // The root of the subtree being removed should take itself out from its parent's relative 321 // length set. For the other nodes in the subtree we don't need to do anything: they will 322 // get their own removedFrom() notification and just clear their sets. 323 if (rootParent->isSVGElement() && !parentNode()) { 324 ASSERT(toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this)); 325 toSVGElement(rootParent)->updateRelativeLengthsInformation(false, this); 326 } 327 328 m_elementsWithRelativeLengths.clear(); 329 } 330 331 ASSERT_WITH_SECURITY_IMPLICATION(!rootParent->isSVGElement() || !toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this)); 332 333 Element::removedFrom(rootParent); 334 335 if (wasInDocument) { 336 document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this); 337 document().accessSVGExtensions().removeAllElementReferencesForTarget(this); 338 } 339 340 invalidateInstances(); 341 } 342 343 void SVGElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 344 { 345 Element::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 346 347 // Invalidate all instances associated with us. 348 if (!changedByParser) 349 invalidateInstances(); 350 } 351 352 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName) 353 { 354 if (!attrName.namespaceURI().isNull()) 355 return CSSPropertyInvalid; 356 357 static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0; 358 if (!propertyNameToIdMap) { 359 propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>; 360 // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes 361 mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr); 362 mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr); 363 mapAttributeToCSSProperty(propertyNameToIdMap, buffered_renderingAttr); 364 mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr); 365 mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr); 366 mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr); 367 mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr); 368 mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr); 369 mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr); 370 mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr); 371 mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr); 372 mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr); 373 mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr); 374 mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr); 375 mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr); 376 mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr); 377 mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr); 378 mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr); 379 mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr); 380 mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr); 381 mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr); 382 mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr); 383 mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr); 384 mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr); 385 mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr); 386 mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr); 387 mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr); 388 mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr); 389 mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr); 390 mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr); 391 mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr); 392 mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr); 393 mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr); 394 mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr); 395 mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr); 396 mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr); 397 mapAttributeToCSSProperty(propertyNameToIdMap, mask_typeAttr); 398 mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr); 399 mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr); 400 mapAttributeToCSSProperty(propertyNameToIdMap, paint_orderAttr); 401 mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr); 402 mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr); 403 mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr); 404 mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr); 405 mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr); 406 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr); 407 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr); 408 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr); 409 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr); 410 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr); 411 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr); 412 mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr); 413 mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr); 414 mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr); 415 mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr); 416 mapAttributeToCSSProperty(propertyNameToIdMap, transform_originAttr); 417 mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr); 418 mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr); 419 mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr); 420 mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr); 421 mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr); 422 } 423 424 return propertyNameToIdMap->get(attrName.localName().impl()); 425 } 426 427 void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement) 428 { 429 ASSERT(clientElement); 430 431 // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now. 432 if (!inDocument()) 433 return; 434 435 // An element wants to notify us that its own relative lengths state changed. 436 // Register it in the relative length map, and register us in the parent relative length map. 437 // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree. 438 for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) { 439 SVGElement* currentElement = toSVGElement(currentNode); 440 ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation); 441 442 bool hadRelativeLengths = currentElement->hasRelativeLengths(); 443 if (clientHasRelativeLengths) 444 currentElement->m_elementsWithRelativeLengths.add(clientElement); 445 else 446 currentElement->m_elementsWithRelativeLengths.remove(clientElement); 447 448 // If the relative length state hasn't changed, we can stop propagating the notification. 449 if (hadRelativeLengths == currentElement->hasRelativeLengths()) 450 return; 451 452 clientElement = currentElement; 453 clientHasRelativeLengths = clientElement->hasRelativeLengths(); 454 } 455 456 // Register root SVG elements for top level viewport change notifications. 457 if (isSVGSVGElement(*clientElement)) { 458 SVGDocumentExtensions& svgExtensions = accessDocumentSVGExtensions(); 459 if (clientElement->hasRelativeLengths()) 460 svgExtensions.addSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement)); 461 else 462 svgExtensions.removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement)); 463 } 464 } 465 466 void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope) 467 { 468 if (!inDocument()) 469 return; 470 471 ASSERT(!m_inRelativeLengthClientsInvalidation); 472 #if ASSERT_ENABLED 473 TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true); 474 #endif 475 476 RenderObject* renderer = this->renderer(); 477 if (renderer && selfHasRelativeLengths()) { 478 if (renderer->isSVGResourceContainer()) 479 toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope); 480 else 481 renderer->setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, layoutScope); 482 } 483 484 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator end = m_elementsWithRelativeLengths.end(); 485 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) { 486 if (*it != this) 487 (*it)->invalidateRelativeLengthClients(layoutScope); 488 } 489 } 490 491 SVGSVGElement* SVGElement::ownerSVGElement() const 492 { 493 ContainerNode* n = parentOrShadowHostNode(); 494 while (n) { 495 if (isSVGSVGElement(*n)) 496 return toSVGSVGElement(n); 497 498 n = n->parentOrShadowHostNode(); 499 } 500 501 return 0; 502 } 503 504 SVGElement* SVGElement::viewportElement() const 505 { 506 // This function needs shadow tree support - as RenderSVGContainer uses this function 507 // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise. 508 ContainerNode* n = parentOrShadowHostNode(); 509 while (n) { 510 if (isSVGSVGElement(*n) || isSVGImageElement(*n) || isSVGSymbolElement(*n)) 511 return toSVGElement(n); 512 513 n = n->parentOrShadowHostNode(); 514 } 515 516 return 0; 517 } 518 519 SVGDocumentExtensions& SVGElement::accessDocumentSVGExtensions() 520 { 521 // This function is provided for use by SVGAnimatedProperty to avoid 522 // global inclusion of core/dom/Document.h in SVG code. 523 return document().accessSVGExtensions(); 524 } 525 526 void SVGElement::mapInstanceToElement(SVGElement* instance) 527 { 528 ASSERT(instance); 529 ASSERT(instance->inUseShadowTree()); 530 531 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = ensureSVGRareData()->elementInstances(); 532 ASSERT(!instances.contains(instance)); 533 534 instances.add(instance); 535 } 536 537 void SVGElement::removeInstanceMapping(SVGElement* instance) 538 { 539 ASSERT(instance); 540 ASSERT(instance->inUseShadowTree()); 541 542 if (!hasSVGRareData()) 543 return; 544 545 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = svgRareData()->elementInstances(); 546 ASSERT(instances.contains(instance)); 547 548 instances.remove(instance); 549 } 550 551 static WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& emptyInstances() 552 { 553 #if ENABLE(OILPAN) 554 DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<WeakMember<SVGElement> > >, emptyInstances, (new HeapHashSet<WeakMember<SVGElement> >)); 555 return *emptyInstances; 556 #else 557 DEFINE_STATIC_LOCAL(HashSet<RawPtr<SVGElement> >, emptyInstances, ()); 558 return emptyInstances; 559 #endif 560 } 561 562 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& SVGElement::instancesForElement() const 563 { 564 if (!hasSVGRareData()) 565 return emptyInstances(); 566 return svgRareData()->elementInstances(); 567 } 568 569 bool SVGElement::getBoundingBox(FloatRect& rect) 570 { 571 if (!isSVGGraphicsElement()) 572 return false; 573 574 rect = toSVGGraphicsElement(this)->getBBox(); 575 return true; 576 } 577 578 void SVGElement::setCursorElement(SVGCursorElement* cursorElement) 579 { 580 SVGElementRareData* rareData = ensureSVGRareData(); 581 if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) { 582 if (cursorElement == oldCursorElement) 583 return; 584 oldCursorElement->removeReferencedElement(this); 585 } 586 rareData->setCursorElement(cursorElement); 587 } 588 589 #if !ENABLE(OILPAN) 590 void SVGElement::cursorElementRemoved() 591 { 592 svgRareData()->setCursorElement(0); 593 } 594 #endif 595 596 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue) 597 { 598 SVGElementRareData* rareData = ensureSVGRareData(); 599 #if !ENABLE(OILPAN) 600 if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) { 601 if (cursorImageValue == oldCursorImageValue) 602 return; 603 oldCursorImageValue->removeReferencedElement(this); 604 } 605 #endif 606 rareData->setCursorImageValue(cursorImageValue); 607 } 608 609 #if !ENABLE(OILPAN) 610 void SVGElement::cursorImageValueRemoved() 611 { 612 svgRareData()->setCursorImageValue(0); 613 } 614 #endif 615 616 SVGElement* SVGElement::correspondingElement() 617 { 618 ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot()); 619 return hasSVGRareData() ? svgRareData()->correspondingElement() : 0; 620 } 621 622 SVGUseElement* SVGElement::correspondingUseElement() const 623 { 624 if (ShadowRoot* root = containingShadowRoot()) { 625 if (isSVGUseElement(root->host()) && (root->type() == ShadowRoot::UserAgentShadowRoot)) 626 return toSVGUseElement(root->host()); 627 } 628 return 0; 629 } 630 631 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement) 632 { 633 ensureSVGRareData()->setCorrespondingElement(correspondingElement); 634 } 635 636 bool SVGElement::inUseShadowTree() const 637 { 638 return correspondingUseElement(); 639 } 640 641 bool SVGElement::supportsSpatialNavigationFocus() const 642 { 643 // This function checks whether the element satisfies the extended criteria 644 // for the element to be focusable, introduced by spatial navigation feature, 645 // i.e. checks if click or keyboard event handler is specified. 646 // This is the way to make it possible to navigate to (focus) elements 647 // which web designer meant for being active (made them respond to click events). 648 649 if (!document().settings() || !document().settings()->spatialNavigationEnabled()) 650 return false; 651 return hasEventListeners(EventTypeNames::click) 652 || hasEventListeners(EventTypeNames::keydown) 653 || hasEventListeners(EventTypeNames::keypress) 654 || hasEventListeners(EventTypeNames::keyup) 655 || hasEventListeners(EventTypeNames::focus) 656 || hasEventListeners(EventTypeNames::blur) 657 || hasEventListeners(EventTypeNames::focusin) 658 || hasEventListeners(EventTypeNames::focusout); 659 } 660 661 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 662 { 663 if (name == HTMLNames::classAttr) { 664 // SVG animation has currently requires special storage of values so we set 665 // the className here. svgAttributeChanged actually causes the resulting 666 // style updates (instead of Element::parseAttribute). We don't 667 // tell Element about the change to avoid parsing the class list twice 668 SVGParsingError parseError = NoError; 669 m_className->setBaseValueAsString(value, parseError); 670 reportAttributeParsingError(parseError, name, value); 671 } else if (name.matches(XMLNames::langAttr) || name.matches(XMLNames::spaceAttr)) { 672 } else if (name == tabindexAttr) { 673 Element::parseAttribute(name, value); 674 } else { 675 // standard events 676 const AtomicString& eventName = HTMLElement::eventNameForAttributeName(name); 677 if (!eventName.isNull()) 678 setAttributeEventListener(eventName, createAttributeEventListener(this, name, value, eventParameterName())); 679 else 680 Element::parseAttribute(name, value); 681 } 682 } 683 684 typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap; 685 AnimatedPropertyType SVGElement::animatedPropertyTypeForCSSAttribute(const QualifiedName& attributeName) 686 { 687 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, cssPropertyMap, ()); 688 689 if (cssPropertyMap.isEmpty()) { 690 // Fill the map for the first use. 691 cssPropertyMap.set(alignment_baselineAttr, AnimatedString); 692 cssPropertyMap.set(baseline_shiftAttr, AnimatedString); 693 cssPropertyMap.set(buffered_renderingAttr, AnimatedString); 694 cssPropertyMap.set(clipAttr, AnimatedRect); 695 cssPropertyMap.set(clip_pathAttr, AnimatedString); 696 cssPropertyMap.set(clip_ruleAttr, AnimatedString); 697 cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor); 698 cssPropertyMap.set(color_interpolationAttr, AnimatedString); 699 cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString); 700 cssPropertyMap.set(color_renderingAttr, AnimatedString); 701 cssPropertyMap.set(cursorAttr, AnimatedString); 702 cssPropertyMap.set(displayAttr, AnimatedString); 703 cssPropertyMap.set(dominant_baselineAttr, AnimatedString); 704 cssPropertyMap.set(fillAttr, AnimatedColor); 705 cssPropertyMap.set(fill_opacityAttr, AnimatedNumber); 706 cssPropertyMap.set(fill_ruleAttr, AnimatedString); 707 cssPropertyMap.set(filterAttr, AnimatedString); 708 cssPropertyMap.set(flood_colorAttr, AnimatedColor); 709 cssPropertyMap.set(flood_opacityAttr, AnimatedNumber); 710 cssPropertyMap.set(font_familyAttr, AnimatedString); 711 cssPropertyMap.set(font_sizeAttr, AnimatedLength); 712 cssPropertyMap.set(font_stretchAttr, AnimatedString); 713 cssPropertyMap.set(font_styleAttr, AnimatedString); 714 cssPropertyMap.set(font_variantAttr, AnimatedString); 715 cssPropertyMap.set(font_weightAttr, AnimatedString); 716 cssPropertyMap.set(image_renderingAttr, AnimatedString); 717 cssPropertyMap.set(letter_spacingAttr, AnimatedLength); 718 cssPropertyMap.set(lighting_colorAttr, AnimatedColor); 719 cssPropertyMap.set(marker_endAttr, AnimatedString); 720 cssPropertyMap.set(marker_midAttr, AnimatedString); 721 cssPropertyMap.set(marker_startAttr, AnimatedString); 722 cssPropertyMap.set(maskAttr, AnimatedString); 723 cssPropertyMap.set(mask_typeAttr, AnimatedString); 724 cssPropertyMap.set(opacityAttr, AnimatedNumber); 725 cssPropertyMap.set(overflowAttr, AnimatedString); 726 cssPropertyMap.set(paint_orderAttr, AnimatedString); 727 cssPropertyMap.set(pointer_eventsAttr, AnimatedString); 728 cssPropertyMap.set(shape_renderingAttr, AnimatedString); 729 cssPropertyMap.set(stop_colorAttr, AnimatedColor); 730 cssPropertyMap.set(stop_opacityAttr, AnimatedNumber); 731 cssPropertyMap.set(strokeAttr, AnimatedColor); 732 cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList); 733 cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength); 734 cssPropertyMap.set(stroke_linecapAttr, AnimatedString); 735 cssPropertyMap.set(stroke_linejoinAttr, AnimatedString); 736 cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber); 737 cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber); 738 cssPropertyMap.set(stroke_widthAttr, AnimatedLength); 739 cssPropertyMap.set(text_anchorAttr, AnimatedString); 740 cssPropertyMap.set(text_decorationAttr, AnimatedString); 741 cssPropertyMap.set(text_renderingAttr, AnimatedString); 742 cssPropertyMap.set(vector_effectAttr, AnimatedString); 743 cssPropertyMap.set(visibilityAttr, AnimatedString); 744 cssPropertyMap.set(word_spacingAttr, AnimatedLength); 745 } 746 747 if (cssPropertyMap.contains(attributeName)) 748 return cssPropertyMap.get(attributeName); 749 750 return AnimatedUnknown; 751 } 752 753 void SVGElement::addToPropertyMap(PassRefPtr<SVGAnimatedPropertyBase> passProperty) 754 { 755 RefPtr<SVGAnimatedPropertyBase> property(passProperty); 756 QualifiedName attributeName = property->attributeName(); 757 m_newAttributeToPropertyMap.set(attributeName, property.release()); 758 } 759 760 PassRefPtr<SVGAnimatedPropertyBase> SVGElement::propertyFromAttribute(const QualifiedName& attributeName) 761 { 762 return m_newAttributeToPropertyMap.get(attributeName); 763 } 764 765 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName) 766 { 767 return animatedPropertyTypeForCSSAttribute(attrName) != AnimatedUnknown; 768 } 769 770 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const 771 { 772 return cssPropertyIdForSVGAttributeName(name) > 0; 773 } 774 775 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style) 776 { 777 CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name); 778 if (propertyID > 0) 779 addPropertyToPresentationAttributeStyle(style, propertyID, value); 780 } 781 782 bool SVGElement::haveLoadedRequiredResources() 783 { 784 for (SVGElement* child = Traversal<SVGElement>::firstChild(*this); child; child = Traversal<SVGElement>::nextSibling(*child)) { 785 if (!child->haveLoadedRequiredResources()) 786 return false; 787 } 788 return true; 789 } 790 791 static inline void collectInstancesForSVGElement(SVGElement* element, WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances) 792 { 793 ASSERT(element); 794 if (element->containingShadowRoot()) 795 return; 796 797 ASSERT(!element->instanceUpdatesBlocked()); 798 799 instances = element->instancesForElement(); 800 } 801 802 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture) 803 { 804 RefPtr<EventListener> listener = prpListener; 805 806 // Add event listener to regular DOM element 807 if (!Node::addEventListener(eventType, listener, useCapture)) 808 return false; 809 810 // Add event listener to all shadow tree DOM element instances 811 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances; 812 collectInstancesForSVGElement(this, instances); 813 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end(); 814 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) { 815 bool result = (*it)->Node::addEventListener(eventType, listener, useCapture); 816 ASSERT_UNUSED(result, result); 817 } 818 819 return true; 820 } 821 822 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) 823 { 824 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances; 825 collectInstancesForSVGElement(this, instances); 826 if (instances.isEmpty()) 827 return Node::removeEventListener(eventType, listener, useCapture); 828 829 // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener 830 // object when creating a temporary RegisteredEventListener object used to look up the 831 // event listener in a cache. If we want to be able to call removeEventListener() multiple 832 // times on different nodes, we have to delay its immediate destruction, which would happen 833 // after the first call below. 834 RefPtr<EventListener> protector(listener); 835 836 // Remove event listener from regular DOM element 837 if (!Node::removeEventListener(eventType, listener, useCapture)) 838 return false; 839 840 // Remove event listener from all shadow tree DOM element instances 841 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end(); 842 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) { 843 SVGElement* shadowTreeElement = *it; 844 ASSERT(shadowTreeElement); 845 846 shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture); 847 } 848 849 return true; 850 } 851 852 static bool hasLoadListener(Element* element) 853 { 854 if (element->hasEventListeners(EventTypeNames::load)) 855 return true; 856 857 for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) { 858 const EventListenerVector& entry = element->getEventListeners(EventTypeNames::load); 859 for (size_t i = 0; i < entry.size(); ++i) { 860 if (entry[i].useCapture) 861 return true; 862 } 863 } 864 865 return false; 866 } 867 868 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents) 869 { 870 RefPtrWillBeRawPtr<SVGElement> currentTarget = this; 871 while (currentTarget && currentTarget->haveLoadedRequiredResources()) { 872 RefPtrWillBeRawPtr<Element> parent = nullptr; 873 if (sendParentLoadEvents) 874 parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree 875 if (hasLoadListener(currentTarget.get()) 876 && (currentTarget->isStructurallyExternal() || isSVGSVGElement(*currentTarget))) 877 currentTarget->dispatchEvent(Event::create(EventTypeNames::load)); 878 currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : nullptr; 879 SVGElement* element = currentTarget.get(); 880 if (!element || !element->isOutermostSVGSVGElement()) 881 continue; 882 883 // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>. 884 // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through 885 // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded. 886 ASSERT(sendParentLoadEvents); 887 888 // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example 889 // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document 890 // to be "ready to render", first. 891 if (!document().loadEventFinished()) 892 break; 893 } 894 } 895 896 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously() 897 { 898 svgLoadEventTimer()->startOneShot(0, FROM_HERE); 899 } 900 901 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*) 902 { 903 sendSVGLoadEventIfPossible(); 904 } 905 906 Timer<SVGElement>* SVGElement::svgLoadEventTimer() 907 { 908 ASSERT_NOT_REACHED(); 909 return 0; 910 } 911 912 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason) 913 { 914 Element::attributeChanged(name, newValue); 915 916 if (isIdAttributeName(name)) 917 document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this); 918 919 // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods), 920 // so we don't want changes to the style attribute to result in extra work here. 921 if (name != HTMLNames::styleAttr) 922 svgAttributeChanged(name); 923 } 924 925 void SVGElement::svgAttributeChanged(const QualifiedName& attrName) 926 { 927 CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName); 928 if (propId > 0) { 929 invalidateInstances(); 930 return; 931 } 932 933 if (attrName == HTMLNames::classAttr) { 934 classAttributeChanged(AtomicString(m_className->currentValue()->value())); 935 invalidateInstances(); 936 return; 937 } 938 939 if (isIdAttributeName(attrName)) { 940 RenderObject* object = renderer(); 941 // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions 942 if (object && object->isSVGResourceContainer()) 943 toRenderSVGResourceContainer(object)->idChanged(); 944 if (inDocument()) 945 buildPendingResourcesIfNeeded(); 946 invalidateInstances(); 947 return; 948 } 949 } 950 951 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const 952 { 953 if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty) 954 return; 955 956 if (name == anyQName()) { 957 AttributeToPropertyMap::const_iterator::Values it = m_newAttributeToPropertyMap.values().begin(); 958 AttributeToPropertyMap::const_iterator::Values end = m_newAttributeToPropertyMap.values().end(); 959 for (; it != end; ++it) { 960 if ((*it)->needsSynchronizeAttribute()) 961 (*it)->synchronizeAttribute(); 962 } 963 964 elementData()->m_animatedSVGAttributesAreDirty = false; 965 } else { 966 RefPtr<SVGAnimatedPropertyBase> property = m_newAttributeToPropertyMap.get(name); 967 if (property && property->needsSynchronizeAttribute()) 968 property->synchronizeAttribute(); 969 } 970 } 971 972 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer() 973 { 974 if (!correspondingElement()) 975 return document().ensureStyleResolver().styleForElement(this); 976 977 RenderStyle* style = 0; 978 if (Element* parent = parentOrShadowHostElement()) { 979 if (RenderObject* renderer = parent->renderer()) 980 style = renderer->style(); 981 } 982 983 return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing); 984 } 985 986 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const 987 { 988 if (hasSVGRareData()) 989 return svgRareData()->animatedSMILStyleProperties(); 990 return 0; 991 } 992 993 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties() 994 { 995 return ensureSVGRareData()->ensureAnimatedSMILStyleProperties(); 996 } 997 998 void SVGElement::setUseOverrideComputedStyle(bool value) 999 { 1000 if (hasSVGRareData()) 1001 svgRareData()->setUseOverrideComputedStyle(value); 1002 } 1003 1004 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier) 1005 { 1006 if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle()) 1007 return Element::computedStyle(pseudoElementSpecifier); 1008 1009 RenderStyle* parentStyle = 0; 1010 if (Element* parent = parentOrShadowHostElement()) { 1011 if (RenderObject* renderer = parent->renderer()) 1012 parentStyle = renderer->style(); 1013 } 1014 1015 return svgRareData()->overrideComputedStyle(this, parentStyle); 1016 } 1017 1018 bool SVGElement::hasFocusEventListeners() const 1019 { 1020 return hasEventListeners(EventTypeNames::focusin) || hasEventListeners(EventTypeNames::focusout) 1021 || hasEventListeners(EventTypeNames::focus) || hasEventListeners(EventTypeNames::blur); 1022 } 1023 1024 void SVGElement::invalidateInstances() 1025 { 1026 if (!inDocument()) 1027 return; 1028 1029 if (instanceUpdatesBlocked()) 1030 return; 1031 1032 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& set = instancesForElement(); 1033 if (set.isEmpty()) 1034 return; 1035 1036 // Mark all use elements referencing 'element' for rebuilding 1037 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = set.end(); 1038 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = set.begin(); it != end; ++it) { 1039 (*it)->setCorrespondingElement(0); 1040 1041 if (SVGUseElement* element = (*it)->correspondingUseElement()) { 1042 ASSERT(element->inDocument()); 1043 element->invalidateShadowTree(); 1044 } 1045 } 1046 1047 svgRareData()->elementInstances().clear(); 1048 1049 document().updateRenderTreeIfNeeded(); 1050 } 1051 1052 SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement) 1053 : m_targetElement(targetElement) 1054 { 1055 if (m_targetElement) 1056 m_targetElement->setInstanceUpdatesBlocked(true); 1057 } 1058 1059 SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker() 1060 { 1061 if (m_targetElement) 1062 m_targetElement->setInstanceUpdatesBlocked(false); 1063 } 1064 1065 #ifndef NDEBUG 1066 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const 1067 { 1068 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ()); 1069 1070 if (animatableAttributes.isEmpty()) { 1071 animatableAttributes.add(XLinkNames::hrefAttr); 1072 animatableAttributes.add(SVGNames::amplitudeAttr); 1073 animatableAttributes.add(SVGNames::azimuthAttr); 1074 animatableAttributes.add(SVGNames::baseFrequencyAttr); 1075 animatableAttributes.add(SVGNames::biasAttr); 1076 animatableAttributes.add(SVGNames::clipPathUnitsAttr); 1077 animatableAttributes.add(SVGNames::cxAttr); 1078 animatableAttributes.add(SVGNames::cyAttr); 1079 animatableAttributes.add(SVGNames::diffuseConstantAttr); 1080 animatableAttributes.add(SVGNames::divisorAttr); 1081 animatableAttributes.add(SVGNames::dxAttr); 1082 animatableAttributes.add(SVGNames::dyAttr); 1083 animatableAttributes.add(SVGNames::edgeModeAttr); 1084 animatableAttributes.add(SVGNames::elevationAttr); 1085 animatableAttributes.add(SVGNames::exponentAttr); 1086 animatableAttributes.add(SVGNames::filterResAttr); 1087 animatableAttributes.add(SVGNames::filterUnitsAttr); 1088 animatableAttributes.add(SVGNames::fxAttr); 1089 animatableAttributes.add(SVGNames::fyAttr); 1090 animatableAttributes.add(SVGNames::gradientTransformAttr); 1091 animatableAttributes.add(SVGNames::gradientUnitsAttr); 1092 animatableAttributes.add(SVGNames::heightAttr); 1093 animatableAttributes.add(SVGNames::in2Attr); 1094 animatableAttributes.add(SVGNames::inAttr); 1095 animatableAttributes.add(SVGNames::interceptAttr); 1096 animatableAttributes.add(SVGNames::k1Attr); 1097 animatableAttributes.add(SVGNames::k2Attr); 1098 animatableAttributes.add(SVGNames::k3Attr); 1099 animatableAttributes.add(SVGNames::k4Attr); 1100 animatableAttributes.add(SVGNames::kernelMatrixAttr); 1101 animatableAttributes.add(SVGNames::kernelUnitLengthAttr); 1102 animatableAttributes.add(SVGNames::lengthAdjustAttr); 1103 animatableAttributes.add(SVGNames::limitingConeAngleAttr); 1104 animatableAttributes.add(SVGNames::markerHeightAttr); 1105 animatableAttributes.add(SVGNames::markerUnitsAttr); 1106 animatableAttributes.add(SVGNames::markerWidthAttr); 1107 animatableAttributes.add(SVGNames::maskContentUnitsAttr); 1108 animatableAttributes.add(SVGNames::maskUnitsAttr); 1109 animatableAttributes.add(SVGNames::methodAttr); 1110 animatableAttributes.add(SVGNames::modeAttr); 1111 animatableAttributes.add(SVGNames::numOctavesAttr); 1112 animatableAttributes.add(SVGNames::offsetAttr); 1113 animatableAttributes.add(SVGNames::operatorAttr); 1114 animatableAttributes.add(SVGNames::orderAttr); 1115 animatableAttributes.add(SVGNames::orientAttr); 1116 animatableAttributes.add(SVGNames::pathLengthAttr); 1117 animatableAttributes.add(SVGNames::patternContentUnitsAttr); 1118 animatableAttributes.add(SVGNames::patternTransformAttr); 1119 animatableAttributes.add(SVGNames::patternUnitsAttr); 1120 animatableAttributes.add(SVGNames::pointsAtXAttr); 1121 animatableAttributes.add(SVGNames::pointsAtYAttr); 1122 animatableAttributes.add(SVGNames::pointsAtZAttr); 1123 animatableAttributes.add(SVGNames::preserveAlphaAttr); 1124 animatableAttributes.add(SVGNames::preserveAspectRatioAttr); 1125 animatableAttributes.add(SVGNames::primitiveUnitsAttr); 1126 animatableAttributes.add(SVGNames::radiusAttr); 1127 animatableAttributes.add(SVGNames::rAttr); 1128 animatableAttributes.add(SVGNames::refXAttr); 1129 animatableAttributes.add(SVGNames::refYAttr); 1130 animatableAttributes.add(SVGNames::resultAttr); 1131 animatableAttributes.add(SVGNames::rotateAttr); 1132 animatableAttributes.add(SVGNames::rxAttr); 1133 animatableAttributes.add(SVGNames::ryAttr); 1134 animatableAttributes.add(SVGNames::scaleAttr); 1135 animatableAttributes.add(SVGNames::seedAttr); 1136 animatableAttributes.add(SVGNames::slopeAttr); 1137 animatableAttributes.add(SVGNames::spacingAttr); 1138 animatableAttributes.add(SVGNames::specularConstantAttr); 1139 animatableAttributes.add(SVGNames::specularExponentAttr); 1140 animatableAttributes.add(SVGNames::spreadMethodAttr); 1141 animatableAttributes.add(SVGNames::startOffsetAttr); 1142 animatableAttributes.add(SVGNames::stdDeviationAttr); 1143 animatableAttributes.add(SVGNames::stitchTilesAttr); 1144 animatableAttributes.add(SVGNames::surfaceScaleAttr); 1145 animatableAttributes.add(SVGNames::tableValuesAttr); 1146 animatableAttributes.add(SVGNames::targetAttr); 1147 animatableAttributes.add(SVGNames::targetXAttr); 1148 animatableAttributes.add(SVGNames::targetYAttr); 1149 animatableAttributes.add(SVGNames::transformAttr); 1150 animatableAttributes.add(SVGNames::typeAttr); 1151 animatableAttributes.add(SVGNames::valuesAttr); 1152 animatableAttributes.add(SVGNames::viewBoxAttr); 1153 animatableAttributes.add(SVGNames::widthAttr); 1154 animatableAttributes.add(SVGNames::x1Attr); 1155 animatableAttributes.add(SVGNames::x2Attr); 1156 animatableAttributes.add(SVGNames::xAttr); 1157 animatableAttributes.add(SVGNames::xChannelSelectorAttr); 1158 animatableAttributes.add(SVGNames::y1Attr); 1159 animatableAttributes.add(SVGNames::y2Attr); 1160 animatableAttributes.add(SVGNames::yAttr); 1161 animatableAttributes.add(SVGNames::yChannelSelectorAttr); 1162 animatableAttributes.add(SVGNames::zAttr); 1163 } 1164 1165 if (name == classAttr) 1166 return true; 1167 1168 return animatableAttributes.contains(name); 1169 } 1170 #endif 1171 1172 void SVGElement::trace(Visitor* visitor) 1173 { 1174 visitor->trace(m_elementsWithRelativeLengths); 1175 visitor->trace(m_SVGRareData); 1176 Element::trace(visitor); 1177 } 1178 1179 const AtomicString& SVGElement::eventParameterName() 1180 { 1181 DEFINE_STATIC_LOCAL(const AtomicString, evtString, ("evt", AtomicString::ConstructFromLiteral)); 1182 return evtString; 1183 } 1184 1185 } 1186