Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / svg / SVGDocumentExtensions.cpp
blobe3a6fb5560101aaf7b26b4fc20d123c8d68ccb68
1 /*
2 * Copyright (C) 2006 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
4 * Copyright (C) 2007 Rob Buis <buis@kde.org>
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.
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.
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.
22 #include "config.h"
23 #include "core/svg/SVGDocumentExtensions.h"
25 #include "core/dom/Document.h"
26 #include "core/inspector/ConsoleMessage.h"
27 #include "core/layout/svg/SVGResourcesCache.h"
28 #include "core/svg/SVGSVGElement.h"
29 #include "core/svg/animation/SMILTimeContainer.h"
30 #include "wtf/TemporaryChange.h"
31 #include "wtf/text/AtomicString.h"
33 namespace blink {
35 SVGDocumentExtensions::SVGDocumentExtensions(Document* document)
36 : m_document(document)
37 #if ENABLE(ASSERT)
38 , m_inRelativeLengthSVGRootsInvalidation(false)
39 #endif
43 SVGDocumentExtensions::~SVGDocumentExtensions()
47 void SVGDocumentExtensions::addTimeContainer(SVGSVGElement* element)
49 m_timeContainers.add(element);
52 void SVGDocumentExtensions::removeTimeContainer(SVGSVGElement* element)
54 m_timeContainers.remove(element);
57 void SVGDocumentExtensions::addResource(const AtomicString& id, LayoutSVGResourceContainer* resource)
59 ASSERT(resource);
61 if (id.isEmpty())
62 return;
64 // Replaces resource if already present, to handle potential id changes
65 m_resources.set(id, resource);
68 void SVGDocumentExtensions::removeResource(const AtomicString& id)
70 if (id.isEmpty())
71 return;
73 m_resources.remove(id);
76 LayoutSVGResourceContainer* SVGDocumentExtensions::resourceById(const AtomicString& id) const
78 if (id.isEmpty())
79 return nullptr;
81 return m_resources.get(id);
84 void SVGDocumentExtensions::serviceOnAnimationFrame(Document& document, double monotonicAnimationStartTime)
86 if (!document.svgExtensions() || !RuntimeEnabledFeatures::smilEnabled())
87 return;
88 document.accessSVGExtensions().serviceAnimations(monotonicAnimationStartTime);
91 void SVGDocumentExtensions::serviceAnimations(double monotonicAnimationStartTime)
93 WillBeHeapVector<RefPtrWillBeMember<SVGSVGElement>> timeContainers;
94 copyToVector(m_timeContainers, timeContainers);
95 for (const auto& container : timeContainers)
96 container->timeContainer()->serviceAnimations(monotonicAnimationStartTime);
99 void SVGDocumentExtensions::startAnimations()
101 // FIXME: Eventually every "Time Container" will need a way to latch on to some global timer
102 // starting animations for a document will do this "latching"
103 // FIXME: We hold a ref pointers to prevent a shadow tree from getting removed out from underneath us.
104 // In the future we should refactor the use-element to avoid this. See https://webkit.org/b/53704
105 WillBeHeapVector<RefPtrWillBeMember<SVGSVGElement>> timeContainers;
106 copyToVector(m_timeContainers, timeContainers);
107 for (const auto& container : timeContainers) {
108 SMILTimeContainer* timeContainer = container->timeContainer();
109 if (!timeContainer->isStarted())
110 timeContainer->begin();
114 void SVGDocumentExtensions::pauseAnimations()
116 for (SVGSVGElement* element : m_timeContainers)
117 element->pauseAnimations();
120 void SVGDocumentExtensions::dispatchSVGLoadEventToOutermostSVGElements()
122 WillBeHeapVector<RefPtrWillBeMember<SVGSVGElement>> timeContainers;
123 copyToVector(m_timeContainers, timeContainers);
124 for (const auto& container : timeContainers) {
125 SVGSVGElement* outerSVG = container.get();
126 if (!outerSVG->isOutermostSVGSVGElement())
127 continue;
129 // don't dispatch the load event document is not wellformed (for XML/standalone svg)
130 if (outerSVG->document().wellFormed() || !outerSVG->document().isSVGDocument())
131 outerSVG->sendSVGLoadEventIfPossible();
135 static void reportMessage(Document* document, MessageLevel level, const String& message)
137 if (document->frame())
138 document->addConsoleMessage(ConsoleMessage::create(RenderingMessageSource, level, message));
141 void SVGDocumentExtensions::reportWarning(const String& message)
143 reportMessage(m_document, WarningMessageLevel, "Warning: " + message);
146 void SVGDocumentExtensions::reportError(const String& message)
148 reportMessage(m_document, ErrorMessageLevel, "Error: " + message);
151 void SVGDocumentExtensions::addPendingResource(const AtomicString& id, Element* element)
153 ASSERT(element);
154 ASSERT(element->inDocument());
156 if (id.isEmpty())
157 return;
159 WillBeHeapHashMap<AtomicString, OwnPtrWillBeMember<SVGPendingElements>>::AddResult result = m_pendingResources.add(id, nullptr);
160 if (result.isNewEntry)
161 result.storedValue->value = adoptPtrWillBeNoop(new SVGPendingElements);
162 result.storedValue->value->add(element);
164 element->setHasPendingResources();
167 bool SVGDocumentExtensions::hasPendingResource(const AtomicString& id) const
169 if (id.isEmpty())
170 return false;
172 return m_pendingResources.contains(id);
175 bool SVGDocumentExtensions::isElementPendingResources(Element* element) const
177 // This algorithm takes time proportional to the number of pending resources and need not.
178 // If performance becomes an issue we can keep a counted set of elements and answer the question efficiently.
180 ASSERT(element);
182 for (const auto& entry : m_pendingResources) {
183 SVGPendingElements* elements = entry.value.get();
184 ASSERT(elements);
186 if (elements->contains(element))
187 return true;
189 return false;
192 bool SVGDocumentExtensions::isElementPendingResource(Element* element, const AtomicString& id) const
194 ASSERT(element);
196 if (!hasPendingResource(id))
197 return false;
199 return m_pendingResources.get(id)->contains(element);
202 void SVGDocumentExtensions::clearHasPendingResourcesIfPossible(Element* element)
204 if (!isElementPendingResources(element))
205 element->clearHasPendingResources();
208 void SVGDocumentExtensions::removeElementFromPendingResources(Element* element)
210 ASSERT(element);
212 // Remove the element from pending resources.
213 if (!m_pendingResources.isEmpty() && element->hasPendingResources()) {
214 Vector<AtomicString> toBeRemoved;
215 for (const auto& entry : m_pendingResources) {
216 SVGPendingElements* elements = entry.value.get();
217 ASSERT(elements);
218 ASSERT(!elements->isEmpty());
220 elements->remove(element);
221 if (elements->isEmpty())
222 toBeRemoved.append(entry.key);
225 clearHasPendingResourcesIfPossible(element);
227 // We use the removePendingResource function here because it deals with set lifetime correctly.
228 for (const AtomicString& id : toBeRemoved)
229 removePendingResource(id);
232 // Remove the element from pending resources that were scheduled for removal.
233 if (!m_pendingResourcesForRemoval.isEmpty()) {
234 Vector<AtomicString> toBeRemoved;
235 for (const auto& entry : m_pendingResourcesForRemoval) {
236 SVGPendingElements* elements = entry.value.get();
237 ASSERT(elements);
238 ASSERT(!elements->isEmpty());
240 elements->remove(element);
241 if (elements->isEmpty())
242 toBeRemoved.append(entry.key);
245 // We use the removePendingResourceForRemoval function here because it deals with set lifetime correctly.
246 for (const AtomicString& id : toBeRemoved)
247 removePendingResourceForRemoval(id);
251 PassOwnPtrWillBeRawPtr<SVGDocumentExtensions::SVGPendingElements> SVGDocumentExtensions::removePendingResource(const AtomicString& id)
253 ASSERT(m_pendingResources.contains(id));
254 return m_pendingResources.take(id);
257 PassOwnPtrWillBeRawPtr<SVGDocumentExtensions::SVGPendingElements> SVGDocumentExtensions::removePendingResourceForRemoval(const AtomicString& id)
259 ASSERT(m_pendingResourcesForRemoval.contains(id));
260 return m_pendingResourcesForRemoval.take(id);
263 void SVGDocumentExtensions::markPendingResourcesForRemoval(const AtomicString& id)
265 if (id.isEmpty())
266 return;
268 ASSERT(!m_pendingResourcesForRemoval.contains(id));
270 OwnPtrWillBeMember<SVGPendingElements> existing = m_pendingResources.take(id);
271 if (existing && !existing->isEmpty())
272 m_pendingResourcesForRemoval.add(id, existing.release());
275 Element* SVGDocumentExtensions::removeElementFromPendingResourcesForRemoval(const AtomicString& id)
277 if (id.isEmpty())
278 return nullptr;
280 SVGPendingElements* resourceSet = m_pendingResourcesForRemoval.get(id);
281 if (!resourceSet || resourceSet->isEmpty())
282 return nullptr;
284 SVGPendingElements::iterator firstElement = resourceSet->begin();
285 Element* element = *firstElement;
287 resourceSet->remove(firstElement);
289 if (resourceSet->isEmpty())
290 removePendingResourceForRemoval(id);
292 return element;
295 void SVGDocumentExtensions::addSVGRootWithRelativeLengthDescendents(SVGSVGElement* svgRoot)
297 ASSERT(!m_inRelativeLengthSVGRootsInvalidation);
298 m_relativeLengthSVGRoots.add(svgRoot);
301 void SVGDocumentExtensions::removeSVGRootWithRelativeLengthDescendents(SVGSVGElement* svgRoot)
303 ASSERT(!m_inRelativeLengthSVGRootsInvalidation);
304 m_relativeLengthSVGRoots.remove(svgRoot);
307 bool SVGDocumentExtensions::isSVGRootWithRelativeLengthDescendents(SVGSVGElement* svgRoot) const
309 return m_relativeLengthSVGRoots.contains(svgRoot);
312 void SVGDocumentExtensions::invalidateSVGRootsWithRelativeLengthDescendents(SubtreeLayoutScope* scope)
314 ASSERT(!m_inRelativeLengthSVGRootsInvalidation);
315 #if ENABLE(ASSERT)
316 TemporaryChange<bool> inRelativeLengthSVGRootsChange(m_inRelativeLengthSVGRootsInvalidation, true);
317 #endif
319 for (SVGSVGElement* element : m_relativeLengthSVGRoots)
320 element->invalidateRelativeLengthClients(scope);
323 bool SVGDocumentExtensions::zoomAndPanEnabled() const
325 if (SVGSVGElement* svg = rootElement(*m_document))
326 return svg->zoomAndPanEnabled();
327 return false;
330 void SVGDocumentExtensions::startPan(const FloatPoint& start)
332 if (SVGSVGElement* svg = rootElement(*m_document))
333 m_translate = FloatPoint(start.x() - svg->currentTranslate().x(), start.y() - svg->currentTranslate().y());
336 void SVGDocumentExtensions::updatePan(const FloatPoint& pos) const
338 if (SVGSVGElement* svg = rootElement(*m_document))
339 svg->setCurrentTranslate(FloatPoint(pos.x() - m_translate.x(), pos.y() - m_translate.y()));
342 SVGSVGElement* SVGDocumentExtensions::rootElement(const Document& document)
344 Element* elem = document.documentElement();
345 return isSVGSVGElement(elem) ? toSVGSVGElement(elem) : 0;
348 SVGSVGElement* SVGDocumentExtensions::rootElement() const
350 ASSERT(m_document);
351 return rootElement(*m_document);
354 DEFINE_TRACE(SVGDocumentExtensions)
356 #if ENABLE(OILPAN)
357 visitor->trace(m_document);
358 visitor->trace(m_timeContainers);
359 visitor->trace(m_relativeLengthSVGRoots);
360 visitor->trace(m_pendingResources);
361 visitor->trace(m_pendingResourcesForRemoval);
362 #endif