Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis (at) 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     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 
    140 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 
    149 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 
    158 float SVGSVGElement::pixelUnitToMillimeterX() const
    159 {
    160     // 2.54 / cssPixelsPerInch gives CM.
    161     return (2.54f / cssPixelsPerInch) * 10.0f;
    162 }
    163 
    164 float SVGSVGElement::pixelUnitToMillimeterY() const
    165 {
    166     // 2.54 / cssPixelsPerInch gives CM.
    167     return (2.54f / cssPixelsPerInch) * 10.0f;
    168 }
    169 
    170 float SVGSVGElement::screenPixelToMillimeterX() const
    171 {
    172     return pixelUnitToMillimeterX();
    173 }
    174 
    175 float SVGSVGElement::screenPixelToMillimeterY() const
    176 {
    177     return pixelUnitToMillimeterY();
    178 }
    179 
    180 bool SVGSVGElement::useCurrentView() const
    181 {
    182     return m_useCurrentView;
    183 }
    184 
    185 void SVGSVGElement::setUseCurrentView(bool currentView)
    186 {
    187     m_useCurrentView = currentView;
    188 }
    189 
    190 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 
    197 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 
    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 
    220 void SVGSVGElement::setCurrentTranslate(const FloatPoint& translation)
    221 {
    222     m_translation = translation;
    223     updateCurrentTranslate();
    224 }
    225 
    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 
    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.
    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 
    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 
    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 
    374 AttributeToPropertyTypeMap& SVGSVGElement::attributeToPropertyTypeMap()
    375 {
    376     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
    377     return s_attributeToPropertyTypeMap;
    378 }
    379 
    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 
    391 unsigned SVGSVGElement::suspendRedraw(unsigned /* maxWaitMilliseconds */)
    392 {
    393     // FIXME: Implement me (see bug 11275)
    394     return 0;
    395 }
    396 
    397 void SVGSVGElement::unsuspendRedraw(unsigned /* suspendHandleId */)
    398 {
    399     // FIXME: Implement me (see bug 11275)
    400 }
    401 
    402 void SVGSVGElement::unsuspendRedrawAll()
    403 {
    404     // FIXME: Implement me (see bug 11275)
    405 }
    406 
    407 void SVGSVGElement::forceRedraw()
    408 {
    409     // FIXME: Implement me (see bug 11275)
    410 }
    411 
    412 NodeList* SVGSVGElement::getIntersectionList(const FloatRect&, SVGElement*)
    413 {
    414     // FIXME: Implement me (see bug 11274)
    415     return 0;
    416 }
    417 
    418 NodeList* SVGSVGElement::getEnclosureList(const FloatRect&, SVGElement*)
    419 {
    420     // FIXME: Implement me (see bug 11274)
    421     return 0;
    422 }
    423 
    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 
    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 
    440 void SVGSVGElement::deselectAll()
    441 {
    442     if (Frame* frame = document()->frame())
    443         frame->selection()->clear();
    444 }
    445 
    446 float SVGSVGElement::createSVGNumber()
    447 {
    448     return 0.0f;
    449 }
    450 
    451 SVGLength SVGSVGElement::createSVGLength()
    452 {
    453     return SVGLength();
    454 }
    455 
    456 SVGAngle SVGSVGElement::createSVGAngle()
    457 {
    458     return SVGAngle();
    459 }
    460 
    461 FloatPoint SVGSVGElement::createSVGPoint()
    462 {
    463     return FloatPoint();
    464 }
    465 
    466 SVGMatrix SVGSVGElement::createSVGMatrix()
    467 {
    468     return SVGMatrix();
    469 }
    470 
    471 FloatRect SVGSVGElement::createSVGRect()
    472 {
    473     return FloatRect();
    474 }
    475 
    476 SVGTransform SVGSVGElement::createSVGTransform()
    477 {
    478     return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX);
    479 }
    480 
    481 SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix)
    482 {
    483     return SVGTransform(static_cast<const AffineTransform&>(matrix));
    484 }
    485 
    486 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 
    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 
    525 void SVGSVGElement::insertedIntoDocument()
    526 {
    527     document()->accessSVGExtensions()->addTimeContainer(this);
    528     SVGStyledLocatableElement::insertedIntoDocument();
    529 }
    530 
    531 void SVGSVGElement::removedFromDocument()
    532 {
    533     document()->accessSVGExtensions()->removeTimeContainer(this);
    534     SVGStyledLocatableElement::removedFromDocument();
    535 }
    536 
    537 void SVGSVGElement::pauseAnimations()
    538 {
    539     if (!m_timeContainer->isPaused())
    540         m_timeContainer->pause();
    541 }
    542 
    543 void SVGSVGElement::unpauseAnimations()
    544 {
    545     if (m_timeContainer->isPaused())
    546         m_timeContainer->resume();
    547 }
    548 
    549 bool SVGSVGElement::animationsPaused() const
    550 {
    551     return m_timeContainer->isPaused();
    552 }
    553 
    554 float SVGSVGElement::getCurrentTime() const
    555 {
    556     return narrowPrecisionToFloat(m_timeContainer->elapsed().value());
    557 }
    558 
    559 void SVGSVGElement::setCurrentTime(float /* seconds */)
    560 {
    561     // FIXME: Implement me, bug 12073
    562 }
    563 
    564 bool SVGSVGElement::selfHasRelativeLengths() const
    565 {
    566     return x().isRelative()
    567         || y().isRelative()
    568         || width().isRelative()
    569         || height().isRelative()
    570         || hasAttribute(SVGNames::viewBoxAttr);
    571 }
    572 
    573 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 
    589 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 
    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 
    631 void SVGSVGElement::documentWillBecomeInactive()
    632 {
    633     pauseAnimations();
    634 }
    635 
    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
    643 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