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>
5  *
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.
10  *
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.
15  *
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.
20  */
21 
22 #include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
23 
24 #include "base/auto_reset.h"
25 #include "third_party/blink/renderer/core/dom/document.h"
26 #include "third_party/blink/renderer/core/svg/animation/smil_time_container.h"
27 #include "third_party/blink/renderer/core/svg/svg_svg_element.h"
28 
29 namespace blink {
30 
SVGDocumentExtensions(Document * document)31 SVGDocumentExtensions::SVGDocumentExtensions(Document* document)
32     : document_(document) {}
33 
34 SVGDocumentExtensions::~SVGDocumentExtensions() = default;
35 
AddTimeContainer(SVGSVGElement * element)36 void SVGDocumentExtensions::AddTimeContainer(SVGSVGElement* element) {
37   time_containers_.insert(element);
38 }
39 
RemoveTimeContainer(SVGSVGElement * element)40 void SVGDocumentExtensions::RemoveTimeContainer(SVGSVGElement* element) {
41   time_containers_.erase(element);
42 }
43 
AddWebAnimationsPendingSVGElement(SVGElement & element)44 void SVGDocumentExtensions::AddWebAnimationsPendingSVGElement(
45     SVGElement& element) {
46   web_animations_pending_svg_elements_.insert(&element);
47 }
48 
ServiceOnAnimationFrame(Document & document)49 void SVGDocumentExtensions::ServiceOnAnimationFrame(Document& document) {
50   if (!document.SvgExtensions())
51     return;
52   document.AccessSVGExtensions().ServiceAnimations();
53 }
54 
ServiceAnimations()55 void SVGDocumentExtensions::ServiceAnimations() {
56   HeapVector<Member<SVGSVGElement>> time_containers;
57   CopyToVector(time_containers_, time_containers);
58   for (const auto& container : time_containers)
59     container->TimeContainer()->ServiceAnimations();
60 
61   SVGElementSet web_animations_pending_svg_elements;
62   web_animations_pending_svg_elements.swap(
63       web_animations_pending_svg_elements_);
64 
65   // TODO(alancutter): Make SVG animation effect application a separate document
66   // lifecycle phase from servicing animations to be responsive to Javascript
67   // manipulation of exposed animation objects.
68   for (auto& svg_element : web_animations_pending_svg_elements)
69     svg_element->ApplyActiveWebAnimations();
70 
71   DCHECK(web_animations_pending_svg_elements_.IsEmpty());
72 }
73 
StartAnimations()74 void SVGDocumentExtensions::StartAnimations() {
75   // FIXME: Eventually every "Time Container" will need a way to latch on to
76   // some global timer starting animations for a document will do this
77   // "latching"
78   // FIXME: We hold a ref pointers to prevent a shadow tree from getting removed
79   // out from underneath us.  In the future we should refactor the use-element
80   // to avoid this. See https://webkit.org/b/53704
81   HeapVector<Member<SVGSVGElement>> time_containers;
82   CopyToVector(time_containers_, time_containers);
83   for (const auto& container : time_containers) {
84     SMILTimeContainer* time_container = container->TimeContainer();
85     if (!time_container->IsStarted())
86       time_container->Start();
87   }
88 }
89 
PauseAnimations()90 void SVGDocumentExtensions::PauseAnimations() {
91   for (SVGSVGElement* element : time_containers_)
92     element->pauseAnimations();
93 }
94 
DispatchSVGLoadEventToOutermostSVGElements()95 void SVGDocumentExtensions::DispatchSVGLoadEventToOutermostSVGElements() {
96   HeapVector<Member<SVGSVGElement>> time_containers;
97   CopyToVector(time_containers_, time_containers);
98   for (const auto& container : time_containers) {
99     SVGSVGElement* outer_svg = container.Get();
100     if (!outer_svg->IsOutermostSVGSVGElement())
101       continue;
102 
103     // Don't dispatch the load event document is not wellformed (for
104     // XML/standalone svg).
105     if (outer_svg->GetDocument().WellFormed() ||
106         !outer_svg->GetDocument().IsSVGDocument())
107       outer_svg->SendSVGLoadEventIfPossible();
108   }
109 }
110 
AddSVGRootWithRelativeLengthDescendents(SVGSVGElement * svg_root)111 void SVGDocumentExtensions::AddSVGRootWithRelativeLengthDescendents(
112     SVGSVGElement* svg_root) {
113 #if DCHECK_IS_ON()
114   DCHECK(!in_relative_length_svg_roots_invalidation_);
115 #endif
116   relative_length_svg_roots_.insert(svg_root);
117 }
118 
RemoveSVGRootWithRelativeLengthDescendents(SVGSVGElement * svg_root)119 void SVGDocumentExtensions::RemoveSVGRootWithRelativeLengthDescendents(
120     SVGSVGElement* svg_root) {
121 #if DCHECK_IS_ON()
122   DCHECK(!in_relative_length_svg_roots_invalidation_);
123 #endif
124   relative_length_svg_roots_.erase(svg_root);
125 }
126 
InvalidateSVGRootsWithRelativeLengthDescendents(SubtreeLayoutScope * scope)127 void SVGDocumentExtensions::InvalidateSVGRootsWithRelativeLengthDescendents(
128     SubtreeLayoutScope* scope) {
129 #if DCHECK_IS_ON()
130   DCHECK(!in_relative_length_svg_roots_invalidation_);
131   base::AutoReset<bool> in_relative_length_svg_roots_change(
132       &in_relative_length_svg_roots_invalidation_, true);
133 #endif
134 
135   for (SVGSVGElement* element : relative_length_svg_roots_)
136     element->InvalidateRelativeLengthClients(scope);
137 }
138 
ZoomAndPanEnabled() const139 bool SVGDocumentExtensions::ZoomAndPanEnabled() const {
140   SVGSVGElement* svg = rootElement(*document_);
141   return !svg || svg->ZoomAndPanEnabled();
142 }
143 
StartPan(const FloatPoint & start)144 void SVGDocumentExtensions::StartPan(const FloatPoint& start) {
145   if (SVGSVGElement* svg = rootElement(*document_))
146     translate_ = FloatPoint(start.X() - svg->CurrentTranslate().X(),
147                             start.Y() - svg->CurrentTranslate().Y());
148 }
149 
UpdatePan(const FloatPoint & pos) const150 void SVGDocumentExtensions::UpdatePan(const FloatPoint& pos) const {
151   if (SVGSVGElement* svg = rootElement(*document_))
152     svg->SetCurrentTranslate(
153         FloatPoint(pos.X() - translate_.X(), pos.Y() - translate_.Y()));
154 }
155 
rootElement(const Document & document)156 SVGSVGElement* SVGDocumentExtensions::rootElement(const Document& document) {
157   return DynamicTo<SVGSVGElement>(document.documentElement());
158 }
159 
rootElement() const160 SVGSVGElement* SVGDocumentExtensions::rootElement() const {
161   DCHECK(document_);
162   return rootElement(*document_);
163 }
164 
Trace(Visitor * visitor)165 void SVGDocumentExtensions::Trace(Visitor* visitor) {
166   visitor->Trace(document_);
167   visitor->Trace(time_containers_);
168   visitor->Trace(web_animations_pending_svg_elements_);
169   visitor->Trace(relative_length_svg_roots_);
170 }
171 
172 }  // namespace blink
173