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
- SqlFacetAttribute.cs
- CodeMemberEvent.cs
- DrawListViewSubItemEventArgs.cs
- JsonFormatGeneratorStatics.cs
- MapPathBasedVirtualPathProvider.cs
- TemplateNameScope.cs
- EventLogPermission.cs
- TraceShell.cs
- IMembershipProvider.cs
- WebEventTraceProvider.cs
- InkPresenterAutomationPeer.cs
- ISCIIEncoding.cs
- BookmarkTable.cs
- GlobalizationAssembly.cs
- CreateUserWizardStep.cs
- FormsIdentity.cs
- XPathParser.cs
- CodeEntryPointMethod.cs
- Utils.cs
- ContentPlaceHolder.cs
- _LoggingObject.cs
- InputBuffer.cs
- ObjectCacheHost.cs
- RequestChannel.cs
- EdmProperty.cs
- DeferrableContent.cs
- GridViewColumnCollection.cs
- PageCatalogPart.cs
- DependentTransaction.cs
- DriveNotFoundException.cs
- ScrollContentPresenter.cs
- MembershipUser.cs
- DataService.cs
- SkipQueryOptionExpression.cs
- FormsAuthenticationEventArgs.cs
- WorkflowInspectionServices.cs
- X509SecurityTokenProvider.cs
- VariantWrapper.cs
- ActivityTypeCodeDomSerializer.cs
- HtmlInputSubmit.cs
- LoadedOrUnloadedOperation.cs
- BufferModeSettings.cs
- GPPOINT.cs
- ModelItemDictionaryImpl.cs
- HtmlTextArea.cs
- ConfigurationStrings.cs
- UnSafeCharBuffer.cs
- DataSourceExpression.cs
- ArrayHelper.cs
- RuntimeConfigLKG.cs
- PageContentCollection.cs
- DocumentViewerAutomationPeer.cs
- CompositeScriptReferenceEventArgs.cs
- AttributeConverter.cs
- FontWeights.cs
- ListBoxDesigner.cs
- StrongNameMembershipCondition.cs
- DataException.cs
- SqlConnectionPoolProviderInfo.cs
- ImmutableObjectAttribute.cs
- linebase.cs
- TextSchema.cs
- ReaderWriterLock.cs
- GradientBrush.cs
- ImageSource.cs
- SymbolEqualComparer.cs
- TextParentUndoUnit.cs
- UTF8Encoding.cs
- xml.cs
- Composition.cs
- MachineKeySection.cs
- BmpBitmapDecoder.cs
- ContentElement.cs
- CommonRemoteMemoryBlock.cs
- SystemWebSectionGroup.cs
- UpdateExpressionVisitor.cs
- PrimitiveDataContract.cs
- _HelperAsyncResults.cs
- FragmentNavigationEventArgs.cs
- InitializeCorrelation.cs
- GridViewCancelEditEventArgs.cs
- ComplexPropertyEntry.cs
- RuntimeConfigurationRecord.cs
- FixedSOMGroup.cs
- ConnectAlgorithms.cs
- ThrowHelper.cs
- LayoutUtils.cs
- _DigestClient.cs
- SurrogateChar.cs
- CRYPTPROTECT_PROMPTSTRUCT.cs
- RegexParser.cs
- _AuthenticationState.cs
- LineInfo.cs
- XmlText.cs
- SeekableReadStream.cs
- CollectionViewSource.cs
- Setter.cs
- IBuiltInEvidence.cs
- TableRow.cs
- _LocalDataStore.cs