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 ListInternalChildren { get { Debug.Assert(!IsTimeManager); return _children; } } /// /// Uncheck internal access to the root children /// internal ListInternalRootChildren { 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; Listchildren = _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"); WeakRefEnumeratorenumerator = 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 WeakRefEnumeratorenumerator = 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 ListInternalChildren { get { Debug.Assert(!IsTimeManager); return _children; } } /// /// Uncheck internal access to the root children /// internal ListInternalRootChildren { 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; Listchildren = _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"); WeakRefEnumeratorenumerator = 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 WeakRefEnumeratorenumerator = 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RemotingConfiguration.cs
- KoreanCalendar.cs
- PropertyEmitter.cs
- ErrorRuntimeConfig.cs
- CompModSwitches.cs
- XPathSelfQuery.cs
- Debugger.cs
- CoTaskMemHandle.cs
- DependencyObject.cs
- RadioButton.cs
- OperationAbortedException.cs
- TimeSpanSecondsOrInfiniteConverter.cs
- FieldBuilder.cs
- SimpleLine.cs
- UInt16Storage.cs
- ToolStripPanelRow.cs
- ValidatorUtils.cs
- DbConnectionStringCommon.cs
- FileUpload.cs
- PenThreadWorker.cs
- CodeMemberField.cs
- HttpStreams.cs
- SqlParameterCollection.cs
- RepeatInfo.cs
- _SpnDictionary.cs
- SelectionItemPatternIdentifiers.cs
- EncodingNLS.cs
- Group.cs
- InputBinding.cs
- SerialStream.cs
- SortKey.cs
- SQLStringStorage.cs
- HttpRuntime.cs
- CurrencyManager.cs
- SafeNativeMethodsOther.cs
- TreeNodeCollection.cs
- FlagsAttribute.cs
- Control.cs
- CompilerGlobalScopeAttribute.cs
- WebBaseEventKeyComparer.cs
- DbgCompiler.cs
- StateMachineTimers.cs
- XmlCustomFormatter.cs
- CompModSwitches.cs
- BitmapPalette.cs
- XmlDeclaration.cs
- Roles.cs
- XmlSerializerSection.cs
- Tag.cs
- TemplateControlParser.cs
- FamilyTypeface.cs
- AssociationSetMetadata.cs
- XmlNotation.cs
- LocatorPartList.cs
- UserControlBuildProvider.cs
- Int32Collection.cs
- SchemaImporterExtensionsSection.cs
- ClientRoleProvider.cs
- ColorBlend.cs
- ServiceHost.cs
- ZipIOExtraFieldElement.cs
- BindingList.cs
- MaterialGroup.cs
- Symbol.cs
- CapabilitiesPattern.cs
- CaseExpr.cs
- InlinedAggregationOperator.cs
- EventSourceCreationData.cs
- DbXmlEnabledProviderManifest.cs
- ObjectList.cs
- SymmetricKey.cs
- MenuItem.cs
- DispatcherExceptionEventArgs.cs
- FrameworkEventSource.cs
- MsdtcClusterUtils.cs
- Serializer.cs
- DPCustomTypeDescriptor.cs
- DragCompletedEventArgs.cs
- CheckBoxField.cs
- BindingOperations.cs
- TcpClientChannel.cs
- XmlElementCollection.cs
- HostingEnvironment.cs
- GetMemberBinder.cs
- Lazy.cs
- FileNotFoundException.cs
- AncestorChangedEventArgs.cs
- ExpressionDumper.cs
- GZipDecoder.cs
- OneOfConst.cs
- SiteMapHierarchicalDataSourceView.cs
- ViewDesigner.cs
- DeferredSelectedIndexReference.cs
- TrustDriver.cs
- BounceEase.cs
- NamespaceDecl.cs
- Setter.cs
- Control.cs
- SettingsPropertyValue.cs
- Slider.cs