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