1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla SMIL module.
16 : *
17 : * The Initial Developer of the Original Code is Brian Birtles.
18 : * Portions created by the Initial Developer are Copyright (C) 2005
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Brian Birtles <birtles@gmail.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsSMILInstanceTime.h"
39 : #include "nsSMILInterval.h"
40 : #include "nsSMILTimeValueSpec.h"
41 : #include "mozilla/AutoRestore.h"
42 :
43 : //----------------------------------------------------------------------
44 : // Implementation
45 :
46 0 : nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
47 : nsSMILInstanceTimeSource aSource,
48 : nsSMILTimeValueSpec* aCreator,
49 : nsSMILInterval* aBaseInterval)
50 : : mTime(aTime),
51 : mFlags(0),
52 : mVisited(false),
53 : mFixedEndpointRefCnt(0),
54 : mSerial(0),
55 : mCreator(aCreator),
56 0 : mBaseInterval(nsnull) // This will get set to aBaseInterval in a call to
57 : // SetBaseInterval() at end of constructor
58 : {
59 0 : switch (aSource) {
60 : case SOURCE_NONE:
61 : // No special flags
62 0 : break;
63 :
64 : case SOURCE_DOM:
65 0 : mFlags = kDynamic | kFromDOM;
66 0 : break;
67 :
68 : case SOURCE_SYNCBASE:
69 0 : mFlags = kMayUpdate;
70 0 : break;
71 :
72 : case SOURCE_EVENT:
73 0 : mFlags = kDynamic;
74 0 : break;
75 : }
76 :
77 0 : SetBaseInterval(aBaseInterval);
78 0 : }
79 :
80 0 : nsSMILInstanceTime::~nsSMILInstanceTime()
81 : {
82 0 : NS_ABORT_IF_FALSE(!mBaseInterval,
83 : "Destroying instance time without first calling Unlink()");
84 0 : NS_ABORT_IF_FALSE(mFixedEndpointRefCnt == 0,
85 : "Destroying instance time that is still used as the fixed endpoint of an "
86 : "interval");
87 0 : }
88 :
89 : void
90 0 : nsSMILInstanceTime::Unlink()
91 : {
92 0 : nsRefPtr<nsSMILInstanceTime> deathGrip(this);
93 0 : if (mBaseInterval) {
94 0 : mBaseInterval->RemoveDependentTime(*this);
95 0 : mBaseInterval = nsnull;
96 : }
97 0 : mCreator = nsnull;
98 0 : }
99 :
100 : void
101 0 : nsSMILInstanceTime::HandleChangedInterval(
102 : const nsSMILTimeContainer* aSrcContainer,
103 : bool aBeginObjectChanged,
104 : bool aEndObjectChanged)
105 : {
106 : // It's possible a sequence of notifications might cause our base interval to
107 : // be updated and then deleted. Furthermore, the delete might happen whilst
108 : // we're still in the queue to be notified of the change. In any case, if we
109 : // don't have a base interval, just ignore the change.
110 0 : if (!mBaseInterval)
111 0 : return;
112 :
113 0 : NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not.");
114 :
115 0 : if (mVisited) {
116 : // Break the cycle here
117 0 : Unlink();
118 0 : return;
119 : }
120 :
121 0 : bool objectChanged = mCreator->DependsOnBegin() ? aBeginObjectChanged :
122 0 : aEndObjectChanged;
123 :
124 0 : mozilla::AutoRestore<bool> setVisited(mVisited);
125 0 : mVisited = true;
126 :
127 0 : nsRefPtr<nsSMILInstanceTime> deathGrip(this);
128 0 : mCreator->HandleChangedInstanceTime(*GetBaseTime(), aSrcContainer, *this,
129 0 : objectChanged);
130 : }
131 :
132 : void
133 0 : nsSMILInstanceTime::HandleDeletedInterval()
134 : {
135 0 : NS_ABORT_IF_FALSE(mBaseInterval,
136 : "Got call to HandleDeletedInterval on an independent instance time");
137 0 : NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not");
138 :
139 0 : mBaseInterval = nsnull;
140 0 : mFlags &= ~kMayUpdate; // Can't update without a base interval
141 :
142 0 : nsRefPtr<nsSMILInstanceTime> deathGrip(this);
143 0 : mCreator->HandleDeletedInstanceTime(*this);
144 0 : mCreator = nsnull;
145 0 : }
146 :
147 : void
148 0 : nsSMILInstanceTime::HandleFilteredInterval()
149 : {
150 0 : NS_ABORT_IF_FALSE(mBaseInterval,
151 : "Got call to HandleFilteredInterval on an independent instance time");
152 :
153 0 : mBaseInterval = nsnull;
154 0 : mFlags &= ~kMayUpdate; // Can't update without a base interval
155 0 : mCreator = nsnull;
156 0 : }
157 :
158 : bool
159 0 : nsSMILInstanceTime::ShouldPreserve() const
160 : {
161 0 : return mFixedEndpointRefCnt > 0 || (mFlags & kWasDynamicEndpoint);
162 : }
163 :
164 : void
165 0 : nsSMILInstanceTime::UnmarkShouldPreserve()
166 : {
167 0 : mFlags &= ~kWasDynamicEndpoint;
168 0 : }
169 :
170 : void
171 0 : nsSMILInstanceTime::AddRefFixedEndpoint()
172 : {
173 0 : NS_ABORT_IF_FALSE(mFixedEndpointRefCnt < PR_UINT16_MAX,
174 : "Fixed endpoint reference count upper limit reached");
175 0 : ++mFixedEndpointRefCnt;
176 0 : mFlags &= ~kMayUpdate; // Once fixed, always fixed
177 0 : }
178 :
179 : void
180 0 : nsSMILInstanceTime::ReleaseFixedEndpoint()
181 : {
182 0 : NS_ABORT_IF_FALSE(mFixedEndpointRefCnt > 0, "Duplicate release");
183 0 : --mFixedEndpointRefCnt;
184 0 : if (mFixedEndpointRefCnt == 0 && IsDynamic()) {
185 0 : mFlags |= kWasDynamicEndpoint;
186 : }
187 0 : }
188 :
189 : bool
190 0 : nsSMILInstanceTime::IsDependentOn(const nsSMILInstanceTime& aOther) const
191 : {
192 0 : if (mVisited)
193 0 : return false;
194 :
195 0 : const nsSMILInstanceTime* myBaseTime = GetBaseTime();
196 0 : if (!myBaseTime)
197 0 : return false;
198 :
199 0 : if (myBaseTime == &aOther)
200 0 : return true;
201 :
202 : // mVisited is mutable
203 0 : mozilla::AutoRestore<bool> setVisited(const_cast<nsSMILInstanceTime*>(this)->mVisited);
204 0 : const_cast<nsSMILInstanceTime*>(this)->mVisited = true;
205 0 : return myBaseTime->IsDependentOn(aOther);
206 : }
207 :
208 : const nsSMILInstanceTime*
209 0 : nsSMILInstanceTime::GetBaseTime() const
210 : {
211 0 : if (!mBaseInterval) {
212 0 : return nsnull;
213 : }
214 :
215 0 : NS_ABORT_IF_FALSE(mCreator, "Base interval is set but there is no creator.");
216 0 : if (!mCreator) {
217 0 : return nsnull;
218 : }
219 :
220 0 : return mCreator->DependsOnBegin() ? mBaseInterval->Begin() :
221 0 : mBaseInterval->End();
222 : }
223 :
224 : void
225 0 : nsSMILInstanceTime::SetBaseInterval(nsSMILInterval* aBaseInterval)
226 : {
227 0 : NS_ABORT_IF_FALSE(!mBaseInterval,
228 : "Attempting to reassociate an instance time with a different interval.");
229 :
230 0 : if (aBaseInterval) {
231 0 : NS_ABORT_IF_FALSE(mCreator,
232 : "Attempting to create a dependent instance time without reference "
233 : "to the creating nsSMILTimeValueSpec object.");
234 0 : if (!mCreator)
235 0 : return;
236 :
237 0 : aBaseInterval->AddDependentTime(*this);
238 : }
239 :
240 0 : mBaseInterval = aBaseInterval;
241 : }
|