summaryrefslogtreecommitdiff
path: root/Source/WebCore/svg/SVGSVGElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/svg/SVGSVGElement.cpp')
-rw-r--r--Source/WebCore/svg/SVGSVGElement.cpp592
1 files changed, 260 insertions, 332 deletions
diff --git a/Source/WebCore/svg/SVGSVGElement.cpp b/Source/WebCore/svg/SVGSVGElement.cpp
index 5a9fe0ce5..13738b754 100644
--- a/Source/WebCore/svg/SVGSVGElement.cpp
+++ b/Source/WebCore/svg/SVGSVGElement.cpp
@@ -1,7 +1,8 @@
/*
* Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Rob Buis <buis@kde.org>
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -20,44 +21,30 @@
*/
#include "config.h"
-
-#if ENABLE(SVG)
#include "SVGSVGElement.h"
-#include "AffineTransform.h"
-#include "Attribute.h"
#include "CSSHelper.h"
-#include "Document.h"
+#include "DOMWrapperWorld.h"
#include "ElementIterator.h"
-#include "EventListener.h"
#include "EventNames.h"
-#include "FloatConversion.h"
-#include "FloatRect.h"
-#include "Frame.h"
#include "FrameSelection.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-#include "HTMLNames.h"
-#include "RenderObject.h"
+#include "MainFrame.h"
#include "RenderSVGResource.h"
-#include "RenderSVGModelObject.h"
#include "RenderSVGRoot.h"
#include "RenderSVGViewportContainer.h"
#include "RenderView.h"
-#include "RenderWidget.h"
#include "SMILTimeContainer.h"
#include "SVGAngle.h"
-#include "SVGElementInstance.h"
-#include "SVGFitToViewBox.h"
-#include "SVGNames.h"
-#include "SVGPreserveAspectRatio.h"
+#include "SVGLength.h"
+#include "SVGMatrix.h"
+#include "SVGNumber.h"
+#include "SVGPoint.h"
+#include "SVGRect.h"
+#include "SVGStaticPropertyTearOff.h"
#include "SVGTransform.h"
-#include "SVGTransformList.h"
#include "SVGViewElement.h"
#include "SVGViewSpec.h"
-#include "SVGZoomEvent.h"
#include "StaticNodeList.h"
-#include <wtf/StdLibExtras.h>
namespace WebCore {
@@ -85,81 +72,80 @@ inline SVGSVGElement::SVGSVGElement(const QualifiedName& tagName, Document& docu
: SVGGraphicsElement(tagName, document)
, m_x(LengthModeWidth)
, m_y(LengthModeHeight)
- , m_width(LengthModeWidth, "100%")
- , m_height(LengthModeHeight, "100%")
- , m_useCurrentView(false)
- , m_zoomAndPan(SVGZoomAndPanMagnify)
+ , m_width(LengthModeWidth, ASCIILiteral("100%"))
+ , m_height(LengthModeHeight, ASCIILiteral("100%"))
, m_timeContainer(SMILTimeContainer::create(this))
{
ASSERT(hasTagName(SVGNames::svgTag));
registerAnimatedPropertiesForSVGSVGElement();
- document.registerForPageCacheSuspensionCallbacks(this);
+ document.registerForDocumentSuspensionCallbacks(this);
+}
+
+Ref<SVGSVGElement> SVGSVGElement::create(const QualifiedName& tagName, Document& document)
+{
+ return adoptRef(*new SVGSVGElement(tagName, document));
}
-PassRefPtr<SVGSVGElement> SVGSVGElement::create(const QualifiedName& tagName, Document& document)
+Ref<SVGSVGElement> SVGSVGElement::create(Document& document)
{
- return adoptRef(new SVGSVGElement(tagName, document));
+ return create(SVGNames::svgTag, document);
}
SVGSVGElement::~SVGSVGElement()
{
if (m_viewSpec)
m_viewSpec->resetContextElement();
- document().unregisterForPageCacheSuspensionCallbacks(this);
- // There are cases where removedFromDocument() is not called.
- // see ContainerNode::removeAllChildren, called by its destructor.
- document().accessSVGExtensions()->removeTimeContainer(this);
+ document().unregisterForDocumentSuspensionCallbacks(this);
+ document().accessSVGExtensions().removeTimeContainer(this);
}
-void SVGSVGElement::didMoveToNewDocument(Document* oldDocument)
+void SVGSVGElement::didMoveToNewDocument(Document& oldDocument)
{
- if (oldDocument)
- oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
- document().registerForPageCacheSuspensionCallbacks(this);
+ oldDocument.unregisterForDocumentSuspensionCallbacks(this);
+ document().registerForDocumentSuspensionCallbacks(this);
SVGGraphicsElement::didMoveToNewDocument(oldDocument);
}
const AtomicString& SVGSVGElement::contentScriptType() const
{
- DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/ecmascript", AtomicString::ConstructFromLiteral));
- const AtomicString& n = fastGetAttribute(SVGNames::contentScriptTypeAttr);
- return n.isNull() ? defaultValue : n;
+ static NeverDestroyed<AtomicString> defaultScriptType { "text/ecmascript" };
+ const AtomicString& type = attributeWithoutSynchronization(SVGNames::contentScriptTypeAttr);
+ return type.isNull() ? defaultScriptType.get() : type;
}
void SVGSVGElement::setContentScriptType(const AtomicString& type)
{
- setAttribute(SVGNames::contentScriptTypeAttr, type);
+ setAttributeWithoutSynchronization(SVGNames::contentScriptTypeAttr, type);
}
const AtomicString& SVGSVGElement::contentStyleType() const
{
- DEFINE_STATIC_LOCAL(const AtomicString, defaultValue, ("text/css", AtomicString::ConstructFromLiteral));
- const AtomicString& n = fastGetAttribute(SVGNames::contentStyleTypeAttr);
- return n.isNull() ? defaultValue : n;
+ static NeverDestroyed<AtomicString> defaultStyleType { "text/css" };
+ const AtomicString& type = attributeWithoutSynchronization(SVGNames::contentStyleTypeAttr);
+ return type.isNull() ? defaultStyleType.get() : type;
}
void SVGSVGElement::setContentStyleType(const AtomicString& type)
{
- setAttribute(SVGNames::contentStyleTypeAttr, type);
+ setAttributeWithoutSynchronization(SVGNames::contentStyleTypeAttr, type);
}
-FloatRect SVGSVGElement::viewport() const
+Ref<SVGRect> SVGSVGElement::viewport() const
{
- // FIXME: This method doesn't follow the spec and is basically untested. Parent documents are not considered here.
- // As we have no test coverage for this, we're going to disable it completly for now.
- return FloatRect();
+ // FIXME: Not implemented.
+ return SVGRect::create();
}
float SVGSVGElement::pixelUnitToMillimeterX() const
{
- // 2.54 / cssPixelsPerInch gives CM.
- return (2.54f / cssPixelsPerInch) * 10.0f;
+ // There are 25.4 millimeters in an inch.
+ return 25.4f / cssPixelsPerInch;
}
float SVGSVGElement::pixelUnitToMillimeterY() const
{
- // 2.54 / cssPixelsPerInch gives CM.
- return (2.54f / cssPixelsPerInch) * 10.0f;
+ // There are 25.4 millimeters in an inch.
+ return 25.4f / cssPixelsPerInch;
}
float SVGSVGElement::screenPixelToMillimeterX() const
@@ -172,49 +158,47 @@ float SVGSVGElement::screenPixelToMillimeterY() const
return pixelUnitToMillimeterY();
}
-SVGViewSpec* SVGSVGElement::currentView()
+SVGViewSpec& SVGSVGElement::currentView()
{
if (!m_viewSpec)
- m_viewSpec = SVGViewSpec::create(this);
- return m_viewSpec.get();
+ m_viewSpec = SVGViewSpec::create(*this);
+ return *m_viewSpec;
}
-float SVGSVGElement::currentScale() const
+Frame* SVGSVGElement::frameForCurrentScale() const
{
- if (!inDocument() || !isOutermostSVGSVGElement())
- return 1;
-
+ // The behavior of currentScale() is undefined when we're dealing with non-standalone SVG documents.
+ // If the document is embedded, the scaling is handled by the host renderer.
+ if (!isConnected() || !isOutermostSVGSVGElement())
+ return nullptr;
Frame* frame = document().frame();
- if (!frame)
- return 1;
+ return frame && frame->isMainFrame() ? frame : nullptr;
+}
- // The behaviour of currentScale() is undefined, when we're dealing with non-standalone SVG documents.
- // If the svg is embedded, the scaling is handled by the host renderer, so when asking from inside
- // the SVG document, a scale value of 1 seems reasonable, as it doesn't know anything about the parent scale.
- return frame->tree().parent() ? 1 : frame->pageZoomFactor();
+float SVGSVGElement::currentScale() const
+{
+ // When asking from inside an embedded SVG document, a scale value of 1 seems reasonable, as it doesn't
+ // know anything about the parent scale.
+ Frame* frame = frameForCurrentScale();
+ return frame ? frame->pageZoomFactor() : 1;
}
void SVGSVGElement::setCurrentScale(float scale)
{
- if (!inDocument() || !isOutermostSVGSVGElement())
- return;
-
- Frame* frame = document().frame();
- if (!frame)
- return;
-
- // The behaviour of setCurrentScale() is undefined, when we're dealing with non-standalone SVG documents.
- // We choose the ignore this call, it's pretty useless to support calling setCurrentScale() from within
- // an embedded SVG document, for the same reasons as in currentScale() - needs resolution by SVG WG.
- if (frame->tree().parent())
- return;
+ if (Frame* frame = frameForCurrentScale())
+ frame->setPageZoomFactor(scale);
+}
- frame->setPageZoomFactor(scale);
+Ref<SVGPoint> SVGSVGElement::currentTranslate()
+{
+ return SVGStaticPropertyTearOff<SVGSVGElement, SVGPoint>::create(*this, m_currentTranslate, &SVGSVGElement::updateCurrentTranslate);
}
void SVGSVGElement::setCurrentTranslate(const FloatPoint& translation)
{
- m_translation = translation;
+ if (m_currentTranslate == translation)
+ return;
+ m_currentTranslate = translation;
updateCurrentTranslate();
}
@@ -222,83 +206,92 @@ void SVGSVGElement::updateCurrentTranslate()
{
if (RenderObject* object = renderer())
object->setNeedsLayout();
-
if (parentNode() == &document() && document().renderView())
document().renderView()->repaint();
}
void SVGSVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
- SVGParsingError parseError = NoError;
-
if (!nearestViewportElement()) {
- bool setListener = true;
-
- // Only handle events if we're the outermost <svg> element
- if (name == HTMLNames::onunloadAttr)
- document().setWindowAttributeEventListener(eventNames().unloadEvent, name, value);
- else if (name == HTMLNames::onresizeAttr)
- document().setWindowAttributeEventListener(eventNames().resizeEvent, name, value);
- else if (name == HTMLNames::onscrollAttr)
- document().setWindowAttributeEventListener(eventNames().scrollEvent, name, value);
- else if (name == SVGNames::onzoomAttr)
- document().setWindowAttributeEventListener(eventNames().zoomEvent, name, value);
- else
- setListener = false;
-
- if (setListener)
+ // For these events, the outermost <svg> element works like a <body> element does,
+ // setting certain event handlers directly on the window object.
+ if (name == HTMLNames::onunloadAttr) {
+ document().setWindowAttributeEventListener(eventNames().unloadEvent, name, value, mainThreadNormalWorld());
+ return;
+ }
+ if (name == HTMLNames::onresizeAttr) {
+ document().setWindowAttributeEventListener(eventNames().resizeEvent, name, value, mainThreadNormalWorld());
+ return;
+ }
+ if (name == HTMLNames::onscrollAttr) {
+ document().setWindowAttributeEventListener(eventNames().scrollEvent, name, value, mainThreadNormalWorld());
return;
+ }
+ if (name == SVGNames::onzoomAttr) {
+ document().setWindowAttributeEventListener(eventNames().zoomEvent, name, value, mainThreadNormalWorld());
+ return;
+ }
+ }
+
+ // For these events, any <svg> element works like a <body> element does,
+ // setting certain event handlers directly on the window object.
+ // FIXME: Why different from the events above that work only on the outermost <svg> element?
+ if (name == HTMLNames::onabortAttr) {
+ document().setWindowAttributeEventListener(eventNames().abortEvent, name, value, mainThreadNormalWorld());
+ return;
+ }
+ if (name == HTMLNames::onerrorAttr) {
+ document().setWindowAttributeEventListener(eventNames().errorEvent, name, value, mainThreadNormalWorld());
+ return;
}
- if (name == HTMLNames::onabortAttr)
- document().setWindowAttributeEventListener(eventNames().abortEvent, name, value);
- else if (name == HTMLNames::onerrorAttr)
- document().setWindowAttributeEventListener(eventNames().errorEvent, name, value);
- else if (name == SVGNames::xAttr)
- setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
+ SVGParsingError parseError = NoError;
+
+ if (name == SVGNames::xAttr)
+ setXBaseValue(SVGLengthValue::construct(LengthModeWidth, value, parseError));
else if (name == SVGNames::yAttr)
- setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
- else if (name == SVGNames::widthAttr)
- setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
- else if (name == SVGNames::heightAttr)
- setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
- else if (SVGLangSpace::parseAttribute(name, value)
- || SVGExternalResourcesRequired::parseAttribute(name, value)
- || SVGFitToViewBox::parseAttribute(this, name, value)
- || SVGZoomAndPan::parseAttribute(this, name, value)) {
- } else
- SVGGraphicsElement::parseAttribute(name, value);
+ setYBaseValue(SVGLengthValue::construct(LengthModeHeight, value, parseError));
+ else if (name == SVGNames::widthAttr) {
+ auto length = SVGLengthValue::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths);
+ if (parseError != NoError || value.isEmpty()) {
+ // FIXME: This is definitely the correct behavior for a missing/removed attribute.
+ // Not sure it's correct for the empty string or for something that can't be parsed.
+ length = SVGLengthValue(LengthModeWidth, ASCIILiteral("100%"));
+ }
+ setWidthBaseValue(length);
+ } else if (name == SVGNames::heightAttr) {
+ auto length = SVGLengthValue::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths);
+ if (parseError != NoError || value.isEmpty()) {
+ // FIXME: This is definitely the correct behavior for a removed attribute.
+ // Not sure it's correct for the empty string or for something that can't be parsed.
+ length = SVGLengthValue(LengthModeHeight, ASCIILiteral("100%"));
+ }
+ setHeightBaseValue(length);
+ }
reportAttributeParsingError(parseError, name, value);
+
+ SVGExternalResourcesRequired::parseAttribute(name, value);
+ SVGFitToViewBox::parseAttribute(this, name, value);
+ SVGZoomAndPan::parseAttribute(*this, name, value);
+ SVGGraphicsElement::parseAttribute(name, value);
}
void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName)
{
bool updateRelativeLengthsOrViewBox = false;
- bool widthChanged = attrName == SVGNames::widthAttr;
- if (widthChanged
- || attrName == SVGNames::heightAttr
- || attrName == SVGNames::xAttr
- || attrName == SVGNames::yAttr) {
+ if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr || attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) {
+ invalidateSVGPresentationAttributeStyle();
updateRelativeLengthsOrViewBox = true;
- updateRelativeLengthsInformation();
-
- // At the SVG/HTML boundary (aka RenderSVGRoot), the width attribute can
- // affect the replaced size so we need to mark it for updating.
- if (widthChanged) {
- RenderObject* renderObject = renderer();
- if (renderObject && renderObject->isSVGRoot())
- toRenderSVGRoot(renderObject)->setNeedsLayoutAndPrefWidthsRecalc();
- }
}
if (SVGFitToViewBox::isKnownAttribute(attrName)) {
updateRelativeLengthsOrViewBox = true;
- if (RenderObject* object = renderer())
- object->setNeedsTransformUpdate();
+ if (auto* renderer = this->renderer())
+ renderer->setNeedsTransformUpdate();
}
- SVGElementInstance::InvalidationGuard invalidationGuard(this);
+ InstanceInvalidationGuard guard(*this);
if (updateRelativeLengthsOrViewBox
|| SVGLangSpace::isKnownAttribute(attrName)
@@ -312,66 +305,52 @@ void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName)
SVGGraphicsElement::svgAttributeChanged(attrName);
}
-unsigned SVGSVGElement::suspendRedraw(unsigned /* maxWaitMilliseconds */)
+unsigned SVGSVGElement::suspendRedraw(unsigned)
{
- // FIXME: Implement me (see bug 11275)
return 0;
}
-void SVGSVGElement::unsuspendRedraw(unsigned /* suspendHandleId */)
+void SVGSVGElement::unsuspendRedraw(unsigned)
{
- // FIXME: Implement me (see bug 11275)
}
void SVGSVGElement::unsuspendRedrawAll()
{
- // FIXME: Implement me (see bug 11275)
}
void SVGSVGElement::forceRedraw()
{
- // FIXME: Implement me (see bug 11275)
}
-PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const FloatRect& rect, SVGElement* referenceElement, CollectIntersectionOrEnclosure collect) const
+Ref<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(SVGRect& rect, SVGElement* referenceElement, bool (*checkFunction)(const SVGElement*, SVGRect&))
{
Vector<Ref<Element>> elements;
-
- for (auto& svgElement : descendantsOfType<SVGElement>(*(referenceElement ? referenceElement : this))) {
- if (collect == CollectIntersectionList) {
- if (RenderSVGModelObject::checkIntersection(svgElement.renderer(), rect))
- elements.append(const_cast<SVGElement&>(svgElement));
- } else {
- if (RenderSVGModelObject::checkEnclosure(svgElement.renderer(), rect))
- elements.append(const_cast<SVGElement&>(svgElement));
- }
+ for (auto& element : descendantsOfType<SVGElement>(referenceElement ? *referenceElement : *this)) {
+ if (checkFunction(&element, rect))
+ elements.append(element);
}
-
- return StaticElementList::adopt(elements);
+ return StaticElementList::create(WTFMove(elements));
}
-PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(const FloatRect& rect, SVGElement* referenceElement) const
+Ref<NodeList> SVGSVGElement::getIntersectionList(SVGRect& rect, SVGElement* referenceElement)
{
- return collectIntersectionOrEnclosureList(rect, referenceElement, CollectIntersectionList);
+ document().updateLayoutIgnorePendingStylesheets();
+ return collectIntersectionOrEnclosureList(rect, referenceElement, checkIntersection);
}
-PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(const FloatRect& rect, SVGElement* referenceElement) const
+Ref<NodeList> SVGSVGElement::getEnclosureList(SVGRect& rect, SVGElement* referenceElement)
{
- return collectIntersectionOrEnclosureList(rect, referenceElement, CollectEnclosureList);
+ return collectIntersectionOrEnclosureList(rect, referenceElement, checkEnclosure);
}
-bool SVGSVGElement::checkIntersection(const SVGElement* element, const FloatRect& rect) const
+bool SVGSVGElement::checkIntersection(const SVGElement* element, SVGRect& rect)
{
- if (!element)
- return false;
- return RenderSVGModelObject::checkIntersection(element->renderer(), rect);
+ return element && RenderSVGModelObject::checkIntersection(element->renderer(), rect.propertyReference());
}
-bool SVGSVGElement::checkEnclosure(const SVGElement* element, const FloatRect& rect) const
+bool SVGSVGElement::checkEnclosure(const SVGElement* element, SVGRect& rect)
{
- if (!element)
- return false;
- return RenderSVGModelObject::checkEnclosure(element->renderer(), rect);
+ return element && RenderSVGModelObject::checkEnclosure(element->renderer(), rect.propertyReference());
}
void SVGSVGElement::deselectAll()
@@ -380,44 +359,44 @@ void SVGSVGElement::deselectAll()
frame->selection().clear();
}
-float SVGSVGElement::createSVGNumber()
+Ref<SVGNumber> SVGSVGElement::createSVGNumber()
{
- return 0.0f;
+ return SVGNumber::create();
}
-SVGLength SVGSVGElement::createSVGLength()
+Ref<SVGLength> SVGSVGElement::createSVGLength()
{
- return SVGLength();
+ return SVGLength::create();
}
-SVGAngle SVGSVGElement::createSVGAngle()
+Ref<SVGAngle> SVGSVGElement::createSVGAngle()
{
- return SVGAngle();
+ return SVGAngle::create();
}
-SVGPoint SVGSVGElement::createSVGPoint()
+Ref<SVGPoint> SVGSVGElement::createSVGPoint()
{
- return SVGPoint();
+ return SVGPoint::create();
}
-SVGMatrix SVGSVGElement::createSVGMatrix()
+Ref<SVGMatrix> SVGSVGElement::createSVGMatrix()
{
- return SVGMatrix();
+ return SVGMatrix::create();
}
-FloatRect SVGSVGElement::createSVGRect()
+Ref<SVGRect> SVGSVGElement::createSVGRect()
{
- return FloatRect();
+ return SVGRect::create();
}
-SVGTransform SVGSVGElement::createSVGTransform()
+Ref<SVGTransform> SVGSVGElement::createSVGTransform()
{
- return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX);
+ return SVGTransform::create(SVGTransformValue { SVGTransformValue::SVG_TRANSFORM_MATRIX });
}
-SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix)
+Ref<SVGTransform> SVGSVGElement::createSVGTransformFromMatrix(SVGMatrix& matrix)
{
- return SVGTransform(static_cast<const AffineTransform&>(matrix));
+ return SVGTransform::create(SVGTransformValue { matrix.propertyReference() });
}
AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const
@@ -433,7 +412,7 @@ AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMSc
SVGLengthContext lengthContext(this);
transform.translate(x().value(lengthContext), y().value(lengthContext));
} else if (mode == SVGLocatable::ScreenScope) {
- if (RenderObject* renderer = this->renderer()) {
+ if (auto* renderer = this->renderer()) {
FloatPoint location;
float zoomFactor = 1;
@@ -441,15 +420,15 @@ AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMSc
// to map an element from SVG viewport coordinates to CSS box coordinates.
// RenderSVGRoot's localToAbsolute method expects CSS box coordinates.
// We also need to adjust for the zoom level factored into CSS coordinates (bug #96361).
- if (renderer->isSVGRoot()) {
- location = toRenderSVGRoot(renderer)->localToBorderBoxTransform().mapPoint(location);
+ if (is<RenderSVGRoot>(*renderer)) {
+ location = downcast<RenderSVGRoot>(*renderer).localToBorderBoxTransform().mapPoint(location);
zoomFactor = 1 / renderer->style().effectiveZoom();
}
// Translate in our CSS parent coordinate space
// FIXME: This doesn't work correctly with CSS transforms.
location = renderer->localToAbsolute(location, UseTransforms);
- location.scale(zoomFactor, zoomFactor);
+ location.scale(zoomFactor);
// Be careful here! localToBorderBoxTransform() included the x/y offset coming from the viewBoxToViewTransform(),
// so we have to subtract it here (original cause of bug #27183)
@@ -457,9 +436,9 @@ AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMSc
// Respect scroll offset.
if (FrameView* view = document().view()) {
- LayoutSize scrollOffset = view->scrollOffset();
- scrollOffset.scale(zoomFactor);
- transform.translate(-scrollOffset.width(), -scrollOffset.height());
+ LayoutPoint scrollPosition = view->scrollPosition();
+ scrollPosition.scale(zoomFactor);
+ transform.translate(-scrollPosition.x(), -scrollPosition.y());
}
}
}
@@ -469,6 +448,8 @@ AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMSc
bool SVGSVGElement::rendererIsNeeded(const RenderStyle& style)
{
+ if (!isValid())
+ return false;
// FIXME: We should respect display: none on the documentElement svg element
// but many things in FrameView and SVGImage depend on the RenderSVGRoot when
// they should instead depend on the RenderView.
@@ -478,32 +459,31 @@ bool SVGSVGElement::rendererIsNeeded(const RenderStyle& style)
return StyledElement::rendererIsNeeded(style);
}
-RenderPtr<RenderElement> SVGSVGElement::createElementRenderer(PassRef<RenderStyle> style)
+RenderPtr<RenderElement> SVGSVGElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
{
if (isOutermostSVGSVGElement())
- return createRenderer<RenderSVGRoot>(*this, std::move(style));
-
- return createRenderer<RenderSVGViewportContainer>(*this, std::move(style));
+ return createRenderer<RenderSVGRoot>(*this, WTFMove(style));
+ return createRenderer<RenderSVGViewportContainer>(*this, WTFMove(style));
}
Node::InsertionNotificationRequest SVGSVGElement::insertedInto(ContainerNode& rootParent)
{
- if (rootParent.inDocument()) {
- document().accessSVGExtensions()->addTimeContainer(this);
+ if (rootParent.isConnected()) {
+ document().accessSVGExtensions().addTimeContainer(this);
// Animations are started at the end of document parsing and after firing the load event,
// but if we miss that train (deferred programmatic element insertion for example) we need
// to initialize the time container here.
- if (!document().parsing() && !document().processingLoadEvent() && document().loadEventFinished() && !timeContainer()->isStarted())
- timeContainer()->begin();
+ if (!document().parsing() && !document().processingLoadEvent() && document().loadEventFinished() && !m_timeContainer->isStarted())
+ m_timeContainer->begin();
}
return SVGGraphicsElement::insertedInto(rootParent);
}
void SVGSVGElement::removedFrom(ContainerNode& rootParent)
{
- if (rootParent.inDocument())
- document().accessSVGExtensions()->removeTimeContainer(this);
+ if (rootParent.isConnected())
+ document().accessSVGExtensions().removeTimeContainer(this);
SVGGraphicsElement::removedFrom(rootParent);
}
@@ -531,10 +511,9 @@ float SVGSVGElement::getCurrentTime() const
void SVGSVGElement::setCurrentTime(float seconds)
{
- if (std::isnan(seconds))
+ if (!std::isfinite(seconds))
return;
- seconds = std::max(seconds, 0.0f);
- m_timeContainer->setElapsed(seconds);
+ m_timeContainer->setElapsed(std::max(seconds, 0.0f));
}
bool SVGSVGElement::selfHasRelativeLengths() const
@@ -551,117 +530,72 @@ FloatRect SVGSVGElement::currentViewBoxRect() const
if (m_useCurrentView)
return m_viewSpec ? m_viewSpec->viewBox() : FloatRect();
- FloatRect useViewBox = viewBox();
- if (!useViewBox.isEmpty())
- return useViewBox;
- if (!renderer() || !renderer()->isSVGRoot())
- return FloatRect();
- if (!toRenderSVGRoot(renderer())->isEmbeddedThroughSVGImage())
- return FloatRect();
+ FloatRect viewBox = this->viewBox();
+ if (!viewBox.isEmpty())
+ return viewBox;
+
+ if (!is<RenderSVGRoot>(renderer()))
+ return { };
+ if (!downcast<RenderSVGRoot>(*renderer()).isEmbeddedThroughSVGImage())
+ return { };
Length intrinsicWidth = this->intrinsicWidth();
Length intrinsicHeight = this->intrinsicHeight();
if (!intrinsicWidth.isFixed() || !intrinsicHeight.isFixed())
- return FloatRect();
+ return { };
// If no viewBox is specified but non-relative width/height values, then we
// should always synthesize a viewBox if we're embedded through a SVGImage.
- return FloatRect(FloatPoint(), FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)));
+ return { 0, 0, floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0) };
}
FloatSize SVGSVGElement::currentViewportSize() const
{
- Length intrinsicWidth = this->intrinsicWidth();
- Length intrinsicHeight = this->intrinsicHeight();
- if (intrinsicWidth.isFixed() && intrinsicHeight.isFixed())
- return FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0));
-
- if (!renderer())
- return FloatSize();
+ FloatSize viewportSize;
- if (renderer()->isSVGRoot()) {
- LayoutRect contentBoxRect = toRenderSVGRoot(renderer())->contentBoxRect();
- return FloatSize(contentBoxRect.width() / renderer()->style().effectiveZoom(), contentBoxRect.height() / renderer()->style().effectiveZoom());
+ if (renderer()) {
+ if (is<RenderSVGRoot>(*renderer())) {
+ auto& root = downcast<RenderSVGRoot>(*renderer());
+ viewportSize = root.contentBoxRect().size() / root.style().effectiveZoom();
+ } else
+ viewportSize = downcast<RenderSVGViewportContainer>(*renderer()).viewport().size();
}
- FloatRect viewportRect = toRenderSVGViewportContainer(renderer())->viewport();
- return FloatSize(viewportRect.width(), viewportRect.height());
-}
-
-bool SVGSVGElement::widthAttributeEstablishesViewport() const
-{
- if (!renderer() || renderer()->isSVGViewportContainer())
- return true;
-
- // Spec: http://www.w3.org/TR/SVG/coords.html#ViewportSpace
- // The ‘width’ attribute on the outermost svg element establishes the viewport's width, unless the following conditions are met:
- // - the SVG content is a separately stored resource that is embedded by reference (such as the ‘object’ element in XHTML [XHTML]), or
- // the SVG content is embedded inline within a containing document;
- // - and the referencing element or containing document is styled using CSS [CSS2] or XSL [XSL];
- // - and there are CSS-compatible positioning properties ([CSS2], section 9.3) specified on the referencing element (e.g., the ‘object’ element)
- // or on the containing document's outermost svg element that are sufficient to establish the width of the viewport. Under these conditions,
- // the positioning properties establish the viewport's width.
- RenderSVGRoot* root = toRenderSVGRoot(renderer());
+ if (!viewportSize.isEmpty())
+ return viewportSize;
- // SVG embedded through object/embed/iframe.
- if (root->isEmbeddedThroughFrameContainingSVGDocument())
- return !root->hasReplacedLogicalWidth() && !document().frame()->ownerRenderer()->hasReplacedLogicalWidth();
+ if (!(hasIntrinsicWidth() && hasIntrinsicHeight()))
+ return { };
- // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
- if (root->isEmbeddedThroughSVGImage() || document().documentElement() != this)
- return !root->hasReplacedLogicalWidth();
-
- return true;
+ return FloatSize(floatValueForLength(intrinsicWidth(), 0), floatValueForLength(intrinsicHeight(), 0));
}
-bool SVGSVGElement::heightAttributeEstablishesViewport() const
+bool SVGSVGElement::hasIntrinsicWidth() const
{
- if (!renderer() || renderer()->isSVGViewportContainer())
- return true;
-
- // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing
- // Similarly, if there are positioning properties specified on the referencing element or on the outermost svg element
- // that are sufficient to establish the height of the viewport, then these positioning properties establish the viewport's
- // height; otherwise, the ‘height’ attribute on the outermost svg element establishes the viewport's height.
- RenderSVGRoot* root = toRenderSVGRoot(renderer());
-
- // SVG embedded through object/embed/iframe.
- if (root->isEmbeddedThroughFrameContainingSVGDocument())
- return !root->hasReplacedLogicalHeight() && !document().frame()->ownerRenderer()->hasReplacedLogicalHeight();
-
- // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG.
- if (root->isEmbeddedThroughSVGImage() || document().documentElement() != this)
- return !root->hasReplacedLogicalHeight();
-
- return true;
+ return width().unitType() != LengthTypePercentage;
}
-Length SVGSVGElement::intrinsicWidth(ConsiderCSSMode mode) const
+bool SVGSVGElement::hasIntrinsicHeight() const
{
- if (widthAttributeEstablishesViewport() || mode == IgnoreCSSProperties) {
- if (width().unitType() == LengthTypePercentage)
- return Length(width().valueAsPercentage() * 100, Percent);
+ return height().unitType() != LengthTypePercentage;
+}
- SVGLengthContext lengthContext(this);
- return Length(width().value(lengthContext), Fixed);
- }
+Length SVGSVGElement::intrinsicWidth() const
+{
+ if (width().unitType() == LengthTypePercentage)
+ return Length(0, Fixed);
- ASSERT(renderer());
- return renderer()->style().width();
+ SVGLengthContext lengthContext(this);
+ return Length(width().value(lengthContext), Fixed);
}
-Length SVGSVGElement::intrinsicHeight(ConsiderCSSMode mode) const
+Length SVGSVGElement::intrinsicHeight() const
{
- if (heightAttributeEstablishesViewport() || mode == IgnoreCSSProperties) {
- if (height().unitType() == LengthTypePercentage)
- return Length(height().valueAsPercentage() * 100, Percent);
+ if (height().unitType() == LengthTypePercentage)
+ return Length(0, Fixed);
- SVGLengthContext lengthContext(this);
- return Length(height().value(lengthContext), Fixed);
- }
-
- ASSERT(renderer());
- return renderer()->style().height();
+ SVGLengthContext lengthContext(this);
+ return Length(height().value(lengthContext), Fixed);
}
AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
@@ -669,19 +603,12 @@ AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float vie
if (!m_useCurrentView || !m_viewSpec)
return SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), preserveAspectRatio(), viewWidth, viewHeight);
- AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), m_viewSpec->preserveAspectRatio(), viewWidth, viewHeight);
- const SVGTransformList& transformList = m_viewSpec->transformBaseValue();
- if (transformList.isEmpty())
- return ctm;
-
- AffineTransform transform;
- if (transformList.concatenate(transform))
- ctm *= transform;
-
- return ctm;
+ AffineTransform transform = SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), m_viewSpec->preserveAspectRatio(), viewWidth, viewHeight);
+ m_viewSpec->transformBaseValue().concatenate(transform);
+ return transform;
}
-void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, Element* anchorNode)
+void SVGSVGElement::scrollToAnchor(const String& fragmentIdentifier, Element* anchorNode)
{
auto renderer = this->renderer();
SVGViewSpec* view = m_viewSpec.get();
@@ -700,32 +627,28 @@ void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, Element*
if (fragmentIdentifier.startsWith("svgView(")) {
if (!view)
- view = currentView(); // Create the SVGViewSpec.
-
+ view = &currentView(); // Create the SVGViewSpec.
if (view->parseViewSpec(fragmentIdentifier))
m_useCurrentView = true;
else
view->reset();
-
if (renderer && (hadUseCurrentView || m_useCurrentView))
RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
return;
}
- // Spec: If the SVG fragment identifier addresses a ‘view’ element within an SVG document (e.g., MyDrawing.svg#MyView
- // or MyDrawing.svg#xpointer(id('MyView'))) then the closest ancestor ‘svg’ element is displayed in the viewport.
- // Any view specification attributes included on the given ‘view’ element override the corresponding view specification
- // attributes on the closest ancestor ‘svg’ element.
- if (anchorNode && isSVGViewElement(anchorNode)) {
- if (SVGViewElement* viewElement = toSVGViewElement(anchorNode)) {
- SVGElement* element = SVGLocatable::nearestViewportElement(viewElement);
- if (element->hasTagName(SVGNames::svgTag)) {
- SVGSVGElement* svg = static_cast<SVGSVGElement*>(element);
- svg->inheritViewAttributes(viewElement);
-
- if (RenderElement* renderer = svg->renderer())
- RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
- }
+ // Spec: If the SVG fragment identifier addresses a "view" element within an SVG document (e.g., MyDrawing.svg#MyView
+ // or MyDrawing.svg#xpointer(id('MyView'))) then the closest ancestor "svg" element is displayed in the viewport.
+ // Any view specification attributes included on the given "view" element override the corresponding view specification
+ // attributes on the closest ancestor "svg" element.
+ if (is<SVGViewElement>(anchorNode)) {
+ auto& viewElement = downcast<SVGViewElement>(*anchorNode);
+ auto* viewportElement = SVGLocatable::nearestViewportElement(&viewElement);
+ if (is<SVGSVGElement>(viewportElement)) {
+ auto& element = downcast<SVGSVGElement>(*viewportElement);
+ element.inheritViewAttributes(viewElement);
+ if (auto* renderer = element.renderer())
+ RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
}
return;
}
@@ -734,33 +657,33 @@ void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, Element*
// FIXME: We need to actually "highlight" the viewTarget(s).
}
-void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement)
+void SVGSVGElement::inheritViewAttributes(const SVGViewElement& viewElement)
{
- SVGViewSpec* view = currentView();
+ SVGViewSpec& view = currentView();
m_useCurrentView = true;
- if (viewElement->hasAttribute(SVGNames::viewBoxAttr))
- view->setViewBoxBaseValue(viewElement->viewBox());
+ if (viewElement.hasAttribute(SVGNames::viewBoxAttr))
+ view.setViewBoxBaseValue(viewElement.viewBox());
else
- view->setViewBoxBaseValue(viewBox());
+ view.setViewBoxBaseValue(viewBox());
- if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr))
- view->setPreserveAspectRatioBaseValue(viewElement->preserveAspectRatioBaseValue());
+ if (viewElement.hasAttribute(SVGNames::preserveAspectRatioAttr))
+ view.setPreserveAspectRatioBaseValue(viewElement.preserveAspectRatioBaseValue());
else
- view->setPreserveAspectRatioBaseValue(preserveAspectRatioBaseValue());
+ view.setPreserveAspectRatioBaseValue(preserveAspectRatioBaseValue());
- if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr))
- view->setZoomAndPanBaseValue(viewElement->zoomAndPan());
+ if (viewElement.hasAttribute(SVGNames::zoomAndPanAttr))
+ view.setZoomAndPanBaseValue(viewElement.zoomAndPan());
else
- view->setZoomAndPanBaseValue(zoomAndPan());
+ view.setZoomAndPanBaseValue(zoomAndPan());
}
-void SVGSVGElement::documentWillSuspendForPageCache()
+void SVGSVGElement::prepareForDocumentSuspension()
{
pauseAnimations();
}
-void SVGSVGElement::documentDidResumeFromPageCache()
+void SVGSVGElement::resumeFromDocumentSuspension()
{
unpauseAnimations();
}
@@ -769,19 +692,24 @@ void SVGSVGElement::documentDidResumeFromPageCache()
// See http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement
Element* SVGSVGElement::getElementById(const AtomicString& id)
{
+ if (id.isNull())
+ return nullptr;
+
Element* element = treeScope().getElementById(id);
- if (element && element->isDescendantOf(this))
+ if (element && element->isDescendantOf(*this))
return element;
-
- // Fall back to traversing our subtree. Duplicate ids are allowed, the first found will
- // be returned.
- for (auto& element : descendantsOfType<Element>(*this)) {
- if (element.getIdAttribute() == id)
- return &element;
+ if (treeScope().containsMultipleElementsWithId(id)) {
+ for (auto* element : *treeScope().getAllElementsById(id)) {
+ if (element->isDescendantOf(*this))
+ return element;
+ }
}
- return 0;
+ return nullptr;
}
+bool SVGSVGElement::isValid() const
+{
+ return SVGTests::isValid();
}
-#endif // ENABLE(SVG)
+}