1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "TimelineManager.h"
9 #include "mozilla/ElementAnimationData.h"
10 #include "mozilla/dom/Element.h"
11 #include "mozilla/dom/ScrollTimeline.h"
12 #include "mozilla/dom/ViewTimeline.h"
13 #include "nsPresContext.h"
17 using dom::ScrollTimeline
;
18 using dom::ViewTimeline
;
20 template <typename TimelineType
>
21 void TryDestroyTimeline(Element
* aElement
, PseudoStyleType aPseudoType
) {
23 TimelineCollection
<TimelineType
>::Get(aElement
, aPseudoType
);
27 collection
->Destroy();
30 void TimelineManager::UpdateTimelines(Element
* aElement
,
31 PseudoStyleType aPseudoType
,
32 const ComputedStyle
* aComputedStyle
,
33 ProgressTimelineType aType
) {
35 aElement
->IsInComposedDoc(),
36 "No need to update timelines that are not attached to the document tree");
38 // If we are in a display:none subtree we will have no computed values.
39 // However, if we are on the root of display:none subtree, the computed values
40 // might not have been cleared yet. In either case, since CSS animations
41 // should not run in display:none subtrees, so we don't need timeline, either.
42 const bool shouldDestroyTimelines
=
44 aComputedStyle
->StyleDisplay()->mDisplay
== StyleDisplay::None
;
47 case ProgressTimelineType::Scroll
:
48 if (shouldDestroyTimelines
) {
49 TryDestroyTimeline
<ScrollTimeline
>(aElement
, aPseudoType
);
52 DoUpdateTimelines
<StyleScrollTimeline
, ScrollTimeline
>(
53 mPresContext
, aElement
, aPseudoType
,
54 aComputedStyle
->StyleUIReset()->mScrollTimelines
,
55 aComputedStyle
->StyleUIReset()->mScrollTimelineNameCount
);
58 case ProgressTimelineType::View
:
59 if (shouldDestroyTimelines
) {
60 TryDestroyTimeline
<ViewTimeline
>(aElement
, aPseudoType
);
63 DoUpdateTimelines
<StyleViewTimeline
, ViewTimeline
>(
64 mPresContext
, aElement
, aPseudoType
,
65 aComputedStyle
->StyleUIReset()->mViewTimelines
,
66 aComputedStyle
->StyleUIReset()->mViewTimelineNameCount
);
71 template <typename TimelineType
>
72 static already_AddRefed
<TimelineType
> PopExistingTimeline(
73 nsAtom
* aName
, TimelineCollection
<TimelineType
>* aCollection
) {
77 return aCollection
->Extract(aName
);
80 template <typename StyleType
, typename TimelineType
>
81 static auto BuildTimelines(nsPresContext
* aPresContext
, Element
* aElement
,
82 PseudoStyleType aPseudoType
,
83 const nsStyleAutoArray
<StyleType
>& aTimelines
,
84 size_t aTimelineCount
,
85 TimelineCollection
<TimelineType
>* aCollection
) {
86 typename TimelineCollection
<TimelineType
>::TimelineMap result
;
87 // If multiple timelines are attempting to modify the same property, then the
88 // timeline closest to the end of the list of names wins.
89 // The spec doesn't mention this specifically for scroll-timeline-name and
90 // view-timeline-name, so we follow the same rule with animation-name.
91 for (size_t idx
= 0; idx
< aTimelineCount
; ++idx
) {
92 const StyleType
& timeline
= aTimelines
[idx
];
93 if (timeline
.GetName() == nsGkAtoms::_empty
) {
97 RefPtr
<TimelineType
> dest
=
98 PopExistingTimeline(timeline
.GetName(), aCollection
);
100 dest
->ReplacePropertiesWith(aElement
, aPseudoType
, timeline
);
102 dest
= TimelineType::MakeNamed(aPresContext
->Document(), aElement
,
103 aPseudoType
, timeline
);
107 // Override the previous one if it is duplicated.
108 Unused
<< result
.InsertOrUpdate(timeline
.GetName(), dest
);
113 template <typename TimelineType
>
114 static TimelineCollection
<TimelineType
>& EnsureTimelineCollection(
115 Element
& aElement
, PseudoStyleType aPseudoType
);
118 ScrollTimelineCollection
& EnsureTimelineCollection
<ScrollTimeline
>(
119 Element
& aElement
, PseudoStyleType aPseudoType
) {
120 return aElement
.EnsureAnimationData().EnsureScrollTimelineCollection(
121 aElement
, aPseudoType
);
125 ViewTimelineCollection
& EnsureTimelineCollection
<ViewTimeline
>(
126 Element
& aElement
, PseudoStyleType aPseudoType
) {
127 return aElement
.EnsureAnimationData().EnsureViewTimelineCollection(
128 aElement
, aPseudoType
);
131 template <typename StyleType
, typename TimelineType
>
132 void TimelineManager::DoUpdateTimelines(
133 nsPresContext
* aPresContext
, Element
* aElement
, PseudoStyleType aPseudoType
,
134 const nsStyleAutoArray
<StyleType
>& aStyleTimelines
, size_t aTimelineCount
) {
136 TimelineCollection
<TimelineType
>::Get(aElement
, aPseudoType
);
137 if (!collection
&& aTimelineCount
== 1 &&
138 aStyleTimelines
[0].GetName() == nsGkAtoms::_empty
) {
142 // We create a new timeline list based on its computed style and the existing
144 auto newTimelines
= BuildTimelines
<StyleType
, TimelineType
>(
145 aPresContext
, aElement
, aPseudoType
, aStyleTimelines
, aTimelineCount
,
148 if (newTimelines
.IsEmpty()) {
150 collection
->Destroy();
157 &EnsureTimelineCollection
<TimelineType
>(*aElement
, aPseudoType
);
158 if (!collection
->isInList()) {
159 AddTimelineCollection(collection
);
163 // Replace unused timeline with new ones.
164 collection
->Swap(newTimelines
);
166 // FIXME: Bug 1774060. We may have to restyle the animations which use the
167 // dropped timelines. Or rely on restyling the subtree and the following
168 // siblings when mutating {scroll|view}-timeline-name.
171 } // namespace mozilla