|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsSMILInstanceTime.h" |
|
7 #include "nsSMILInterval.h" |
|
8 #include "nsSMILTimeValueSpec.h" |
|
9 #include "mozilla/AutoRestore.h" |
|
10 |
|
11 //---------------------------------------------------------------------- |
|
12 // Implementation |
|
13 |
|
14 nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime, |
|
15 nsSMILInstanceTimeSource aSource, |
|
16 nsSMILTimeValueSpec* aCreator, |
|
17 nsSMILInterval* aBaseInterval) |
|
18 : mTime(aTime), |
|
19 mFlags(0), |
|
20 mVisited(false), |
|
21 mFixedEndpointRefCnt(0), |
|
22 mSerial(0), |
|
23 mCreator(aCreator), |
|
24 mBaseInterval(nullptr) // This will get set to aBaseInterval in a call to |
|
25 // SetBaseInterval() at end of constructor |
|
26 { |
|
27 switch (aSource) { |
|
28 case SOURCE_NONE: |
|
29 // No special flags |
|
30 break; |
|
31 |
|
32 case SOURCE_DOM: |
|
33 mFlags = kDynamic | kFromDOM; |
|
34 break; |
|
35 |
|
36 case SOURCE_SYNCBASE: |
|
37 mFlags = kMayUpdate; |
|
38 break; |
|
39 |
|
40 case SOURCE_EVENT: |
|
41 mFlags = kDynamic; |
|
42 break; |
|
43 } |
|
44 |
|
45 SetBaseInterval(aBaseInterval); |
|
46 } |
|
47 |
|
48 nsSMILInstanceTime::~nsSMILInstanceTime() |
|
49 { |
|
50 NS_ABORT_IF_FALSE(!mBaseInterval, |
|
51 "Destroying instance time without first calling Unlink()"); |
|
52 NS_ABORT_IF_FALSE(mFixedEndpointRefCnt == 0, |
|
53 "Destroying instance time that is still used as the fixed endpoint of an " |
|
54 "interval"); |
|
55 } |
|
56 |
|
57 void |
|
58 nsSMILInstanceTime::Unlink() |
|
59 { |
|
60 nsRefPtr<nsSMILInstanceTime> deathGrip(this); |
|
61 if (mBaseInterval) { |
|
62 mBaseInterval->RemoveDependentTime(*this); |
|
63 mBaseInterval = nullptr; |
|
64 } |
|
65 mCreator = nullptr; |
|
66 } |
|
67 |
|
68 void |
|
69 nsSMILInstanceTime::HandleChangedInterval( |
|
70 const nsSMILTimeContainer* aSrcContainer, |
|
71 bool aBeginObjectChanged, |
|
72 bool aEndObjectChanged) |
|
73 { |
|
74 // It's possible a sequence of notifications might cause our base interval to |
|
75 // be updated and then deleted. Furthermore, the delete might happen whilst |
|
76 // we're still in the queue to be notified of the change. In any case, if we |
|
77 // don't have a base interval, just ignore the change. |
|
78 if (!mBaseInterval) |
|
79 return; |
|
80 |
|
81 NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not."); |
|
82 |
|
83 if (mVisited) { |
|
84 // Break the cycle here |
|
85 Unlink(); |
|
86 return; |
|
87 } |
|
88 |
|
89 bool objectChanged = mCreator->DependsOnBegin() ? aBeginObjectChanged : |
|
90 aEndObjectChanged; |
|
91 |
|
92 mozilla::AutoRestore<bool> setVisited(mVisited); |
|
93 mVisited = true; |
|
94 |
|
95 nsRefPtr<nsSMILInstanceTime> deathGrip(this); |
|
96 mCreator->HandleChangedInstanceTime(*GetBaseTime(), aSrcContainer, *this, |
|
97 objectChanged); |
|
98 } |
|
99 |
|
100 void |
|
101 nsSMILInstanceTime::HandleDeletedInterval() |
|
102 { |
|
103 NS_ABORT_IF_FALSE(mBaseInterval, |
|
104 "Got call to HandleDeletedInterval on an independent instance time"); |
|
105 NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not"); |
|
106 |
|
107 mBaseInterval = nullptr; |
|
108 mFlags &= ~kMayUpdate; // Can't update without a base interval |
|
109 |
|
110 nsRefPtr<nsSMILInstanceTime> deathGrip(this); |
|
111 mCreator->HandleDeletedInstanceTime(*this); |
|
112 mCreator = nullptr; |
|
113 } |
|
114 |
|
115 void |
|
116 nsSMILInstanceTime::HandleFilteredInterval() |
|
117 { |
|
118 NS_ABORT_IF_FALSE(mBaseInterval, |
|
119 "Got call to HandleFilteredInterval on an independent instance time"); |
|
120 |
|
121 mBaseInterval = nullptr; |
|
122 mFlags &= ~kMayUpdate; // Can't update without a base interval |
|
123 mCreator = nullptr; |
|
124 } |
|
125 |
|
126 bool |
|
127 nsSMILInstanceTime::ShouldPreserve() const |
|
128 { |
|
129 return mFixedEndpointRefCnt > 0 || (mFlags & kWasDynamicEndpoint); |
|
130 } |
|
131 |
|
132 void |
|
133 nsSMILInstanceTime::UnmarkShouldPreserve() |
|
134 { |
|
135 mFlags &= ~kWasDynamicEndpoint; |
|
136 } |
|
137 |
|
138 void |
|
139 nsSMILInstanceTime::AddRefFixedEndpoint() |
|
140 { |
|
141 NS_ABORT_IF_FALSE(mFixedEndpointRefCnt < UINT16_MAX, |
|
142 "Fixed endpoint reference count upper limit reached"); |
|
143 ++mFixedEndpointRefCnt; |
|
144 mFlags &= ~kMayUpdate; // Once fixed, always fixed |
|
145 } |
|
146 |
|
147 void |
|
148 nsSMILInstanceTime::ReleaseFixedEndpoint() |
|
149 { |
|
150 NS_ABORT_IF_FALSE(mFixedEndpointRefCnt > 0, "Duplicate release"); |
|
151 --mFixedEndpointRefCnt; |
|
152 if (mFixedEndpointRefCnt == 0 && IsDynamic()) { |
|
153 mFlags |= kWasDynamicEndpoint; |
|
154 } |
|
155 } |
|
156 |
|
157 bool |
|
158 nsSMILInstanceTime::IsDependentOn(const nsSMILInstanceTime& aOther) const |
|
159 { |
|
160 if (mVisited) |
|
161 return false; |
|
162 |
|
163 const nsSMILInstanceTime* myBaseTime = GetBaseTime(); |
|
164 if (!myBaseTime) |
|
165 return false; |
|
166 |
|
167 if (myBaseTime == &aOther) |
|
168 return true; |
|
169 |
|
170 mozilla::AutoRestore<bool> setVisited(mVisited); |
|
171 mVisited = true; |
|
172 return myBaseTime->IsDependentOn(aOther); |
|
173 } |
|
174 |
|
175 const nsSMILInstanceTime* |
|
176 nsSMILInstanceTime::GetBaseTime() const |
|
177 { |
|
178 if (!mBaseInterval) { |
|
179 return nullptr; |
|
180 } |
|
181 |
|
182 NS_ABORT_IF_FALSE(mCreator, "Base interval is set but there is no creator."); |
|
183 if (!mCreator) { |
|
184 return nullptr; |
|
185 } |
|
186 |
|
187 return mCreator->DependsOnBegin() ? mBaseInterval->Begin() : |
|
188 mBaseInterval->End(); |
|
189 } |
|
190 |
|
191 void |
|
192 nsSMILInstanceTime::SetBaseInterval(nsSMILInterval* aBaseInterval) |
|
193 { |
|
194 NS_ABORT_IF_FALSE(!mBaseInterval, |
|
195 "Attempting to reassociate an instance time with a different interval."); |
|
196 |
|
197 if (aBaseInterval) { |
|
198 NS_ABORT_IF_FALSE(mCreator, |
|
199 "Attempting to create a dependent instance time without reference " |
|
200 "to the creating nsSMILTimeValueSpec object."); |
|
201 if (!mCreator) |
|
202 return; |
|
203 |
|
204 aBaseInterval->AddDependentTime(*this); |
|
205 } |
|
206 |
|
207 mBaseInterval = aBaseInterval; |
|
208 } |