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.
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.
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.
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.
25 #include "SVGSVGElement.h"
27 #include "AffineTransform.h"
28 #include "Attribute.h"
29 #include "CSSHelper.h"
31 #include "EventListener.h"
32 #include "EventNames.h"
33 #include "FloatConversion.h"
34 #include "FloatRect.h"
36 #include "FrameSelection.h"
37 #include "FrameTree.h"
38 #include "FrameView.h"
39 #include "HTMLNames.h"
40 #include "RenderPart.h"
41 #include "RenderSVGResource.h"
42 #include "RenderSVGModelObject.h"
43 #include "RenderSVGRoot.h"
44 #include "RenderSVGViewportContainer.h"
45 #include "SMILTimeContainer.h"
47 #include "SVGElementInstance.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>
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)
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
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))
91 ASSERT(hasTagName(SVGNames::svgTag));
92 registerAnimatedPropertiesForSVGSVGElement();
93 doc->registerForPageCacheSuspensionCallbacks(this);
96 PassRefPtr<SVGSVGElement> SVGSVGElement::create(const QualifiedName& tagName, Document* document)
98 return adoptRef(new SVGSVGElement(tagName, document));
101 SVGSVGElement::~SVGSVGElement()
103 document()->unregisterForPageCacheSuspensionCallbacks(this);
104 // There are cases where removedFromDocument() is not called.
105 // see ContainerNode::removeAllChildren, called by its destructor.
106 document()->accessSVGExtensions()->removeTimeContainer(this);
109 void SVGSVGElement::didMoveToNewDocument(Document* oldDocument)
112 oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
113 document()->registerForPageCacheSuspensionCallbacks(this);
114 SVGStyledLocatableElement::didMoveToNewDocument(oldDocument);
117 const AtomicString& SVGSVGElement::contentScriptType() const
119 DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/ecmascript"));
120 const AtomicString& n = fastGetAttribute(SVGNames::contentScriptTypeAttr);
121 return n.isNull() ? defaultValue : n;
124 void SVGSVGElement::setContentScriptType(const AtomicString& type)
126 setAttribute(SVGNames::contentScriptTypeAttr, type);
129 const AtomicString& SVGSVGElement::contentStyleType() const
131 DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/css"));
132 const AtomicString& n = fastGetAttribute(SVGNames::contentStyleTypeAttr);
133 return n.isNull() ? defaultValue : n;
136 void SVGSVGElement::setContentStyleType(const AtomicString& type)
138 setAttribute(SVGNames::contentStyleTypeAttr, type);
141 FloatRect SVGSVGElement::viewport() const
143 // FIXME: This method doesn't follow the spec and is basically untested. Parent documents are not considered here.
144 // As we have no test coverage for this, we're going to disable it completly for now.
148 float SVGSVGElement::pixelUnitToMillimeterX() const
150 // 2.54 / cssPixelsPerInch gives CM.
151 return (2.54f / cssPixelsPerInch) * 10.0f;
154 float SVGSVGElement::pixelUnitToMillimeterY() const
156 // 2.54 / cssPixelsPerInch gives CM.
157 return (2.54f / cssPixelsPerInch) * 10.0f;
160 float SVGSVGElement::screenPixelToMillimeterX() const
162 return pixelUnitToMillimeterX();
165 float SVGSVGElement::screenPixelToMillimeterY() const
167 return pixelUnitToMillimeterY();
170 bool SVGSVGElement::useCurrentView() const
172 return m_useCurrentView;
175 void SVGSVGElement::setUseCurrentView(bool currentView)
177 m_useCurrentView = currentView;
180 SVGViewSpec* SVGSVGElement::currentView() const
183 m_viewSpec = adoptPtr(new SVGViewSpec(const_cast<SVGSVGElement*>(this)));
184 return m_viewSpec.get();
187 float SVGSVGElement::currentScale() const
189 if (!inDocument() || !isOutermostSVGSVGElement())
192 Frame* frame = document()->frame();
196 FrameTree* frameTree = frame->tree();
199 // The behaviour of currentScale() is undefined, when we're dealing with non-standalone SVG documents.
200 // If the svg is embedded, the scaling is handled by the host renderer, so when asking from inside
201 // the SVG document, a scale value of 1 seems reasonable, as it doesn't know anything about the parent scale.
202 return frameTree->parent() ? 1 : frame->pageZoomFactor();
205 void SVGSVGElement::setCurrentScale(float scale)
207 if (!inDocument() || !isOutermostSVGSVGElement())
210 Frame* frame = document()->frame();
214 FrameTree* frameTree = frame->tree();
217 // The behaviour of setCurrentScale() is undefined, when we're dealing with non-standalone SVG documents.
218 // We choose the ignore this call, it's pretty useless to support calling setCurrentScale() from within
219 // an embedded SVG document, for the same reasons as in currentScale() - needs resolution by SVG WG.
220 if (frameTree->parent())
223 frame->setPageZoomFactor(scale);
226 void SVGSVGElement::setCurrentTranslate(const FloatPoint& translation)
228 m_translation = translation;
229 updateCurrentTranslate();
232 void SVGSVGElement::updateCurrentTranslate()
234 if (RenderObject* object = renderer())
235 object->setNeedsLayout(true);
237 if (parentNode() == document() && document()->renderer())
238 document()->renderer()->repaint();
241 void SVGSVGElement::parseAttribute(Attribute* attr)
243 SVGParsingError parseError = NoError;
245 if (!nearestViewportElement()) {
246 bool setListener = true;
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));
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::construct(LengthModeWidth, attr->value(), parseError));
270 else if (attr->name() == SVGNames::yAttr)
271 setYBaseValue(SVGLength::construct(LengthModeHeight, attr->value(), parseError));
272 else if (attr->name() == SVGNames::widthAttr)
273 setWidthBaseValue(SVGLength::construct(LengthModeWidth, attr->value(), parseError, ForbidNegativeLengths));
274 else if (attr->name() == SVGNames::heightAttr)
275 setHeightBaseValue(SVGLength::construct(LengthModeHeight, attr->value(), parseError, ForbidNegativeLengths));
276 else if (SVGTests::parseAttribute(attr)
277 || SVGLangSpace::parseAttribute(attr)
278 || SVGExternalResourcesRequired::parseAttribute(attr)
279 || SVGFitToViewBox::parseAttribute(document(), attr)
280 || SVGZoomAndPan::parseAttribute(attr)) {
282 SVGStyledLocatableElement::parseAttribute(attr);
284 reportAttributeParsingError(parseError, attr);
287 void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName)
289 bool updateRelativeLengths = false;
290 if (attrName == SVGNames::widthAttr
291 || attrName == SVGNames::heightAttr
292 || attrName == SVGNames::xAttr
293 || attrName == SVGNames::yAttr
294 || SVGFitToViewBox::isKnownAttribute(attrName)) {
295 updateRelativeLengths = true;
296 updateRelativeLengthsInformation();
299 SVGElementInstance::InvalidationGuard invalidationGuard(this);
300 if (SVGTests::handleAttributeChange(this, attrName))
303 if (updateRelativeLengths
304 || SVGLangSpace::isKnownAttribute(attrName)
305 || SVGExternalResourcesRequired::isKnownAttribute(attrName)
306 || SVGZoomAndPan::isKnownAttribute(attrName)) {
308 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer());
312 SVGStyledElement::svgAttributeChanged(attrName);
315 unsigned SVGSVGElement::suspendRedraw(unsigned /* maxWaitMilliseconds */)
317 // FIXME: Implement me (see bug 11275)
321 void SVGSVGElement::unsuspendRedraw(unsigned /* suspendHandleId */)
323 // FIXME: Implement me (see bug 11275)
326 void SVGSVGElement::unsuspendRedrawAll()
328 // FIXME: Implement me (see bug 11275)
331 void SVGSVGElement::forceRedraw()
333 // FIXME: Implement me (see bug 11275)
336 PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const FloatRect& rect, SVGElement* referenceElement, CollectIntersectionOrEnclosure collect) const
338 Vector<RefPtr<Node> > nodes;
339 Node* node = traverseNextNode(referenceElement ? referenceElement : this);
341 if (node->isSVGElement()) {
342 if (collect == CollectIntersectionList) {
343 if (checkIntersection(static_cast<SVGElement*>(node), rect))
346 if (checkEnclosure(static_cast<SVGElement*>(node), rect))
351 node = node->traverseNextNode(referenceElement ? referenceElement : this);
353 return StaticNodeList::adopt(nodes);
356 PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(const FloatRect& rect, SVGElement* referenceElement) const
358 return collectIntersectionOrEnclosureList(rect, referenceElement, CollectIntersectionList);
361 PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(const FloatRect& rect, SVGElement* referenceElement) const
363 return collectIntersectionOrEnclosureList(rect, referenceElement, CollectEnclosureList);
366 bool SVGSVGElement::checkIntersection(SVGElement* element, const FloatRect& rect) const
368 return RenderSVGModelObject::checkIntersection(element->renderer(), rect);
371 bool SVGSVGElement::checkEnclosure(SVGElement* element, const FloatRect& rect) const
373 return RenderSVGModelObject::checkEnclosure(element->renderer(), rect);
376 void SVGSVGElement::deselectAll()
378 if (Frame* frame = document()->frame())
379 frame->selection()->clear();
382 float SVGSVGElement::createSVGNumber()
387 SVGLength SVGSVGElement::createSVGLength()
392 SVGAngle SVGSVGElement::createSVGAngle()
397 FloatPoint SVGSVGElement::createSVGPoint()
402 SVGMatrix SVGSVGElement::createSVGMatrix()
407 FloatRect SVGSVGElement::createSVGRect()
412 SVGTransform SVGSVGElement::createSVGTransform()
414 return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX);
417 SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix)
419 return SVGTransform(static_cast<const AffineTransform&>(matrix));
422 AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const
424 AffineTransform viewBoxTransform;
425 if (hasAttribute(SVGNames::viewBoxAttr)) {
426 FloatSize size = currentViewportSize();
427 viewBoxTransform = viewBoxToViewTransform(size.width(), size.height());
430 AffineTransform transform;
431 if (!isOutermostSVGSVGElement()) {
432 SVGLengthContext lengthContext(this);
433 transform.translate(x().value(lengthContext), y().value(lengthContext));
434 } else if (mode == SVGLocatable::ScreenScope) {
435 if (RenderObject* renderer = this->renderer()) {
436 // Translate in our CSS parent coordinate space
437 // FIXME: This doesn't work correctly with CSS transforms.
438 FloatPoint location = renderer->localToAbsolute(FloatPoint(), false, true);
440 // Be careful here! localToAbsolute() includes the x/y offset coming from the viewBoxToViewTransform(), because
441 // RenderSVGRoot::localToBorderBoxTransform() (called through mapLocalToContainer(), called from localToAbsolute())
442 // also takes the viewBoxToViewTransform() into account, so we have to subtract it here (original cause of bug #27183)
443 transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f());
445 // Respect scroll offset.
446 if (FrameView* view = document()->view()) {
447 LayoutSize scrollOffset = view->scrollOffset();
448 transform.translate(-scrollOffset.width(), -scrollOffset.height());
453 return transform.multiply(viewBoxTransform);
456 RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*)
458 if (isOutermostSVGSVGElement())
459 return new (arena) RenderSVGRoot(this);
461 return new (arena) RenderSVGViewportContainer(this);
464 void SVGSVGElement::insertedIntoDocument()
466 document()->accessSVGExtensions()->addTimeContainer(this);
467 SVGStyledLocatableElement::insertedIntoDocument();
470 void SVGSVGElement::removedFromDocument()
472 document()->accessSVGExtensions()->removeTimeContainer(this);
473 SVGStyledLocatableElement::removedFromDocument();
476 void SVGSVGElement::pauseAnimations()
478 if (!m_timeContainer->isPaused())
479 m_timeContainer->pause();
482 void SVGSVGElement::unpauseAnimations()
484 if (m_timeContainer->isPaused())
485 m_timeContainer->resume();
488 bool SVGSVGElement::animationsPaused() const
490 return m_timeContainer->isPaused();
493 float SVGSVGElement::getCurrentTime() const
495 return narrowPrecisionToFloat(m_timeContainer->elapsed().value());
498 void SVGSVGElement::setCurrentTime(float seconds)
502 seconds = max(seconds, 0.0f);
503 m_timeContainer->setElapsed(seconds);
506 bool SVGSVGElement::selfHasRelativeLengths() const
508 return x().isRelative()
510 || width().isRelative()
511 || height().isRelative()
512 || hasAttribute(SVGNames::viewBoxAttr);
515 FloatRect SVGSVGElement::currentViewBoxRect() const
517 if (useCurrentView()) {
518 if (SVGViewSpec* view = currentView()) // what if we should use it but it is not set?
519 return view->viewBox();
523 FloatRect useViewBox = viewBox();
524 if (!useViewBox.isEmpty())
526 if (!renderer() || !renderer()->isSVGRoot())
528 if (!toRenderSVGRoot(renderer())->isEmbeddedThroughSVGImage())
531 Length intrinsicWidth = this->intrinsicWidth();
532 Length intrinsicHeight = this->intrinsicHeight();
533 if (!intrinsicWidth.isFixed() || !intrinsicHeight.isFixed())
536 // If no viewBox is specified but non-relative width/height values, then we
537 // should always synthesize a viewBox if we're embedded through a SVGImage.
538 return FloatRect(FloatPoint(), FloatSize(intrinsicWidth.calcFloatValue(0), intrinsicHeight.calcFloatValue(0)));
541 FloatSize SVGSVGElement::currentViewportSize() const
543 Length intrinsicWidth = this->intrinsicWidth();
544 Length intrinsicHeight = this->intrinsicHeight();
545 if (intrinsicWidth.isFixed() && intrinsicHeight.isFixed())
546 return FloatSize(intrinsicWidth.calcFloatValue(0), intrinsicHeight.calcFloatValue(0));
551 if (renderer()->isSVGRoot()) {
552 LayoutRect frameRect = toRenderSVGRoot(renderer())->frameRect();
553 return FloatSize(frameRect.width() / renderer()->style()->effectiveZoom(), frameRect.height() / renderer()->style()->effectiveZoom());
556 FloatRect frameRect = toRenderSVGViewportContainer(renderer())->viewport();
557 return FloatSize(frameRect.width() / renderer()->style()->effectiveZoom(), frameRect.height() / renderer()->style()->effectiveZoom());
560 bool SVGSVGElement::widthAttributeEstablishesViewport() const
562 if (!renderer() || renderer()->isSVGViewportContainer())
565 // Spec: http://www.w3.org/TR/SVG/coords.html#ViewportSpace
566 // The ‘width’ attribute on the outermost svg element establishes the viewport's width, unless the following conditions are met:
567 // - the SVG content is a separately stored resource that is embedded by reference (such as the ‘object’ element in XHTML [XHTML]), or
568 // the SVG content is embedded inline within a containing document;
569 // - and the referencing element or containing document is styled using CSS [CSS2] or XSL [XSL];
570 // - and there are CSS-compatible positioning properties ([CSS2], section 9.3) specified on the referencing element (e.g., the ‘object’ element)
571 // or on the containing document's outermost svg element that are sufficient to establish the width of the viewport. Under these conditions,
572 // the positioning properties establish the viewport's width.
573 RenderSVGRoot* root = toRenderSVGRoot(renderer());
575 // SVG embedded through object/embed/iframe.
576 if (root->isEmbeddedThroughFrameContainingSVGDocument())
577 return !root->hasReplacedLogicalWidth() && !document()->frame()->ownerRenderer()->hasReplacedLogicalWidth();
579 // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
580 if (root->isEmbeddedThroughSVGImage() || document()->documentElement() != this)
581 return !root->hasReplacedLogicalWidth();
586 bool SVGSVGElement::heightAttributeEstablishesViewport() const
588 if (!renderer() || renderer()->isSVGViewportContainer())
591 // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing
592 // Similarly, if there are positioning properties specified on the referencing element or on the outermost svg element
593 // that are sufficient to establish the height of the viewport, then these positioning properties establish the viewport's
594 // height; otherwise, the ‘height’ attribute on the outermost svg element establishes the viewport's height.
595 RenderSVGRoot* root = toRenderSVGRoot(renderer());
597 // SVG embedded through object/embed/iframe.
598 if (root->isEmbeddedThroughFrameContainingSVGDocument())
599 return !root->hasReplacedLogicalHeight() && !document()->frame()->ownerRenderer()->hasReplacedLogicalHeight();
601 // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
602 if (root->isEmbeddedThroughSVGImage() || document()->documentElement() != this)
603 return !root->hasReplacedLogicalHeight();
608 Length SVGSVGElement::intrinsicWidth(ConsiderCSSMode mode) const
610 if (widthAttributeEstablishesViewport() || mode == IgnoreCSSProperties) {
611 if (width().unitType() == LengthTypePercentage)
612 return Length(width().valueAsPercentage() * 100, Percent);
614 SVGLengthContext lengthContext(this);
615 return Length(width().value(lengthContext), Fixed);
619 return renderer()->style()->width();
622 Length SVGSVGElement::intrinsicHeight(ConsiderCSSMode mode) const
624 if (heightAttributeEstablishesViewport() || mode == IgnoreCSSProperties) {
625 if (height().unitType() == LengthTypePercentage)
626 return Length(height().valueAsPercentage() * 100, Percent);
628 SVGLengthContext lengthContext(this);
629 return Length(height().value(lengthContext), Fixed);
633 return renderer()->style()->height();
636 AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
638 AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), preserveAspectRatio(), viewWidth, viewHeight);
639 if (useCurrentView() && currentView()) {
640 AffineTransform transform;
641 if (currentView()->transform().concatenate(transform))
648 void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, Element* anchorNode)
650 bool hadUseCurrentView = m_useCurrentView;
651 if (fragmentIdentifier.startsWith("xpointer(")) {
652 // FIXME: XPointer references are ignored (https://bugs.webkit.org/show_bug.cgi?id=17491)
653 setUseCurrentView(false);
654 } else if (fragmentIdentifier.startsWith("svgView(")) {
655 if (currentView()->parseViewSpec(fragmentIdentifier))
656 setUseCurrentView(true);
657 } else if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
658 if (SVGViewElement* viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0) {
659 SVGElement* element = SVGLocatable::nearestViewportElement(viewElement);
660 if (element->hasTagName(SVGNames::svgTag)) {
661 SVGSVGElement* svg = static_cast<SVGSVGElement*>(element);
662 svg->inheritViewAttributes(viewElement);
663 setUseCurrentView(true);
668 if (!hadUseCurrentView) {
669 if (!m_useCurrentView)
671 } else if (!m_useCurrentView)
672 currentView()->setTransform(emptyString());
674 // Force a layout, otherwise RenderSVGRoots localToBorderBoxTransform won't be rebuild.
675 if (RenderObject* object = renderer())
676 RenderSVGResource::markForLayoutAndParentResourceInvalidation(object);
678 // FIXME: We need to decide which <svg> to focus on, and zoom to it.
679 // FIXME: We need to actually "highlight" the viewTarget(s).
682 void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement)
684 if (viewElement->hasAttribute(SVGNames::viewBoxAttr))
685 currentView()->setViewBoxBaseValue(viewElement->viewBox());
687 currentView()->setViewBoxBaseValue(viewBox());
689 SVGPreserveAspectRatio aspectRatio;
690 if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr))
691 aspectRatio = viewElement->preserveAspectRatioBaseValue();
693 aspectRatio = preserveAspectRatioBaseValue();
694 currentView()->setPreserveAspectRatioBaseValue(aspectRatio);
696 if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr))
697 currentView()->setZoomAndPan(viewElement->zoomAndPan());
699 if (RenderObject* object = renderer())
700 RenderSVGResource::markForLayoutAndParentResourceInvalidation(object);
703 void SVGSVGElement::documentWillSuspendForPageCache()
708 void SVGSVGElement::documentDidResumeFromPageCache()
713 // getElementById on SVGSVGElement is restricted to only the child subtree defined by the <svg> element.
714 // See http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement
715 Element* SVGSVGElement::getElementById(const AtomicString& id) const
717 Element* element = treeScope()->getElementById(id);
718 if (element && element->isDescendantOf(this))
721 // Fall back to traversing our subtree. Duplicate ids are allowed, the first found will
723 for (Node* node = traverseNextNode(this); node; node = node->traverseNextNode(this)) {
724 if (!node->isElementNode())
727 Element* element = static_cast<Element*>(node);
728 if (element->hasID() && element->getIdAttribute() == id)
736 #endif // ENABLE(SVG)