1 /* 2 * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis (at) 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 54 namespace WebCore { 55 56 // Animated property definitions 57 DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::xAttr, X, x) 58 DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::yAttr, Y, y) 59 DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::widthAttr, Width, width) 60 DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::heightAttr, Height, height) 61 DEFINE_ANIMATED_BOOLEAN(SVGSVGElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 62 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGSVGElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio) 63 DEFINE_ANIMATED_RECT(SVGSVGElement, SVGNames::viewBoxAttr, ViewBox, viewBox) 64 65 inline 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 81 PassRefPtr<SVGSVGElement> SVGSVGElement::create(const QualifiedName& tagName, Document* document) 82 { 83 return adoptRef(new SVGSVGElement(tagName, document)); 84 } 85 86 SVGSVGElement::~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 94 void SVGSVGElement::willMoveToNewOwnerDocument() 95 { 96 document()->unregisterForDocumentActivationCallbacks(this); 97 SVGStyledLocatableElement::willMoveToNewOwnerDocument(); 98 } 99 100 void SVGSVGElement::didMoveToNewOwnerDocument() 101 { 102 document()->registerForDocumentActivationCallbacks(this); 103 SVGStyledLocatableElement::didMoveToNewOwnerDocument(); 104 } 105 106 const 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 113 void SVGSVGElement::setContentScriptType(const AtomicString& type) 114 { 115 setAttribute(SVGNames::contentScriptTypeAttr, type); 116 } 117 118 const 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 125 void SVGSVGElement::setContentStyleType(const AtomicString& type) 126 { 127 setAttribute(SVGNames::contentStyleTypeAttr, type); 128 } 129 130 FloatRect 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 140 int 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 149 int 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 158 float SVGSVGElement::pixelUnitToMillimeterX() const 159 { 160 // 2.54 / cssPixelsPerInch gives CM. 161 return (2.54f / cssPixelsPerInch) * 10.0f; 162 } 163 164 float SVGSVGElement::pixelUnitToMillimeterY() const 165 { 166 // 2.54 / cssPixelsPerInch gives CM. 167 return (2.54f / cssPixelsPerInch) * 10.0f; 168 } 169 170 float SVGSVGElement::screenPixelToMillimeterX() const 171 { 172 return pixelUnitToMillimeterX(); 173 } 174 175 float SVGSVGElement::screenPixelToMillimeterY() const 176 { 177 return pixelUnitToMillimeterY(); 178 } 179 180 bool SVGSVGElement::useCurrentView() const 181 { 182 return m_useCurrentView; 183 } 184 185 void SVGSVGElement::setUseCurrentView(bool currentView) 186 { 187 m_useCurrentView = currentView; 188 } 189 190 SVGViewSpec* 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 197 float 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 205 void 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 220 void SVGSVGElement::setCurrentTranslate(const FloatPoint& translation) 221 { 222 m_translation = translation; 223 updateCurrentTranslate(); 224 } 225 226 void 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 235 void 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. 292 static 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 300 void 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 340 void 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 374 AttributeToPropertyTypeMap& SVGSVGElement::attributeToPropertyTypeMap() 375 { 376 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 377 return s_attributeToPropertyTypeMap; 378 } 379 380 void 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 391 unsigned SVGSVGElement::suspendRedraw(unsigned /* maxWaitMilliseconds */) 392 { 393 // FIXME: Implement me (see bug 11275) 394 return 0; 395 } 396 397 void SVGSVGElement::unsuspendRedraw(unsigned /* suspendHandleId */) 398 { 399 // FIXME: Implement me (see bug 11275) 400 } 401 402 void SVGSVGElement::unsuspendRedrawAll() 403 { 404 // FIXME: Implement me (see bug 11275) 405 } 406 407 void SVGSVGElement::forceRedraw() 408 { 409 // FIXME: Implement me (see bug 11275) 410 } 411 412 NodeList* SVGSVGElement::getIntersectionList(const FloatRect&, SVGElement*) 413 { 414 // FIXME: Implement me (see bug 11274) 415 return 0; 416 } 417 418 NodeList* SVGSVGElement::getEnclosureList(const FloatRect&, SVGElement*) 419 { 420 // FIXME: Implement me (see bug 11274) 421 return 0; 422 } 423 424 bool 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 432 bool 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 440 void SVGSVGElement::deselectAll() 441 { 442 if (Frame* frame = document()->frame()) 443 frame->selection()->clear(); 444 } 445 446 float SVGSVGElement::createSVGNumber() 447 { 448 return 0.0f; 449 } 450 451 SVGLength SVGSVGElement::createSVGLength() 452 { 453 return SVGLength(); 454 } 455 456 SVGAngle SVGSVGElement::createSVGAngle() 457 { 458 return SVGAngle(); 459 } 460 461 FloatPoint SVGSVGElement::createSVGPoint() 462 { 463 return FloatPoint(); 464 } 465 466 SVGMatrix SVGSVGElement::createSVGMatrix() 467 { 468 return SVGMatrix(); 469 } 470 471 FloatRect SVGSVGElement::createSVGRect() 472 { 473 return FloatRect(); 474 } 475 476 SVGTransform SVGSVGElement::createSVGTransform() 477 { 478 return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX); 479 } 480 481 SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix) 482 { 483 return SVGTransform(static_cast<const AffineTransform&>(matrix)); 484 } 485 486 AffineTransform 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 517 RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*) 518 { 519 if (isOutermostSVG()) 520 return new (arena) RenderSVGRoot(this); 521 522 return new (arena) RenderSVGViewportContainer(this); 523 } 524 525 void SVGSVGElement::insertedIntoDocument() 526 { 527 document()->accessSVGExtensions()->addTimeContainer(this); 528 SVGStyledLocatableElement::insertedIntoDocument(); 529 } 530 531 void SVGSVGElement::removedFromDocument() 532 { 533 document()->accessSVGExtensions()->removeTimeContainer(this); 534 SVGStyledLocatableElement::removedFromDocument(); 535 } 536 537 void SVGSVGElement::pauseAnimations() 538 { 539 if (!m_timeContainer->isPaused()) 540 m_timeContainer->pause(); 541 } 542 543 void SVGSVGElement::unpauseAnimations() 544 { 545 if (m_timeContainer->isPaused()) 546 m_timeContainer->resume(); 547 } 548 549 bool SVGSVGElement::animationsPaused() const 550 { 551 return m_timeContainer->isPaused(); 552 } 553 554 float SVGSVGElement::getCurrentTime() const 555 { 556 return narrowPrecisionToFloat(m_timeContainer->elapsed().value()); 557 } 558 559 void SVGSVGElement::setCurrentTime(float /* seconds */) 560 { 561 // FIXME: Implement me, bug 12073 562 } 563 564 bool SVGSVGElement::selfHasRelativeLengths() const 565 { 566 return x().isRelative() 567 || y().isRelative() 568 || width().isRelative() 569 || height().isRelative() 570 || hasAttribute(SVGNames::viewBoxAttr); 571 } 572 573 bool 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 589 AffineTransform 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 609 void 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 631 void SVGSVGElement::documentWillBecomeInactive() 632 { 633 pauseAnimations(); 634 } 635 636 void 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 643 Element* 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