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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- OleDbCommandBuilder.cs
- DesignerView.Commands.cs
- EventItfInfo.cs
- SecurityTokenTypes.cs
- DataBoundControl.cs
- CollectionCodeDomSerializer.cs
- StructuredType.cs
- Stackframe.cs
- UnhandledExceptionEventArgs.cs
- Timeline.cs
- X500Name.cs
- TypefaceMap.cs
- PageCodeDomTreeGenerator.cs
- HandlerBase.cs
- OleDbConnection.cs
- HttpWriter.cs
- EntityTypeEmitter.cs
- IntSecurity.cs
- BuildProviderAppliesToAttribute.cs
- ShutDownListener.cs
- UnsafeNativeMethods.cs
- StringBuilder.cs
- HtmlFormParameterReader.cs
- newinstructionaction.cs
- CustomWebEventKey.cs
- MultiByteCodec.cs
- ZipIOCentralDirectoryFileHeader.cs
- _HeaderInfoTable.cs
- DataGrid.cs
- MulticastDelegate.cs
- CroppedBitmap.cs
- TransactionScope.cs
- MetadataItemSerializer.cs
- RawUIStateInputReport.cs
- HtmlControlPersistable.cs
- ReadOnlyMetadataCollection.cs
- SelectionItemPattern.cs
- PolyQuadraticBezierSegmentFigureLogic.cs
- InputLanguageProfileNotifySink.cs
- TreeViewEvent.cs
- DbgCompiler.cs
- TableCellAutomationPeer.cs
- NameValueCollection.cs
- SelfSignedCertificate.cs
- TracedNativeMethods.cs
- EntityStoreSchemaFilterEntry.cs
- ToolStripOverflowButton.cs
- SimpleRecyclingCache.cs
- DataGridViewCellLinkedList.cs
- ToolboxItemImageConverter.cs
- WebPartRestoreVerb.cs
- QilPatternVisitor.cs
- WebPartDisplayModeCollection.cs
- DataColumn.cs
- Effect.cs
- HashRepartitionEnumerator.cs
- ClientBuildManagerCallback.cs
- DbConnectionStringCommon.cs
- CommonServiceBehaviorElement.cs
- SchemaAttDef.cs
- MetafileHeader.cs
- TextContainerChangedEventArgs.cs
- TypeDelegator.cs
- XmlTypeAttribute.cs
- IPipelineRuntime.cs
- RuntimeWrappedException.cs
- GridViewCancelEditEventArgs.cs
- SizeAnimationClockResource.cs
- WCFServiceClientProxyGenerator.cs
- XmlProcessingInstruction.cs
- SizeFConverter.cs
- ObjectDataSourceStatusEventArgs.cs
- StructuredTypeEmitter.cs
- NetDataContractSerializer.cs
- QilChoice.cs
- TableLayoutPanelDesigner.cs
- NetworkStream.cs
- EntityDataSource.cs
- ASCIIEncoding.cs
- EventManager.cs
- Vector3D.cs
- SwitchElementsCollection.cs
- ResXResourceReader.cs
- DbMetaDataFactory.cs
- Emitter.cs
- SamlSecurityToken.cs
- XmlIncludeAttribute.cs
- PartialList.cs
- WebConfigurationHostFileChange.cs
- ClientBuildManagerCallback.cs
- BitmapSizeOptions.cs
- InputLanguage.cs
- GenericWebPart.cs
- LineBreakRecord.cs
- ProgressBarRenderer.cs
- ArraySegment.cs
- DesignerListAdapter.cs
- AnnotationAuthorChangedEventArgs.cs
- WindowVisualStateTracker.cs
- CodeGenerator.cs