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