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