1/*
2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 * Copyright (C) 2018 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "SVGMPathElement.h"
23
24#include "Document.h"
25#include "SVGAnimateMotionElement.h"
26#include "SVGDocumentExtensions.h"
27#include "SVGNames.h"
28#include "SVGPathElement.h"
29#include <wtf/IsoMallocInlines.h>
30
31namespace WebCore {
32
33WTF_MAKE_ISO_ALLOCATED_IMPL(SVGMPathElement);
34
35inline SVGMPathElement::SVGMPathElement(const QualifiedName& tagName, Document& document)
36 : SVGElement(tagName, document)
37 , SVGExternalResourcesRequired(this)
38 , SVGURIReference(this)
39{
40 ASSERT(hasTagName(SVGNames::mpathTag));
41}
42
43Ref<SVGMPathElement> SVGMPathElement::create(const QualifiedName& tagName, Document& document)
44{
45 return adoptRef(*new SVGMPathElement(tagName, document));
46}
47
48SVGMPathElement::~SVGMPathElement()
49{
50 clearResourceReferences();
51}
52
53void SVGMPathElement::buildPendingResource()
54{
55 clearResourceReferences();
56 if (!isConnected())
57 return;
58
59 auto target = SVGURIReference::targetElementFromIRIString(href(), treeScope());
60 if (!target.element) {
61 // Do not register as pending if we are already pending this resource.
62 if (document().accessSVGExtensions().isPendingResource(*this, target.identifier))
63 return;
64
65 if (!target.identifier.isEmpty()) {
66 document().accessSVGExtensions().addPendingResource(target.identifier, *this);
67 ASSERT(hasPendingResources());
68 }
69 } else if (is<SVGElement>(*target.element)) {
70 // Register us with the target in the dependencies map. Any change of hrefElement
71 // that leads to relayout/repainting now informs us, so we can react to it.
72 document().accessSVGExtensions().addElementReferencingTarget(*this, downcast<SVGElement>(*target.element));
73 }
74
75 targetPathChanged();
76}
77
78void SVGMPathElement::clearResourceReferences()
79{
80 document().accessSVGExtensions().removeAllTargetReferencesForElement(*this);
81}
82
83Node::InsertedIntoAncestorResult SVGMPathElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
84{
85 SVGElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
86 if (insertionType.connectedToDocument)
87 return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
88 return InsertedIntoAncestorResult::Done;
89}
90
91void SVGMPathElement::didFinishInsertingNode()
92{
93 buildPendingResource();
94}
95
96void SVGMPathElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
97{
98 SVGElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
99 notifyParentOfPathChange(&oldParentOfRemovedTree);
100 if (removalType.disconnectedFromDocument)
101 clearResourceReferences();
102}
103
104void SVGMPathElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
105{
106 SVGElement::parseAttribute(name, value);
107 SVGURIReference::parseAttribute(name, value);
108 SVGExternalResourcesRequired::parseAttribute(name, value);
109}
110
111void SVGMPathElement::svgAttributeChanged(const QualifiedName& attrName)
112{
113 if (SVGURIReference::isKnownAttribute(attrName)) {
114 InstanceInvalidationGuard guard(*this);
115 buildPendingResource();
116 return;
117 }
118
119 SVGElement::svgAttributeChanged(attrName);
120 SVGExternalResourcesRequired::svgAttributeChanged(attrName);
121}
122
123RefPtr<SVGPathElement> SVGMPathElement::pathElement()
124{
125 auto target = targetElementFromIRIString(href(), treeScope());
126 if (is<SVGPathElement>(target.element))
127 return downcast<SVGPathElement>(target.element.get());
128 return nullptr;
129}
130
131void SVGMPathElement::targetPathChanged()
132{
133 notifyParentOfPathChange(parentNode());
134}
135
136void SVGMPathElement::notifyParentOfPathChange(ContainerNode* parent)
137{
138 if (is<SVGAnimateMotionElement>(parent))
139 downcast<SVGAnimateMotionElement>(*parent).updateAnimationPath();
140}
141
142} // namespace WebCore
143