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