1/* 2 * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis@kde.org> 4 * Copyright (C) 2007 Apple Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22#include "config.h" 23 24#if ENABLE(SVG) 25#include "SVGSVGElement.h" 26 27#include "AffineTransform.h" 28#include "Attribute.h" 29#include "CSSHelper.h" 30#include "CSSPropertyNames.h" 31#include "Document.h" 32#include "EventListener.h" 33#include "EventNames.h" 34#include "FloatConversion.h" 35#include "FloatRect.h" 36#include "FrameView.h" 37#include "HTMLNames.h" 38#include "RenderSVGResource.h" 39#include "RenderSVGRoot.h" 40#include "RenderSVGViewportContainer.h" 41#include "SMILTimeContainer.h" 42#include "SVGAngle.h" 43#include "SVGNames.h" 44#include "SVGPreserveAspectRatio.h" 45#include "SVGTransform.h" 46#include "SVGTransformList.h" 47#include "SVGViewElement.h" 48#include "SVGViewSpec.h" 49#include "SVGZoomEvent.h" 50#include "ScriptEventListener.h" 51#include "SelectionController.h" 52#include <wtf/StdLibExtras.h> 53 54namespace WebCore { 55 56// Animated property definitions 57DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::xAttr, X, x) 58DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::yAttr, Y, y) 59DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::widthAttr, Width, width) 60DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::heightAttr, Height, height) 61DEFINE_ANIMATED_BOOLEAN(SVGSVGElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 62DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGSVGElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio) 63DEFINE_ANIMATED_RECT(SVGSVGElement, SVGNames::viewBoxAttr, ViewBox, viewBox) 64 65inline SVGSVGElement::SVGSVGElement(const QualifiedName& tagName, Document* doc) 66 : SVGStyledLocatableElement(tagName, doc) 67 , m_x(LengthModeWidth) 68 , m_y(LengthModeHeight) 69 , m_width(LengthModeWidth, "100%") 70 , m_height(LengthModeHeight, "100%") 71 , m_useCurrentView(false) 72 , m_timeContainer(SMILTimeContainer::create(this)) 73 , m_scale(1) 74 , m_viewSpec(0) 75 , m_containerSize(300, 150) 76 , m_hasSetContainerSize(false) 77{ 78 doc->registerForDocumentActivationCallbacks(this); 79} 80 81PassRefPtr<SVGSVGElement> SVGSVGElement::create(const QualifiedName& tagName, Document* document) 82{ 83 return adoptRef(new SVGSVGElement(tagName, document)); 84} 85 86SVGSVGElement::~SVGSVGElement() 87{ 88 document()->unregisterForDocumentActivationCallbacks(this); 89 // There are cases where removedFromDocument() is not called. 90 // see ContainerNode::removeAllChildren, called by its destructor. 91 document()->accessSVGExtensions()->removeTimeContainer(this); 92} 93 94void SVGSVGElement::willMoveToNewOwnerDocument() 95{ 96 document()->unregisterForDocumentActivationCallbacks(this); 97 SVGStyledLocatableElement::willMoveToNewOwnerDocument(); 98} 99 100void SVGSVGElement::didMoveToNewOwnerDocument() 101{ 102 document()->registerForDocumentActivationCallbacks(this); 103 SVGStyledLocatableElement::didMoveToNewOwnerDocument(); 104} 105 106const AtomicString& SVGSVGElement::contentScriptType() const 107{ 108 DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/ecmascript")); 109 const AtomicString& n = getAttribute(SVGNames::contentScriptTypeAttr); 110 return n.isNull() ? defaultValue : n; 111} 112 113void SVGSVGElement::setContentScriptType(const AtomicString& type) 114{ 115 setAttribute(SVGNames::contentScriptTypeAttr, type); 116} 117 118const AtomicString& SVGSVGElement::contentStyleType() const 119{ 120 DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/css")); 121 const AtomicString& n = getAttribute(SVGNames::contentStyleTypeAttr); 122 return n.isNull() ? defaultValue : n; 123} 124 125void SVGSVGElement::setContentStyleType(const AtomicString& type) 126{ 127 setAttribute(SVGNames::contentStyleTypeAttr, type); 128} 129 130FloatRect SVGSVGElement::viewport() const 131{ 132 FloatRect viewRectangle; 133 if (!isOutermostSVG()) 134 viewRectangle.setLocation(FloatPoint(x().value(this), y().value(this))); 135 136 viewRectangle.setSize(FloatSize(width().value(this), height().value(this))); 137 return viewBoxToViewTransform(viewRectangle.width(), viewRectangle.height()).mapRect(viewRectangle); 138} 139 140int SVGSVGElement::relativeWidthValue() const 141{ 142 SVGLength w = width(); 143 if (w.unitType() != LengthTypePercentage) 144 return 0; 145 146 return static_cast<int>(w.valueAsPercentage() * m_containerSize.width()); 147} 148 149int SVGSVGElement::relativeHeightValue() const 150{ 151 SVGLength h = height(); 152 if (h.unitType() != LengthTypePercentage) 153 return 0; 154 155 return static_cast<int>(h.valueAsPercentage() * m_containerSize.height()); 156} 157 158float SVGSVGElement::pixelUnitToMillimeterX() const 159{ 160 // 2.54 / cssPixelsPerInch gives CM. 161 return (2.54f / cssPixelsPerInch) * 10.0f; 162} 163 164float SVGSVGElement::pixelUnitToMillimeterY() const 165{ 166 // 2.54 / cssPixelsPerInch gives CM. 167 return (2.54f / cssPixelsPerInch) * 10.0f; 168} 169 170float SVGSVGElement::screenPixelToMillimeterX() const 171{ 172 return pixelUnitToMillimeterX(); 173} 174 175float SVGSVGElement::screenPixelToMillimeterY() const 176{ 177 return pixelUnitToMillimeterY(); 178} 179 180bool SVGSVGElement::useCurrentView() const 181{ 182 return m_useCurrentView; 183} 184 185void SVGSVGElement::setUseCurrentView(bool currentView) 186{ 187 m_useCurrentView = currentView; 188} 189 190SVGViewSpec* SVGSVGElement::currentView() const 191{ 192 if (!m_viewSpec) 193 m_viewSpec = adoptPtr(new SVGViewSpec(const_cast<SVGSVGElement*>(this))); 194 return m_viewSpec.get(); 195} 196 197float SVGSVGElement::currentScale() const 198{ 199 // Only the page zoom factor is relevant for SVG 200 if (Frame* frame = document()->frame()) 201 return frame->pageZoomFactor(); 202 return m_scale; 203} 204 205void SVGSVGElement::setCurrentScale(float scale) 206{ 207 if (Frame* frame = document()->frame()) { 208 // Calling setCurrentScale() on the outermost <svg> element in a standalone SVG document 209 // is allowed to change the page zoom factor, influencing the document size, scrollbars etc. 210 if (parentNode() == document()) 211 frame->setPageZoomFactor(scale); 212 return; 213 } 214 215 m_scale = scale; 216 if (RenderObject* object = renderer()) 217 RenderSVGResource::markForLayoutAndParentResourceInvalidation(object); 218} 219 220void SVGSVGElement::setCurrentTranslate(const FloatPoint& translation) 221{ 222 m_translation = translation; 223 updateCurrentTranslate(); 224} 225 226void SVGSVGElement::updateCurrentTranslate() 227{ 228 if (RenderObject* object = renderer()) 229 object->setNeedsLayout(true); 230 231 if (parentNode() == document() && document()->renderer()) 232 document()->renderer()->repaint(); 233} 234 235void SVGSVGElement::parseMappedAttribute(Attribute* attr) 236{ 237 if (!nearestViewportElement()) { 238 bool setListener = true; 239 240 // Only handle events if we're the outermost <svg> element 241 if (attr->name() == HTMLNames::onunloadAttr) 242 document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), attr)); 243 else if (attr->name() == HTMLNames::onresizeAttr) 244 document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), attr)); 245 else if (attr->name() == HTMLNames::onscrollAttr) 246 document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), attr)); 247 else if (attr->name() == SVGNames::onzoomAttr) 248 document()->setWindowAttributeEventListener(eventNames().zoomEvent, createAttributeEventListener(document()->frame(), attr)); 249 else 250 setListener = false; 251 252 if (setListener) 253 return; 254 } 255 256 if (attr->name() == HTMLNames::onabortAttr) 257 document()->setWindowAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(document()->frame(), attr)); 258 else if (attr->name() == HTMLNames::onerrorAttr) 259 document()->setWindowAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(document()->frame(), attr)); 260 else if (attr->name() == SVGNames::xAttr) 261 setXBaseValue(SVGLength(LengthModeWidth, attr->value())); 262 else if (attr->name() == SVGNames::yAttr) 263 setYBaseValue(SVGLength(LengthModeHeight, attr->value())); 264 else if (attr->name() == SVGNames::widthAttr) { 265 setWidthBaseValue(SVGLength(LengthModeWidth, attr->value())); 266 addCSSProperty(attr, CSSPropertyWidth, attr->value()); 267 if (widthBaseValue().value(this) < 0.0) 268 document()->accessSVGExtensions()->reportError("A negative value for svg attribute <width> is not allowed"); 269 } else if (attr->name() == SVGNames::heightAttr) { 270 setHeightBaseValue(SVGLength(LengthModeHeight, attr->value())); 271 addCSSProperty(attr, CSSPropertyHeight, attr->value()); 272 if (heightBaseValue().value(this) < 0.0) 273 document()->accessSVGExtensions()->reportError("A negative value for svg attribute <height> is not allowed"); 274 } else { 275 if (SVGTests::parseMappedAttribute(attr)) 276 return; 277 if (SVGLangSpace::parseMappedAttribute(attr)) 278 return; 279 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) 280 return; 281 if (SVGFitToViewBox::parseMappedAttribute(document(), attr)) 282 return; 283 if (SVGZoomAndPan::parseMappedAttribute(attr)) 284 return; 285 286 SVGStyledLocatableElement::parseMappedAttribute(attr); 287 } 288} 289 290// This hack will not handle the case where we're setting a width/height 291// on a root <svg> via svg.width.baseValue = when it has none. 292static void updateCSSForAttribute(SVGSVGElement* element, const QualifiedName& attrName, CSSPropertyID property, const SVGLength& value) 293{ 294 Attribute* attribute = element->attributes(false)->getAttributeItem(attrName); 295 if (!attribute || !attribute->isMappedAttribute()) 296 return; 297 element->addCSSProperty(attribute, property, value.valueAsString()); 298} 299 300void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) 301{ 302 SVGStyledElement::svgAttributeChanged(attrName); 303 304 // FIXME: Ugly, ugly hack to around that parseMappedAttribute is not called 305 // when svg.width.baseValue = 100 is evaluated. 306 // Thus the CSS length value for width is not updated, and width() computeLogicalWidth() 307 // calculations on RenderSVGRoot will be wrong. 308 // https://bugs.webkit.org/show_bug.cgi?id=25387 309 bool updateRelativeLengths = false; 310 if (attrName == SVGNames::widthAttr) { 311 updateCSSForAttribute(this, attrName, CSSPropertyWidth, widthBaseValue()); 312 updateRelativeLengths = true; 313 } else if (attrName == SVGNames::heightAttr) { 314 updateCSSForAttribute(this, attrName, CSSPropertyHeight, heightBaseValue()); 315 updateRelativeLengths = true; 316 } 317 318 if (updateRelativeLengths 319 || attrName == SVGNames::xAttr 320 || attrName == SVGNames::yAttr 321 || SVGFitToViewBox::isKnownAttribute(attrName)) { 322 updateRelativeLengths = true; 323 updateRelativeLengthsInformation(); 324 } 325 326 if (SVGTests::handleAttributeChange(this, attrName)) 327 return; 328 329 if (!renderer()) 330 return; 331 332 if (updateRelativeLengths 333 || SVGLangSpace::isKnownAttribute(attrName) 334 || SVGExternalResourcesRequired::isKnownAttribute(attrName) 335 || SVGZoomAndPan::isKnownAttribute(attrName) 336 || SVGStyledLocatableElement::isKnownAttribute(attrName)) 337 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer()); 338} 339 340void SVGSVGElement::synchronizeProperty(const QualifiedName& attrName) 341{ 342 SVGStyledElement::synchronizeProperty(attrName); 343 344 if (attrName == anyQName()) { 345 synchronizeX(); 346 synchronizeY(); 347 synchronizeWidth(); 348 synchronizeHeight(); 349 synchronizeExternalResourcesRequired(); 350 synchronizeViewBox(); 351 synchronizePreserveAspectRatio(); 352 SVGTests::synchronizeProperties(this, attrName); 353 return; 354 } 355 356 if (attrName == SVGNames::xAttr) 357 synchronizeX(); 358 else if (attrName == SVGNames::yAttr) 359 synchronizeY(); 360 else if (attrName == SVGNames::widthAttr) 361 synchronizeWidth(); 362 else if (attrName == SVGNames::heightAttr) 363 synchronizeHeight(); 364 else if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) 365 synchronizeExternalResourcesRequired(); 366 else if (attrName == SVGNames::viewBoxAttr) 367 synchronizeViewBox(); 368 else if (attrName == SVGNames::preserveAspectRatioAttr) 369 synchronizePreserveAspectRatio(); 370 else if (SVGTests::isKnownAttribute(attrName)) 371 SVGTests::synchronizeProperties(this, attrName); 372} 373 374AttributeToPropertyTypeMap& SVGSVGElement::attributeToPropertyTypeMap() 375{ 376 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 377 return s_attributeToPropertyTypeMap; 378} 379 380void SVGSVGElement::fillAttributeToPropertyTypeMap() 381{ 382 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap(); 383 attributeToPropertyTypeMap.set(SVGNames::xAttr, AnimatedLength); 384 attributeToPropertyTypeMap.set(SVGNames::yAttr, AnimatedLength); 385 attributeToPropertyTypeMap.set(SVGNames::widthAttr, AnimatedLength); 386 attributeToPropertyTypeMap.set(SVGNames::heightAttr, AnimatedLength); 387 attributeToPropertyTypeMap.set(SVGNames::viewBoxAttr, AnimatedRect); 388 attributeToPropertyTypeMap.set(SVGNames::preserveAspectRatioAttr, AnimatedPreserveAspectRatio); 389} 390 391unsigned SVGSVGElement::suspendRedraw(unsigned /* maxWaitMilliseconds */) 392{ 393 // FIXME: Implement me (see bug 11275) 394 return 0; 395} 396 397void SVGSVGElement::unsuspendRedraw(unsigned /* suspendHandleId */) 398{ 399 // FIXME: Implement me (see bug 11275) 400} 401 402void SVGSVGElement::unsuspendRedrawAll() 403{ 404 // FIXME: Implement me (see bug 11275) 405} 406 407void SVGSVGElement::forceRedraw() 408{ 409 // FIXME: Implement me (see bug 11275) 410} 411 412NodeList* SVGSVGElement::getIntersectionList(const FloatRect&, SVGElement*) 413{ 414 // FIXME: Implement me (see bug 11274) 415 return 0; 416} 417 418NodeList* SVGSVGElement::getEnclosureList(const FloatRect&, SVGElement*) 419{ 420 // FIXME: Implement me (see bug 11274) 421 return 0; 422} 423 424bool SVGSVGElement::checkIntersection(SVGElement*, const FloatRect& rect) 425{ 426 // TODO : take into account pointer-events? 427 // FIXME: Why is element ignored?? 428 // FIXME: Implement me (see bug 11274) 429 return rect.intersects(getBBox()); 430} 431 432bool SVGSVGElement::checkEnclosure(SVGElement*, const FloatRect& rect) 433{ 434 // TODO : take into account pointer-events? 435 // FIXME: Why is element ignored?? 436 // FIXME: Implement me (see bug 11274) 437 return rect.contains(getBBox()); 438} 439 440void SVGSVGElement::deselectAll() 441{ 442 if (Frame* frame = document()->frame()) 443 frame->selection()->clear(); 444} 445 446float SVGSVGElement::createSVGNumber() 447{ 448 return 0.0f; 449} 450 451SVGLength SVGSVGElement::createSVGLength() 452{ 453 return SVGLength(); 454} 455 456SVGAngle SVGSVGElement::createSVGAngle() 457{ 458 return SVGAngle(); 459} 460 461FloatPoint SVGSVGElement::createSVGPoint() 462{ 463 return FloatPoint(); 464} 465 466SVGMatrix SVGSVGElement::createSVGMatrix() 467{ 468 return SVGMatrix(); 469} 470 471FloatRect SVGSVGElement::createSVGRect() 472{ 473 return FloatRect(); 474} 475 476SVGTransform SVGSVGElement::createSVGTransform() 477{ 478 return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX); 479} 480 481SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix) 482{ 483 return SVGTransform(static_cast<const AffineTransform&>(matrix)); 484} 485 486AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const 487{ 488 AffineTransform viewBoxTransform; 489 if (attributes()->getAttributeItem(SVGNames::viewBoxAttr)) 490 viewBoxTransform = viewBoxToViewTransform(width().value(this), height().value(this)); 491 492 AffineTransform transform; 493 if (!isOutermostSVG()) 494 transform.translate(x().value(this), y().value(this)); 495 else if (mode == SVGLocatable::ScreenScope) { 496 if (RenderObject* renderer = this->renderer()) { 497 // Translate in our CSS parent coordinate space 498 // FIXME: This doesn't work correctly with CSS transforms. 499 FloatPoint location = renderer->localToAbsolute(FloatPoint(), false, true); 500 501 // Be careful here! localToAbsolute() includes the x/y offset coming from the viewBoxToViewTransform(), because 502 // RenderSVGRoot::localToBorderBoxTransform() (called through mapLocalToContainer(), called from localToAbsolute()) 503 // also takes the viewBoxToViewTransform() into account, so we have to subtract it here (original cause of bug #27183) 504 transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); 505 506 // Respect scroll offset. 507 if (FrameView* view = document()->view()) { 508 IntSize scrollOffset = view->scrollOffset(); 509 transform.translate(-scrollOffset.width(), -scrollOffset.height()); 510 } 511 } 512 } 513 514 return transform.multiply(viewBoxTransform); 515} 516 517RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*) 518{ 519 if (isOutermostSVG()) 520 return new (arena) RenderSVGRoot(this); 521 522 return new (arena) RenderSVGViewportContainer(this); 523} 524 525void SVGSVGElement::insertedIntoDocument() 526{ 527 document()->accessSVGExtensions()->addTimeContainer(this); 528 SVGStyledLocatableElement::insertedIntoDocument(); 529} 530 531void SVGSVGElement::removedFromDocument() 532{ 533 document()->accessSVGExtensions()->removeTimeContainer(this); 534 SVGStyledLocatableElement::removedFromDocument(); 535} 536 537void SVGSVGElement::pauseAnimations() 538{ 539 if (!m_timeContainer->isPaused()) 540 m_timeContainer->pause(); 541} 542 543void SVGSVGElement::unpauseAnimations() 544{ 545 if (m_timeContainer->isPaused()) 546 m_timeContainer->resume(); 547} 548 549bool SVGSVGElement::animationsPaused() const 550{ 551 return m_timeContainer->isPaused(); 552} 553 554float SVGSVGElement::getCurrentTime() const 555{ 556 return narrowPrecisionToFloat(m_timeContainer->elapsed().value()); 557} 558 559void SVGSVGElement::setCurrentTime(float /* seconds */) 560{ 561 // FIXME: Implement me, bug 12073 562} 563 564bool SVGSVGElement::selfHasRelativeLengths() const 565{ 566 return x().isRelative() 567 || y().isRelative() 568 || width().isRelative() 569 || height().isRelative() 570 || hasAttribute(SVGNames::viewBoxAttr); 571} 572 573bool SVGSVGElement::isOutermostSVG() const 574{ 575 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc. 576 if (!parentNode()) 577 return true; 578 579#if ENABLE(SVG_FOREIGN_OBJECT) 580 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element. 581 if (parentNode()->hasTagName(SVGNames::foreignObjectTag)) 582 return true; 583#endif 584 585 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it 586 return !parentNode()->isSVGElement(); 587} 588 589AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const 590{ 591 FloatRect viewBoxRect; 592 if (useCurrentView()) { 593 if (currentView()) // what if we should use it but it is not set? 594 viewBoxRect = currentView()->viewBox(); 595 } else 596 viewBoxRect = viewBox(); 597 598 AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform(viewBoxRect, preserveAspectRatio(), viewWidth, viewHeight); 599 600 if (useCurrentView() && currentView()) { 601 AffineTransform transform; 602 if (currentView()->transform().concatenate(transform)) 603 ctm *= transform; 604 } 605 606 return ctm; 607} 608 609void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement) 610{ 611 setUseCurrentView(true); 612 if (viewElement->hasAttribute(SVGNames::viewBoxAttr)) 613 currentView()->setViewBoxBaseValue(viewElement->viewBox()); 614 else 615 currentView()->setViewBoxBaseValue(viewBox()); 616 617 SVGPreserveAspectRatio aspectRatio; 618 if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr)) 619 aspectRatio = viewElement->preserveAspectRatioBaseValue(); 620 else 621 aspectRatio = preserveAspectRatioBaseValue(); 622 currentView()->setPreserveAspectRatioBaseValue(aspectRatio); 623 624 if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr)) 625 currentView()->setZoomAndPan(viewElement->zoomAndPan()); 626 627 if (RenderObject* object = renderer()) 628 RenderSVGResource::markForLayoutAndParentResourceInvalidation(object); 629} 630 631void SVGSVGElement::documentWillBecomeInactive() 632{ 633 pauseAnimations(); 634} 635 636void SVGSVGElement::documentDidBecomeActive() 637{ 638 unpauseAnimations(); 639} 640 641// getElementById on SVGSVGElement is restricted to only the child subtree defined by the <svg> element. 642// See http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement 643Element* SVGSVGElement::getElementById(const AtomicString& id) const 644{ 645 Element* element = document()->getElementById(id); 646 if (element && element->isDescendantOf(this)) 647 return element; 648 649 // Fall back to traversing our subtree. Duplicate ids are allowed, the first found will 650 // be returned. 651 for (Node* node = traverseNextNode(this); node; node = node->traverseNextNode(this)) { 652 if (!node->isElementNode()) 653 continue; 654 655 Element* element = static_cast<Element*>(node); 656 if (element->hasID() && element->getIdAttribute() == id) 657 return element; 658 } 659 return 0; 660} 661 662} 663 664#endif // ENABLE(SVG) 665