OSDN Git Service

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