Add WTF::move()
[WebKit-https.git] / Source / WebCore / svg / SVGTextPathElement.cpp
1 /*
2  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2010 Rob Buis <rwlbuis@gmail.com>
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 "SVGTextPathElement.h"
23
24 #include "Attribute.h"
25 #include "RenderSVGResource.h"
26 #include "RenderSVGTextPath.h"
27 #include "SVGElementInstance.h"
28 #include "SVGNames.h"
29 #include "XLinkNames.h"
30 #include <wtf/NeverDestroyed.h>
31
32 namespace WebCore {
33
34 // Animated property definitions
35 DEFINE_ANIMATED_LENGTH(SVGTextPathElement, SVGNames::startOffsetAttr, StartOffset, startOffset)
36 DEFINE_ANIMATED_ENUMERATION(SVGTextPathElement, SVGNames::methodAttr, Method, method, SVGTextPathMethodType)
37 DEFINE_ANIMATED_ENUMERATION(SVGTextPathElement, SVGNames::spacingAttr, Spacing, spacing, SVGTextPathSpacingType)
38 DEFINE_ANIMATED_STRING(SVGTextPathElement, XLinkNames::hrefAttr, Href, href)
39
40 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGTextPathElement)
41     REGISTER_LOCAL_ANIMATED_PROPERTY(startOffset)
42     REGISTER_LOCAL_ANIMATED_PROPERTY(method)
43     REGISTER_LOCAL_ANIMATED_PROPERTY(spacing)
44     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
45     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTextContentElement)
46 END_REGISTER_ANIMATED_PROPERTIES
47
48 inline SVGTextPathElement::SVGTextPathElement(const QualifiedName& tagName, Document& document)
49     : SVGTextContentElement(tagName, document)
50     , m_startOffset(LengthModeOther)
51     , m_method(SVGTextPathMethodAlign)
52     , m_spacing(SVGTextPathSpacingExact)
53 {
54     ASSERT(hasTagName(SVGNames::textPathTag));
55     registerAnimatedPropertiesForSVGTextPathElement();
56 }
57
58 PassRefPtr<SVGTextPathElement> SVGTextPathElement::create(const QualifiedName& tagName, Document& document)
59 {
60     return adoptRef(new SVGTextPathElement(tagName, document));
61 }
62
63 SVGTextPathElement::~SVGTextPathElement()
64 {
65     clearResourceReferences();
66 }
67
68 void SVGTextPathElement::clearResourceReferences()
69 {
70     document().accessSVGExtensions()->removeAllTargetReferencesForElement(this);
71 }
72
73 bool SVGTextPathElement::isSupportedAttribute(const QualifiedName& attrName)
74 {
75     static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
76     if (supportedAttributes.get().isEmpty()) {
77         SVGURIReference::addSupportedAttributes(supportedAttributes);
78         supportedAttributes.get().add(SVGNames::startOffsetAttr);
79         supportedAttributes.get().add(SVGNames::methodAttr);
80         supportedAttributes.get().add(SVGNames::spacingAttr);
81     }
82     return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
83 }
84
85 void SVGTextPathElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
86 {
87     SVGParsingError parseError = NoError;
88
89     if (!isSupportedAttribute(name))
90         SVGTextContentElement::parseAttribute(name, value);
91     else if (name == SVGNames::startOffsetAttr)
92         setStartOffsetBaseValue(SVGLength::construct(LengthModeOther, value, parseError));
93     else if (name == SVGNames::methodAttr) {
94         SVGTextPathMethodType propertyValue = SVGPropertyTraits<SVGTextPathMethodType>::fromString(value);
95         if (propertyValue > 0)
96             setMethodBaseValue(propertyValue);
97     } else if (name == SVGNames::spacingAttr) {
98         SVGTextPathSpacingType propertyValue = SVGPropertyTraits<SVGTextPathSpacingType>::fromString(value);
99         if (propertyValue > 0)
100             setSpacingBaseValue(propertyValue);
101     } else if (SVGURIReference::parseAttribute(name, value)) {
102     } else
103         ASSERT_NOT_REACHED();
104
105     reportAttributeParsingError(parseError, name, value);
106 }
107
108 void SVGTextPathElement::svgAttributeChanged(const QualifiedName& attrName)
109 {
110     if (!isSupportedAttribute(attrName)) {
111         SVGTextContentElement::svgAttributeChanged(attrName);
112         return;
113     }
114
115     SVGElementInstance::InvalidationGuard invalidationGuard(this);
116
117     if (SVGURIReference::isKnownAttribute(attrName)) {
118         buildPendingResource();
119         return;
120     }
121
122     if (attrName == SVGNames::startOffsetAttr)
123         updateRelativeLengthsInformation();
124
125     if (auto renderer = this->renderer())
126         RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
127 }
128
129 RenderPtr<RenderElement> SVGTextPathElement::createElementRenderer(PassRef<RenderStyle> style)
130 {
131     return createRenderer<RenderSVGTextPath>(*this, WTF::move(style));
132 }
133
134 bool SVGTextPathElement::childShouldCreateRenderer(const Node& child) const
135 {
136     if (child.isTextNode()
137         || child.hasTagName(SVGNames::aTag)
138         || child.hasTagName(SVGNames::trefTag)
139         || child.hasTagName(SVGNames::tspanTag))
140         return true;
141
142     return false;
143 }
144
145 bool SVGTextPathElement::rendererIsNeeded(const RenderStyle& style)
146 {
147     if (parentNode()
148         && (parentNode()->hasTagName(SVGNames::aTag)
149             || parentNode()->hasTagName(SVGNames::textTag)))
150         return StyledElement::rendererIsNeeded(style);
151
152     return false;
153 }
154
155 void SVGTextPathElement::buildPendingResource()
156 {
157     clearResourceReferences();
158     if (!inDocument())
159         return;
160
161     String id;
162     Element* target = SVGURIReference::targetElementFromIRIString(href(), document(), &id);
163     if (!target) {
164         // Do not register as pending if we are already pending this resource.
165         if (document().accessSVGExtensions()->isPendingResource(this, id))
166             return;
167
168         if (!id.isEmpty()) {
169             document().accessSVGExtensions()->addPendingResource(id, this);
170             ASSERT(hasPendingResources());
171         }
172     } else if (target->hasTagName(SVGNames::pathTag)) {
173         // Register us with the target in the dependencies map. Any change of hrefElement
174         // that leads to relayout/repainting now informs us, so we can react to it.
175         document().accessSVGExtensions()->addElementReferencingTarget(this, toSVGElement(target));
176     }
177 }
178
179 Node::InsertionNotificationRequest SVGTextPathElement::insertedInto(ContainerNode& rootParent)
180 {
181     SVGTextContentElement::insertedInto(rootParent);
182     return InsertionShouldCallDidNotifySubtreeInsertions;
183 }
184
185 void SVGTextPathElement::didNotifySubtreeInsertions(ContainerNode*)
186 {
187     buildPendingResource();
188 }
189
190 void SVGTextPathElement::removedFrom(ContainerNode& rootParent)
191 {
192     SVGTextContentElement::removedFrom(rootParent);
193     if (rootParent.inDocument())
194         clearResourceReferences();
195 }
196
197 bool SVGTextPathElement::selfHasRelativeLengths() const
198 {
199     return startOffset().isRelative()
200         || SVGTextContentElement::selfHasRelativeLengths();
201 }
202
203 }