Ejemplo n.º 1
0
        /// <summary>
        /// Deactivates and disables this root clock.
        /// </summary>
        internal void RootDisable()
        {
            Debug.Assert(IsTimeManager, "Invalid call to RootDeactivate for a non-root Clock");

            // Reset the state of the timing tree
            WeakRefEnumerator <Clock> enumerator = new WeakRefEnumerator <Clock>(_rootChildren);

            while (enumerator.MoveNext())
            {
                PrefixSubtreeEnumerator subtree = new PrefixSubtreeEnumerator(enumerator.Current, true);

                while (subtree.MoveNext())
                {
                    if (subtree.Current.InternalCurrentClockState != ClockState.Stopped)
                    {
                        subtree.Current.ResetCachedStateToStopped();

                        subtree.Current.RaiseCurrentStateInvalidated();
                        subtree.Current.RaiseCurrentTimeInvalidated();
                        subtree.Current.RaiseCurrentGlobalSpeedInvalidated();
                    }
                    else
                    {
                        subtree.SkipSubtree();
                    }
                }
            }
        }
Ejemplo n.º 2
0
        // Called on the root
        internal void ComputeTreeState()
        {
            Debug.Assert(IsTimeManager);

            // Revive all children
            WeakRefEnumerator <Clock> enumerator = new WeakRefEnumerator <Clock>(_rootChildren);

            while (enumerator.MoveNext())
            {
                PrefixSubtreeEnumerator prefixEnumerator = new PrefixSubtreeEnumerator(enumerator.Current, true);
                while (prefixEnumerator.MoveNext())
                {
                    Clock current = prefixEnumerator.Current;

                    // Only traverse the "ripe" subset of the Timing tree
                    if (CurrentGlobalTime >= current.InternalNextTickNeededTime)
                    {
                        current.ApplyDesiredFrameRateToGlobalTime();
                        current.ComputeLocalState();       // Compute the state of the node
                        current.ClipNextTickByParent();    // Perform NextTick clipping, stage 1

                        // Make a note to visit for stage 2, only for ClockGroups and Roots
                        current.NeedsPostfixTraversal = (current is ClockGroup) || (current.IsRoot);
                    }
                    else
                    {
                        prefixEnumerator.SkipSubtree();
                    }
                }
            }

            // To perform a postfix walk culled by NeedsPostfixTraversal flag, we use a local recursive method
            // Note that since we called for this operation, it is probably already needed by the root clock
            ComputeTreeStateRoot();
        }
Ejemplo n.º 3
0
        /// <summary>
        /// The only things that can change for this are the begin time of this
        /// timeline
        /// </summary>
        /// <param name="destination">
        /// The destination to seek to, relative to the clock's BeginTime. If this is past the
        /// active perioed execute the FillBehavior.
        /// </param>
        internal void InternalSeekAlignedToLastTick(TimeSpan destination)
        {
            Debug.Assert(IsRoot);

            // This is a no-op with a null TimeManager or when all durations have not yet been resolved
            if (_timeManager == null || HasDescendantsWithUnresolvedDuration)
            {
                return;
            }

            // Adjust _beginTime such that our current time equals the Seek position
            // that was requested
            _beginTime = CurrentGlobalTime - DivideTimeSpan(destination, _appliedSpeedRatio);
            if (CanGrow)
            {
                _currentIteration = null;  // This node is not visited by ResetSlipOnSubtree
                _currentIterationBeginTime = _beginTime;

                ResetSlipOnSubtree();
                UpdateSyncBeginTime();
            }

            IsInteractivelyStopped = false;  // We have unset disabled status
            PendingInteractiveStop = false;
            RootBeginPending = false;        // Cancel a pending begin
            ResetNodesWithSlip();            // Reset [....] tracking

            _timeManager.InternalCurrentIntervals = TimeIntervalCollection.Empty;

            PrefixSubtreeEnumerator subtree = new PrefixSubtreeEnumerator(this, true);

            while (subtree.MoveNext())
            {
                // We are processing a Seek immediately. We don't need a TIC yet
                // since we are not computing events, and we don't want to
                // process pending stuff either.
                subtree.Current.ComputeLocalStateHelper(false, true);       // Compute the state of the node
                if (HasDiscontinuousTimeMovementOccured)
                {
                    DiscontinuousTimeMovement();
                    HasDiscontinuousTimeMovementOccured = false;
                }

                subtree.Current.ClipNextTickByParent();    // Perform NextTick clipping, stage 1

                // Make a note to visit for stage 2, only for ClockGroups
                subtree.Current.NeedsPostfixTraversal = (subtree.Current is ClockGroup);
            }

            _parent.ComputeTreeStateRoot();  // Re-clip the next tick estimates by children

            // Fire the events indicating that we've invalidated this whole subtree
            subtree.Reset();
            while (subtree.MoveNext())
            {
                // CurrentTimeInvalidated should be fired first to give AnimationStorage a chance
                // to update the value.  We directly set the flags, then fire RaiseAccumulatedEvents
                // to avoid involving the TimeManager for this local subtree operation.
                subtree.Current.CurrentTimeInvalidatedEventRaised = true;
                subtree.Current.CurrentStateInvalidatedEventRaised = true;
                subtree.Current.CurrentGlobalSpeedInvalidatedEventRaised = true;
                subtree.Current.RaiseAccumulatedEvents();
            }
        }
Ejemplo n.º 4
0
        //
        // Private Methods
        //

        #region Private Methods

        //
        // Local State Computation Helpers
        //

        #region Local State Computation Helpers

        //
        // Seek, Begin and Pause are internally implemented by adjusting the begin time.
        // For example, when paused, each tick moves the begin time forward so that 
        // overall the clock hasn't moved. 
        //
        // Note that _beginTime is an offset from the parent's begin.  Since
        // these are root clocks, the parent is the TimeManager, and we 
        // must add in the CurrentGlobalTime
        private void AdjustBeginTime()
        {
            Debug.Assert(IsRoot);  // root clocks only; non-roots have constant begin time
            Debug.Assert(_rootData != null);

            // Process the effects of Seek, Begin, and Pause; delay request if not all durations are resolved in this subtree.
            if (_rootData.PendingSeekDestination.HasValue && !HasDescendantsWithUnresolvedDuration)
            {
                Debug.Assert(!RootBeginPending);  // we can have either a begin or a seek, not both

                // Adjust the begin time such that our current time equals PendingSeekDestination
                _beginTime = CurrentGlobalTime - DivideTimeSpan(_rootData.PendingSeekDestination.Value, _appliedSpeedRatio);
                if (CanGrow)  // One of our descendants has set this flag on us
                {
                    _currentIterationBeginTime = _beginTime;  // We relied on a combination of _currentIterationBeginTime and _currentIteration for our state
                    _currentIteration = null;  // Therefore, we should reset both to reset our position
                    ResetSlipOnSubtree();
                }
                UpdateSyncBeginTime();

                _rootData.PendingSeekDestination = null;

                // We have seeked, so raise all events signifying that no assumptions can be made about our state
                PrefixSubtreeEnumerator subtree = new PrefixSubtreeEnumerator(this, true);
                while (subtree.MoveNext())
                {
                    subtree.Current.RaiseCurrentStateInvalidated();
                    subtree.Current.RaiseCurrentTimeInvalidated();
                    subtree.Current.RaiseCurrentGlobalSpeedInvalidated();
                }
            }
            else if (RootBeginPending)
            {
                // RootBeginPending is set when a root is parented to a tree (in AddToRoot()).
                // It allows us to interpret Timeline.BeginTime as an offset from the current
                // time and thus schedule a begin in the future.

                _beginTime = CurrentGlobalTime + _timeline.BeginTime;
                if (CanGrow)  // One of our descendants has set this flag on us
                {
                    _currentIterationBeginTime = _beginTime;  // We should be just starting our first iteration now
                }
                UpdateSyncBeginTime();

                RootBeginPending = false;
            }
            else if ((IsInteractivelyPaused || _rootData.InteractiveSpeedRatio == 0) &&
                     (_syncData == null || !_syncData.IsInSyncPeriod))
            // We were paused at the last tick, so move _beginTime by the delta from last tick to this one
            // Only perform this iff we are *continuously* moving, e.g. if we haven't seeked between ticks.
            // [....] NOTE: If we are syncing, then the [....] code should be the one to make this adjustment
            // by using the Media's current time (which should already be paused).
            {
                if (_beginTime.HasValue)
                {
                    // Adjust for the speed of this timelineClock
                    _beginTime += _timeManager.LastTickDelta;
                    UpdateSyncBeginTime();

                    if (_currentIterationBeginTime.HasValue)  // One of our descendants has set this flag on us
                    {
                        _currentIterationBeginTime += _timeManager.LastTickDelta;
                    }
                }
            }

            // Adjust for changes to the speed ratio
            if (_rootData.PendingSpeedRatio.HasValue)
            {
                double pendingSpeedRatio = _rootData.PendingSpeedRatio.Value * _timeline.SpeedRatio;

                // If the calculated speed ratio is 0, we reset it to 1. I believe this is
                // because we don't want to support pausing by setting speed ratio. Instead
                // they should call pause.
                if (pendingSpeedRatio == 0)
                {
                    pendingSpeedRatio = 1;
                }

                Debug.Assert(_beginTime.HasValue);                

                // Below code uses the above assumption that beginTime has a value
                TimeSpan previewParentTime = CurrentGlobalTime;
                
                if (_currentIterationBeginTime.HasValue)
                {
                    // Adjusting SpeedRatio is not a discontiuous event, we don't want to reset slip after doing this
                    _currentIterationBeginTime = previewParentTime - MultiplyTimeSpan(previewParentTime - _currentIterationBeginTime.Value,
                                                                                      _appliedSpeedRatio / pendingSpeedRatio);
                }
                else
                {
                    _beginTime = previewParentTime - MultiplyTimeSpan(previewParentTime - _beginTime.Value,
                                                                      _appliedSpeedRatio / pendingSpeedRatio);
                }

                RaiseCurrentGlobalSpeedInvalidated();

                // _appliedSpeedRatio represents the speed ratio we're actually using
                // for this Clock.
                _appliedSpeedRatio = pendingSpeedRatio;

                // _rootData.InteractiveSpeedRatio represents the actual user set interactive
                // speed ratio value even though we may override it if it's 0.
                _rootData.InteractiveSpeedRatio = _rootData.PendingSpeedRatio.Value;  

                // Clear out the new pending speed ratio since we've finished applying it.
                _rootData.PendingSpeedRatio = null;

                UpdateSyncBeginTime();
            }

            return;
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Deactivates and disables this root clock.
        /// </summary>
        internal void RootDisable()
        {
            Debug.Assert(IsTimeManager, "Invalid call to RootDeactivate for a non-root Clock");

            // Reset the state of the timing tree
            WeakRefEnumerator<Clock> enumerator = new WeakRefEnumerator<Clock>(_rootChildren);

            while (enumerator.MoveNext())
            {
                PrefixSubtreeEnumerator subtree = new PrefixSubtreeEnumerator(enumerator.Current, true);

                while (subtree.MoveNext())
                {
                    if (subtree.Current.InternalCurrentClockState != ClockState.Stopped)
                    {
                        subtree.Current.ResetCachedStateToStopped();

                        subtree.Current.RaiseCurrentStateInvalidated();
                        subtree.Current.RaiseCurrentTimeInvalidated();
                        subtree.Current.RaiseCurrentGlobalSpeedInvalidated();
                    }
                    else
                    {
                        subtree.SkipSubtree();
                    }
                }
            }
        }
Ejemplo n.º 6
0
        // Called on the root
        internal void ComputeTreeState()
        {
            Debug.Assert(IsTimeManager);
            
            // Revive all children
            WeakRefEnumerator<Clock> enumerator = new WeakRefEnumerator<Clock>(_rootChildren);

            while (enumerator.MoveNext())
            {
                PrefixSubtreeEnumerator prefixEnumerator = new PrefixSubtreeEnumerator(enumerator.Current, true);
                while (prefixEnumerator.MoveNext())
                {
                    Clock current = prefixEnumerator.Current;

                    // Only traverse the "ripe" subset of the Timing tree
                    if (CurrentGlobalTime >= current.InternalNextTickNeededTime)
                    {
                        current.ApplyDesiredFrameRateToGlobalTime();
                        current.ComputeLocalState();       // Compute the state of the node
                        current.ClipNextTickByParent();    // Perform NextTick clipping, stage 1

                        // Make a note to visit for stage 2, only for ClockGroups and Roots
                        current.NeedsPostfixTraversal = (current is ClockGroup) || (current.IsRoot);
                    }
                    else
                    {
                        prefixEnumerator.SkipSubtree();
                    }
                }
            }

            // To perform a postfix walk culled by NeedsPostfixTraversal flag, we use a local recursive method
            // Note that since we called for this operation, it is probably already needed by the root clock
            ComputeTreeStateRoot();
        }