RealizationContext.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//      Accumulates state during a realization pass of the scene. 
//
//----------------------------------------------------------------------------- 

using System;
using System.Windows.Threading;
 
using System.Collections;
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Windows.Media;
using System.Windows.Media.Animation; 
using System.Windows.Media.Composition;
using System.Runtime.InteropServices;
using MS.Internal;
using System.Windows.Media.Media3D; 

 
namespace System.Windows.Media 
{
    ///  
    /// Implemented by resources that need realizations.
    /// 
    internal interface IRealizationContextClient
    { 
        void ExecuteRealizationsUpdate();
    } 
 
    internal struct RealizationBrushHelper
    { 
        internal RealizationBrushHelper(Pen stroke, Brush fill)
        {
            _stroke = null;
            if (stroke != null) 
            {
                _stroke = stroke.Brush; 
            } 
            _fill = fill;
        } 

        internal bool NeedsRealizationUpdates
        {
            get 
            {
                return (_stroke != null && _stroke.RequiresRealizationUpdates) 
                    || (_fill != null && _fill.RequiresRealizationUpdates); 
            }
        } 

        internal void UpdateRealizations(Rect strokeBounds, Rect fillBounds, RealizationContext ctx)
        {
            if (_stroke != null) 
            {
                _stroke.UpdateRealizations(strokeBounds, ctx); 
            } 
            if (_fill != null)
            { 
                _fill.UpdateRealizations(fillBounds, ctx);
            }
        }
 
        private Brush _fill;
        private Brush _stroke; 
 
    }
 
    /// 
    /// This class accumulates state during a realization pass of the scene.
    /// 
    ///  
    /// This class is to replace RenderContext during the realization pass.
    ///  
    internal sealed class RealizationContext 
    {
        //--------------------------------------------------------------------- 
        //
        //  Private Types
        //
        //--------------------------------------------------------------------- 

        #region Private Types 
 
        /// 
        /// Storage manager for the schedule finalization calls. 
        /// 
        private class RealizationUpdateSchedule
        {
            // ---------------------------------------------------------------- 
            // -- CONSTRUCTOR -------------------------------------------------
 
            ///  
            /// Creates a new schedule list.
            ///  
            internal RealizationUpdateSchedule()
            {
                _schedule = new List(INITIAL_SIZE);
            } 

 
            // --------------------------------------------------------------- 
            // -- METHODS ------------------------------------------------------
 
            /// 
            /// Adds an object to the realization update schedule.
            /// 
            /// The object to be scheduled. 
            internal void Schedule(IRealizationContextClient client)
            { 
                if (client != null) 
                {
                    _schedule.Add(client); 
                }
            }

 
            /// 
            /// Executes the schedule list. 
            ///  
            internal void Execute()
            { 
                try
                {
                    foreach (IRealizationContextClient scheduled in _schedule)
                    { 
                        // guaranteed to be not null, see the Schedule method
                        scheduled.ExecuteRealizationsUpdate(); 
                    } 
                }
                finally 
                {
                    _schedule.Clear();
                }
            } 

 
            ///  
            /// Instead of allocating and releasing memory continuously while scheduling
            /// and clearing the list, we call the optimize method after each frame 
            /// to readjust the internal list capacity.
            /// 
            /// 
            internal void Optimize() 
            {
                Debug.Assert(_schedule.Count == 0); // The list must be empty before this is called. 
                Debug.Assert(_highWaterMark <= _schedule.Capacity); 

                // After TRIM_COUNT calls to this method we check the past usage of the stack. 
                if (_observeCount == TRIM_COUNT)
                {
                    int newSize = Math.Max(_highWaterMark, INITIAL_SIZE);
                    if (newSize * SHRINK_FACTOR <= _schedule.Capacity) 
                    {
                        // If the water mark is less or equal to capacity divided by the shrink 
                        // factor, then we shrink the stack. Usually the shrink factor is greater 
                        // than the grow factor. This avoids an oscillation of shrinking and growing
                        // the list if the high water mark goes only slightly up and down. 

                        // Note that we don't need to copy the contents because the list is empty.
                        _schedule = new List(newSize);
                    } 

                    _highWaterMark = 0; 
                    _observeCount = 0; 
                }
                else 
                {
                    // Keep incrementing our observe count
                    _observeCount++;
                } 
            }
 
 
            // ----------------------------------------------------------------
            // -- PROPERTIES -------------------------------------------------- 

            /// 
            /// Checks if the schedule is empty.
            ///  
            internal bool IsEmpty
            { 
                get { return _schedule.Count == 0; } 
            }
 

            // ---------------------------------------------------------------
            // -- FIELDS ------------------------------------------------------
 
            // The storage for the scheduled finalization calls.
            private List _schedule; 
 
            // The following fields are used to lazily manage the memory
            // allocated by the stack. 
            private int _highWaterMark;
            private int _observeCount;

 
            // ---------------------------------------------------------------
            // -- CONSTANTS --------------------------------------------------- 
 
            // The initial size of the schedule storage.
#if _DEBUG 
            private const int INITIAL_SIZE = 40;
#else
            private const int INITIAL_SIZE = 4;
#endif 

            // The shrink factor for the schedule storage. 
            private const int SHRINK_FACTOR = 3; 

            // This constant is used to lazily manage the memory allocated 
            // by the list.
            private const int TRIM_COUNT = 10;
        }
 
        #endregion Private Types
 
 
        //---------------------------------------------------------------------
        // 
        //  Internal Constructors
        //
        //----------------------------------------------------------------------
 
        #region Internal Constructors
 
        ///  
        /// Creates a world transform matrix stack for reuse between frames
        /// and a list for finalization calls scheduling. 
        /// 
        internal RealizationContext()
        {
            _transformStack = new MatrixStack(); 
            _transform3DStack = new Matrix3DStack();
            _scheduleList = new RealizationUpdateSchedule(); 
            _drawingContextWalker = new RealizationDrawingContextWalker(this); 
            _visualsRequiringNextFrameRealizations = new ArrayList();
            _currentVisualRequiresNewRealizationNextFrame = false; 
        }

        #endregion Internal Constructors
 

        //--------------------------------------------------------------------- 
        // 
        //  Internal Methods
        // 
        //----------------------------------------------------------------------

        #region Internal Methods
 
        /// 
        /// BeginFrame must be called before a frame is rendered. 
        ///  
        internal void BeginFrame(
            bool incrementalWalk, bool walkForBitmapRenderTarget 
            )
        {
            Debug.Assert(_transformStack.IsEmpty, "Matrix stack must be empty.");
            Debug.Assert(_transform3DStack.IsEmpty, "3D transform stack must be empty."); 
            Debug.Assert(
                _scheduleList.IsEmpty, 
                "The schedule list must be empty."); 
            Debug.Assert(_visualsRequiringNextFrameRealizations.Count == 0);
            Debug.Assert(!_currentVisualRequiresNewRealizationNextFrame); 

            _currentTime = Environment.TickCount;
            _incrementalPass = incrementalWalk;
            _incrementalDisableCount = 0; 
            _walkForBitmapRenderTarget = walkForBitmapRenderTarget;
 
            // 
            // At the beginning of a frame assume that we won't need any more
            // frames in the future for additional realization work. Only if 
            // a resource makes a request for more cycles during the realization
            // pass will we ask the MediaContext for more. In the meantime, if
            // we previously hooked the Rendering event then unhook it now,
            // because if we experience an exception during the realization 
            // pass the MediaContext will let the realization context object go
            // to garbage collection. Keeping the event hooked would prevent it 
            // from being collected, and it would also prevent the event from 
            // being unhooked, which would cause the MedaiContext to continually
            // render frames forever from that point on. 
            //

            _needAdditionalFrames = false;
            if (_requestedAdditionalFrames) 
            {
                MediaContext.From(Dispatcher.CurrentDispatcher).Rendering -= _additionalFramesDelegate; 
                _requestedAdditionalFrames = false; 
            }
        } 


        /// 
        /// This method should be called after a frame has been rendered. 
        /// 
        ///  
        /// This method should be called after the realization context is not 
        /// needed anymore. The method expects that all stacks have been
        /// cleared by popping all items from the stack. 
        ///
        /// NOTE: If for whatever reason the render pass should fail, the
        /// realization context is thrown away since it might be in an
        /// inconsistent state. In such cases EndFrame must not be called! 
        /// (There are ways to implement this cleaner, but it requires more
        /// infra-structure for which there isn't really any need). 
        ///  
        internal void EndFrame()
        { 
            Debug.Assert(_transformStack.IsEmpty, "Matrix stack must be empty. The remark to the EndFrame method has more detail.");
            Debug.Assert(_transform3DStack.IsEmpty, "Matrix3D stack must be empty.");
            Debug.Assert(_scheduleList.IsEmpty, "The schedule list must be empty. The remark to the EndFrame method has more detail.");
 
            _transformStack.Optimize();
            _scheduleList.Optimize(); 
 
            Debug.Assert(_incrementalDisableCount == 0);
 
            //
            // If a resource requested additional cycles during the last
            // realization pass, use the MediaContext.Rendering event to schedule
            // additional frames. 
            //
 
            if (_needAdditionalFrames) 
            {
                if (_additionalFramesDelegate == null) 
                {
                    _additionalFramesDelegate = delegate(object sender, EventArgs e) { };
                }
                MediaContext.From(Dispatcher.CurrentDispatcher).Rendering += _additionalFramesDelegate; 
                _requestedAdditionalFrames = true;
            } 
 
            foreach (Visual v in _visualsRequiringNextFrameRealizations)
            { 
                v.PropagateChangedFlags();
            }
            _visualsRequiringNextFrameRealizations.Clear();
        } 

 
        ///  
        /// Schedules a call to the method ExecuteRealizationsUpdate() for given object.
        /// This method will be called only after completing traversing the tree, 
        /// so the client can gather complete information about all visible instances.
        /// 
        /// 
        /// The client object that needs to have ExecuteRealizationsUpdate() to be called. 
        /// 
        ///  
        /// Note that we do not check for duplicated entries on the schedule. 
        /// It is the responsibility of the caller to ensure that no object
        /// will be scheduled more than once if it is undesiderable. 
        /// 
        internal void ScheduleForRealizationsUpdate(IRealizationContextClient client)
        {
            _scheduleList.Schedule(client); 
        }
 
 
        /// 
        /// Executes the deferred realizations update schedule. 
        /// 
        /// 
        internal void ExecuteRealizationsUpdateSchedule()
        { 
            _scheduleList.Execute();
        } 
 
        /// 
        /// Callback from client that found itself in "incomplete" state 
        /// and wants more MarkVisibleRealization() calls.
        /// When this routine is being called in animated scenario,
        /// it does not infer any additional burden. The essential is
        /// the completion of animation pass. When everything have got 
        /// stabilized, this call forces additional rendering pass
        /// that allow client to detect animation completion and 
        /// optimize their looking on the screen. 
        /// 
        ///  
        internal void ScheduleAdditionalFrames()
        {
            _needAdditionalFrames = true;
            _currentVisualRequiresNewRealizationNextFrame = true; 
        }
 
        ///  
        /// Designed to be called from only within a Visual after it has
        /// called UpdateRealizations on its content. This will check 
        /// if the content contained glyphs which require a new realization
        /// on the next frame outside of normal realization affecting
        /// changes to the tree. This is required at the end of an animation
        /// to re-render text which has completed an animation at a higher 
        /// fidelity. If new realizations are required, the Visual is added to
        /// a list of Visuals to have the appropriate flags set after the realization 
        /// pass completes. 
        /// 
        ///  
        internal void CheckVisualRequiresNextFrameRealizations(Visual v)
        {
            if (_currentVisualRequiresNewRealizationNextFrame)
            { 
                _visualsRequiringNextFrameRealizations.Add(v);
                _currentVisualRequiresNewRealizationNextFrame = false; 
            } 
        }
 
        /// 
        /// Sets or resets "in 3d mode" flag to notify traversed resources in subtree.
        /// 
        ///  
        /// "in 3d mode" flag before the call
        internal bool Set3DMode(bool mode) 
        { 
            bool oldMode = _3DMode;
            _3DMode = mode; 
            return oldMode;
        }

        ///  
        /// Checks "in 3d mode" flag recently set by Set3DMode.
        ///  
        ///  
        internal bool IsIn3DMode()
        { 
            return _3DMode;
        }

        #endregion Internal Methods 

 
        //---------------------------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //---------------------------------------------------------------------

        #region Internal Properties 
        /// 
        /// Returns the current channel set. 
        ///  
        internal DUCE.ChannelSet ChannelSet
        { 
            get
            {
                return _targetChannels;
            } 
            set { _targetChannels = value; }
        } 
 
        /// 
        /// Returns the current channel. 
        /// 
        internal DUCE.Channel Channel
        {
            get 
            {
                return _targetChannels.Channel; 
            } 
        }
 

        /// 
        /// Returns the matrix stack for maintaining the world transform.
        ///  
        internal MatrixStack TransformStack
        { 
            get { return _transformStack; } 
        }
 
        /// 
        /// Returns the 3d matrix stack for maintaining the 3d transform.
        /// 
        internal Matrix3DStack Transform3DStack 
        {
            get { return _transform3DStack; } 
        } 

        ///  
        /// Gets the number of milliseconds elapsed since the system started
        /// till traversal pass has been started.
        /// 
        internal int CurrentTime 
        {
            get { return _currentTime; } 
        } 

        ///  
        /// Returns the cached realization drawing context walker.
        /// 
        /// 
        /// Note that it is safe to re-use this walker as the only 
        /// state it has is the operation type stack used to balance
        /// push and pop instructions. 
        ///  
        internal RealizationDrawingContextWalker DrawingContextWalker
        { 
            get
            {
                return _drawingContextWalker;
            } 
        }
 
        ///  
        /// Gets the window clip
        ///  
        internal Rect WindowClip
        {
            get { return _windowClip; }
            set { _windowClip = value; } 
        }
 
        ///  
        /// Get the base transform
        ///  
        internal Matrix BaseTransform
        {
            get { return _baseTransform; }
            set { _baseTransform = value; } 
        }
 
        ///  
        /// Reports what type of walk is occurring at
        /// the current time. The walk can be incremental (updated 
        /// nodes only, true) or complete (all nodes containing
        /// realizations, false). This value can change within a single
        /// realization pass. The reason for this is that when a node
        /// which requires new realizations 
        /// (has NodeRequiresNewRealization flag set) is encountered,
        /// all of its children which contain realizations are also dirty 
        /// for realization updates, whether they are marked so or not. 
        /// We refer to this as a "fan out" effect from the original
        /// node. 
        /// 
        internal bool IncrementalWalk
        {
            get { return _incrementalPass && (_incrementalDisableCount == 0); } 
        }
 
        ///  
        /// This is called pre-subgraph to temporarily disable the incremental
        /// walk so that we can "fan out" and touch all the 
        /// realization requiring nodes underneath a node that
        /// is marked dirty for realizations. See comment for
        /// IncrementalWalk for detail.
        ///  
        internal void DisableIncrementalWalk()
        { 
            _incrementalDisableCount++; 
        }
 
        /// 
        /// This is called post-subgraph to re-enable the
        /// incremental walk after "fanning out" below
        /// a node that requires new realizations. See comments 
        /// on IncrementalWalk and DisableIncrementalWalk() also.
        ///  
        internal void EnableIncrementalWalk() 
        {
            if (_incrementalDisableCount > 0) 
            {
                _incrementalDisableCount--;
            }
        } 

        ///  
        /// (See DevDiv Bug 107454).  WalkForBitmapRenderTarget indicates that in the current 
        /// frame, we are performing the Visual tree walk as part of a bitmap render as opposed
        /// to a regular render visual tree walk.  The purpose of this flag is to 
        /// prevent Visual flags (NodeRequiresNewRealization, NodeInSubtreeRequiresNewRealization)
        /// from being reset at the end of the walk, which would cause realizations
        /// to not be applied later when a "regular" render pass occurs.
        ///  
        internal bool WalkForBitmapRenderTarget
        { 
            get 
            {
                return _walkForBitmapRenderTarget; 
            }
        }

        #endregion Internal Properties 

        //---------------------------------------------------------------------- 
        // 
        //  Private Fields
        // 
        //---------------------------------------------------------------------

        #region Private Fields
 
        // The channel we're operating on.
        DUCE.ChannelSet _targetChannels; 
 
        // Window clip
        private Rect _windowClip; 

        // Base transform
        private Matrix _baseTransform = Matrix.Identity;
 
        // The transform stack.
        private readonly MatrixStack _transformStack; 
 
        // 3D transform stack.
        private readonly Matrix3DStack _transform3DStack; 


        // The list of objects scheduled for realization update finalization.
        private readonly RealizationUpdateSchedule _scheduleList; 

        // Current time, in milliseconds 
        private int _currentTime; 

        // Cached realization drawing context walker 
        private readonly RealizationDrawingContextWalker _drawingContextWalker;

        // True if we need to request additional future frames
        private bool _needAdditionalFrames; 

        // True if we are previously requested additional frames from the MediaContext 
        private bool _requestedAdditionalFrames; 

        // True if are performing the visual walk for a BitmapRenderTarget (See DevDiv Bug 107454) 
        private bool _walkForBitmapRenderTarget;

        // True if we need to mark the current Visual as requiring new realizations
        // This is used when drawing glyphs in the content of a visual to allow them 
        // to be correctly updated after the final frame of an animation completes
        private bool _currentVisualRequiresNewRealizationNextFrame; 
 
        // List of Visuals that require new realizations on the next frame. These
        // are added after each Visual has its content 
        private ArrayList _visualsRequiringNextFrameRealizations;

        // True while traversing Viewport3DVisual subtree
        private bool _3DMode; 

        // The delegate we use to request frames from the MediaContext 
        private EventHandler _additionalFramesDelegate; 

        // State representing whether this is a full or incremental 
        // realization pass
        private bool _incrementalPass;

        // Stack counter for determining when we disable/enable incremental walk 
        private uint _incrementalDisableCount;
 
        #endregion Private Fields 
    }
} 


// 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.
//  
//
// Description: 
//      Accumulates state during a realization pass of the scene. 
//
//----------------------------------------------------------------------------- 

using System;
using System.Windows.Threading;
 
using System.Collections;
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Windows.Media;
using System.Windows.Media.Animation; 
using System.Windows.Media.Composition;
using System.Runtime.InteropServices;
using MS.Internal;
using System.Windows.Media.Media3D; 

 
namespace System.Windows.Media 
{
    ///  
    /// Implemented by resources that need realizations.
    /// 
    internal interface IRealizationContextClient
    { 
        void ExecuteRealizationsUpdate();
    } 
 
    internal struct RealizationBrushHelper
    { 
        internal RealizationBrushHelper(Pen stroke, Brush fill)
        {
            _stroke = null;
            if (stroke != null) 
            {
                _stroke = stroke.Brush; 
            } 
            _fill = fill;
        } 

        internal bool NeedsRealizationUpdates
        {
            get 
            {
                return (_stroke != null && _stroke.RequiresRealizationUpdates) 
                    || (_fill != null && _fill.RequiresRealizationUpdates); 
            }
        } 

        internal void UpdateRealizations(Rect strokeBounds, Rect fillBounds, RealizationContext ctx)
        {
            if (_stroke != null) 
            {
                _stroke.UpdateRealizations(strokeBounds, ctx); 
            } 
            if (_fill != null)
            { 
                _fill.UpdateRealizations(fillBounds, ctx);
            }
        }
 
        private Brush _fill;
        private Brush _stroke; 
 
    }
 
    /// 
    /// This class accumulates state during a realization pass of the scene.
    /// 
    ///  
    /// This class is to replace RenderContext during the realization pass.
    ///  
    internal sealed class RealizationContext 
    {
        //--------------------------------------------------------------------- 
        //
        //  Private Types
        //
        //--------------------------------------------------------------------- 

        #region Private Types 
 
        /// 
        /// Storage manager for the schedule finalization calls. 
        /// 
        private class RealizationUpdateSchedule
        {
            // ---------------------------------------------------------------- 
            // -- CONSTRUCTOR -------------------------------------------------
 
            ///  
            /// Creates a new schedule list.
            ///  
            internal RealizationUpdateSchedule()
            {
                _schedule = new List(INITIAL_SIZE);
            } 

 
            // --------------------------------------------------------------- 
            // -- METHODS ------------------------------------------------------
 
            /// 
            /// Adds an object to the realization update schedule.
            /// 
            /// The object to be scheduled. 
            internal void Schedule(IRealizationContextClient client)
            { 
                if (client != null) 
                {
                    _schedule.Add(client); 
                }
            }

 
            /// 
            /// Executes the schedule list. 
            ///  
            internal void Execute()
            { 
                try
                {
                    foreach (IRealizationContextClient scheduled in _schedule)
                    { 
                        // guaranteed to be not null, see the Schedule method
                        scheduled.ExecuteRealizationsUpdate(); 
                    } 
                }
                finally 
                {
                    _schedule.Clear();
                }
            } 

 
            ///  
            /// Instead of allocating and releasing memory continuously while scheduling
            /// and clearing the list, we call the optimize method after each frame 
            /// to readjust the internal list capacity.
            /// 
            /// 
            internal void Optimize() 
            {
                Debug.Assert(_schedule.Count == 0); // The list must be empty before this is called. 
                Debug.Assert(_highWaterMark <= _schedule.Capacity); 

                // After TRIM_COUNT calls to this method we check the past usage of the stack. 
                if (_observeCount == TRIM_COUNT)
                {
                    int newSize = Math.Max(_highWaterMark, INITIAL_SIZE);
                    if (newSize * SHRINK_FACTOR <= _schedule.Capacity) 
                    {
                        // If the water mark is less or equal to capacity divided by the shrink 
                        // factor, then we shrink the stack. Usually the shrink factor is greater 
                        // than the grow factor. This avoids an oscillation of shrinking and growing
                        // the list if the high water mark goes only slightly up and down. 

                        // Note that we don't need to copy the contents because the list is empty.
                        _schedule = new List(newSize);
                    } 

                    _highWaterMark = 0; 
                    _observeCount = 0; 
                }
                else 
                {
                    // Keep incrementing our observe count
                    _observeCount++;
                } 
            }
 
 
            // ----------------------------------------------------------------
            // -- PROPERTIES -------------------------------------------------- 

            /// 
            /// Checks if the schedule is empty.
            ///  
            internal bool IsEmpty
            { 
                get { return _schedule.Count == 0; } 
            }
 

            // ---------------------------------------------------------------
            // -- FIELDS ------------------------------------------------------
 
            // The storage for the scheduled finalization calls.
            private List _schedule; 
 
            // The following fields are used to lazily manage the memory
            // allocated by the stack. 
            private int _highWaterMark;
            private int _observeCount;

 
            // ---------------------------------------------------------------
            // -- CONSTANTS --------------------------------------------------- 
 
            // The initial size of the schedule storage.
#if _DEBUG 
            private const int INITIAL_SIZE = 40;
#else
            private const int INITIAL_SIZE = 4;
#endif 

            // The shrink factor for the schedule storage. 
            private const int SHRINK_FACTOR = 3; 

            // This constant is used to lazily manage the memory allocated 
            // by the list.
            private const int TRIM_COUNT = 10;
        }
 
        #endregion Private Types
 
 
        //---------------------------------------------------------------------
        // 
        //  Internal Constructors
        //
        //----------------------------------------------------------------------
 
        #region Internal Constructors
 
        ///  
        /// Creates a world transform matrix stack for reuse between frames
        /// and a list for finalization calls scheduling. 
        /// 
        internal RealizationContext()
        {
            _transformStack = new MatrixStack(); 
            _transform3DStack = new Matrix3DStack();
            _scheduleList = new RealizationUpdateSchedule(); 
            _drawingContextWalker = new RealizationDrawingContextWalker(this); 
            _visualsRequiringNextFrameRealizations = new ArrayList();
            _currentVisualRequiresNewRealizationNextFrame = false; 
        }

        #endregion Internal Constructors
 

        //--------------------------------------------------------------------- 
        // 
        //  Internal Methods
        // 
        //----------------------------------------------------------------------

        #region Internal Methods
 
        /// 
        /// BeginFrame must be called before a frame is rendered. 
        ///  
        internal void BeginFrame(
            bool incrementalWalk, bool walkForBitmapRenderTarget 
            )
        {
            Debug.Assert(_transformStack.IsEmpty, "Matrix stack must be empty.");
            Debug.Assert(_transform3DStack.IsEmpty, "3D transform stack must be empty."); 
            Debug.Assert(
                _scheduleList.IsEmpty, 
                "The schedule list must be empty."); 
            Debug.Assert(_visualsRequiringNextFrameRealizations.Count == 0);
            Debug.Assert(!_currentVisualRequiresNewRealizationNextFrame); 

            _currentTime = Environment.TickCount;
            _incrementalPass = incrementalWalk;
            _incrementalDisableCount = 0; 
            _walkForBitmapRenderTarget = walkForBitmapRenderTarget;
 
            // 
            // At the beginning of a frame assume that we won't need any more
            // frames in the future for additional realization work. Only if 
            // a resource makes a request for more cycles during the realization
            // pass will we ask the MediaContext for more. In the meantime, if
            // we previously hooked the Rendering event then unhook it now,
            // because if we experience an exception during the realization 
            // pass the MediaContext will let the realization context object go
            // to garbage collection. Keeping the event hooked would prevent it 
            // from being collected, and it would also prevent the event from 
            // being unhooked, which would cause the MedaiContext to continually
            // render frames forever from that point on. 
            //

            _needAdditionalFrames = false;
            if (_requestedAdditionalFrames) 
            {
                MediaContext.From(Dispatcher.CurrentDispatcher).Rendering -= _additionalFramesDelegate; 
                _requestedAdditionalFrames = false; 
            }
        } 


        /// 
        /// This method should be called after a frame has been rendered. 
        /// 
        ///  
        /// This method should be called after the realization context is not 
        /// needed anymore. The method expects that all stacks have been
        /// cleared by popping all items from the stack. 
        ///
        /// NOTE: If for whatever reason the render pass should fail, the
        /// realization context is thrown away since it might be in an
        /// inconsistent state. In such cases EndFrame must not be called! 
        /// (There are ways to implement this cleaner, but it requires more
        /// infra-structure for which there isn't really any need). 
        ///  
        internal void EndFrame()
        { 
            Debug.Assert(_transformStack.IsEmpty, "Matrix stack must be empty. The remark to the EndFrame method has more detail.");
            Debug.Assert(_transform3DStack.IsEmpty, "Matrix3D stack must be empty.");
            Debug.Assert(_scheduleList.IsEmpty, "The schedule list must be empty. The remark to the EndFrame method has more detail.");
 
            _transformStack.Optimize();
            _scheduleList.Optimize(); 
 
            Debug.Assert(_incrementalDisableCount == 0);
 
            //
            // If a resource requested additional cycles during the last
            // realization pass, use the MediaContext.Rendering event to schedule
            // additional frames. 
            //
 
            if (_needAdditionalFrames) 
            {
                if (_additionalFramesDelegate == null) 
                {
                    _additionalFramesDelegate = delegate(object sender, EventArgs e) { };
                }
                MediaContext.From(Dispatcher.CurrentDispatcher).Rendering += _additionalFramesDelegate; 
                _requestedAdditionalFrames = true;
            } 
 
            foreach (Visual v in _visualsRequiringNextFrameRealizations)
            { 
                v.PropagateChangedFlags();
            }
            _visualsRequiringNextFrameRealizations.Clear();
        } 

 
        ///  
        /// Schedules a call to the method ExecuteRealizationsUpdate() for given object.
        /// This method will be called only after completing traversing the tree, 
        /// so the client can gather complete information about all visible instances.
        /// 
        /// 
        /// The client object that needs to have ExecuteRealizationsUpdate() to be called. 
        /// 
        ///  
        /// Note that we do not check for duplicated entries on the schedule. 
        /// It is the responsibility of the caller to ensure that no object
        /// will be scheduled more than once if it is undesiderable. 
        /// 
        internal void ScheduleForRealizationsUpdate(IRealizationContextClient client)
        {
            _scheduleList.Schedule(client); 
        }
 
 
        /// 
        /// Executes the deferred realizations update schedule. 
        /// 
        /// 
        internal void ExecuteRealizationsUpdateSchedule()
        { 
            _scheduleList.Execute();
        } 
 
        /// 
        /// Callback from client that found itself in "incomplete" state 
        /// and wants more MarkVisibleRealization() calls.
        /// When this routine is being called in animated scenario,
        /// it does not infer any additional burden. The essential is
        /// the completion of animation pass. When everything have got 
        /// stabilized, this call forces additional rendering pass
        /// that allow client to detect animation completion and 
        /// optimize their looking on the screen. 
        /// 
        ///  
        internal void ScheduleAdditionalFrames()
        {
            _needAdditionalFrames = true;
            _currentVisualRequiresNewRealizationNextFrame = true; 
        }
 
        ///  
        /// Designed to be called from only within a Visual after it has
        /// called UpdateRealizations on its content. This will check 
        /// if the content contained glyphs which require a new realization
        /// on the next frame outside of normal realization affecting
        /// changes to the tree. This is required at the end of an animation
        /// to re-render text which has completed an animation at a higher 
        /// fidelity. If new realizations are required, the Visual is added to
        /// a list of Visuals to have the appropriate flags set after the realization 
        /// pass completes. 
        /// 
        ///  
        internal void CheckVisualRequiresNextFrameRealizations(Visual v)
        {
            if (_currentVisualRequiresNewRealizationNextFrame)
            { 
                _visualsRequiringNextFrameRealizations.Add(v);
                _currentVisualRequiresNewRealizationNextFrame = false; 
            } 
        }
 
        /// 
        /// Sets or resets "in 3d mode" flag to notify traversed resources in subtree.
        /// 
        ///  
        /// "in 3d mode" flag before the call
        internal bool Set3DMode(bool mode) 
        { 
            bool oldMode = _3DMode;
            _3DMode = mode; 
            return oldMode;
        }

        ///  
        /// Checks "in 3d mode" flag recently set by Set3DMode.
        ///  
        ///  
        internal bool IsIn3DMode()
        { 
            return _3DMode;
        }

        #endregion Internal Methods 

 
        //---------------------------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //---------------------------------------------------------------------

        #region Internal Properties 
        /// 
        /// Returns the current channel set. 
        ///  
        internal DUCE.ChannelSet ChannelSet
        { 
            get
            {
                return _targetChannels;
            } 
            set { _targetChannels = value; }
        } 
 
        /// 
        /// Returns the current channel. 
        /// 
        internal DUCE.Channel Channel
        {
            get 
            {
                return _targetChannels.Channel; 
            } 
        }
 

        /// 
        /// Returns the matrix stack for maintaining the world transform.
        ///  
        internal MatrixStack TransformStack
        { 
            get { return _transformStack; } 
        }
 
        /// 
        /// Returns the 3d matrix stack for maintaining the 3d transform.
        /// 
        internal Matrix3DStack Transform3DStack 
        {
            get { return _transform3DStack; } 
        } 

        ///  
        /// Gets the number of milliseconds elapsed since the system started
        /// till traversal pass has been started.
        /// 
        internal int CurrentTime 
        {
            get { return _currentTime; } 
        } 

        ///  
        /// Returns the cached realization drawing context walker.
        /// 
        /// 
        /// Note that it is safe to re-use this walker as the only 
        /// state it has is the operation type stack used to balance
        /// push and pop instructions. 
        ///  
        internal RealizationDrawingContextWalker DrawingContextWalker
        { 
            get
            {
                return _drawingContextWalker;
            } 
        }
 
        ///  
        /// Gets the window clip
        ///  
        internal Rect WindowClip
        {
            get { return _windowClip; }
            set { _windowClip = value; } 
        }
 
        ///  
        /// Get the base transform
        ///  
        internal Matrix BaseTransform
        {
            get { return _baseTransform; }
            set { _baseTransform = value; } 
        }
 
        ///  
        /// Reports what type of walk is occurring at
        /// the current time. The walk can be incremental (updated 
        /// nodes only, true) or complete (all nodes containing
        /// realizations, false). This value can change within a single
        /// realization pass. The reason for this is that when a node
        /// which requires new realizations 
        /// (has NodeRequiresNewRealization flag set) is encountered,
        /// all of its children which contain realizations are also dirty 
        /// for realization updates, whether they are marked so or not. 
        /// We refer to this as a "fan out" effect from the original
        /// node. 
        /// 
        internal bool IncrementalWalk
        {
            get { return _incrementalPass && (_incrementalDisableCount == 0); } 
        }
 
        ///  
        /// This is called pre-subgraph to temporarily disable the incremental
        /// walk so that we can "fan out" and touch all the 
        /// realization requiring nodes underneath a node that
        /// is marked dirty for realizations. See comment for
        /// IncrementalWalk for detail.
        ///  
        internal void DisableIncrementalWalk()
        { 
            _incrementalDisableCount++; 
        }
 
        /// 
        /// This is called post-subgraph to re-enable the
        /// incremental walk after "fanning out" below
        /// a node that requires new realizations. See comments 
        /// on IncrementalWalk and DisableIncrementalWalk() also.
        ///  
        internal void EnableIncrementalWalk() 
        {
            if (_incrementalDisableCount > 0) 
            {
                _incrementalDisableCount--;
            }
        } 

        ///  
        /// (See DevDiv Bug 107454).  WalkForBitmapRenderTarget indicates that in the current 
        /// frame, we are performing the Visual tree walk as part of a bitmap render as opposed
        /// to a regular render visual tree walk.  The purpose of this flag is to 
        /// prevent Visual flags (NodeRequiresNewRealization, NodeInSubtreeRequiresNewRealization)
        /// from being reset at the end of the walk, which would cause realizations
        /// to not be applied later when a "regular" render pass occurs.
        ///  
        internal bool WalkForBitmapRenderTarget
        { 
            get 
            {
                return _walkForBitmapRenderTarget; 
            }
        }

        #endregion Internal Properties 

        //---------------------------------------------------------------------- 
        // 
        //  Private Fields
        // 
        //---------------------------------------------------------------------

        #region Private Fields
 
        // The channel we're operating on.
        DUCE.ChannelSet _targetChannels; 
 
        // Window clip
        private Rect _windowClip; 

        // Base transform
        private Matrix _baseTransform = Matrix.Identity;
 
        // The transform stack.
        private readonly MatrixStack _transformStack; 
 
        // 3D transform stack.
        private readonly Matrix3DStack _transform3DStack; 


        // The list of objects scheduled for realization update finalization.
        private readonly RealizationUpdateSchedule _scheduleList; 

        // Current time, in milliseconds 
        private int _currentTime; 

        // Cached realization drawing context walker 
        private readonly RealizationDrawingContextWalker _drawingContextWalker;

        // True if we need to request additional future frames
        private bool _needAdditionalFrames; 

        // True if we are previously requested additional frames from the MediaContext 
        private bool _requestedAdditionalFrames; 

        // True if are performing the visual walk for a BitmapRenderTarget (See DevDiv Bug 107454) 
        private bool _walkForBitmapRenderTarget;

        // True if we need to mark the current Visual as requiring new realizations
        // This is used when drawing glyphs in the content of a visual to allow them 
        // to be correctly updated after the final frame of an animation completes
        private bool _currentVisualRequiresNewRealizationNextFrame; 
 
        // List of Visuals that require new realizations on the next frame. These
        // are added after each Visual has its content 
        private ArrayList _visualsRequiringNextFrameRealizations;

        // True while traversing Viewport3DVisual subtree
        private bool _3DMode; 

        // The delegate we use to request frames from the MediaContext 
        private EventHandler _additionalFramesDelegate; 

        // State representing whether this is a full or incremental 
        // realization pass
        private bool _incrementalPass;

        // Stack counter for determining when we disable/enable incremental walk 
        private uint _incrementalDisableCount;
 
        #endregion Private Fields 
    }
} 


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

                        

Link Menu

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