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