ClockGroup.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Media / Animation / ClockGroup.cs / 1 / ClockGroup.cs

                            //---------------------------------------------------------------------------- 
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// 
//--------------------------------------------------------------------------- 

using System.Collections.Generic; 
using System.Diagnostics; 
using SR = MS.Internal.PresentationCore.SR;
using SRID = MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Media.Animation
{
    ///  
    /// The Clock instance type that will be created based on TimelineGroup
    /// objects. 
    ///  
    public class ClockGroup : Clock
    { 
        /// 
        /// Creates a new empty ClockGroup to be used in a Clock tree.
        /// 
        /// The TimelineGroup used to define the new 
        /// ClockGroup.
        protected internal ClockGroup(TimelineGroup timelineGroup) 
            : base(timelineGroup) 
        {
        } 

        /// 
        /// Gets the TimelineGroup object that holds the description controlling the
        /// behavior of this clock. 
        /// 
        ///  
        /// The TimelineGroup object that holds the description controlling the 
        /// behavior of this clock.
        ///  
        public new TimelineGroup Timeline
        {
            get
            { 
                return (TimelineGroup)base.Timeline;
            } 
        } 

 
        /// 
        /// Gets a collection containing the children of this clock.
        /// 
        ///  
        /// A collection containing the children of this clock.
        ///  
        public ClockCollection Children 
        {
            get 
            {
//                 VerifyAccess();
                Debug.Assert(!IsTimeManager);
 
                return new ClockCollection(this);
            } 
        } 

        ///  
        /// Unchecked internal access to the child collection of this Clock.
        /// 
        internal List InternalChildren
        { 
            get
            { 
                Debug.Assert(!IsTimeManager); 

                return _children; 
            }
        }

        ///  
        /// Uncheck internal access to the root children
        ///  
        internal List InternalRootChildren 
        {
            get 
            {
                Debug.Assert(IsTimeManager);

                return _rootChildren; 
            }
        } 
 

        internal override void BuildClockSubTreeFromTimeline( 
            Timeline timeline,
            bool hasControllableRoot)
        {
            // This is not currently necessary 
            //base.BuildClockSubTreeFromTimeline(timeline);
 
            // Only TimelineGroup has children 
            TimelineGroup timelineGroup = timeline as TimelineGroup;
 
            // Only a TimelineGroup should have allocated a ClockGroup.
            Debug.Assert(timelineGroup != null);

            // Create a clock for each of the children of the timeline 
            TimelineCollection timelineChildren = timelineGroup.Children;
 
            if (timelineChildren != null && timelineChildren.Count > 0) 
            {
                Clock childClock; 

                // Create a collection for the children of the clock
                _children = new List();
 
                // Create clocks for the children
                for (int index = 0; index < timelineChildren.Count; index++) 
                { 
                    childClock = AllocateClock(timelineChildren[index], hasControllableRoot);
                    childClock._parent = this;  // We connect the child to the subtree before calling BuildClockSubtreeFromTimeline 
                    childClock.BuildClockSubTreeFromTimeline(timelineChildren[index], hasControllableRoot);
                    _children.Add(childClock);
                    childClock._childIndex = index;
                } 

                // If we have SlipBehavior, check if we have any childen with which to slip. 
                if (_timeline is ParallelTimeline && 
                    ((ParallelTimeline)_timeline).SlipBehavior == SlipBehavior.Slip)
                { 
                    // Verify that we only use SlipBehavior in supported scenarios
                    if (!IsRoot ||
                       (_timeline.RepeatBehavior.HasDuration) ||
                       (_timeline.AutoReverse == true) || 
                       (_timeline.AccelerationRatio > 0) ||
                       (_timeline.DecelerationRatio > 0)) 
                    { 
                        throw new NotSupportedException(SR.Get(SRID.Timing_SlipBehavior_SlipOnlyOnSimpleTimelines));
                    } 

                    for (int index = 0; index < _children.Count; index++)
                    {
                        Clock child = _children[index]; 
                        if (child.CanSlip)
                        { 
                            Duration duration = child.ResolvedDuration; 

                            // A [....] clock with duration of zero or no begin time has no effect, so do skip it 
                            if ((!duration.HasTimeSpan || duration.TimeSpan > TimeSpan.Zero)
                                && child._timeline.BeginTime.HasValue)
                            {
                                _syncData = new SyncData(child); 
                                child._syncData = null;  // The child will no longer self-[....]
                            } 
 
                            break;  // We only want the first child with CanSlip
                        } 
                    }
                }
            }
        } 

        ///  
        /// Gets the first child of this timeline. 
        /// 
        ///  
        /// The first child of this timeline if the collection is not empty;
        /// otherwise, null.
        /// 
        internal override Clock FirstChild 
        {
            get 
            { 
                // ROOT Debug.Assert(!IsTimeManager);
 
                Clock firstChild = null;

                List children = _children;
 
                if (children != null)
                { 
                    firstChild = children[0]; 
                }
 
                return firstChild;
            }
        }
 
        // This is only to be called on the TimeManager clock. Go through our
        // top level clocks and find the clock with the highest desired framerate. 
        // DFR has to be > 0, so starting the accumulator at 0 is fine. 
        internal int GetMaxDesiredFrameRate()
        { 
            Debug.Assert(IsTimeManager);

            int desiredFrameRate = 0;
 
            // Ask all top-level clock their desired framerate
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_rootChildren); 
 
            while (enumerator.MoveNext())
            { 
                Clock currentClock = enumerator.Current;

                if (currentClock != null && currentClock.CurrentState == ClockState.Active)
                { 
                    int? currentDesiredFrameRate = currentClock.DesiredFrameRate;
                    if (currentDesiredFrameRate.HasValue) 
                    { 
                        desiredFrameRate = Math.Max(desiredFrameRate, currentDesiredFrameRate.Value);
                    } 
                }
            }

            return desiredFrameRate; 
        }
 
 
        // Called on the root
        internal void ComputeTreeState() 
        {
            Debug.Assert(IsTimeManager);

            // Revive all children 
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_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(); 
        } 

 
        internal void ComputeTreeStateRoot()
        {
            Debug.Assert(IsTimeManager);
            TimeSpan? previousTickNeededTime = InternalNextTickNeededTime; 
            InternalNextTickNeededTime = null;  // Reset the root's next tick needed time
 
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_rootChildren); 

            while (enumerator.MoveNext()) 
            {
                Clock current = enumerator.Current;

                if (current.NeedsPostfixTraversal) 
                {
                    if (current is ClockGroup) 
                    { 
                        ((ClockGroup)current).ComputeTreeStatePostfix();
                    } 
                    current.ApplyDesiredFrameRateToNextTick();  // Apply the effects of DFR on each root as needed
                    current.NeedsPostfixTraversal = false;  // Reset the flag
                }
 
                if(!InternalNextTickNeededTime.HasValue ||
                    (enumerator.Current.InternalNextTickNeededTime.HasValue && 
                     enumerator.Current.InternalNextTickNeededTime < InternalNextTickNeededTime)) 
                {
                    InternalNextTickNeededTime = enumerator.Current.InternalNextTickNeededTime; 
                }
            }

            if (InternalNextTickNeededTime.HasValue && 
                (!previousTickNeededTime.HasValue || previousTickNeededTime > InternalNextTickNeededTime))
            { 
                _timeManager.NotifyNewEarliestFutureActivity(); 
            }
        } 


        // Recursive postfix walk, culled by NeedsPostfixTraversal flags (hence cannot use PostfixSubtreeEnumerator)
        private void ComputeTreeStatePostfix() 
        {
            if (_children != null) 
            { 
                for (int c = 0; c < _children.Count; c++)
                { 
                    if (_children[c].NeedsPostfixTraversal)  // Traverse deeper if this is part of the visited tree subset
                    {
                        ClockGroup group = _children[c] as ClockGroup;
                        Debug.Assert(group != null);  // We should only have this flag set for ClockGroups 

                        group.ComputeTreeStatePostfix(); 
                    } 
                }
 
                ClipNextTickByChildren();
            }
        }
 
        // Perform Stage 2 of clipping next tick time: clip by children
        // Derived class does the actual clipping 
        private void ClipNextTickByChildren() 
        {
            Debug.Assert(_children != null); 

            for (int c = 0; c < _children.Count; c++)
            {
                // Clip by child's NTNT if needed 
                if (!InternalNextTickNeededTime.HasValue ||
                    (_children[c].InternalNextTickNeededTime.HasValue && _children[c].InternalNextTickNeededTime < InternalNextTickNeededTime)) 
                { 
                    InternalNextTickNeededTime = _children[c].InternalNextTickNeededTime;
                } 
            }
        }

 
        /// 
        /// Return the current duration from a specific clock 
        ///  
        /// 
        /// A Duration quantity representing the current iteration's estimated duration. 
        /// 
        internal override Duration CurrentDuration
        {
            get 
            {
                Duration manualDuration = _timeline.Duration;  // Check if a duration is specified by the user 
                if (manualDuration != Duration.Automatic) 
                {
                    return manualDuration; 
                }

                Duration currentDuration = TimeSpan.Zero;
 
                // The container ends when all of its children have ended at least
                // one of their active periods. 
                if (_children != null) 
                {
                    bool hasChildWithUnresolvedDuration = false; 
                    bool bufferingSlipNode = (_syncData != null    // This variable makes sure that our slip node completes as needed
                                             && _syncData.IsInSyncPeriod
                                             && !_syncData.SyncClockHasReachedEffectiveDuration);
 
                    for (int childIndex = 0; childIndex < _children.Count; childIndex++)
                    { 
                        Clock current = _children[childIndex]; 
                        Duration childEndOfActivePeriod = current.EndOfActivePeriod;
 
                        if (childEndOfActivePeriod == Duration.Forever)
                        {
                            // If we have even one child with a duration of forever
                            // our resolved duration will also be forever. It doesn't 
                            // matter if other _children have unresolved durations.
                            return Duration.Forever; 
                        } 
                        else if (childEndOfActivePeriod == Duration.Automatic)
                        { 
                            hasChildWithUnresolvedDuration = true;
                        }
                        else
                        { 
                            // Make sure that until Media completes, it is not treated as expired
                            if (bufferingSlipNode && _syncData.SyncClock == this) 
                            { 
                                childEndOfActivePeriod += TimeSpan.FromMilliseconds(50);  // This compensation is roughly one frame of video
                                bufferingSlipNode = false; 
                            }

                            if (childEndOfActivePeriod > currentDuration)
                            { 
                                currentDuration = childEndOfActivePeriod;
                            } 
                        } 
                    }
 
                    // We've iterated through all our _children. We know that at this
                    // point none of them have a duration of Forever or we would have
                    // returned already. If any of them still have unresolved
                    // durations then our duration is also still unresolved and we 
                    // will return automatic. Otherwise, we'll fall out of the 'if'
                    // block and return the currentDuration as our final resolved 
                    // duration. 
                    if (hasChildWithUnresolvedDuration)
                    { 
                        return Duration.Automatic;
                    }
                }
 
                return currentDuration;
            } 
        } 

 
        /// 
        /// Marks this Clock as the root of a timing tree.
        /// 
        ///  
        /// The TimeManager that controls this timing tree.
        ///  
        internal void MakeRoot(TimeManager timeManager) 
        {
            Debug.Assert(!IsTimeManager, "Cannot associate a root with multiple timing trees"); 
            Debug.Assert(this._timeManager == null, "Cannot use a timeline already in the timing tree as a root");
            Debug.Assert(timeManager.TimeManagerClock == this, "Cannot associate more than one root per timing tree");
            Debug.Assert(this._parent == null && _children == null, "Cannot use a timeline connected to other timelines as a root");
 
            IsTimeManager = true;
            _rootChildren = new List(); 
            _timeManager = timeManager; 
            _depth = 0;
 
            //

            InternalCurrentIteration = 1;
            InternalCurrentProgress = 0; 
            InternalCurrentGlobalSpeed = 1;
            InternalCurrentClockState = ClockState.Active; 
        } 

 
        // Upon a discontinuous interactive operation (begin/seek/stop), this resets children with SyncData
        // (e.g. media) to track this change, specifically:
        //  1) Realign their begin times evenly with the parent, discounting past slippage that may have occured
        //  2) Reset their state, in case they leave their "[....]" period. 
        internal override void ResetNodesWithSlip()
        { 
            Debug.Assert(IsRoot); 
            if (_children != null)
            { 
                for (int c = 0; c < _children.Count; c++)
                {
                    Clock child = _children[c];
 
                    if (child._syncData != null)
                    { 
                        child._beginTime = child._timeline.BeginTime;  // Realign the clock 
                        child._syncData.IsInSyncPeriod = false;
                        child._syncData.UpdateClockBeginTime();  // Apply effects of realigning 
                    }
                }
            }
 
            base.ResetNodesWithSlip();
        } 
 

        ///  
        /// Activates this root clock.
        /// 
        internal void RootActivate()
        { 
            Debug.Assert(IsTimeManager, "Invalid call to RootActivate for a non-root Clock");
            Debug.Assert(_timeManager != null);  // RootActivate should be called by our own TimeManager 
 
            // Reset the state of the timing tree
            TimeIntervalCollection currentIntervals = TimeIntervalCollection.CreatePoint(_timeManager.InternalCurrentGlobalTime); 
            currentIntervals.AddNullPoint();
            _timeManager.InternalCurrentIntervals = currentIntervals;

            ComputeTreeState(); 
        }
 
        ///  
        /// Removes dead weak references from the child list of the root clock.
        ///  
        internal void RootCleanChildren()
        {
            Debug.Assert(IsTimeManager, "Invalid call to RootCleanChildren for a non-root Clock");
 
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_rootChildren);
 
            // Simply enumerating the children with the weak reference 
            // enumerator is sufficient to clean up the list. Therefore, the
            // body of the loop can remain empty 
            while (enumerator.MoveNext())
            {
            }
 
            // When the loop terminates naturally the enumerator will clean
            // up the list of any dead references. Therefore, by the time we 
            // get here we are done. 
        }
 
        /// 
        /// Returns true if any children are left, false if none are left
        /// 
        internal bool RootHasChildren 
        {
            get 
            { 
                Debug.Assert(IsTimeManager, "Invalid call to RootHasChildren for a non-root Clock");
 
                return (_rootChildren.Count > 0);
            }
        }
 
        /// 
        /// Deactivates and disables this root clock. 
        ///  
        internal void RootDisable()
        { 
            Debug.Assert(IsTimeManager, "Invalid call to RootDeactivate for a non-root Clock");

            // Reset the state of the timing tree
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_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(); 
                    }
                } 
            } 
        }
 
        /// 
        /// Check if our descendants have resolved their duration, and resets the HasDescendantsWithUnresolvedDuration
        /// flag from true to false once that happens.
        ///  
        /// Returns true when this node or one of its descendants have unresolved duration.
        internal override void UpdateDescendantsWithUnresolvedDuration() 
        { 
            // If the flag was already unset, or our own node doesn't know its duration yet, the flag will not change now.
            if (!HasDescendantsWithUnresolvedDuration ||  !HasResolvedDuration) 
            {
                return;
            }
 
            if (_children != null)
            { 
                for (int childIndex = 0; childIndex < _children.Count; childIndex++) 
                {
                    _children[childIndex].UpdateDescendantsWithUnresolvedDuration(); 
                    if (_children[childIndex].HasDescendantsWithUnresolvedDuration)
                    {
                        return;  // If any child has unresolved descendants, we cannot unset our flag yet
                    } 
                }
            } 
 
            // If we finished the loop, then every child subtree has fully resolved its duration during this method call.
            HasDescendantsWithUnresolvedDuration = false; 
            return;
        }

 
        internal override void ClearCurrentIntervalsToNull()
        { 
            _currentIntervals.Clear(); 
            _currentIntervals.AddNullPoint();
        } 

        internal override void AddNullPointToCurrentIntervals()
        {
            _currentIntervals.AddNullPoint(); 
        }
 
        internal override void ComputeCurrentIntervals(TimeIntervalCollection parentIntervalCollection, 
                                                       TimeSpan beginTime, TimeSpan? endTime,
                                                       Duration fillDuration, Duration period, 
                                                       double appliedSpeedRatio, double accelRatio, double decelRatio,
                                                       bool isAutoReversed)
        {
            _currentIntervals.Clear(); 
            parentIntervalCollection.ProjectOntoPeriodicFunction(ref _currentIntervals,
                                                                 beginTime, endTime, 
                                                                 fillDuration, period, appliedSpeedRatio, 
                                                                 accelRatio, decelRatio, isAutoReversed);
        } 


        internal override void ComputeCurrentFillInterval(TimeIntervalCollection parentIntervalCollection,
                                                          TimeSpan beginTime, TimeSpan endTime, Duration period, 
                                                          double appliedSpeedRatio, double accelRatio, double decelRatio,
                                                          bool isAutoReversed) 
        { 
            _currentIntervals.Clear();
            parentIntervalCollection.ProjectPostFillZone(ref _currentIntervals, 
                                                         beginTime, endTime,
                                                         period, appliedSpeedRatio,
                                                         accelRatio, decelRatio, isAutoReversed);
        } 

        internal TimeIntervalCollection CurrentIntervals 
        { 
            get
            { 
                return _currentIntervals;
            }
        }
 
        private List _children;
        private List _rootChildren; 
        private TimeIntervalCollection _currentIntervals; 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// 
//--------------------------------------------------------------------------- 

using System.Collections.Generic; 
using System.Diagnostics; 
using SR = MS.Internal.PresentationCore.SR;
using SRID = MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Media.Animation
{
    ///  
    /// The Clock instance type that will be created based on TimelineGroup
    /// objects. 
    ///  
    public class ClockGroup : Clock
    { 
        /// 
        /// Creates a new empty ClockGroup to be used in a Clock tree.
        /// 
        /// The TimelineGroup used to define the new 
        /// ClockGroup.
        protected internal ClockGroup(TimelineGroup timelineGroup) 
            : base(timelineGroup) 
        {
        } 

        /// 
        /// Gets the TimelineGroup object that holds the description controlling the
        /// behavior of this clock. 
        /// 
        ///  
        /// The TimelineGroup object that holds the description controlling the 
        /// behavior of this clock.
        ///  
        public new TimelineGroup Timeline
        {
            get
            { 
                return (TimelineGroup)base.Timeline;
            } 
        } 

 
        /// 
        /// Gets a collection containing the children of this clock.
        /// 
        ///  
        /// A collection containing the children of this clock.
        ///  
        public ClockCollection Children 
        {
            get 
            {
//                 VerifyAccess();
                Debug.Assert(!IsTimeManager);
 
                return new ClockCollection(this);
            } 
        } 

        ///  
        /// Unchecked internal access to the child collection of this Clock.
        /// 
        internal List InternalChildren
        { 
            get
            { 
                Debug.Assert(!IsTimeManager); 

                return _children; 
            }
        }

        ///  
        /// Uncheck internal access to the root children
        ///  
        internal List InternalRootChildren 
        {
            get 
            {
                Debug.Assert(IsTimeManager);

                return _rootChildren; 
            }
        } 
 

        internal override void BuildClockSubTreeFromTimeline( 
            Timeline timeline,
            bool hasControllableRoot)
        {
            // This is not currently necessary 
            //base.BuildClockSubTreeFromTimeline(timeline);
 
            // Only TimelineGroup has children 
            TimelineGroup timelineGroup = timeline as TimelineGroup;
 
            // Only a TimelineGroup should have allocated a ClockGroup.
            Debug.Assert(timelineGroup != null);

            // Create a clock for each of the children of the timeline 
            TimelineCollection timelineChildren = timelineGroup.Children;
 
            if (timelineChildren != null && timelineChildren.Count > 0) 
            {
                Clock childClock; 

                // Create a collection for the children of the clock
                _children = new List();
 
                // Create clocks for the children
                for (int index = 0; index < timelineChildren.Count; index++) 
                { 
                    childClock = AllocateClock(timelineChildren[index], hasControllableRoot);
                    childClock._parent = this;  // We connect the child to the subtree before calling BuildClockSubtreeFromTimeline 
                    childClock.BuildClockSubTreeFromTimeline(timelineChildren[index], hasControllableRoot);
                    _children.Add(childClock);
                    childClock._childIndex = index;
                } 

                // If we have SlipBehavior, check if we have any childen with which to slip. 
                if (_timeline is ParallelTimeline && 
                    ((ParallelTimeline)_timeline).SlipBehavior == SlipBehavior.Slip)
                { 
                    // Verify that we only use SlipBehavior in supported scenarios
                    if (!IsRoot ||
                       (_timeline.RepeatBehavior.HasDuration) ||
                       (_timeline.AutoReverse == true) || 
                       (_timeline.AccelerationRatio > 0) ||
                       (_timeline.DecelerationRatio > 0)) 
                    { 
                        throw new NotSupportedException(SR.Get(SRID.Timing_SlipBehavior_SlipOnlyOnSimpleTimelines));
                    } 

                    for (int index = 0; index < _children.Count; index++)
                    {
                        Clock child = _children[index]; 
                        if (child.CanSlip)
                        { 
                            Duration duration = child.ResolvedDuration; 

                            // A [....] clock with duration of zero or no begin time has no effect, so do skip it 
                            if ((!duration.HasTimeSpan || duration.TimeSpan > TimeSpan.Zero)
                                && child._timeline.BeginTime.HasValue)
                            {
                                _syncData = new SyncData(child); 
                                child._syncData = null;  // The child will no longer self-[....]
                            } 
 
                            break;  // We only want the first child with CanSlip
                        } 
                    }
                }
            }
        } 

        ///  
        /// Gets the first child of this timeline. 
        /// 
        ///  
        /// The first child of this timeline if the collection is not empty;
        /// otherwise, null.
        /// 
        internal override Clock FirstChild 
        {
            get 
            { 
                // ROOT Debug.Assert(!IsTimeManager);
 
                Clock firstChild = null;

                List children = _children;
 
                if (children != null)
                { 
                    firstChild = children[0]; 
                }
 
                return firstChild;
            }
        }
 
        // This is only to be called on the TimeManager clock. Go through our
        // top level clocks and find the clock with the highest desired framerate. 
        // DFR has to be > 0, so starting the accumulator at 0 is fine. 
        internal int GetMaxDesiredFrameRate()
        { 
            Debug.Assert(IsTimeManager);

            int desiredFrameRate = 0;
 
            // Ask all top-level clock their desired framerate
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_rootChildren); 
 
            while (enumerator.MoveNext())
            { 
                Clock currentClock = enumerator.Current;

                if (currentClock != null && currentClock.CurrentState == ClockState.Active)
                { 
                    int? currentDesiredFrameRate = currentClock.DesiredFrameRate;
                    if (currentDesiredFrameRate.HasValue) 
                    { 
                        desiredFrameRate = Math.Max(desiredFrameRate, currentDesiredFrameRate.Value);
                    } 
                }
            }

            return desiredFrameRate; 
        }
 
 
        // Called on the root
        internal void ComputeTreeState() 
        {
            Debug.Assert(IsTimeManager);

            // Revive all children 
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_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(); 
        } 

 
        internal void ComputeTreeStateRoot()
        {
            Debug.Assert(IsTimeManager);
            TimeSpan? previousTickNeededTime = InternalNextTickNeededTime; 
            InternalNextTickNeededTime = null;  // Reset the root's next tick needed time
 
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_rootChildren); 

            while (enumerator.MoveNext()) 
            {
                Clock current = enumerator.Current;

                if (current.NeedsPostfixTraversal) 
                {
                    if (current is ClockGroup) 
                    { 
                        ((ClockGroup)current).ComputeTreeStatePostfix();
                    } 
                    current.ApplyDesiredFrameRateToNextTick();  // Apply the effects of DFR on each root as needed
                    current.NeedsPostfixTraversal = false;  // Reset the flag
                }
 
                if(!InternalNextTickNeededTime.HasValue ||
                    (enumerator.Current.InternalNextTickNeededTime.HasValue && 
                     enumerator.Current.InternalNextTickNeededTime < InternalNextTickNeededTime)) 
                {
                    InternalNextTickNeededTime = enumerator.Current.InternalNextTickNeededTime; 
                }
            }

            if (InternalNextTickNeededTime.HasValue && 
                (!previousTickNeededTime.HasValue || previousTickNeededTime > InternalNextTickNeededTime))
            { 
                _timeManager.NotifyNewEarliestFutureActivity(); 
            }
        } 


        // Recursive postfix walk, culled by NeedsPostfixTraversal flags (hence cannot use PostfixSubtreeEnumerator)
        private void ComputeTreeStatePostfix() 
        {
            if (_children != null) 
            { 
                for (int c = 0; c < _children.Count; c++)
                { 
                    if (_children[c].NeedsPostfixTraversal)  // Traverse deeper if this is part of the visited tree subset
                    {
                        ClockGroup group = _children[c] as ClockGroup;
                        Debug.Assert(group != null);  // We should only have this flag set for ClockGroups 

                        group.ComputeTreeStatePostfix(); 
                    } 
                }
 
                ClipNextTickByChildren();
            }
        }
 
        // Perform Stage 2 of clipping next tick time: clip by children
        // Derived class does the actual clipping 
        private void ClipNextTickByChildren() 
        {
            Debug.Assert(_children != null); 

            for (int c = 0; c < _children.Count; c++)
            {
                // Clip by child's NTNT if needed 
                if (!InternalNextTickNeededTime.HasValue ||
                    (_children[c].InternalNextTickNeededTime.HasValue && _children[c].InternalNextTickNeededTime < InternalNextTickNeededTime)) 
                { 
                    InternalNextTickNeededTime = _children[c].InternalNextTickNeededTime;
                } 
            }
        }

 
        /// 
        /// Return the current duration from a specific clock 
        ///  
        /// 
        /// A Duration quantity representing the current iteration's estimated duration. 
        /// 
        internal override Duration CurrentDuration
        {
            get 
            {
                Duration manualDuration = _timeline.Duration;  // Check if a duration is specified by the user 
                if (manualDuration != Duration.Automatic) 
                {
                    return manualDuration; 
                }

                Duration currentDuration = TimeSpan.Zero;
 
                // The container ends when all of its children have ended at least
                // one of their active periods. 
                if (_children != null) 
                {
                    bool hasChildWithUnresolvedDuration = false; 
                    bool bufferingSlipNode = (_syncData != null    // This variable makes sure that our slip node completes as needed
                                             && _syncData.IsInSyncPeriod
                                             && !_syncData.SyncClockHasReachedEffectiveDuration);
 
                    for (int childIndex = 0; childIndex < _children.Count; childIndex++)
                    { 
                        Clock current = _children[childIndex]; 
                        Duration childEndOfActivePeriod = current.EndOfActivePeriod;
 
                        if (childEndOfActivePeriod == Duration.Forever)
                        {
                            // If we have even one child with a duration of forever
                            // our resolved duration will also be forever. It doesn't 
                            // matter if other _children have unresolved durations.
                            return Duration.Forever; 
                        } 
                        else if (childEndOfActivePeriod == Duration.Automatic)
                        { 
                            hasChildWithUnresolvedDuration = true;
                        }
                        else
                        { 
                            // Make sure that until Media completes, it is not treated as expired
                            if (bufferingSlipNode && _syncData.SyncClock == this) 
                            { 
                                childEndOfActivePeriod += TimeSpan.FromMilliseconds(50);  // This compensation is roughly one frame of video
                                bufferingSlipNode = false; 
                            }

                            if (childEndOfActivePeriod > currentDuration)
                            { 
                                currentDuration = childEndOfActivePeriod;
                            } 
                        } 
                    }
 
                    // We've iterated through all our _children. We know that at this
                    // point none of them have a duration of Forever or we would have
                    // returned already. If any of them still have unresolved
                    // durations then our duration is also still unresolved and we 
                    // will return automatic. Otherwise, we'll fall out of the 'if'
                    // block and return the currentDuration as our final resolved 
                    // duration. 
                    if (hasChildWithUnresolvedDuration)
                    { 
                        return Duration.Automatic;
                    }
                }
 
                return currentDuration;
            } 
        } 

 
        /// 
        /// Marks this Clock as the root of a timing tree.
        /// 
        ///  
        /// The TimeManager that controls this timing tree.
        ///  
        internal void MakeRoot(TimeManager timeManager) 
        {
            Debug.Assert(!IsTimeManager, "Cannot associate a root with multiple timing trees"); 
            Debug.Assert(this._timeManager == null, "Cannot use a timeline already in the timing tree as a root");
            Debug.Assert(timeManager.TimeManagerClock == this, "Cannot associate more than one root per timing tree");
            Debug.Assert(this._parent == null && _children == null, "Cannot use a timeline connected to other timelines as a root");
 
            IsTimeManager = true;
            _rootChildren = new List(); 
            _timeManager = timeManager; 
            _depth = 0;
 
            //

            InternalCurrentIteration = 1;
            InternalCurrentProgress = 0; 
            InternalCurrentGlobalSpeed = 1;
            InternalCurrentClockState = ClockState.Active; 
        } 

 
        // Upon a discontinuous interactive operation (begin/seek/stop), this resets children with SyncData
        // (e.g. media) to track this change, specifically:
        //  1) Realign their begin times evenly with the parent, discounting past slippage that may have occured
        //  2) Reset their state, in case they leave their "[....]" period. 
        internal override void ResetNodesWithSlip()
        { 
            Debug.Assert(IsRoot); 
            if (_children != null)
            { 
                for (int c = 0; c < _children.Count; c++)
                {
                    Clock child = _children[c];
 
                    if (child._syncData != null)
                    { 
                        child._beginTime = child._timeline.BeginTime;  // Realign the clock 
                        child._syncData.IsInSyncPeriod = false;
                        child._syncData.UpdateClockBeginTime();  // Apply effects of realigning 
                    }
                }
            }
 
            base.ResetNodesWithSlip();
        } 
 

        ///  
        /// Activates this root clock.
        /// 
        internal void RootActivate()
        { 
            Debug.Assert(IsTimeManager, "Invalid call to RootActivate for a non-root Clock");
            Debug.Assert(_timeManager != null);  // RootActivate should be called by our own TimeManager 
 
            // Reset the state of the timing tree
            TimeIntervalCollection currentIntervals = TimeIntervalCollection.CreatePoint(_timeManager.InternalCurrentGlobalTime); 
            currentIntervals.AddNullPoint();
            _timeManager.InternalCurrentIntervals = currentIntervals;

            ComputeTreeState(); 
        }
 
        ///  
        /// Removes dead weak references from the child list of the root clock.
        ///  
        internal void RootCleanChildren()
        {
            Debug.Assert(IsTimeManager, "Invalid call to RootCleanChildren for a non-root Clock");
 
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_rootChildren);
 
            // Simply enumerating the children with the weak reference 
            // enumerator is sufficient to clean up the list. Therefore, the
            // body of the loop can remain empty 
            while (enumerator.MoveNext())
            {
            }
 
            // When the loop terminates naturally the enumerator will clean
            // up the list of any dead references. Therefore, by the time we 
            // get here we are done. 
        }
 
        /// 
        /// Returns true if any children are left, false if none are left
        /// 
        internal bool RootHasChildren 
        {
            get 
            { 
                Debug.Assert(IsTimeManager, "Invalid call to RootHasChildren for a non-root Clock");
 
                return (_rootChildren.Count > 0);
            }
        }
 
        /// 
        /// Deactivates and disables this root clock. 
        ///  
        internal void RootDisable()
        { 
            Debug.Assert(IsTimeManager, "Invalid call to RootDeactivate for a non-root Clock");

            // Reset the state of the timing tree
            WeakRefEnumerator enumerator = new WeakRefEnumerator(_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(); 
                    }
                } 
            } 
        }
 
        /// 
        /// Check if our descendants have resolved their duration, and resets the HasDescendantsWithUnresolvedDuration
        /// flag from true to false once that happens.
        ///  
        /// Returns true when this node or one of its descendants have unresolved duration.
        internal override void UpdateDescendantsWithUnresolvedDuration() 
        { 
            // If the flag was already unset, or our own node doesn't know its duration yet, the flag will not change now.
            if (!HasDescendantsWithUnresolvedDuration ||  !HasResolvedDuration) 
            {
                return;
            }
 
            if (_children != null)
            { 
                for (int childIndex = 0; childIndex < _children.Count; childIndex++) 
                {
                    _children[childIndex].UpdateDescendantsWithUnresolvedDuration(); 
                    if (_children[childIndex].HasDescendantsWithUnresolvedDuration)
                    {
                        return;  // If any child has unresolved descendants, we cannot unset our flag yet
                    } 
                }
            } 
 
            // If we finished the loop, then every child subtree has fully resolved its duration during this method call.
            HasDescendantsWithUnresolvedDuration = false; 
            return;
        }

 
        internal override void ClearCurrentIntervalsToNull()
        { 
            _currentIntervals.Clear(); 
            _currentIntervals.AddNullPoint();
        } 

        internal override void AddNullPointToCurrentIntervals()
        {
            _currentIntervals.AddNullPoint(); 
        }
 
        internal override void ComputeCurrentIntervals(TimeIntervalCollection parentIntervalCollection, 
                                                       TimeSpan beginTime, TimeSpan? endTime,
                                                       Duration fillDuration, Duration period, 
                                                       double appliedSpeedRatio, double accelRatio, double decelRatio,
                                                       bool isAutoReversed)
        {
            _currentIntervals.Clear(); 
            parentIntervalCollection.ProjectOntoPeriodicFunction(ref _currentIntervals,
                                                                 beginTime, endTime, 
                                                                 fillDuration, period, appliedSpeedRatio, 
                                                                 accelRatio, decelRatio, isAutoReversed);
        } 


        internal override void ComputeCurrentFillInterval(TimeIntervalCollection parentIntervalCollection,
                                                          TimeSpan beginTime, TimeSpan endTime, Duration period, 
                                                          double appliedSpeedRatio, double accelRatio, double decelRatio,
                                                          bool isAutoReversed) 
        { 
            _currentIntervals.Clear();
            parentIntervalCollection.ProjectPostFillZone(ref _currentIntervals, 
                                                         beginTime, endTime,
                                                         period, appliedSpeedRatio,
                                                         accelRatio, decelRatio, isAutoReversed);
        } 

        internal TimeIntervalCollection CurrentIntervals 
        { 
            get
            { 
                return _currentIntervals;
            }
        }
 
        private List _children;
        private List _rootChildren; 
        private TimeIntervalCollection _currentIntervals; 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK