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