diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp')
-rw-r--r-- | chromium/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp | 571 |
1 files changed, 291 insertions, 280 deletions
diff --git a/chromium/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp b/chromium/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp index f53db048703..9f69a674f74 100644 --- a/chromium/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp +++ b/chromium/third_party/WebKit/Source/core/svg/SVGSVGElement.cpp @@ -2,6 +2,7 @@ * 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) 2014 Google, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,18 +24,16 @@ #include "core/svg/SVGSVGElement.h" -#include "HTMLNames.h" -#include "SVGNames.h" #include "bindings/v8/ScriptEventListener.h" +#include "core/HTMLNames.h" +#include "core/SVGNames.h" #include "core/css/CSSHelper.h" #include "core/dom/Document.h" #include "core/dom/ElementTraversal.h" -#include "core/dom/NodeTraversal.h" #include "core/dom/StaticNodeList.h" #include "core/editing/FrameSelection.h" #include "core/events/EventListener.h" -#include "core/events/ThreadLocalEventNames.h" -#include "core/frame/Frame.h" +#include "core/frame/LocalFrame.h" #include "core/page/FrameTree.h" #include "core/frame/FrameView.h" #include "core/frame/UseCounter.h" @@ -44,11 +43,13 @@ #include "core/rendering/svg/RenderSVGResource.h" #include "core/rendering/svg/RenderSVGRoot.h" #include "core/rendering/svg/RenderSVGViewportContainer.h" -#include "core/svg/SVGAngle.h" -#include "core/svg/SVGElementInstance.h" +#include "core/svg/SVGAngleTearOff.h" +#include "core/svg/SVGNumberTearOff.h" #include "core/svg/SVGPreserveAspectRatio.h" +#include "core/svg/SVGRectTearOff.h" #include "core/svg/SVGTransform.h" #include "core/svg/SVGTransformList.h" +#include "core/svg/SVGTransformTearOff.h" #include "core/svg/SVGViewElement.h" #include "core/svg/SVGViewSpec.h" #include "core/svg/animation/SMILTimeContainer.h" @@ -60,86 +61,53 @@ namespace WebCore { -// Animated property definitions -DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::xAttr, X, x) -DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::yAttr, Y, y) -DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::widthAttr, Width, width) -DEFINE_ANIMATED_LENGTH(SVGSVGElement, SVGNames::heightAttr, Height, height) -DEFINE_ANIMATED_BOOLEAN(SVGSVGElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) -DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGSVGElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio) -DEFINE_ANIMATED_RECT(SVGSVGElement, SVGNames::viewBoxAttr, ViewBox, viewBox) - -BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGSVGElement) - REGISTER_LOCAL_ANIMATED_PROPERTY(x) - REGISTER_LOCAL_ANIMATED_PROPERTY(y) - REGISTER_LOCAL_ANIMATED_PROPERTY(width) - REGISTER_LOCAL_ANIMATED_PROPERTY(height) - REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired) - REGISTER_LOCAL_ANIMATED_PROPERTY(viewBox) - REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio) - REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement) -END_REGISTER_ANIMATED_PROPERTIES - inline SVGSVGElement::SVGSVGElement(Document& doc) : SVGGraphicsElement(SVGNames::svgTag, doc) - , m_x(LengthModeWidth) - , m_y(LengthModeHeight) - , m_width(LengthModeWidth, "100%") - , m_height(LengthModeHeight, "100%") + , SVGFitToViewBox(this) + , m_x(SVGAnimatedLength::create(this, SVGNames::xAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths)) + , m_y(SVGAnimatedLength::create(this, SVGNames::yAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths)) + , m_width(SVGAnimatedLength::create(this, SVGNames::widthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths)) + , m_height(SVGAnimatedLength::create(this, SVGNames::heightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths)) , m_useCurrentView(false) - , m_zoomAndPan(SVGZoomAndPanMagnify) - , m_timeContainer(SMILTimeContainer::create(this)) - , m_weakFactory(this) + , m_timeContainer(SMILTimeContainer::create(*this)) + , m_translation(SVGPoint::create()) { ScriptWrappable::init(this); - registerAnimatedPropertiesForSVGSVGElement(); + + m_width->setDefaultValueAsString("100%"); + m_height->setDefaultValueAsString("100%"); + + addToPropertyMap(m_x); + addToPropertyMap(m_y); + addToPropertyMap(m_width); + addToPropertyMap(m_height); UseCounter::count(doc, UseCounter::SVGSVGElement); } -PassRefPtr<SVGSVGElement> SVGSVGElement::create(Document& document) -{ - return adoptRef(new SVGSVGElement(document)); -} +DEFINE_NODE_FACTORY(SVGSVGElement) SVGSVGElement::~SVGSVGElement() { +#if !ENABLE(OILPAN) + if (m_viewSpec) + m_viewSpec->detachContextElement(); + // There are cases where removedFromDocument() is not called. // see ContainerNode::removeAllChildren, called by its destructor. - document().accessSVGExtensions()->removeTimeContainer(this); - - ASSERT(inDocument() || !accessDocumentSVGExtensions()->isSVGRootWithRelativeLengthDescendents(this)); -} - -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; -} + // With Oilpan, either removedFrom is called or the document + // is dead as well and there is no reason to clear the extensions. + document().accessSVGExtensions().removeTimeContainer(this); -void SVGSVGElement::setContentScriptType(const AtomicString& type) -{ - setAttribute(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; + ASSERT(inDocument() || !accessDocumentSVGExtensions().isSVGRootWithRelativeLengthDescendents(this)); +#endif } -void SVGSVGElement::setContentStyleType(const AtomicString& type) -{ - setAttribute(SVGNames::contentStyleTypeAttr, type); -} - -SVGRect SVGSVGElement::viewport() const +PassRefPtr<SVGRectTearOff> 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 SVGRect(); + return SVGRectTearOff::create(SVGRect::create(), 0, PropertyIsNotAnimVal); } float SVGSVGElement::pixelUnitToMillimeterX() const @@ -165,7 +133,7 @@ float SVGSVGElement::screenPixelToMillimeterY() const SVGViewSpec* SVGSVGElement::currentView() { if (!m_viewSpec) - m_viewSpec = SVGViewSpec::create(m_weakFactory.createWeakPtr()); + m_viewSpec = SVGViewSpec::create(this); return m_viewSpec.get(); } @@ -174,7 +142,7 @@ float SVGSVGElement::currentScale() const if (!inDocument() || !isOutermostSVGSVGElement()) return 1; - Frame* frame = document().frame(); + LocalFrame* frame = document().frame(); if (!frame) return 1; @@ -191,7 +159,7 @@ void SVGSVGElement::setCurrentScale(float scale) if (!inDocument() || !isOutermostSVGSVGElement()) return; - Frame* frame = document().frame(); + LocalFrame* frame = document().frame(); if (!frame) return; @@ -206,19 +174,41 @@ void SVGSVGElement::setCurrentScale(float scale) frame->setPageZoomFactor(scale); } -void SVGSVGElement::setCurrentTranslate(const FloatPoint& translation) +class SVGCurrentTranslateTearOff : public SVGPointTearOff { +public: + static PassRefPtr<SVGCurrentTranslateTearOff> create(SVGSVGElement* contextElement) + { + return adoptRef(new SVGCurrentTranslateTearOff(contextElement)); + } + + virtual void commitChange() OVERRIDE + { + ASSERT(contextElement()); + toSVGSVGElement(contextElement())->updateCurrentTranslate(); + } + +private: + SVGCurrentTranslateTearOff(SVGSVGElement* contextElement) + : SVGPointTearOff(contextElement->m_translation, contextElement, PropertyIsNotAnimVal) + { + } +}; + +PassRefPtr<SVGPointTearOff> SVGSVGElement::currentTranslateFromJavascript() +{ + return SVGCurrentTranslateTearOff::create(this); +} + +void SVGSVGElement::setCurrentTranslate(const FloatPoint& point) { - m_translation = translation; + m_translation->setValue(point); updateCurrentTranslate(); } void SVGSVGElement::updateCurrentTranslate() { if (RenderObject* object = renderer()) - object->setNeedsLayout(); - - if (parentNode() == document() && document().renderer()) - document().renderer()->repaint(); + object->setNeedsLayoutAndFullPaintInvalidation(); } void SVGSVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value) @@ -230,13 +220,13 @@ void SVGSVGElement::parseAttribute(const QualifiedName& name, const AtomicString // Only handle events if we're the outermost <svg> element if (name == HTMLNames::onunloadAttr) - document().setWindowAttributeEventListener(EventTypeNames::unload, createAttributeEventListener(document().frame(), name, value)); + document().setWindowAttributeEventListener(EventTypeNames::unload, createAttributeEventListener(document().frame(), name, value, eventParameterName())); else if (name == HTMLNames::onresizeAttr) - document().setWindowAttributeEventListener(EventTypeNames::resize, createAttributeEventListener(document().frame(), name, value)); + document().setWindowAttributeEventListener(EventTypeNames::resize, createAttributeEventListener(document().frame(), name, value, eventParameterName())); else if (name == HTMLNames::onscrollAttr) - document().setWindowAttributeEventListener(EventTypeNames::scroll, createAttributeEventListener(document().frame(), name, value)); + document().setWindowAttributeEventListener(EventTypeNames::scroll, createAttributeEventListener(document().frame(), name, value, eventParameterName())); else if (name == SVGNames::onzoomAttr) - document().setWindowAttributeEventListener(EventTypeNames::zoom, createAttributeEventListener(document().frame(), name, value)); + document().setWindowAttributeEventListener(EventTypeNames::zoom, createAttributeEventListener(document().frame(), name, value, eventParameterName())); else setListener = false; @@ -244,45 +234,76 @@ void SVGSVGElement::parseAttribute(const QualifiedName& name, const AtomicString return; } - if (name == HTMLNames::onabortAttr) - document().setWindowAttributeEventListener(EventTypeNames::abort, createAttributeEventListener(document().frame(), name, value)); - else if (name == HTMLNames::onerrorAttr) - document().setWindowAttributeEventListener(EventTypeNames::error, createAttributeEventListener(document().frame(), name, value)); - else if (name == SVGNames::xAttr) - setXBaseValue(SVGLength::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 (SVGExternalResourcesRequired::parseAttribute(name, value) - || SVGFitToViewBox::parseAttribute(this, name, value) - || SVGZoomAndPan::parseAttribute(this, name, value)) { - } else + if (name == HTMLNames::onabortAttr) { + document().setWindowAttributeEventListener(EventTypeNames::abort, createAttributeEventListener(document().frame(), name, value, eventParameterName())); + } else if (name == HTMLNames::onerrorAttr) { + document().setWindowAttributeEventListener(EventTypeNames::error, createAttributeEventListener(document().frame(), name, value, eventParameterName())); + } else if (name == SVGNames::xAttr) { + m_x->setBaseValueAsString(value, parseError); + } else if (name == SVGNames::yAttr) { + m_y->setBaseValueAsString(value, parseError); + } else if (name == SVGNames::widthAttr) { + m_width->setBaseValueAsString(value, parseError); + } else if (name == SVGNames::heightAttr) { + m_height->setBaseValueAsString(value, parseError); + } else if (SVGFitToViewBox::parseAttribute(name, value, document(), parseError)) { + } else if (SVGZoomAndPan::parseAttribute(name, value)) { + } else { SVGGraphicsElement::parseAttribute(name, value); + } reportAttributeParsingError(parseError, name, value); } +bool SVGSVGElement::isPresentationAttribute(const QualifiedName& name) const +{ + if (isOutermostSVGSVGElement() && (name == SVGNames::widthAttr || name == SVGNames::heightAttr)) + return true; + return SVGGraphicsElement::isPresentationAttribute(name); +} + +void SVGSVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style) +{ + if (isOutermostSVGSVGElement() && (name == SVGNames::widthAttr || name == SVGNames::heightAttr)) { + RefPtr<SVGLength> length = SVGLength::create(LengthModeOther); + TrackExceptionState exceptionState; + length->setValueAsString(value, exceptionState); + if (!exceptionState.hadException()) { + if (name == SVGNames::widthAttr) + addPropertyToPresentationAttributeStyle(style, CSSPropertyWidth, value); + else if (name == SVGNames::heightAttr) + addPropertyToPresentationAttributeStyle(style, CSSPropertyHeight, value); + } + } else { + SVGGraphicsElement::collectStyleForPresentationAttribute(name, value, style); + } +} + void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) { bool updateRelativeLengthsOrViewBox = false; bool widthChanged = attrName == SVGNames::widthAttr; - if (widthChanged - || attrName == SVGNames::heightAttr + bool heightChanged = attrName == SVGNames::heightAttr; + if (widthChanged || heightChanged || attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) { updateRelativeLengthsOrViewBox = true; updateRelativeLengthsInformation(); invalidateRelativeLengthClients(); - // 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) { + // At the SVG/HTML boundary (aka RenderSVGRoot), the width and + // height attributes can affect the replaced size so we need + // to mark it for updating. + // + // FIXME: For width/height animated as XML attributes on SVG + // roots, there is an attribute synchronization missing. See + // http://crbug.com/364807 + if (widthChanged || heightChanged) { RenderObject* renderObject = renderer(); - if (renderObject && renderObject->isSVGRoot()) - toRenderSVGRoot(renderObject)->setNeedsLayoutAndPrefWidthsRecalc(); + if (renderObject && renderObject->isSVGRoot()) { + invalidateSVGPresentationAttributeStyle(); + setNeedsStyleRecalc(LocalStyleChange); + } } } @@ -292,10 +313,9 @@ void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) object->setNeedsTransformUpdate(); } - SVGElementInstance::InvalidationGuard invalidationGuard(this); + SVGElement::InvalidationGuard invalidationGuard(this); if (updateRelativeLengthsOrViewBox - || SVGExternalResourcesRequired::isKnownAttribute(attrName) || SVGZoomAndPan::isKnownAttribute(attrName)) { if (renderer()) RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer()); @@ -305,116 +325,155 @@ void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName) SVGGraphicsElement::svgAttributeChanged(attrName); } -unsigned SVGSVGElement::suspendRedraw(unsigned /* maxWaitMilliseconds */) +// FloatRect::intersects does not consider horizontal or vertical lines (because of isEmpty()). +static bool intersectsAllowingEmpty(const FloatRect& r1, const FloatRect& r2) { - // FIXME: Implement me (see bug 11275) - return 0; -} + if (r1.width() < 0 || r1.height() < 0 || r2.width() < 0 || r2.height() < 0) + return false; -void SVGSVGElement::unsuspendRedraw(unsigned /* suspendHandleId */) -{ - // FIXME: Implement me (see bug 11275) + return r1.x() < r2.maxX() && r2.x() < r1.maxX() + && r1.y() < r2.maxY() && r2.y() < r1.maxY(); } -void SVGSVGElement::unsuspendRedrawAll() +// One of the element types that can cause graphics to be drawn onto the target canvas. +// Specifically: circle, ellipse, image, line, path, polygon, polyline, rect, text and use. +static bool isIntersectionOrEnclosureTarget(RenderObject* renderer) { - // FIXME: Implement me (see bug 11275) + return renderer->isSVGShape() + || renderer->isSVGText() + || renderer->isSVGImage() + || isSVGUseElement(*renderer->node()); } -void SVGSVGElement::forceRedraw() +bool SVGSVGElement::checkIntersectionOrEnclosure(const SVGElement& element, const FloatRect& rect, + CheckIntersectionOrEnclosure mode) const { - // FIXME: Implement me (see bug 11275) + RenderObject* renderer = element.renderer(); + ASSERT(!renderer || renderer->style()); + if (!renderer || renderer->style()->pointerEvents() == PE_NONE) + return false; + + if (!isIntersectionOrEnclosureTarget(renderer)) + return false; + + AffineTransform ctm = toSVGGraphicsElement(element).computeCTM(AncestorScope, DisallowStyleUpdate, this); + FloatRect mappedRepaintRect = ctm.mapRect(renderer->paintInvalidationRectInLocalCoordinates()); + + bool result = false; + switch (mode) { + case CheckIntersection: + result = intersectsAllowingEmpty(rect, mappedRepaintRect); + break; + case CheckEnclosure: + result = rect.contains(mappedRepaintRect); + break; + default: + ASSERT_NOT_REACHED(); + break; + } + + return result; } -PassRefPtr<NodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const SVGRect& rect, SVGElement* referenceElement, CollectIntersectionOrEnclosure collect) const +PassRefPtrWillBeRawPtr<StaticNodeList> SVGSVGElement::collectIntersectionOrEnclosureList(const FloatRect& rect, + SVGElement* referenceElement, CheckIntersectionOrEnclosure mode) const { - Vector<RefPtr<Node> > nodes; - Element* element = ElementTraversal::next(*(referenceElement ? referenceElement : this)); - while (element) { - if (element->isSVGElement()) { - SVGElement* svgElement = toSVGElement(element); - if (collect == CollectIntersectionList) { - if (checkIntersection(svgElement, rect)) - nodes.append(element); - } else { - if (checkEnclosure(svgElement, rect)) - nodes.append(element); - } + WillBeHeapVector<RefPtrWillBeMember<Node> > nodes; + + const SVGElement* root = this; + if (referenceElement) { + // Only the common subtree needs to be traversed. + if (contains(referenceElement)) { + root = referenceElement; + } else if (!isDescendantOf(referenceElement)) { + // No common subtree. + return StaticNodeList::adopt(nodes); } + } - element = ElementTraversal::next(*element, referenceElement ? referenceElement : this); + for (SVGGraphicsElement* element = Traversal<SVGGraphicsElement>::firstWithin(*root); element; + element = Traversal<SVGGraphicsElement>::next(*element, root)) { + if (checkIntersectionOrEnclosure(*element, rect, mode)) + nodes.append(element); } + return StaticNodeList::adopt(nodes); } -PassRefPtr<NodeList> SVGSVGElement::getIntersectionList(const SVGRect& rect, SVGElement* referenceElement) const +PassRefPtrWillBeRawPtr<StaticNodeList> SVGSVGElement::getIntersectionList(PassRefPtr<SVGRectTearOff> rect, SVGElement* referenceElement) const { - return collectIntersectionOrEnclosureList(rect, referenceElement, CollectIntersectionList); + document().updateLayoutIgnorePendingStylesheets(); + + return collectIntersectionOrEnclosureList(rect->target()->value(), referenceElement, CheckIntersection); } -PassRefPtr<NodeList> SVGSVGElement::getEnclosureList(const SVGRect& rect, SVGElement* referenceElement) const +PassRefPtrWillBeRawPtr<StaticNodeList> SVGSVGElement::getEnclosureList(PassRefPtr<SVGRectTearOff> rect, SVGElement* referenceElement) const { - return collectIntersectionOrEnclosureList(rect, referenceElement, CollectEnclosureList); + document().updateLayoutIgnorePendingStylesheets(); + + return collectIntersectionOrEnclosureList(rect->target()->value(), referenceElement, CheckEnclosure); } -bool SVGSVGElement::checkIntersection(SVGElement* element, const SVGRect& rect) const +bool SVGSVGElement::checkIntersection(SVGElement* element, PassRefPtr<SVGRectTearOff> rect) const { - if (!element) - return false; - return RenderSVGModelObject::checkIntersection(element->renderer(), rect); + ASSERT(element); + document().updateLayoutIgnorePendingStylesheets(); + + return checkIntersectionOrEnclosure(*element, rect->target()->value(), CheckIntersection); } -bool SVGSVGElement::checkEnclosure(SVGElement* element, const SVGRect& rect) const +bool SVGSVGElement::checkEnclosure(SVGElement* element, PassRefPtr<SVGRectTearOff> rect) const { - if (!element) - return false; - return RenderSVGModelObject::checkEnclosure(element->renderer(), rect); + ASSERT(element); + document().updateLayoutIgnorePendingStylesheets(); + + return checkIntersectionOrEnclosure(*element, rect->target()->value(), CheckEnclosure); } void SVGSVGElement::deselectAll() { - if (Frame* frame = document().frame()) + if (LocalFrame* frame = document().frame()) frame->selection().clear(); } -float SVGSVGElement::createSVGNumber() +PassRefPtr<SVGNumberTearOff> SVGSVGElement::createSVGNumber() { - return 0.0f; + return SVGNumberTearOff::create(SVGNumber::create(0.0f), 0, PropertyIsNotAnimVal); } -SVGLength SVGSVGElement::createSVGLength() +PassRefPtr<SVGLengthTearOff> SVGSVGElement::createSVGLength() { - return SVGLength(); + return SVGLengthTearOff::create(SVGLength::create(), 0, PropertyIsNotAnimVal); } -SVGAngle SVGSVGElement::createSVGAngle() +PassRefPtr<SVGAngleTearOff> SVGSVGElement::createSVGAngle() { - return SVGAngle(); + return SVGAngleTearOff::create(SVGAngle::create(), 0, PropertyIsNotAnimVal); } -SVGPoint SVGSVGElement::createSVGPoint() +PassRefPtr<SVGPointTearOff> SVGSVGElement::createSVGPoint() { - return SVGPoint(); + return SVGPointTearOff::create(SVGPoint::create(), 0, PropertyIsNotAnimVal); } -SVGMatrix SVGSVGElement::createSVGMatrix() +PassRefPtr<SVGMatrixTearOff> SVGSVGElement::createSVGMatrix() { - return SVGMatrix(); + return SVGMatrixTearOff::create(AffineTransform()); } -SVGRect SVGSVGElement::createSVGRect() +PassRefPtr<SVGRectTearOff> SVGSVGElement::createSVGRect() { - return SVGRect(); + return SVGRectTearOff::create(SVGRect::create(), 0, PropertyIsNotAnimVal); } -SVGTransform SVGSVGElement::createSVGTransform() +PassRefPtr<SVGTransformTearOff> SVGSVGElement::createSVGTransform() { - return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX); + return SVGTransformTearOff::create(SVGTransform::create(SVG_TRANSFORM_MATRIX), 0, PropertyIsNotAnimVal); } -SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix) +PassRefPtr<SVGTransformTearOff> SVGSVGElement::createSVGTransformFromMatrix(PassRefPtr<SVGMatrixTearOff> matrix) { - return SVGTransform(static_cast<const AffineTransform&>(matrix)); + return SVGTransformTearOff::create(SVGTransform::create(matrix->value()), 0, PropertyIsNotAnimVal); } AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGElement::CTMScope mode) const @@ -428,7 +487,7 @@ AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGElement::CTMScop AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); - transform.translate(xCurrentValue().value(lengthContext), yCurrentValue().value(lengthContext)); + transform.translate(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)); } else if (mode == SVGElement::ScreenScope) { if (RenderObject* renderer = this->renderer()) { FloatPoint location; @@ -486,7 +545,11 @@ RenderObject* SVGSVGElement::createRenderer(RenderStyle*) Node::InsertionNotificationRequest SVGSVGElement::insertedInto(ContainerNode* rootParent) { if (rootParent->inDocument()) { - document().accessSVGExtensions()->addTimeContainer(this); + UseCounter::count(document(), UseCounter::SVGSVGElementInDocument); + if (rootParent->document().isXMLDocument()) + UseCounter::count(document(), UseCounter::SVGSVGElementInXMLDocument); + + 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 @@ -500,9 +563,9 @@ Node::InsertionNotificationRequest SVGSVGElement::insertedInto(ContainerNode* ro void SVGSVGElement::removedFrom(ContainerNode* rootParent) { if (rootParent->inDocument()) { - SVGDocumentExtensions* svgExtensions = document().accessSVGExtensions(); - svgExtensions->removeTimeContainer(this); - svgExtensions->removeSVGRootWithRelativeLengthDescendents(this); + SVGDocumentExtensions& svgExtensions = document().accessSVGExtensions(); + svgExtensions.removeTimeContainer(this); + svgExtensions.removeSVGRootWithRelativeLengthDescendents(this); } SVGGraphicsElement::removedFrom(rootParent); @@ -540,42 +603,38 @@ void SVGSVGElement::setCurrentTime(float seconds) bool SVGSVGElement::selfHasRelativeLengths() const { - return xCurrentValue().isRelative() - || yCurrentValue().isRelative() - || widthCurrentValue().isRelative() - || heightCurrentValue().isRelative() + return m_x->currentValue()->isRelative() + || m_y->currentValue()->isRelative() + || m_width->currentValue()->isRelative() + || m_height->currentValue()->isRelative() || hasAttribute(SVGNames::viewBoxAttr); } -SVGRect SVGSVGElement::currentViewBoxRect() const +FloatRect SVGSVGElement::currentViewBoxRect() const { if (m_useCurrentView) - return m_viewSpec ? m_viewSpec->viewBoxCurrentValue() : SVGRect(); + return m_viewSpec ? m_viewSpec->viewBox()->currentValue()->value() : FloatRect(); - FloatRect useViewBox = viewBoxCurrentValue(); + FloatRect useViewBox = viewBox()->currentValue()->value(); if (!useViewBox.isEmpty()) return useViewBox; if (!renderer() || !renderer()->isSVGRoot()) - return SVGRect(); + return FloatRect(); if (!toRenderSVGRoot(renderer())->isEmbeddedThroughSVGImage()) - return SVGRect(); - - Length intrinsicWidth = this->intrinsicWidth(); - Length intrinsicHeight = this->intrinsicHeight(); - if (!intrinsicWidth.isFixed() || !intrinsicHeight.isFixed()) - return SVGRect(); + return FloatRect(); // 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 SVGRect(FloatPoint(), FloatSize(floatValueForLength(intrinsicWidth, 0, 0), floatValueForLength(intrinsicHeight, 0, 0))); + return FloatRect(FloatPoint(), FloatSize(floatValueForLength(intrinsicWidth(), 0), floatValueForLength(intrinsicHeight(), 0))); } FloatSize SVGSVGElement::currentViewportSize() const { - Length intrinsicWidth = this->intrinsicWidth(); - Length intrinsicHeight = this->intrinsicHeight(); - if (intrinsicWidth.isFixed() && intrinsicHeight.isFixed()) + if (hasIntrinsicWidth() && hasIntrinsicHeight()) { + Length intrinsicWidth = this->intrinsicWidth(); + Length intrinsicHeight = this->intrinsicHeight(); return FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)); + } if (!renderer()) return FloatSize(); @@ -589,94 +648,46 @@ FloatSize SVGSVGElement::currentViewportSize() const return FloatSize(viewportRect.width(), viewportRect.height()); } -bool SVGSVGElement::widthAttributeEstablishesViewport() const +bool SVGSVGElement::hasIntrinsicWidth() 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()); - - // SVG embedded through object/embed/iframe. - if (root->isEmbeddedThroughFrameContainingSVGDocument()) - return !root->hasReplacedLogicalWidth() && !document().frame()->ownerRenderer()->hasReplacedLogicalWidth(); - - // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. - if (root->isEmbeddedThroughSVGImage() || document().documentElement() != this) - return !root->hasReplacedLogicalWidth(); - - return true; + return width()->currentValue()->unitType() != LengthTypePercentage; } -bool SVGSVGElement::heightAttributeEstablishesViewport() const +bool SVGSVGElement::hasIntrinsicHeight() 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 height()->currentValue()->unitType() != LengthTypePercentage; } -Length SVGSVGElement::intrinsicWidth(ConsiderCSSMode mode) const +Length SVGSVGElement::intrinsicWidth() const { - if (widthAttributeEstablishesViewport() || mode == IgnoreCSSProperties) { - if (widthCurrentValue().unitType() == LengthTypePercentage) - return Length(widthCurrentValue().valueAsPercentage() * 100, Percent); + if (width()->currentValue()->unitType() == LengthTypePercentage) + return Length(0, Fixed); - SVGLengthContext lengthContext(this); - return Length(widthCurrentValue().value(lengthContext), Fixed); - } - - ASSERT(renderer()); - return renderer()->style()->width(); + SVGLengthContext lengthContext(this); + return Length(width()->currentValue()->value(lengthContext), Fixed); } -Length SVGSVGElement::intrinsicHeight(ConsiderCSSMode mode) const +Length SVGSVGElement::intrinsicHeight() const { - if (heightAttributeEstablishesViewport() || mode == IgnoreCSSProperties) { - if (heightCurrentValue().unitType() == LengthTypePercentage) - return Length(heightCurrentValue().valueAsPercentage() * 100, Percent); - - SVGLengthContext lengthContext(this); - return Length(heightCurrentValue().value(lengthContext), Fixed); - } + if (height()->currentValue()->unitType() == LengthTypePercentage) + return Length(0, Fixed); - ASSERT(renderer()); - return renderer()->style()->height(); + SVGLengthContext lengthContext(this); + return Length(height()->currentValue()->value(lengthContext), Fixed); } AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const { if (!m_useCurrentView || !m_viewSpec) - return SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), preserveAspectRatioCurrentValue(), viewWidth, viewHeight); + return SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), preserveAspectRatio()->currentValue(), viewWidth, viewHeight); - AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), m_viewSpec->preserveAspectRatioCurrentValue(), viewWidth, viewHeight); - const SVGTransformList& transformList = m_viewSpec->transformBaseValue(); - if (transformList.isEmpty()) + AffineTransform ctm = SVGFitToViewBox::viewBoxToViewTransform(currentViewBoxRect(), m_viewSpec->preserveAspectRatio()->currentValue(), viewWidth, viewHeight); + RefPtr<SVGTransformList> transformList = m_viewSpec->transform(); + if (transformList->isEmpty()) return ctm; AffineTransform transform; - if (transformList.concatenate(transform)) + if (transformList->concatenate(transform)) ctm *= transform; return ctm; @@ -717,13 +728,11 @@ void SVGSVGElement::setupInitialView(const String& fragmentIdentifier, Element* // 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 && anchorNode->hasTagName(SVGNames::viewTag)) { - SVGViewElement* viewElement = toSVGViewElement(anchorNode); - if (!viewElement) - return; + if (isSVGViewElement(anchorNode)) { + SVGViewElement& viewElement = toSVGViewElement(*anchorNode); - if (SVGSVGElement* svg = viewElement->ownerSVGElement()) { - svg->inheritViewAttributes(viewElement); + if (SVGSVGElement* svg = viewElement.ownerSVGElement()) { + svg->inheritViewAttributes(&viewElement); if (RenderObject* renderer = svg->renderer()) RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer); @@ -740,40 +749,42 @@ void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement) m_useCurrentView = true; if (viewElement->hasAttribute(SVGNames::viewBoxAttr)) - view->setViewBoxBaseValue(viewElement->viewBoxCurrentValue()); - else - view->setViewBoxBaseValue(viewBoxCurrentValue()); - - if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr)) - view->setPreserveAspectRatioBaseValue(viewElement->preserveAspectRatioBaseValue()); + view->viewBox()->baseValue()->setValue(viewElement->viewBox()->currentValue()->value()); else - view->setPreserveAspectRatioBaseValue(preserveAspectRatioBaseValue()); + view->viewBox()->baseValue()->setValue(viewBox()->currentValue()->value()); + + if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr)) { + view->preserveAspectRatio()->baseValue()->setAlign(viewElement->preserveAspectRatio()->currentValue()->align()); + view->preserveAspectRatio()->baseValue()->setMeetOrSlice(viewElement->preserveAspectRatio()->currentValue()->meetOrSlice()); + } else { + view->preserveAspectRatio()->baseValue()->setAlign(preserveAspectRatio()->currentValue()->align()); + view->preserveAspectRatio()->baseValue()->setMeetOrSlice(preserveAspectRatio()->currentValue()->meetOrSlice()); + } if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr)) - view->setZoomAndPanBaseValue(viewElement->zoomAndPan()); + view->setZoomAndPan(viewElement->zoomAndPan()); else - view->setZoomAndPanBaseValue(zoomAndPan()); + view->setZoomAndPan(zoomAndPan()); } -// getElementById on SVGSVGElement is restricted to only the child subtree defined by the <svg> element. -// See http://www.w3.org/TR/SVG11/struct.html#InterfaceSVGSVGElement -Element* SVGSVGElement::getElementById(const AtomicString& id) const +void SVGSVGElement::finishParsingChildren() { - Element* element = treeScope().getElementById(id); - if (element && element->isDescendantOf(this)) - return element; + SVGGraphicsElement::finishParsingChildren(); + + // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent. + if (isOutermostSVGSVGElement()) + return; - // Fall back to traversing our subtree. Duplicate ids are allowed, the first found will - // be returned. - for (Node* node = firstChild(); node; node = NodeTraversal::next(*node, this)) { - if (!node->isElementNode()) - continue; + // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>) + // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish + sendSVGLoadEventIfPossible(); +} - Element* element = toElement(node); - if (element->getIdAttribute() == id) - return element; - } - return 0; +void SVGSVGElement::trace(Visitor* visitor) +{ + visitor->trace(m_timeContainer); + visitor->trace(m_viewSpec); + SVGGraphicsElement::trace(visitor); } } |