Visual.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Media / Visual.cs / 8 / Visual.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//      Defines a node in the composition scene graph. 
//
//----------------------------------------------------------------------------- 

using System;
using System.Security;
using System.Windows.Threading; 
using MS.Win32;
using System.Windows.Media; 
using System.Windows.Media.Media3D; 
using System.Windows.Media.Animation;
using System.Windows.Media.Composition; 
using System.Windows.Media.Effects;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic; 
using MS.Internal;
using MS.Internal.Media; 
using MS.Internal.Media3D; 
using System.Resources;
using MS.Utility; 
using System.Runtime.InteropServices;
using MS.Internal.PresentationCore;

using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
 
//----------------------------------------------------------------------------- 
// This section lists various things that we could improve on the Visual class.
// 
// - (Pail) Don't allocate a managed Pail object.
// - (Finalizer) Currently we delete the cob explicitly when a node is removed from
//   the scene graph. However, we don't do this when we remove the root node.
//   currently this is done by the finalizer. If we clean explicitly up when we 
//   remove the root node we won't need a finalizer.
//----------------------------------------------------------------------------- 
 

//------------------------------------------------------------------------------ 
// PUBLIC API EXPOSURE RULES
//
// If you expose a public/protected API you need to check a couple things:
// 
// A) Call the correct version of VerifyAPI.  This checks the following
//      1) That the calling thread has entered the context of this object 
//      2) That the current object is not disposed. 
//      3) If another object is passed in, that it has the same
//         context affinity as this object.  This should be used for 
//         arguments to the API
//      4) That the current permissions are acceptable.
//
// B) That other arguments are not disposed if needed. 
//
// 
//----------------------------------------------------------------------------- 

namespace System.Windows.Media 
{

    // this class is used to wrap the Map struct into an object so
    // that we can use it with the UncommonField infrastructure. 
    internal class MapClass
    { 
        internal MapClass() 
        {
            _map_ofBrushes = new DUCE.Map(); 
        }

        internal bool IsEmpty
        { 
            get
            { 
                return _map_ofBrushes.IsEmpty(); 
            }
        } 

        public DUCE.Map _map_ofBrushes;
    }
 
    /// 
    /// The Visual class is the base class for all Visual types. It provides 
    /// services and properties that all Visuals have in common. Services include 
    /// hit-testing, coordinate transformation, bounding box calculations. Properties
    /// are for example a transform property and an opacity property. 
    ///
    /// Derived Visuals render their content first and then render the children, or in other
    /// words, the content of a Visual is always behind the content of its children.
    ///  
    public abstract partial class Visual : DependencyObject, DUCE.IResource
    { 
        // -------------------------------------------------------------------- 
        //
        //   Constants 
        //
        // --------------------------------------------------------------------

        #region Constants 

        ///  
        /// This is the dirty mask for a visual, set every time we marshall 
        /// a visual to a channel and reset by the end of the render pass.
        ///  
        private const VisualProxyFlags c_ProxyFlagsDirtyMask =
              VisualProxyFlags.IsSubtreeDirtyForRender
            | VisualProxyFlags.IsContentDirty
            | VisualProxyFlags.IsTransformDirty 
            | VisualProxyFlags.IsGuidelineCollectionDirty
            | VisualProxyFlags.IsClipDirty 
            | VisualProxyFlags.IsOpacityDirty 
            | VisualProxyFlags.IsOpacityMaskDirty
            | VisualProxyFlags.IsOffsetDirty 
            | VisualProxyFlags.IsEdgeModeDirty
            | VisualProxyFlags.IsBitmapScalingModeDirty;

 
        /// 
        /// This is the dirty mask for a BitmapEffect. 
        ///  
        private const VisualProxyFlags c_BitmapEffectDirtyMask =
               VisualProxyFlags.IsSubtreeDirtyForRender 
            |  VisualProxyFlags.IsContentDirty
            |  VisualProxyFlags.IsOpacityDirty
            |  VisualProxyFlags.IsOpacityMaskDirty
            |  VisualProxyFlags.IsEdgeModeDirty 
            |  VisualProxyFlags.IsBitmapScalingModeDirty;
 
        ///  
        /// This is the dirty mask for a visual, set every time we marshall
        /// a visual to a channel and reset by the end of the render pass. 
        ///
        /// This mask is only for Viewport3D visual, since the contents
        /// of the Viewport3D are rendered during RenderContent, we
        /// need to set those flags as dirty if the visual is not on 
        /// channel yet
        ///  
        private const VisualProxyFlags c_Viewport3DProxyFlagsDirtyMask = 
              VisualProxyFlags.Viewport3DVisual_IsCameraDirty
            | VisualProxyFlags.Viewport3DVisual_IsViewportDirty; 

        #endregion Constants

 

        // ------------------------------------------------------------------- 
        // 
        //   Internal Constructor
        // 
        // --------------------------------------------------------------------

        #region Internal Constructor
 
        /// 
        /// This internal ctor is a hook to allow Visual subclasses 
        /// to create their unique type of a visual resource. 
        /// 
        internal Visual(DUCE.ResourceType resourceType) 
        {

#if DEBUG
            _parentIndex = -1; 
#endif
 
            switch (resourceType) 
            {
            case DUCE.ResourceType.TYPE_VISUAL: 
                // Default setting
                break;

            case DUCE.ResourceType.TYPE_VIEWPORT3DVISUAL: 
                SetFlags(true, VisualFlags.IsViewport3DVisual);
                break; 
 
            default:
                Debug.Assert(false, "TYPE_VISUAL or TYPE_VIEWPORT3DVISUAL expected."); 
                break;
            }
        }
 
        #endregion Protected Constructor
 
 
        // -------------------------------------------------------------------
        // 
        //   Protected Constructor
        //
        // -------------------------------------------------------------------
 
        #region Protected Constructor
 
        ///  
        /// Ctor Visual
        ///  
        protected Visual() : this(DUCE.ResourceType.TYPE_VISUAL)
        {
        }
 
        #endregion Protected Constructor
 
 
        // -------------------------------------------------------------------
        // 
        //   IResource implementation
        //
        // --------------------------------------------------------------------
 
        #region IResource implementation
 
        ///  
        /// This is used to check if the composition node
        /// for the visual is on channel 
        /// 
        /// 
        /// 
        internal bool IsOnChannel(DUCE.Channel channel) 
        {
            return _proxy.IsOnChannel(channel); 
        } 

        ///  
        /// This is used to check if the composition node
        /// for the visual is on a set of channels
        /// 
        /// ArrayList of DUCE.Channel 
        /// true if and only if the composition node is on all the channels
        internal bool IsOnChannels(List channels) 
        { 
            // Check to ensure that we find at least
            // one channel in the ArrayList. 
            bool foundChannel = false;
            foreach (DUCE.ChannelSet channelSet in channels)
            {
                if (!IsOnChannel(channelSet.Channel)) 
                {
                    return false; 
                } 
                foundChannel = true;
            } 
            return foundChannel;
        }

        ///  
        /// Returns the handle this visual has on the given channel.
        ///  
        ///  
        /// 
        DUCE.ResourceHandle DUCE.IResource.GetHandle(DUCE.Channel channel) 
        {
            return _proxy.GetHandle(channel);
        }
 
        /// 
        /// Only Viewport3DVisual and Visual3D implements this. 
        /// Vieport3DVisual has two handles. One stored in _proxy 
        /// and the other one stored in _proxy3D. This function returns
        /// the handle stored in _proxy3D. 
        /// 
        DUCE.ResourceHandle DUCE.IResource.Get3DHandle(DUCE.Channel channel)
        {
            throw new NotImplementedException(); 
        }
 
        ///  
        /// This is used to create or addref the visual resource
        /// on the given channel 
        /// 
        /// 
        /// 
        DUCE.ResourceHandle DUCE.IResource.AddRefOnChannel(DUCE.Channel channel) 
        {
            return AddRefOnChannelCore(channel); 
        } 

        internal virtual DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel) 
        {
            DUCE.ResourceType resourceType = DUCE.ResourceType.TYPE_VISUAL;

            if (CheckFlagsAnd(VisualFlags.IsViewport3DVisual)) 
            {
                resourceType = DUCE.ResourceType.TYPE_VIEWPORT3DVISUAL; 
            } 

            _proxy.CreateOrAddRefOnChannel(channel, resourceType); 

            return _proxy.GetHandle(channel);
        }
 
        /// 
        /// this is used to release the comp node of the visual 
        /// on the given channel 
        /// 
        ///  
        /// 
        internal virtual void ReleaseOnChannelCore(DUCE.Channel channel)
        {
            _proxy.ReleaseOnChannel(channel); 
        }
 
 
        /// 
        /// Sends a command to compositor to remove the child 
        /// from its parent on the channel.
        /// 
        void DUCE.IResource.RemoveChildFromParent(
                DUCE.IResource parent, 
                DUCE.Channel channel)
        { 
            DUCE.CompositionNode.RemoveChild( 
                parent.GetHandle(channel),
                _proxy.GetHandle(channel), 
                channel);
        }

        int DUCE.IResource.GetChannelCount() 
        {
            return _proxy.Count; 
        } 

        DUCE.Channel DUCE.IResource.GetChannel(int index) 
        {
            return _proxy.GetChannel(index);
        }
 
        #endregion IResource implementation
 
 
        // -------------------------------------------------------------------
        // 
        //   IElement implementation
        //
        // --------------------------------------------------------------------
 
        // --------------------------------------------------------------------
        // 
        //   Internal Properties 
        //
        // ------------------------------------------------------------------- 

        #region Internal Properties

        // Are we in the process of iterating the visual children. 
        // This flag is set during a descendents walk, for property invalidation.
        internal bool IsVisualChildrenIterationInProgress 
        { 
            [FriendAccessAllowed]
            get { return CheckFlagsAnd(VisualFlags.IsVisualChildrenIterationInProgress); } 

            [FriendAccessAllowed]
            set { SetFlags(value, VisualFlags.IsVisualChildrenIterationInProgress); }
        } 

 
        ///  
        /// The CompositionTarget marks the root element. The root element is responsible
        /// for posting renders. 
        /// 
        /// 
        /// The property getter is also used to ensure that the Visual is
        /// not used in multiple CompositionTargets. 
        /// 
        internal bool IsRootElement 
        { 
            get
            { 
                return CheckFlagsAnd(VisualFlags.ShouldPostRender);
            }

            set 
            {
                SetFlags(value, VisualFlags.ShouldPostRender); 
            } 
        }
        #endregion Internal Properties 



        // -------------------------------------------------------------------- 
        //
        //   Visual Content 
        // 
        // -------------------------------------------------------------------
 
        #region Visual Content

        /// 
        /// Derived classes must override this method and return the bounding 
        /// box of their content.
        ///  
        internal virtual Rect GetContentBounds() 
        {
            return Rect.Empty; 
        }


        ///  
        /// RenderContent is implemented by derived classes to hook up their
        /// content. The implementer of this function can assert that the 
        /// visual is marshaled on the current channel when the function 
        /// is executed.
        ///  
        internal virtual void RenderContent(RenderContext ctx, bool isOnChannel)
        {
            /* do nothing */
        } 

        ///  
        /// This method is overrided on Visuals that can instantiate IDrawingContext 
        /// Currently, DrawingVisual and UIElement
        ///  
        internal virtual void RenderClose(IDrawingContent newContent)
        {
        }
 

        ///  
        /// This method is called when the realization caches need to be updated. 
        /// 
        internal virtual void UpdateRealizations(RealizationContext ctx) 
        {
            //
            // Visuals have only one type of realizable content: bitmap effects,
            // which are handled as a special case for rendering purposes, making 
            // UpdateRealization essentialy a no-op.
            // 
            // We allow the Visual descendants to handle other kinds of realizable 
            // content (for example, glyph runs referenced from render data on
            // a DrawingVisual) by overriding this method. 
            //
        }

 
        /// 
        /// VisualContentBounds returns the bounding box for the contents of the current visual. 
        ///  
        internal Rect VisualContentBounds
        { 
            get
            {
                // Probably too restrictive. Let's see who wants it during OnRender.
                VerifyAPIReadWrite(); 

                return GetContentBounds(); 
            } 
        }
 

        /// 
        /// VisualDescendantBounds returns the union of all of the content bounding
        /// boxes for all of the descendants of the current visual,and also including 
        /// the contents of the current visual. So we end up with the
        /// bounds of the whole sub-graph in inner space. 
        ///  
        internal Rect VisualDescendantBounds
        { 
            get
            {
                // Probably too restrictive. Let's see who wants it during OnRender.
                VerifyAPIReadWrite(); 

                Rect bboxSubgraph = CalculateSubgraphBoundsInnerSpace(); 
 
                // If bounding box has NaN, then we set the bounding box to infinity.
                if (DoubleUtil.RectHasNaN(bboxSubgraph)) 
                {
                    bboxSubgraph.X = Double.NegativeInfinity;
                    bboxSubgraph.Y = Double.NegativeInfinity;
                    bboxSubgraph.Width = Double.PositiveInfinity; 
                    bboxSubgraph.Height = Double.PositiveInfinity;
                } 
                return bboxSubgraph; 
            }
        } 


        /// 
        /// Computes the union of all content bounding boxes of this Visual's sub-graph 
        /// in inner space. Note that the result includes the root Visual's content.
        /// 
        /// Definition: Outer/Inner Space: 
        ///
        ///      A Visual has a set of properties which include clip, transform, offset 
        ///      and bitmap effect. Those properties affect in which space (coordinate
        ///      clip space) a Visual's vector graphics and sub-graph is interpreted.
        ///      Inner space is the space before applying any of the properties. Outer
        ///      space is the space where all the properties have been taken into account. 
        ///      For example if the Visual draws a rectangle {0, 0, 100, 100} and the
        ///      Offset property is set to {20, 20} and the clip is set to {40, 40, 10, 10} 
        ///      then the bounding box of the Visual in inner space is {0, 0, 100, 100} and 
        ///      in outer space {60, 60, 10, 10} (start out with the bbox of {0, 0, 100, 100}
        ///      then apply the clip {40, 40, 10, 10} which leaves us with a bbox of 
        ///      {40, 40, 10, 10} and finally apply the offset and we end up with a bbox
        ///      of {60, 60, 10, 10}
        /// 
        internal Rect CalculateSubgraphBoundsInnerSpace() 
        {
            return CalculateSubgraphBoundsInnerSpace(false); 
        } 

        ///  
        /// Computes the union of all rendering bounding boxes of this Visual's sub-graph
        /// in inner space. Note that the result includes the root Visual's content.
        /// 
        internal Rect CalculateSubgraphRenderBoundsInnerSpace() 
        {
            return CalculateSubgraphBoundsInnerSpace(true); 
        } 

        ///  
        /// Same as the parameterless CalculateSubgraphBoundsInnerSpace except it takes a
        /// boolean indicating whether or not to calculate the rendering bounds.
        /// If the renderBounds parameter is set to true then the render bounds are returned.
        /// The render bounds differ in that they treat zero area bounds as emtpy rectangles. 
        ///
        /// 
 

 


        internal virtual Rect CalculateSubgraphBoundsInnerSpace(bool renderBounds)
        { 
            Rect bboxSubgraph = Rect.Empty;
 
            // Recursively calculate sub-graph bounds of children of this node. We get 
            // the bounds of each child Visual in outer space which is this Visual's
            // inner space and union them together. 

            int count = VisualChildrenCount;

            for (int i = 0; i < count; i++) 
            {
                Visual child = GetVisualChild(i); 
                if (child != null) 
                {
                    Rect bboxSubgraphChild = child.CalculateSubgraphBoundsOuterSpace(renderBounds); 

                    bboxSubgraph.Union(bboxSubgraphChild);
                }
            } 

            // Get the content bounds of the Visual.  In the case that we're interested in render 
            // bounds (i.e. what MIL will consider the size of the object), we set 0 area rects 
            // to be empty so that they don't union to create larger sized rects.
            Rect contentBounds = GetContentBounds(); 
            if (renderBounds && IsEmptyRenderBounds(ref contentBounds /* ref for perf - not modified */))
            {
                contentBounds = Rect.Empty;
            } 

            // Union the content bounds to the sub-graph bounds so that we end up with the 
            // bounds of the whole sub-graph in inner space and return it. 
            bboxSubgraph.Union(contentBounds);
 
            return bboxSubgraph;
        }

 

        ///  
        /// Computes the union of all content bounding boxes of this Visual's sub-graph 
        /// in outer space. Note that the result includes the root Visual's content.
        /// For a definition of outer/inner space see CalculateSubgraphBoundsInnerSpace. 
        /// 
        internal Rect CalculateSubgraphBoundsOuterSpace()
        {
            return CalculateSubgraphBoundsOuterSpace(false /* renderBounds */); 
        }
 
        ///  
        /// Computes the union of all rendering bounding boxes of this Visual's sub-graph
        /// in outer space. Note that the result includes the root Visual's content. 
        /// For a definition of outer/inner space see CalculateSubgraphBoundsInnerSpace.
        /// 
        internal Rect CalculateSubgraphRenderBoundsOuterSpace()
        { 
            return CalculateSubgraphBoundsOuterSpace(true /* renderBounds */);
        } 
 
        /// 
        /// Same as the parameterless CalculateSubgraphBoundsOuterSpace except it takes a 
        /// boolean indicating whether or not to calculate the rendering bounds.
        /// If the renderBounds parameter is set to true then the render bounds are returned.
        /// The render bounds differ in that they treat zero area bounds as emtpy rectangles.
        /// 
        ///
 
 

 

        private Rect CalculateSubgraphBoundsOuterSpace(bool renderBounds)
        {
            Rect bboxSubgraph = Rect.Empty; 

            // Get the inner space bounding box of this node and then transform it into outer 
            // space. 

            bboxSubgraph = CalculateSubgraphBoundsInnerSpace(renderBounds); 

            // Apply Effect

            if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect)) 
            {
                Rect bitmapEffectBounds = BitmapEffectStateField.GetValue(this).GetBounds(bboxSubgraph); 
                if (renderBounds && IsEmptyRenderBounds(ref bitmapEffectBounds /* ref for perf - not modified */)) 
                {
                    bitmapEffectBounds = Rect.Empty; 
                }

                bboxSubgraph.Union(bitmapEffectBounds);
            } 

            // Apply Clip. 
 
            Geometry clip = ClipField.GetValue(this);
            if (clip != null) 
            {
                bboxSubgraph.Intersect(clip.Bounds);
            }
 
            // Apply Transform.
            Transform transform = TransformField.GetValue(this); 
 
            if ((transform != null) && (!transform.IsIdentity))
            { 
                Matrix m = transform.Value;
                MatrixUtil.TransformRect(ref bboxSubgraph, ref m);
            }
 
            // Apply Offset.
            if (!bboxSubgraph.IsEmpty) 
            { 
                bboxSubgraph.X += _offset.X;
                bboxSubgraph.Y += _offset.Y; 
            }

            // If bounding box has NaN, then we set the bounding box to infinity.
            if (DoubleUtil.RectHasNaN(bboxSubgraph)) 
            {
                bboxSubgraph.X = Double.NegativeInfinity; 
                bboxSubgraph.Y = Double.NegativeInfinity; 
                bboxSubgraph.Width = Double.PositiveInfinity;
                bboxSubgraph.Height = Double.PositiveInfinity; 
            }

            return bboxSubgraph;
        } 

        ///  
        /// This method returns true if the given WPF bounds will be considered 
        /// empty in terms of rendering.  This is the case when the bounds describe
        /// a zero-area space.  bounds are passed by ref for speed but are not modified 
        ///
        ///

 

        private bool IsEmptyRenderBounds(ref Rect bounds) 
        { 
            return (bounds.Width <= 0 || bounds.Height <= 0);
        } 

        #endregion Visual Content

 

        // ------------------------------------------------------------------- 
        // 
        //   Bitmap Effects
        // 
        // -------------------------------------------------------------------

        #region Bitmap Effects
 
        /// 
        /// This method schedules the bitmap effect content for 
        /// realization update 
        /// 
        ///  
        internal void UpdateBitmapEffectRealizations(RealizationContext ctx)
        {
            BitmapEffectVisualState effectState = BitmapEffectStateField.GetValue(this);
            if (effectState.BitmapEffectDrawing.ScheduleForUpdates) 
            {
                BitmapEffectContent content = new BitmapEffectContent(this, ctx); 
 
                ctx.ScheduleForRealizationsUpdate(content);
 
                // if the bitmap effect or the visual changed,
                // we need to rerender all realizations
                foreach (DUCE.ChannelSet channelSet in ctx.Channels)
                { 
                    if (CheckFlagsAnd(channelSet.Channel, VisualProxyFlags.IsBitmapEffectDirty))
                    { 
                        effectState.BitmapEffectDrawing = null; 
                    }
                } 

                effectState.BitmapEffectDrawing.ScheduleForUpdates = false;
            }
 
            effectState.BitmapEffectDrawing.UpdateRealizations(ctx);
        } 
        #endregion Bitmap Effects 

 
        // --------------------------------------------------------------------
        //
        //   Resource Marshalling and Unmarshalling
        // 
        // -------------------------------------------------------------------
 
        #region Resource Marshalling and Unmarshalling 

        ///  
        /// Override this function in derived classes to release unmanaged resources during Dispose
        /// and during removal of a subtree.
        /// 
        internal virtual void FreeContent(DUCE.Channel channel) 
        {
            Debug.Assert(IsOnChannel(channel)); 
            Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentNodeConnected)); 
        }
 

        /// 
        /// Frees up resources in this visual's subtree.
        /// This is only called during the realization pass if the visual has 
        /// a bitmap effect. Free the resources used to render the visual
        /// to a bitmap. 
        ///  
        /// 
        ///   The channel to release the resources on. 
        /// 
        internal void ReleaseOnChannelForBitmapEffect(
            DUCE.Channel channel)
        { 
            if (!IsOnChannel(channel)
                || CheckFlagsAnd(channel, VisualProxyFlags.IsDeleteResourceInProgress)) 
            { 
                return;
            } 

            // Set the flag to true to prevent re-entrancy.
            SetFlags(channel, true, VisualProxyFlags.IsDeleteResourceInProgress);
 
            try
            { 
                // at this point the tree is not connected any more. 
                SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent);
 
                FreeContent(channel);

                //
                // Free dependent DUCE resources. 
                //
                // We don't need to free the dependent resources if they're 
                // marked as dirty because when the flag is set, we also 
                // disconnect the resource from the visual resource.
 
                Brush opacityMask = OpacityMaskField.GetValue(this);
                if ((opacityMask != null)
                    && (!CheckFlagsAnd(channel, VisualProxyFlags.IsOpacityMaskDirty)))
                { 
                    ((DUCE.IResource)opacityMask).ReleaseOnChannel(channel);
                } 
 
                //
                // Release the visual. 
                //

                this.ReleaseOnChannelCore(channel);
 
                //
                // Finally, the children. 
                // 

                int count = VisualChildrenCount; 

                for (int i = 0; i < count; i++)
                {
                    Visual child = GetVisualChild(i); 
                    if (child != null)
                    { 
                        ((DUCE.IResource)child).ReleaseOnChannel(channel); 
                    }
                } 
            }
            finally
            {
                // 
                // We need to reset this flag if we are still on channel since we
                // have only decreased the ref-count and not deleted the resource. 
                // 
                if (IsOnChannel(channel))
                { 
                    SetFlags(channel, false, VisualProxyFlags.IsDeleteResourceInProgress);
                }
            }
        } 

        ///  
        /// Returns true if this is a root of a VisualBrush on the specified channel 
        /// 
        private bool IsVisualBrushRootOnChannel(DUCE.Channel channel) 
        {
            bool isVisualBrushRootOnChannel = false;

            Dictionary channelsToVisualBrushMap = 
              ChannelsToVisualBrushMapField.GetValue(this);
 
            if (channelsToVisualBrushMap != null) 
            {
                int references; 

                if (channelsToVisualBrushMap.TryGetValue(channel, out references))
                {
                    isVisualBrushRootOnChannel = (references > 0); 
                }
            } 
 
            return isVisualBrushRootOnChannel;
        } 

        /// 
        ///   Frees up resources in this visual's subtree.
        ///  
        /// 
        ///   The channel to release the resources on. 
        ///  
        void DUCE.IResource.ReleaseOnChannel(DUCE.Channel channel)
        { 
            if (!IsOnChannel(channel)
                || CheckFlagsAnd(channel, VisualProxyFlags.IsDeleteResourceInProgress))
            {
                return; 
            }
 
            // Set the flag to true to prevent re-entrancy. 
            SetFlags(channel, true, VisualProxyFlags.IsDeleteResourceInProgress);
 
            try
            {
                // at this point the tree is not connected any more.
                SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent); 

                // 
                // Before unmarshaling this visual and its subtree, check if there are any visual 
                // brushes holding references to it. In such case, we want to keep this visual
                // in the marshaled state and wait for all the visual brushes to release their 
                // references through ReleaseOnChannelForVisualBrush.
                //

                // 
                //
 
 

 



 

 
 

 



 

 
 

 
                if (   !CheckFlagsOr(VisualFlags.NodeIsVisualBrushRoot)
                            // If we aren't a root of a VisualBrush, then we aren't referenced
                            // at all and we can go away
                    || !channel.IsConnected 
                            // If the channel isn't connected, there's no reason to keep things alive
                    || channel.IsSynchronous 
                            // If the channel is synchronous, the node isn't going to stick around 
                            // so just delete it. *** THIS IS DANGEROUS ***. See above for
                            // more comments. 
                    || !IsVisualBrushRootOnChannel(channel)
                            // If we got to here, we are the root of a VisualBrush. We can go away
                            // only if the VB is on a different channel. This check is more expensive
                            // and not very common so we put it last. 
                       )
                { 
                    FreeContent(channel); 

                    // Free dependent DUCE resources. 
                    //
                    // We don't need to free the dependent resources if they're
                    // marked as dirty because when the flag is set, we also
                    // disconnect the resource from the visual resource. 

                    Transform transform = TransformField.GetValue(this); 
                    if ((transform != null) 
                        && (!CheckFlagsAnd(channel, VisualProxyFlags.IsTransformDirty)))
                    { 
                        //
                        // Note that in this particular case, the transform is not
                        // really dirty. Namely because the visual is not marshalled.
                        // 

                        ((DUCE.IResource)transform).ReleaseOnChannel(channel); 
                    } 

                    Geometry clip = ClipField.GetValue(this); 
                    if ((clip != null)
                        && (!CheckFlagsAnd(channel, VisualProxyFlags.IsClipDirty)))
                    {
                        ((DUCE.IResource)clip).ReleaseOnChannel(channel); 
                    }
 
                    // 
                    // If the visual has a bitmap effect we don't send the opacity mask
                    // to the async compositor, so we should not try and release it. 
                    // We apply the effect above opacity mask.
                    //
                    if (!CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect))
                    { 
                        Brush opacityMask = OpacityMaskField.GetValue(this);
                        if ((opacityMask != null) 
                            && (!CheckFlagsAnd(channel, VisualProxyFlags.IsOpacityMaskDirty))) 
                        {
                            ((DUCE.IResource)opacityMask).ReleaseOnChannel(channel); 
                        }
                    }

                    // 
                    // Release the visual.
                    // 
 
                    this.ReleaseOnChannelCore(channel);
 
                    //
                    // Finally, the children.
                    //
                    int count = VisualChildrenCount; 

                    for (int i = 0; i < count; i++) 
                    { 
                        Visual visual = GetVisualChild(i);
                        if (visual != null) 
                        {
                            ((DUCE.IResource)visual).ReleaseOnChannel(channel);
                        }
                    } 
                }
            } 
            finally 
            {
                // 
                // We need to reset this flag if we are still on channel since we
                // have only decreased the ref-count and not deleted the resource.
                //
                if (IsOnChannel(channel)) 
                {
                    SetFlags(channel, false, VisualProxyFlags.IsDeleteResourceInProgress); 
                } 
            }
        } 

        /// 
        /// When we attach a bitmap effect to a Visual we are going to render everything
        /// below the bitmap effect on the synchronous compositor. Therefore we need to 
        /// disconnect/reset all the properties below the bitmap effect property on a
        /// Visual in the asynchronous compositor since otherwise they would be applied 
        /// twice (on the sync and async compositor). 
        ///
        /// The properties are content, children, opacity, opacity mask and edge mode 
        /// 
        private void DisconnectBitmapEffectPropertiesOnAllChannels()
        {
            // disconnect the visual properties and content 

            double opacity = OpacityCache; 
            Brush opacityMask = OpacityMaskField.GetValue(this); 
            EdgeMode edgeMode = EdgeModeCache;
 
            //
            // Iterate over the channels this visual is being marshaled to
            //
            for (int iProxy = 0; iProxy < _proxy.Count; iProxy++) 
            {
                DUCE.Channel channel = _proxy.GetChannel(iProxy); 
                DUCE.ResourceHandle visualHandle = _proxy.GetHandle(iProxy); 

                //Release content 
                FreeContent(channel);

                //Reset opacity to 1.0
                DUCE.CompositionNode.SetAlpha( 
                        visualHandle,
                        1.0, 
                        channel); 

                // Reset render options 
                MILRenderOptions renderOptions = new MILRenderOptions();

                renderOptions.Flags = MILRenderOptionFlags.EdgeMode;
                renderOptions.EdgeMode = EdgeMode.Unspecified; 
                renderOptions.Flags = MILRenderOptionFlags.BitmapScalingMode;
                renderOptions.BitmapScalingMode    = BitmapScalingMode.Unspecified; 
 
                DUCE.CompositionNode.SetRenderOptions(
                   visualHandle, 
                    renderOptions,
                    channel);
            }
 
            if (opacityMask != null)
            { 
 
                //Disconnect OpacityMask
                DisconnectAttachedResource( 
                    VisualProxyFlags.IsOpacityMaskDirty,
                    opacityMask);
            }
 
            // disconnect all the children
            DisconnectChildrenOnAllChannels(); 
        } 

        ///  
        /// Disconnect the children of the visual on all channels
        /// it is being marshalled to.
        /// 
        private void DisconnectChildrenOnAllChannels() 
        {
            // if we don't have any children, there is nothing to do 
            if (VisualChildrenCount == 0) 
                return;
 
            //
            // Iterate over the channels this visual is being marshaled to
            //
            for (int iProxy = 0; iProxy < _proxy.Count; iProxy++) 
            {
                DUCE.Channel channel = _proxy.GetChannel(iProxy); 
 
                int childrenCount = VisualChildrenCount;
                for (int iChild = 0; iChild < childrenCount; iChild++) 
                {
                    Visual child = GetVisualChild(iChild);
                    if (child != null)
                    { 
                        if (child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent))
                        { 
                            channel.AddToRemoveAndReleaseQueue( 
                                this,
                                child); 

                            child.SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent);
                        }
                    } 
                }
            } 
        } 

        internal virtual void AddRefOnChannelForVisualBrush( 
            VisualBrush visualBrush,
            DUCE.Channel channel)
        {
 
            //
            // Since the VisualBrush to visual relationship is being created on this channel, 
            // we need to update the number of VisualBrushes using this visual on this channel. 
            //
            Dictionary channelsToVisualBrushMap = 
                ChannelsToVisualBrushMapField.GetValue(this);
            if (channelsToVisualBrushMap == null)
            {
                channelsToVisualBrushMap = new Dictionary(); 
                ChannelsToVisualBrushMapField.SetValue(this, channelsToVisualBrushMap);
            } 
 
            if (!channelsToVisualBrushMap.ContainsKey(channel))
            { 
                channelsToVisualBrushMap[channel] = 1;
            }
            else
            { 
                Debug.Assert(channelsToVisualBrushMap[channel] > 0);
 
                channelsToVisualBrushMap[channel] += 1; 
            }
 

            //
            // Since the VisualBrush to visual relationship is being created on this channel,
            // we need to update the number of times this visual brush is used across all 
            // channels.
            // 
            Dictionary visualBrushToChannelsMap = 
                VisualBrushToChannelsMapField.GetValue(this);
 
            if (visualBrushToChannelsMap == null)
            {
                visualBrushToChannelsMap = new Dictionary();
                VisualBrushToChannelsMapField.SetValue(this, visualBrushToChannelsMap); 
            }
 
            if (!visualBrushToChannelsMap.ContainsKey(visualBrush)) 
            {
                visualBrushToChannelsMap[visualBrush] = 1; 

                // The visual brush is being used the first time, so also register it.
                MediaContext.RegisterICompositionTarget(Dispatcher, visualBrush.BrushRegisterToken);
            } 
            else
            { 
                Debug.Assert(visualBrushToChannelsMap[visualBrush] > 0); 

                visualBrushToChannelsMap[visualBrush] += 1; 
            }


            // 
            // Render the brush's visual and update realizatons.
            // 
 
            visualBrush.RenderForVisualBrush(channel);
        } 


        /// 
        /// Override this function in derived classes to release unmanaged resources 
        /// during Dispose and during removal of a subtree.
        ///  
        internal virtual void ReleaseOnChannelForVisualBrush( 
            VisualBrush visualBrush,
            DUCE.Channel channel) 
        {
            // Update the number of times this visual brush uses this visual across all channels.
            Dictionary visualBrushToChannelsMap =
                VisualBrushToChannelsMapField.GetValue(this); 

            Debug.Assert(visualBrushToChannelsMap != null); 
            Debug.Assert(visualBrushToChannelsMap.ContainsKey(visualBrush)); 
            Debug.Assert(visualBrushToChannelsMap[visualBrush] > 0);
 

            if (visualBrushToChannelsMap[visualBrush] == 1)
            {
                // 
                // If the VisualBrush no longer uses this Visual across all channels, then
                // we can remove it from the map and also unregister as composition target. 
                // 
                visualBrushToChannelsMap.Remove(visualBrush);
 
                MediaContext.UnregisterICompositionTarget(Dispatcher, visualBrush.BrushRegisterToken);
            }
            else
            { 
                // Decrease the number os times this VisualBrush uses this Visual across all channels
                visualBrushToChannelsMap[visualBrush] = 
                    visualBrushToChannelsMap[visualBrush] - 1; 
            }
 
            // Decrease the number of VisualBrushes using the visual as root on this channel
            Dictionary channelsToVisualBrushMap =
                ChannelsToVisualBrushMapField.GetValue(this);
            Debug.Assert(channelsToVisualBrushMap != null); 
            Debug.Assert(channelsToVisualBrushMap.ContainsKey(channel));
            Debug.Assert(channelsToVisualBrushMap[channel] > 0); 
 
            channelsToVisualBrushMap[channel] =
                    channelsToVisualBrushMap[channel] - 1; 

            //
            // If on this channel, there are no more VisualBrushes using this visual as
            // a root then we need to remove the flag syaing that the visual is a visual 
            // brush root and make sure that the dependant resources are released in
            // case we are no longer connected to the visual tree. 
            // 

            if (channelsToVisualBrushMap[channel] == 0) 
            {
                channelsToVisualBrushMap.Remove(channel);

                SetFlags(false, VisualFlags.NodeIsVisualBrushRoot); 

                PropagateFlags( 
                    this, 
                    VisualFlags.NodeNeedsBitmapEffectUpdate,
                    VisualProxyFlags.IsSubtreeDirtyForRender); 

                //
                // If we do not have a parent or we have already disconnected from
                // the parent and we are also not the root then we need to clear out 
                // the tree.
                // 
                if ( (_parent == null 
                      || !CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent))
                    && !IsRootElement) 
                {
                    //
                    // We release the Visual directly on channel instead of using the delayed release
                    // mechanism because the VisualBrush is the last reference holding on to it. 
                    // We can get here if:-
                    // 1. VisualBrush is being released on channel (already in delayed release walk). 
                    // 2. VisualBrush's Visual is being changed (from VisualPropertyChanged). 
                    //
                    ((DUCE.IResource)this).ReleaseOnChannel(channel); 
                }
            }
        }
 
        #endregion Resource Marshalling and Unmarshalling
 
 
        // --------------------------------------------------------------------
        // 
        //   Access Verification
        //
        // --------------------------------------------------------------------
 
        #region Access Verification
 
        ///  
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadOnly()
        {
            // Verify that we are executing on the right context
            VerifyAccess(); 
        }
 
        ///  
        /// Applies various API checks
        ///  
        internal void VerifyAPIReadOnly(DependencyObject value)
        {
            VerifyAPIReadOnly();
 
            // Make sure the value is on the same context as the visual.
            // AssertSameContext handles null and Dispatcher-free values. 
            MediaSystem.AssertSameContext(this, value); 
        }
 
        /// 
        /// Applies various API checks for read/write
        /// 
        internal void VerifyAPIReadWrite() 
        {
            VerifyAPIReadOnly(); 
 
            // Verify the correct access permissions
            MediaContext.From(this.Dispatcher).VerifyWriteAccess(); 
        }

        /// 
        /// Applies various API checks 
        /// 
        internal void VerifyAPIReadWrite(DependencyObject value) 
        { 
            VerifyAPIReadWrite();
 
            // Make sure the value is on the same context as the visual.
            // AssertSameContext handles null and Dispatcher-free values.
            MediaSystem.AssertSameContext(this, value);
        } 

        #endregion Access Verification 
 
        // -------------------------------------------------------------------
        // 
        //   Pre-compute / render / realization passes
        //
        // --------------------------------------------------------------------
 
        #region Pre-compute / render / realization passes
 
        internal void Precompute() 
        {
            if (CheckFlagsAnd(VisualFlags.IsSubtreeDirtyForPrecompute)) 
            {
                // Disable processing of the queue during blocking operations to prevent unrelated reentrancy.
                using(Dispatcher.DisableProcessing())
                { 
                    MediaContext mediaContext = MediaContext.From(Dispatcher);
 
                    try 
                    {
                        mediaContext.PushReadOnlyAccess(); 

                        Rect bboxSubgraph;

                        PrecomputeRecursive(out bboxSubgraph); 
                    }
                    finally 
                    { 
                        mediaContext.PopReadOnlyAccess();
                    } 
                }
            }
        }
 
        /// 
        /// Derived class can do precomputations on their content by overriding this method. 
        /// Derived classes must call the base class. 
        /// 
        internal virtual void PrecomputeContent() 
        {
            _bboxSubgraph = GetHitTestBounds();

            // If bounding box has NaN, then we set the bounding box to infinity. 
            if (DoubleUtil.RectHasNaN(_bboxSubgraph))
            { 
                _bboxSubgraph.X = Double.NegativeInfinity; 
                _bboxSubgraph.Y = Double.NegativeInfinity;
                _bboxSubgraph.Width = Double.PositiveInfinity; 
                _bboxSubgraph.Height = Double.PositiveInfinity;
            }
        }
 
        internal void PrecomputeRecursive(out Rect bboxSubgraph)
        { 
            // Simple loop detection to avoid stack overflow in cyclic Visual 
            // scenarios. This fix is only aimed at mitigating a very common
            // VisualBrush scenario. 
            bool canEnter = Enter();

            if (canEnter)
            { 
                try
                { 
                    if (CheckFlagsAnd(VisualFlags.IsSubtreeDirtyForPrecompute)) 
                    {
                        // 
                        // We need to check which children need realization
                        // updates and/or ink tracking.
                        //
 
                        bool subTreeUsesRealizationCaches = false;
                        bool subTreeNeedsNewRealization = false; 
 
                        // Reset graphness flag, PrecomputeContent() may modify it
                        SetFlags(false, VisualFlags.NodeOrDescendantIntroducesGraphness); 

                        PrecomputeContent();

                        // 
                        // If we have a bitmap effect, we need full realizations
                        // 
                        if (VisualBitmapEffect != null) 
                        {
                            SetFlags(true, VisualFlags.NodeOrDescendantIntroducesGraphness); 
                        }

                        //
                        // VisualFlags.NodeOrDescendantIntroducesGraphness will now be 
                        // true if this node has its own graphness inducing content. We
                        // also need to check the children to see if they have graphness 
                        // inducing content 
                        //
                        bool nodeOrDescendantIntroducesGraphness = 
                            CheckFlagsAnd(VisualFlags.NodeOrDescendantIntroducesGraphness);

                        int childCount = VisualChildrenCount;
 
                        for (int i = 0; i < childCount; i++)
                        { 
                            Visual child = GetVisualChild(i); 
                            if (child != null)
                            { 
                                Rect bboxSubgraphChild;

                                child.PrecomputeRecursive(out bboxSubgraphChild);
 
                                _bboxSubgraph.Union(bboxSubgraphChild);
 
                                // 
                                // Does this subtree require realization updates
                                // and/or ink tracking? 
                                //

                                subTreeUsesRealizationCaches |=
                                    child.CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches); 

                                subTreeNeedsNewRealization |= 
                                    child.CheckFlagsAnd(VisualFlags.NodeInSubtreeRequiresNewRealization); 

                                nodeOrDescendantIntroducesGraphness |= 
                                    child.CheckFlagsAnd(VisualFlags.NodeOrDescendantIntroducesGraphness);
                            }
                        }
 
                        if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect))
                        { 
                            // 
                            // Special case for bitmap effects -- expand the bounding box
                            // and always require realization updates. 
                            //

                            _bboxSubgraph.Union(BitmapEffectStateField.GetValue(this).GetBounds(_bboxSubgraph));
 
                            SetFlags(true, VisualFlags.NodeUsesRealizationCaches);
                        } 
 
                        // Propagate graphness flag
                        SetFlags(nodeOrDescendantIntroducesGraphness, VisualFlags.NodeOrDescendantIntroducesGraphness); 

                        //
                        // Update the per-instance visual flags with the new information
                        // about the need to perform realization updates and track ink. 
                        //
 
                        subTreeUsesRealizationCaches |= CheckFlagsAnd(VisualFlags.NodeUsesRealizationCaches); 
                        SetFlags(subTreeUsesRealizationCaches, VisualFlags.NodeInSubtreeUsesRealizationCaches);
 
                        //
                        // Having recursed into the subgraph, we now know definitively whether this node
                        // or its children contain realizations. We need to set the NodeInSubtreeRequiresNewRealization
                        // flags appropriately to allow the MarkVisibleRealization walk to follow the path to the 
                        // nodes which require new realizations (NodeRequiresNewRealization, which was set when an
                        // operation requiring new realizations occurred). 
                        // 
                        if (!CheckFlagsOr(VisualFlags.NodeUsesRealizationCaches | VisualFlags.NodeInSubtreeUsesRealizationCaches))
                        { 
                            SetFlags(false, VisualFlags.NodeRequiresNewRealization);
                        }
                        SetFlags((subTreeNeedsNewRealization && subTreeUsesRealizationCaches) || CheckFlagsAnd(VisualFlags.NodeRequiresNewRealization),
                                 VisualFlags.NodeInSubtreeRequiresNewRealization); 

                        SetFlags(false, VisualFlags.IsSubtreeDirtyForPrecompute); 
                    } 

                    // Bounding boxes are cached in inner space (below offset, transform, and clip). 
                    // Before returning them we need
                    // to transform them into outer space.

                    bboxSubgraph = _bboxSubgraph; 

                    Geometry clip = ClipField.GetValue(this); 
                    if (clip != null) 
                    {
                        bboxSubgraph.Intersect(clip.Bounds); 
                    }

                    Transform transform = TransformField.GetValue(this);
 
                    if ((transform != null) && (!transform.IsIdentity))
                    { 
                        Matrix m = transform.Value; 
                        MatrixUtil.TransformRect(ref bboxSubgraph, ref m);
                    } 

                    if (!bboxSubgraph.IsEmpty)
                    {
                        bboxSubgraph.X += _offset.X; 
                        bboxSubgraph.Y += _offset.Y;
                    } 
 
                    // If child's bounding box has NaN, then we set the bounding box to infinity.
                    if (DoubleUtil.RectHasNaN(bboxSubgraph)) 
                    {
                        bboxSubgraph.X = Double.NegativeInfinity;
                        bboxSubgraph.Y = Double.NegativeInfinity;
                        bboxSubgraph.Width = Double.PositiveInfinity; 
                        bboxSubgraph.Height = Double.PositiveInfinity;
                    } 
                } 
                finally
                { 
                    Exit();
                }
            }
            else 
            {
                bboxSubgraph = new Rect(); 
            } 
        }
 
        internal void Render(RenderContext ctx, UInt32 childIndex)
        {
            DUCE.Channel channel = ctx.Channel;
 
            //
            // Currently everything is sent to the compositor. IsSubtreeDirtyForRender 
            // indicates that something in the sub-graph of this Visual needs to have an update 
            // sent to the compositor. Hence traverse if this bit is set. Also traverse when the
            // sub-graph has not yet been sent to the compositor. 
            //

            if (CheckFlagsAnd(channel, VisualProxyFlags.IsSubtreeDirtyForRender)
                || !IsOnChannel(channel)) 
            {
                RenderRecursive(ctx); 
            } 

 
            //
            // Connect the root visual to the composition root if necessary.
            //
 
            if (IsOnChannel(channel)
                && !CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent) 
                && !ctx.Root.IsNull) 
            {
                DUCE.CompositionNode.InsertChildAt( 
                    ctx.Root,
                    _proxy.GetHandle(channel),
                    childIndex,
                    channel); 

                SetFlags( 
                    channel, 
                    true,
                    VisualProxyFlags.IsConnectedToParent); 
            }
        }

        ///  
        /// This is only called during the realization pass if the visual has
        /// a bitmap effect. It only renders opacity, opacity mask, content and 
        /// children of the visual. The effect is applied below transform, 
        /// clip, offset and guidelines. Those properties are updated during
        /// the render pass 
        /// 
        /// 
        /// 
        internal void RenderForBitmapEffect(RenderContext ctx, UInt32 childIndex) 
        {
            DUCE.Channel channel = ctx.Channel; 
 
            //
            // See if this visual is already on that channel 
            //
            bool isOnChannel = IsOnChannel(channel);

            // 
            // Currently everything is sent to the compositor. IsSubtreeDirtyForRender
            // indicates that something in the sub-graph of this Visual needs to have an update 
            // sent to the compositor. Hence traverse if this bit is set. Also traverse when the 
            // sub-graph has not yet been sent to the compositor.
            // 

            if (CheckFlagsAnd(channel, VisualProxyFlags.IsSubtreeDirtyForRender)
                || !isOnChannel)
            { 
                //
                // Ensure that the visual resource for this Visual 
                // is being sent to our current channel. 
                //
 
                DUCE.ResourceHandle handle = isOnChannel ?
                    _proxy.GetHandle(channel) :
                    ((DUCE.IResource)this).AddRefOnChannel(channel);
 
                VisualProxyFlags flags = isOnChannel ?
                    _proxy.GetFlags(channel) : 
                    c_ProxyFlagsDirtyMask; 

                if (!isOnChannel) 
                {
                    // we need to set the Viewport3D flags, if the visual is not
                    // on channel so that the viewport sends all its resources
                    // to the compositor 
                    SetFlags(channel, true, c_Viewport3DProxyFlagsDirtyMask);
                } 
 
                // Do the updates
 
                UpdateContent(ctx, flags, isOnChannel);
                UpdateOpacity(channel, handle, flags, isOnChannel);
                UpdateOpacityMask(channel, handle, flags, isOnChannel);
                UpdateChildren(ctx, handle); 

                // 
                // Finally, reset the dirty flags for this visual (at this point, 
                // we have handled them all).
                // 
                SetFlags(channel, false, VisualProxyFlags.IsSubtreeDirtyForRender);
            }

 
            //
            // Connect the root visual to the composition root if necessary. 
            // 

            if (IsOnChannel(channel) 
                && !CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent)
                && !ctx.Root.IsNull)
            {
                DUCE.CompositionNode.InsertChildAt( 
                    ctx.Root,
                    _proxy.GetHandle(channel), 
                    childIndex, 
                    channel);
 
                SetFlags(
                    channel,
                    true,
                    VisualProxyFlags.IsConnectedToParent); 
            }
        } 
 
        internal virtual void RenderRecursive(
            RenderContext ctx) 
        {
            // Simple loop detection to avoid stack overflow in cyclic Visual
            // scenarios. This fix is only aimed at mitigating a very common
            // VisualBrush scenario. 
            bool canEnter = Enter();
 
            if (canEnter) 
            {
                try 
                {
                    DUCE.Channel channel = ctx.Channel;
                    DUCE.ResourceHandle handle = DUCE.ResourceHandle.Null;
                    VisualProxyFlags flags = VisualProxyFlags.None; 

                    // 
                    // See if this visual is already on that channel 
                    //
 
                    bool isOnChannel = IsOnChannel(channel);

                    //
                    // Ensure that the visual resource for this Visual 
                    // is being sent to our current channel.
                    // 
 
                    if (isOnChannel)
                    { 
                        //
                        // Good, we're already on channel. Get the handle and flags.
                        //
 
                        handle = _proxy.GetHandle(channel);
                        flags = _proxy.GetFlags(channel); 
                    } 
                    else
                    { 
                        //
                        // Create the visual resource on the current channel.
                        //
                        // Need to update all set properties. 
                        //
 
                        handle = ((DUCE.IResource)this).AddRefOnChannel(channel); 

                        // we need to set the Viewport3D flags, if the visual is not 
                        // on channel so that the viewport sends all its resources
                        // to the compositor. we need the explicit set, because
                        // the update happens during RenderContent and we have no
                        // other way to pass the flags 
                        //
                        // We do that for all visuals. the flags will be ignored 
                        // if the visual is not a Viewport3D visual 
                        SetFlags(channel, true, c_Viewport3DProxyFlagsDirtyMask);
 
                        flags = c_ProxyFlagsDirtyMask;
                    }

                    UpdateTransform(channel, handle, flags, isOnChannel); 
                    UpdateClip(channel, handle, flags, isOnChannel);
                    UpdateOffset(channel, handle, flags, isOnChannel); 
                    UpdateGuidelines(channel, handle, flags, isOnChannel); 

                    // if we have a bitmap effect, mark the effect as dirty 
                    // we will render the rest of the visual during
                    // the realization pass
                    if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect))
                    { 

                        // if the visual content is dirty or the subtree is dirty for render 
                        // or the opacity or opacity mask changed, 
                        // we would want to re-apply the effect during the realisation pass
                        if (((flags & c_BitmapEffectDirtyMask) != 0) || 
                            CheckFlagsAnd(VisualFlags.NodeNeedsBitmapEffectUpdate))
                        {
                            SetFlags(channel, true, VisualProxyFlags.IsBitmapEffectDirty);
                        } 
                    }
                    else 
                    { 
                        UpdateContent(ctx, flags, isOnChannel);
                        UpdateOpacity(channel, handle, flags, isOnChannel); 
                        UpdateOpacityMask(channel, handle, flags, isOnChannel);
                        UpdateRenderOptions(channel, handle, flags, isOnChannel);
                        UpdateChildren(ctx, handle);
                    } 

                    // 
                    // Finally, reset the dirty flags for this visual (at this point, 
                    // we have handled them all).
                    SetFlags(channel, false, VisualProxyFlags.IsSubtreeDirtyForRender); 
                    SetFlags(false, VisualFlags.NodeNeedsBitmapEffectUpdate);
                }
                finally
                { 
                    Exit();
                } 
            } 
        }
 
        /// 
        /// Enter is used for simple cycle detection in Visual. If the method returns false
        /// the Visual has already been entered and cannot be entered again. Matching invocation of Exit
        /// must be skipped if Enter returns false. 
        /// 
        internal bool Enter() 
        { 
            if (CheckFlagsAnd(VisualFlags.ReentrancyFlag))
            { 
                return false;
            }
            else
            { 
                SetFlags(true, VisualFlags.ReentrancyFlag);
                return true; 
            } 
        }
 
        /// 
        /// Exits the Visual. For more details see Enter method.
        /// 
        internal void Exit() 
        {
            Debug.Assert(CheckFlagsAnd(VisualFlags.ReentrancyFlag)); // Exit must be matched with Enter. See Enter comments. 
            SetFlags(false, VisualFlags.ReentrancyFlag); 
        }
 
        /// 
        /// Update opacity
        /// 
        ///  
        /// 
        ///  
        ///  
        private void UpdateOpacity(DUCE.Channel channel,
                                   DUCE.ResourceHandle handle, 
                                   VisualProxyFlags flags,
                                   bool isOnChannel)
        {
            // Opacity --------------------------------------------------------------------------- 
            if ((flags & VisualProxyFlags.IsOpacityDirty) != 0)
            { 
                double opacity = OpacityCache; 

                if (isOnChannel || !(opacity >= 1.0)) 
                {
                    //
                    // Opacity is 1.0 by default -- do not send it for new visuals.
                    // 

                    DUCE.CompositionNode.SetAlpha( 
                        handle, 
                        opacity,
                        channel); 
                }
                SetFlags(channel, false, VisualProxyFlags.IsOpacityDirty);
            }
        } 

        ///  
        /// Update OpacityMask 
        /// 
        ///  
        /// 
        /// 
        /// The Visual exists on channel.
        private void UpdateOpacityMask(DUCE.Channel channel, 
                                       DUCE.ResourceHandle handle,
                                       VisualProxyFlags flags, 
                                       bool isOnChannel) 
        {
            // Opacity Mask --------------------------------------------------------------------------- 

            if ((flags & VisualProxyFlags.IsOpacityMaskDirty) != 0)
            {
                Brush opacityMask = OpacityMaskField.GetValue(this); 

                if (opacityMask != null) 
                { 
                    //
                    // Set the new opacity mask resource on the visual. 
                    // If opacityMask is null we don't need to do this.
                    // Also note that the old opacity mask was disconnected
                    // in the OpacityMask property setter.
                    // 

                    DUCE.CompositionNode.SetAlphaMask( 
                        handle, 
                        ((DUCE.IResource)opacityMask).AddRefOnChannel(channel),
                        channel); 
                }
                else if (isOnChannel) /* opacityMask == null */
                {
                    DUCE.CompositionNode.SetAlphaMask( 
                        handle,
                        DUCE.ResourceHandle.Null, 
                        channel); 
                }
                SetFlags(channel, false, VisualProxyFlags.IsOpacityMaskDirty); 
            }

        }
 
        /// 
        /// Update transform 
        ///  
        /// 
        ///  
        /// 
        /// The Visual exists on channel.
        private void UpdateTransform(DUCE.Channel channel,
                                     DUCE.ResourceHandle handle, 
                                     VisualProxyFlags flags,
                                     bool isOnChannel) 
        { 
            // Transform -------------------------------------------------------------------------------
 
            if ((flags & VisualProxyFlags.IsTransformDirty) != 0)
            {
                Transform transform = TransformField.GetValue(this);
 
                if (transform != null)
                { 
                    // 
                    // Set the new transform resource on the visual.
                    // If transform is null we don't need to do this. 
                    // Also note that the old transform was disconnected
                    // in the Transform property setter.
                    //
 
                    DUCE.CompositionNode.SetTransform(
                        handle, 
                        ((DUCE.IResource)transform).AddRefOnChannel(channel), 
                        channel);
                } 
                else if (isOnChannel) /* transform == null */
                {
                    DUCE.CompositionNode.SetTransform(
                        handle, 
                        DUCE.ResourceHandle.Null,
                        channel); 
                } 
                SetFlags(channel, false, VisualProxyFlags.IsTransformDirty);
            } 
        }

        /// 
        /// Update clip 
        /// 
        ///  
        ///  
        /// 
        /// The Visual exists on channel. 
        private void UpdateClip(DUCE.Channel channel,
                                DUCE.ResourceHandle handle,
                                VisualProxyFlags flags,
                                bool isOnChannel) 
        {
            // Clip ------------------------------------------------------------------------------------ 
 
            if ((flags & VisualProxyFlags.IsClipDirty) != 0)
            { 
                Geometry clip = ClipField.GetValue(this);

                if (clip != null)
                { 
                    //
                    // Set the new clip resource on the composition node. 
                    // If clip is null we don't need to do this.  Also note 
                    // that the old clip was disconnected in the Clip
                    // property setter. 
                    //

                    DUCE.CompositionNode.SetClip(
                        handle, 
                        ((DUCE.IResource)clip).AddRefOnChannel(channel),
                        channel); 
                } 
                else if (isOnChannel) /* clip == null */
                { 
                    DUCE.CompositionNode.SetClip(
                        handle,
                        DUCE.ResourceHandle.Null,
                        channel); 
                }
 
                SetFlags(channel, false, VisualProxyFlags.IsClipDirty); 
            }
        } 

        /// 
        /// Update offset
        ///  
        /// 
        ///  
        ///  
        /// 
        private void UpdateOffset(DUCE.Channel channel, 
                                  DUCE.ResourceHandle handle,
                                  VisualProxyFlags flags,
                                  bool isOnChannel)
        { 
            // Offset -------------------------------------------------------------------------------------------
 
            if ((flags & VisualProxyFlags.IsOffsetDirty) != 0) 
            {
                if (isOnChannel || _offset != new Vector()) 
                {
                    //
                    // Offset is (0, 0) by default so do not update it for new visuals.
                    // 

                    DUCE.CompositionNode.SetOffset( 
                        handle, 
                        _offset.X,
                        _offset.Y, 
                        channel);
                }
                SetFlags(channel, false, VisualProxyFlags.IsOffsetDirty);
            } 
        }
 
        ///  
        /// Update guidelines
        ///  
        /// 
        /// 
        /// 
        ///  
        private void UpdateGuidelines(DUCE.Channel channel,
                                      DUCE.ResourceHandle handle, 
                                      VisualProxyFlags flags, 
                                      bool isOnChannel)
        { 
            // Guidelines --------------------------------------------------------------------

            if ((flags & VisualProxyFlags.IsGuidelineCollectionDirty) != 0)
            { 
                DoubleCollection guidelinesX = GuidelinesXField.GetValue(this);
                DoubleCollection guidelinesY = GuidelinesYField.GetValue(this); 
 
                if (isOnChannel || (guidelinesX != null || guidelinesY != null))
                { 
                    //
                    // Guidelines are null by default, so do not update them for new visuals.
                    //
 
                    DUCE.CompositionNode.SetGuidelineCollection(
                        handle, 
                        guidelinesX, 
                        guidelinesY,
                        channel); 
                }
                SetFlags(channel, false, VisualProxyFlags.IsGuidelineCollectionDirty);
            }
 
        }
 
        ///  
        /// Update EdgeMode
        ///  
        /// 
        /// 
        /// 
        ///  
        private void UpdateRenderOptions(DUCE.Channel channel,
                                    DUCE.ResourceHandle handle, 
                                    VisualProxyFlags flags, 
                                    bool isOnChannel)
        { 
            if (((flags & VisualProxyFlags.IsEdgeModeDirty) != 0) || ((flags & VisualProxyFlags.IsBitmapScalingModeDirty) != 0))
            {
                 MILRenderOptions renderOptions = new MILRenderOptions();
 
                // EdgeMode ----------------------------------------------------------------------------
                // "isOnChannel" (if true) indicates that this Visual was on channel 
                // previous to this update.  If this is the case, all changes to the EdgeMode 
                // must be reflected in the composition node.  If "isOnChannel" is false it means
                // that this Visual has just been added to a channel.  In this case, we can 
                // skip an EdgeMode update if the EdgeMode is Unspecified, as this is the default
                // behavior.
                if (isOnChannel || (EdgeModeCache != EdgeMode.Unspecified))
                { 
                    renderOptions.Flags |= MILRenderOptionFlags.EdgeMode;
                    renderOptions.EdgeMode = EdgeModeCache; 
                } 

                // ImageScalingMode --------------------------------------------------------------------------- 
                if (isOnChannel || (BitmapScalingModeCache != BitmapScalingMode.Unspecified))
                {
                    renderOptions.Flags |= MILRenderOptionFlags.BitmapScalingMode;
                    renderOptions.BitmapScalingMode    = BitmapScalingModeCache; 
                }
 
                if (renderOptions.Flags != 0) 
                {
                    DUCE.CompositionNode.SetRenderOptions( 
                        handle,
                        renderOptions,
                        channel);
                } 
                SetFlags(channel, false, VisualProxyFlags.IsEdgeModeDirty | VisualProxyFlags.IsBitmapScalingModeDirty);
            } 
        } 

        ///  
        /// Update content
        /// 
        /// 
        ///  
        /// The Visual exists on channel.
        private void UpdateContent(RenderContext ctx, 
                                   VisualProxyFlags flags, 
                                   bool isOnChannel)
        { 
            //
            // Hookup content to the Visual
            //
 
            if ((flags & VisualProxyFlags.IsContentDirty) != 0)
            { 
                RenderContent(ctx, isOnChannel); 
                SetFlags(ctx.Channel, false, VisualProxyFlags.IsContentDirty);
            } 
        }

        /// 
        /// Update children 
        /// 
        ///  
        ///  
        private void UpdateChildren(RenderContext ctx,
                                    DUCE.ResourceHandle handle) 
        {
            DUCE.Channel channel = ctx.Channel;

            // 
            // Visit children of this visual.
            // 
            // 
            // If content node is connected child node indicies need to be offset by one.
            // 

            UInt32 connectedChildIndex =
                CheckFlagsAnd(channel, VisualProxyFlags.IsContentNodeConnected) ? (UInt32)1 : 0;
 

            int childCount = VisualChildrenCount; 
 
            for (int i = 0; i < childCount; i++)
            { 
                Visual child = GetVisualChild(i);
                if (child != null)
                {
                    // 
                    // Recurse if the child visual is dirty
                    // or it has not been marshalled yet. 
                    // 
                    if (child.CheckFlagsAnd(channel, VisualProxyFlags.IsSubtreeDirtyForRender)
                        || !(child.IsOnChannel(channel))) 
                    {
                        child.RenderRecursive(ctx);
                    }
 

                    // 
                    // Make sure that all the marshaled children are 
                    // connected to the parent visual.
                    // 

                    if (child.IsOnChannel(channel))
                    {
                        if (!child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent)) 
                        {
                            DUCE.CompositionNode.InsertChildAt( 
                                handle, 
                                ((DUCE.IResource)child).GetHandle(channel),
                                connectedChildIndex, 
                                channel);

                            child.SetFlags(
                                channel, 
                                true,
                                VisualProxyFlags.IsConnectedToParent); 
                        } 

                        connectedChildIndex++; 
                    }
                }
            }
 
        }
 
 
        /// 
        /// Marks the visible realizations in this visual graph. 
        /// 
        /// The realization context.
        /// 
        ///  
        internal void MarkVisibleRealizations(RealizationContext ctx)
        { 
            Debug.Assert(IsOnChannels(ctx.Channels)); 

            if (    CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches) 
                 || CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect))
            {
                MarkVisibleRealizationsRecursive(ctx);
            } 
        }
 
        internal bool RequiresRealizationUpdates 
        {
            get 
            {
                return CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches);
            }
        } 

 
 
        /// 
        /// Marks the visible realizations in this visual graph. 
        /// This is only called during the realization pass if the visual has
        /// a bitmap effect.
        /// 
        /// The realization context. 
        /// 
        ///  
        internal void MarkVisibleRealizationsForBitmapEffect(RealizationContext ctx) 
        {
            // ---------------------------------------------------------------- 
            // Update realizations.

            if (CheckFlagsAnd(VisualFlags.NodeUsesRealizationCaches))
            { 
                UpdateRealizations(ctx);
            } 
 
            // ---------------------------------------------------------------
            // Recurse into the visible part of the subgraph. 

            MarkVisibleRealizationsForChildren(ctx);
        }
 
        /// 
        /// Performs a recursive walk of the visible part of this visual graph, 
        /// marking the realization nodes to be created or updated. 
        /// 
        ///  
        /// Do not call this method directly.
        /// 
        /// The realization context.
        ///  
        private void MarkVisibleRealizationsRecursive(RealizationContext ctx)
        { 
            // Simple loop detection to avoid stack overflow in cyclic Visual 
            // scenarios. This fix is only aimed at mitigating a very common
            // VisualBrush scenario. 
            bool canEnter = Enter();

            if (canEnter)
            { 
                try
                { 
#if TRACE 
                    MarkVisibleRealizationsCount++;
#endif 

                    // ---------------------------------------------------------------
                    // Update the transform stack (needed by UpdateRealizations).
 
                    //push offset
                    if (_offset != new Vector()) 
                    { 
                        ctx.TransformStack.Push(_offset, true);
                    } 

                    Transform transform = TransformField.GetValue(this);

                    if (transform != null) 
                    {
                        ctx.TransformStack.Push(transform, true); 
                    } 

                    if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect)) 
                    {
                        // if the visual has a bitmap effect, update the realizations.
                        UpdateBitmapEffectRealizations(ctx);
                    } 
                    else
                    { 
                        bool nodeRequiresNewRealization = CheckFlagsAnd(VisualFlags.NodeRequiresNewRealization); 
                        // ---------------------------------------------------------------
                        // Update realizations if NodeUsesRealizationCaches is true and 
                        // we're either doing a full walk (!ctx.IncrementalWalk) or
                        // we're doing an incremental walk and the node actually requires
                        // new realizations (nodeRequiresNewRealization)
                        if (   CheckFlagsAnd(VisualFlags.NodeUsesRealizationCaches) 
                            && (!ctx.IncrementalWalk || nodeRequiresNewRealization))
 
                        { 
                            UpdateRealizations(ctx);
                            ctx.CheckVisualRequiresNextFrameRealizations(this); 
                        }

                        if (nodeRequiresNewRealization)
                        { 
                           // Need to walk all children containing realizations since
                           // this node has had a realizations impacting change 
                           ctx.DisableIncrementalWalk(); 
                        }
 
                        MarkVisibleRealizationsForChildren(ctx);

                        if (nodeRequiresNewRealization)
                        { 
                            ctx.EnableIncrementalWalk();
                        } 
                    } 

                    // ---------------------------------------------------------------- 
                    // Clean up.

                    if (transform != null)
                    { 
                        ctx.TransformStack.Pop();
                    } 
 
                    // pop offset
                    if (_offset != new Vector()) 
                    {
                        ctx.TransformStack.Pop();
                    }
                } 
                finally
                { 
                    // Normally, we reset the flags for node realization to avoid redundant processing of realizations. 
                    // However, in the case of a bitmap render (RenderTargetBitmap), don't reset the flags here, since
                    // we would still need to apply the realizations when a regular render occurs later. 
                    if (!ctx.WalkForBitmapRenderTarget)
                    {
                        SetFlags(false, VisualFlags.NodeRequiresNewRealization | VisualFlags.NodeInSubtreeRequiresNewRealization);
                    } 
                    Exit();
                } 
            } 
        }
 
        /// 
        /// MarkVisibleRealizations for all the children
        /// 
        ///  
        private void MarkVisibleRealizationsForChildren(RealizationContext ctx)
        { 
            // --------------------------------------------------------------- 
            // Recurse into the visible part of the subgraph.
            int childrenCount = this.VisualChildrenCount; 

            for (int i = 0; i < childrenCount; i++)
            {
                Visual child = this.GetVisualChild(i); 

                // Skip this node if currently not on the channel or 
                // if there is nothing to be updated on its subtree. 
                // If this walk is incremental, then walk child
                // only if subtree has a node requiring a new realization 
                if (child != null
                    && child.CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches)
                    && (!ctx.IncrementalWalk
                        || child.CheckFlagsOr(VisualFlags.NodeInSubtreeRequiresNewRealization))) 
                {
                    Debug.Assert(child.IsOnChannels(ctx.Channels)); 
 
                    child.MarkVisibleRealizationsRecursive(ctx);
                } 
            }
        }

        #endregion Pre-compute / render / realization passes 

 
 
        // --------------------------------------------------------------------
        // 
        //   Hit Testing
        //
        // --------------------------------------------------------------------
 
        #region Hit Testing
 
        internal class TopMostHitResult 
        {
            internal HitTestResult _hitResult = null; 

            internal HitTestResultBehavior HitTestResult(HitTestResult result)
            {
                _hitResult = result; 

                return HitTestResultBehavior.Stop; 
            } 

            internal HitTestFilterBehavior NoNested2DFilter(DependencyObject potentialHitTestTarget) 
            {
                if (potentialHitTestTarget is Viewport2DVisual3D)
                {
                    return HitTestFilterBehavior.ContinueSkipChildren; 
                }
 
                return HitTestFilterBehavior.Continue; 
            }
        } 


        /// 
        /// Used by derived classes to invalidate their hit-test bounds. 
        /// 
        internal void InvalidateHitTestBounds() 
        { 
            VerifyAPIReadWrite();
 
            PropagateFlags(
                this,
                VisualFlags.IsSubtreeDirtyForPrecompute,
                VisualProxyFlags.None); 
        }
 
 
        /// 
        /// Derived classes return the hit-test bounding box from the 
        /// GetHitTestBounds virtual. Visual uses the bounds to optimize
        /// hit-testing.
        /// 
        internal virtual Rect GetHitTestBounds() 
        {
            return GetContentBounds(); 
        } 

 
        /// 
        /// Return top most visual of a hit test.
        /// 
        internal HitTestResult HitTest(Point point) 
        {
            return HitTest(point, true); 
        } 

        ///  
        /// Return top most visual of a hit test.  If include2DOn3D is true we will
        /// hit test in to 2D on 3D children, otherwise we will ignore that part of
        /// the tree.
        ///  
        internal HitTestResult HitTest(Point point, bool include2DOn3D)
        { 
            // 

            TopMostHitResult result = new TopMostHitResult(); 

            VisualTreeHelper.HitTest(
                this,
                include2DOn3D? null : new HitTestFilterCallback(result.NoNested2DFilter), 
                new HitTestResultCallback(result.HitTestResult),
                new PointHitTestParameters(point)); 
 
            return result._hitResult;
        } 

        /// 
        /// Initiate a hit test using delegates.
        ///  
        internal void HitTest(
            HitTestFilterCallback filterCallback, 
            HitTestResultCallback resultCallback, 
            HitTestParameters hitTestParameters)
        { 
            if (resultCallback == null)
            {
                throw new ArgumentNullException("resultCallback");
            } 

            if (hitTestParameters == null) 
            { 
                throw new ArgumentNullException("hitTestParameters");
            } 

            VerifyAPIReadWrite();

            Precompute(); 

            PointHitTestParameters pointParams = hitTestParameters as PointHitTestParameters; 
 
            if (pointParams != null)
            { 
                // Because we call dynamic code during the hit testing walk we need to back up
                // the original hit point in case the user's delegate throws an exception so that
                // we can restore it.
                Point backupHitPoint = pointParams.HitPoint; 

                try 
                { 
                    HitTestPoint(filterCallback, resultCallback, pointParams);
                } 
                catch
                {
                    // If an exception occured, restore the user's hit point and rethrow.
                    pointParams.SetHitPoint(backupHitPoint); 

                    throw; 
                } 
                finally
                { 
                    Debug.Assert(Point.Equals(pointParams.HitPoint, backupHitPoint),
                        "Failed to restore user's hit point back to the original coordinate system.");
                }
            } 
            else
            { 
                GeometryHitTestParameters geometryParams = hitTestParameters as GeometryHitTestParameters; 

                if (geometryParams != null) 
                {
                    // Because we call dynamic code during the hit testing walk we need to ensure
                    // that if the user's delegate throws an exception we restore the original
                    // transform on the hit test geometry. 
#if DEBUG
                    // Internally we replace the hit geometry with a copy which is guaranteed to have 
                    // a MatrixTransform so we do not need to worry about null dereferences here. 
                    Matrix originalMatrix = geometryParams.InternalHitGeometry.Transform.Value;
#endif // DEBUG 
                    try
                    {
                        HitTestGeometry(filterCallback, resultCallback, geometryParams);
                    } 
                    catch
                    { 
                        geometryParams.EmergencyRestoreOriginalTransform(); 

                        throw; 
                    }
#if DEBUG
                    finally
                    { 
                        Debug.Assert(Matrix.Equals(geometryParams.InternalHitGeometry.Transform.Value, originalMatrix),
                            "Failed to restore user's hit geometry back to the original coordinate system."); 
                    } 
#endif // DEBUG
                } 
                else
                {
                    // This should never happen, users can not extend the abstract HitTestParameters class.
                    Invariant.Assert(false, 
                        String.Format(System.Globalization.CultureInfo.InvariantCulture,
                            "'{0}' HitTestParameters are not supported on {1}.", 
                            hitTestParameters.GetType().Name, this.GetType().Name)); 
                }
            } 
        }

        internal HitTestResultBehavior HitTestPoint(
            HitTestFilterCallback filterCallback, 
            HitTestResultCallback resultCallback,
            PointHitTestParameters pointParams) 
        { 
            // we do not need parameter checks because they are done in HitTest()
 
            Geometry clip = VisualClip;

            // Before we continue hit-testing we check against the hit-test bounds for the sub-graph.
            // If the point is not with-in the hit-test bounds, the sub-graph can be skipped. 
            if (_bboxSubgraph.Contains(pointParams.HitPoint) &&
                ((null == clip) || clip.FillContains(pointParams.HitPoint))) // Check that the hit-point is with-in the clip. 
            { 
                //
                // Determine if there is a special filter behavior defined for this 
                // Visual.
                //

                HitTestFilterBehavior filter = HitTestFilterBehavior.Continue; 
                if (filterCallback != null)
                { 
                    filter = filterCallback(this); 

                    if (filter == HitTestFilterBehavior.ContinueSkipSelfAndChildren) 
                    {
                        return HitTestResultBehavior.Continue;
                    }
 
                    if (filter == HitTestFilterBehavior.Stop)
                    { 
                        return HitTestResultBehavior.Stop; 
                    }
                } 

                // if there is a bitmap effect transform the point
                // Backup the hit point so that we can restore it later on.
                Point originalHitPoint = pointParams.HitPoint; 
                Point hitPoint = originalHitPoint;
                if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect)) 
                { 
                    if (BitmapEffectStateField.GetValue(this).TransformHitPoint(
                        _bboxSubgraph, originalHitPoint, out hitPoint) == false) 
                    {
                        return HitTestResultBehavior.Continue;
                    }
 
                }
 
                // 
                // Hit test against the children.
                // 
                if (filter != HitTestFilterBehavior.ContinueSkipChildren)
                {
                    int childCount = VisualChildrenCount;
                    for (int i=childCount-1; i>=0; i--) 
                    {
                        Visual child = GetVisualChild(i); 
                        if (child != null) 
                        {
                            // 
                            // Transform the hit-test point below offset and transform.
                            //

                            Point newHitPoint = hitPoint; 

                            // Apply the offset. 
                            newHitPoint = newHitPoint - child._offset; 

                            // If we have a transform, apply the transform. 
                            Transform childTransform = TransformField.GetValue(child);
                            if (childTransform != null)
                            {
                                Matrix inv = childTransform.Value; 

                                // If we can't invert the transform, the child is not hitable. This makes sense since 
                                // the node's rendered content is degenerate, i.e. does not really take up any space. 
                                // Skip the child by continuing in the loop.
                                if (!inv.HasInverse) 
                                {
                                    continue;
                                }
 
                                inv.Invert();
 
                                newHitPoint = newHitPoint * inv; 
                            }
 
                            // Set the new hittesting point into the hittest params.
                            pointParams.SetHitPoint(newHitPoint);

                            // Perform the hit-test against the child. 
                            HitTestResultBehavior result =
                                child.HitTestPoint(filterCallback, resultCallback, pointParams); 
 
                            // Restore the hit-test point.
                            pointParams.SetHitPoint(originalHitPoint); 


                            if (result == HitTestResultBehavior.Stop)
                            { 
                                return HitTestResultBehavior.Stop;
                            } 
                        } 
                    }
                } 

                //
                // Hit test against the content of this Visual.
                // 

                if (filter != HitTestFilterBehavior.ContinueSkipSelf) 
                { 
                    // set the transformed hit point
                    pointParams.SetHitPoint(hitPoint); 

                    HitTestResultBehavior result = HitTestPointInternal(filterCallback, resultCallback, pointParams);

                    // restore the hit point back to its original 
                    pointParams.SetHitPoint(originalHitPoint);
 
                    if (result == HitTestResultBehavior.Stop) 
                    {
                        return HitTestResultBehavior.Stop; 
                    }
                }
            }
 
            return HitTestResultBehavior.Continue;
        } 
 
        // provides a transform that goes between the Visual's coordinate space
        // and that after applying the transforms that bring it to outer space. 
        internal GeneralTransform TransformToOuterSpace()
        {
            Matrix m = Matrix.Identity;
            GeneralTransformGroup group = null; 
            GeneralTransform result = null;
 
            if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect)) 
            {
                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this); 
                BitmapEffect effect = bitmapEffectState.BitmapEffect;

                // if the BitmapEffect has an affine transformation
                // add code to just multiply the matrix here to the effects matrix 
                if (effect.IsAffineTransform)
                { 
                    Matrix cm = effect.GetAffineMatrix(); 
                    MatrixUtil.MultiplyMatrix(ref m, ref cm);
                } 
                else
                {
                    group = new GeneralTransformGroup();
                    group.Children.Add(new BitmapEffectGeneralTransform(bitmapEffectState.BitmapEffect, 
                            bitmapEffectState.BitmapEffectInput, false, VisualContentBounds));
                } 
            } 

            Transform transform = TransformField.GetValue(this); 
            if (transform != null)
            {
                Matrix cm = transform.Value;
                MatrixUtil.MultiplyMatrix(ref m, ref cm); 
            }
            m.Translate(_offset.X, _offset.Y); // Consider having a bit that indicates that we have a non-null offset. 
 
            if (group == null)
            { 
                result = new MatrixTransform(m);
            }
            else
            { 
                group.Children.Add(new MatrixTransform(m));
                result = group; 
            } 

            result.Freeze(); 
            return result;
        }

        internal HitTestResultBehavior HitTestGeometry( 
            HitTestFilterCallback filterCallback,
            HitTestResultCallback resultCallback, 
            GeometryHitTestParameters geometryParams) 
        {
            // we do not need parameter checks because they are done in HitTest() 

            // Check against the clip before checking against geometry
            IntersectionDetail intersectionDetail;
            Geometry clip = VisualClip; 
            if (clip != null)
            { 
                // HitTest with a Geometry and a clip should hit test with 
                // the intersection of the geometry and the clip, not the entire geometry
                intersectionDetail = clip.FillContainsWithDetail(geometryParams.InternalHitGeometry); 
                Debug.Assert(intersectionDetail != IntersectionDetail.NotCalculated);
                if (intersectionDetail == IntersectionDetail.Empty)
                {
                    // bail out if there is a clip and this region is not inside 
                    return HitTestResultBehavior.Continue;
                } 
            } 

            // 
            // Check if the geometry intersects with our hittest bounds.
            // If not, the Visual is not hit-testable at all.

            if (_bboxSubgraph.IntersectsWith(geometryParams.Bounds)) 
            {
                // 
                // Determine if there is a special filter behavior defined for this 
                // Visual.
                // 

                HitTestFilterBehavior filter = HitTestFilterBehavior.Continue;

                if (filterCallback != null) 
                {
                    filter = filterCallback(this); 
 
                    if (filter == HitTestFilterBehavior.ContinueSkipSelfAndChildren)
                    { 
                        return HitTestResultBehavior.Continue;
                    }

                    if (filter == HitTestFilterBehavior.Stop) 
                    {
                        return HitTestResultBehavior.Stop; 
                    } 
                }
 
                //
                // Hit-test against the children.
                //
 
                int childCount = VisualChildrenCount;
 
                if (filter != HitTestFilterBehavior.ContinueSkipChildren) 
                {
                    for (int i=childCount-1; i>=0; i--) 
                    {
                        Visual child = GetVisualChild(i);
                        if (child != null)
                        { 
                            // Transform the geometry below offset and transform.
                            Matrix inv = Matrix.Identity; 
                            inv.Translate(-child._offset.X, -child._offset.Y); 

                            Transform childTransform = TransformField.GetValue(child); 
                            if (childTransform != null)
                            {
                                Matrix m = childTransform.Value;
 
                                // If we can't invert the transform, the child is not hitable. This makes sense since
                                // the node's rendered content is degnerated, i.e. does not really take up any space. 
                                // Skipping the child by continuing the loop. 
                                if (!m.HasInverse)
                                { 
                                   continue;
                                }

                                // Inverse the transform. 
                                m.Invert();
 
                                // Multiply the inverse and the offset together. 
                                // inv = inv * m;
                                MatrixUtil.MultiplyMatrix(ref inv, ref m); 
                            }

                            // Push the transform on the geometry params.
                            geometryParams.PushMatrix(ref inv); 

                            // Hit-Test against the children. 
 
                            HitTestResultBehavior result =
                                child.HitTestGeometry(filterCallback, resultCallback, geometryParams); 

                            // Pop the transform from the geometry params.

                            geometryParams.PopMatrix(); 

                            // Process the result. 
                            if (result == HitTestResultBehavior.Stop) 
                            {
                                return HitTestResultBehavior.Stop; 
                            }
                        }
                    }
                } 

                // 
                // Hit-test against the content of the Visual. 
                //
 
                if (filter != HitTestFilterBehavior.ContinueSkipSelf)
                {
                    GeometryHitTestResult hitResult = HitTestCore(geometryParams);
 
                    if (hitResult != null)
                    { 
                        Debug.Assert(resultCallback != null); 

                        return resultCallback(hitResult); 
                    }
                }
            }
 
            return HitTestResultBehavior.Continue;
        } 
 

        ///  
        /// This method provides an internal extension point for Viewport3DVisual
        /// to grab the HitTestFilterCallback and ResultDelegate before it gets lost in the
        /// forward to HitTestCore.
        ///  
        internal virtual HitTestResultBehavior HitTestPointInternal(
            HitTestFilterCallback filterCallback, 
            HitTestResultCallback resultCallback, 
            PointHitTestParameters hitTestParameters)
        { 
            HitTestResult hitResult = HitTestCore(hitTestParameters);

            if (hitResult != null)
            { 
                return resultCallback(hitResult);
            } 
 
            return HitTestResultBehavior.Continue;
        } 

        /// 
        /// HitTestCore implements whether we have hit the bounds of this visual.
        ///  
        protected virtual HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
        { 
            if (hitTestParameters == null) 
            {
                throw new ArgumentNullException("hitTestParameters"); 
            }

            // If we don't have a clip, or if the clip contains the point, keep going.
            if (GetHitTestBounds().Contains(hitTestParameters.HitPoint)) 
            {
                return new PointHitTestResult(this, hitTestParameters.HitPoint); 
            } 
            else
            { 
                return null;
            }
        }
 
        /// 
        /// HitTestCore implements whether we have hit the bounds of this visual. 
        ///  
        protected virtual GeometryHitTestResult HitTestCore(GeometryHitTestParameters hitTestParameters)
        { 
            if (hitTestParameters == null)
            {
                throw new ArgumentNullException("hitTestParameters");
            } 

            IntersectionDetail intersectionDetail; 
 
            RectangleGeometry contentGeometry = new RectangleGeometry(GetHitTestBounds());
 
            intersectionDetail = contentGeometry.FillContainsWithDetail(hitTestParameters.InternalHitGeometry);
            Debug.Assert(intersectionDetail != IntersectionDetail.NotCalculated);

            if (intersectionDetail != IntersectionDetail.Empty) 
            {
                return new GeometryHitTestResult(this, intersectionDetail); 
            } 

 
            return null;
        }

        #endregion Hit Testing 

 
 
        // -------------------------------------------------------------------
        // 
        //   Visual Operations API
        //
        // --------------------------------------------------------------------
 
        #region VisualChildren
 
        ///  
        ///  Derived classes override this property to enable the Visual code to enumerate
        ///  the Visual children. Derived classes need to return the number of children 
        ///  from this method.
        ///
        ///    By default a Visual does not have any children.
        /// 
        ///  Remark: During this virtual method the Visual tree must not be modified.
        ///  
        protected virtual int VisualChildrenCount 
        {
            get { return 0; } 
        }

        /// 
        /// Returns the number of 2D children. This returns 0 for visuals 
        /// whose children are Visual3Ds.
        ///  
        internal int InternalVisualChildrenCount 
        {
            get 
            {
                // Call the right virtual method.
                return VisualChildrenCount;
            } 
        }
 
        ///  
        /// Returns the number of children of this object (in most cases this will be
        /// the number of Visuals, but it some cases, Viewport3DVisual for instance, 
        /// this is the number of Visual3Ds).
        ///
        /// Used only by VisualTreeHelper.
        ///  
        internal virtual int InternalVisual2DOr3DChildrenCount
        { 
            get 
            {
                // Call the right virtual method. 
                return VisualChildrenCount;
            }
        }
 
        ///
        ///Flag to check if this visual has any children 
        /// 
        internal bool HasVisualChildren
        { 
            get
            {
                return ((_flags & VisualFlags.HasChildren) != 0);
            } 
        }
 
        ///  
        ///   Derived class must implement to support Visual children. The method must return
        ///    the child at the specified index. Index must be between 0 and GetVisualChildrenCount-1. 
        ///
        ///    By default a Visual does not have any children.
        ///
        ///  Remark: 
        ///       Need to lock down Visual tree during the callbacks.
        ///       During this virtual call it is not valid to modify the Visual tree. 
        /// 
        ///       It is okay to type this protected API to the 2D Visual.  The only 2D Visual with
        ///       3D childern is the Viewport3DVisual which is sealed.  -- [....] 01/17/06 
        /// 
        protected virtual Visual GetVisualChild(int index)
        {
           throw new ArgumentOutOfRangeException("index", index, SR.Get(SRID.Visual_ArgumentOutOfRange)); 
        }
 
        ///  
        /// Returns the 2D child at index "index". This will fail for Visuals
        /// whose children are Visual3Ds. 
        /// 
        internal Visual InternalGetVisualChild(int index)
        {
            // Call the right virtual method. 
            return GetVisualChild(index);
        } 
 
        /// 
        /// Returns the child at index "index" (in most cases this will be 
        /// a Visual, but it some cases, Viewport3DVisual for instance,
        /// this is a Visual3D).
        ///
        /// Used only by VisualTreeHelper. 
        /// 
        internal virtual DependencyObject InternalGet2DOr3DVisualChild(int index) 
        { 
            // Call the right virtual method.
            return GetVisualChild(index); 
        }

        /// 
        /// Helper method to provide access to AddVisualChild for the VisualCollection. 
        /// 
        internal void InternalAddVisualChild(Visual child) 
        { 
            this.AddVisualChild(child);
        } 

        /// 
        /// Helper method to provide access to RemoveVisualChild for the VisualCollection.
        ///  
        internal void InternalRemoveVisualChild(Visual child)
        { 
            this.RemoveVisualChild(child); 
        }
 
        /// 
        /// AttachChild
        ///
        ///    Derived classes must call this method to notify the Visual layer that a new 
        ///    child appeard in the children collection. The Visual layer will then call the GetVisualChild
        ///    method to find out where the child was added. 
        /// 
        ///  Remark: To move a Visual child in a collection it must be first disconnected and then connected
        ///    again. (Moving forward we might want to add a special optimization there so that we do not 
        ///    unmarshal our composition resources).
        ///
        ///    It is okay to type this protected API to the 2D Visual.  The only 2D Visual with
        ///    3D childern is the Viewport3DVisual which is sealed.  -- [....] 01/17/06 
        /// 
        protected void AddVisualChild(Visual child) 
        { 
            if (child == null)
            { 
                return;
            }

            if (child._parent != null) 
            {
                throw new ArgumentException(SR.Get(SRID.Visual_HasParent)); 
            } 

            SetFlags(true, VisualFlags.HasChildren); 

            // Set the parent pointer.

            child._parent = this; 

            // 
            // The child might be dirty. Hence we need to propagate dirty information 
            // from the parent and from the child.
            // 

            Visual.PropagateFlags(
                this,
                VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate, 
                VisualProxyFlags.IsSubtreeDirtyForRender);
 
            // 
            // If child has realizations, we need to set NodeRequiresRealizationUpdate flag, and propagate
            // corresponding subtree flag 
            //
            child.SetFlags(true, VisualFlags.NodeRequiresNewRealization);
            Visual.PropagateFlags(
                child, 
                VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate | VisualFlags.NodeInSubtreeRequiresNewRealization,
                VisualProxyFlags.IsSubtreeDirtyForRender); 
 
            //
            // Resume layout. 
            //
            UIElement.PropagateResumeLayout(this, child);

            // Fire notifications 
            this.OnVisualChildrenChanged(child, null /* no removed child */);
            child.FireOnVisualParentChanged(null); 
        } 

        ///  
        /// DisconnectChild
        ///
        ///    Derived classes must call this method to notify the Visual layer that a
        ///    child was removed from the children collection. The Visual layer will then call 
        ///    GetChildren to find out which child has been removed.
        /// 
        ///  
        protected void RemoveVisualChild(Visual child)
        { 
            if (child == null || child._parent == null)
            {
                return;
            } 

            if (child._parent != this) 
            { 
                throw new ArgumentException(SR.Get(SRID.Visual_NotChild));
            } 

            if(InternalVisual2DOr3DChildrenCount == 0)
            {
                SetFlags(false, VisualFlags.HasChildren); 
            }
 
            // 
            // Remove the child on all channels its current parent is marshalled to.
            // 

            for (int i = 0; i < _proxy.Count; i++)
            {
                DUCE.Channel channel = _proxy.GetChannel(i); 

                if (child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent)) 
                { 
                    channel.AddToRemoveAndReleaseQueue(
                        this, 
                        child);
                    child.SetFlags(channel, false, VisualProxyFlags.IsConnectedToParent);
                }
            } 

            // Set the parent pointer to null. 
 
            child._parent = null;
 
            Visual.PropagateFlags(
                this,
                VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate,
                VisualProxyFlags.IsSubtreeDirtyForRender); 

            UIElement.PropagateSuspendLayout(child); 
 
            // Fire notifications
            child.FireOnVisualParentChanged(this); 
            OnVisualChildrenChanged(null /* no child added */, child);
        }

        ///  
        /// InvalidateZOrder
        /// Note: must do invalidation without removing / adding 
        /// to avoid loosing focused element by input system 
        /// 
        [FriendAccessAllowed] 
        internal void InvalidateZOrder()
        {
            //  if we don't have any children, there is nothing to do
            if (VisualChildrenCount == 0) 
                return;
 
            SetFlags(true, VisualFlags.NodeRequiresNewRealization); 

            Visual.PropagateFlags( 
                       this,
                        VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate | VisualFlags.NodeInSubtreeRequiresNewRealization,
                        VisualProxyFlags.IsSubtreeDirtyForRender);
 
            // Disconnect the children of the visual on all channels
            // it is being marshalled to. 
            DisconnectChildrenOnAllChannels(); 

            // 

            System.Windows.Input.InputManager.SafeCurrentNotifyHitTestInvalidated();
        }
 
        //This is used by LayoutManager as a perf optimization for layout updates.
        //During layout updates, LM needs to find which areas of the visual tree 
        //are higher in the tree - they have to be processed first to avoid multiple 
        //updates of lower descendants. The tree level counter is maintained by
        //UIElement.PropagateResume/SuspendLayout methods and uses 8 bits in VisualFlags to 
        //keep the count.
        internal uint TreeLevel
        {
            get 
            {
                return ((uint)_flags & 0xFF000000) >> 24; 
            } 
            set
            { 
                if(value > 0xFF)
                {
                    throw new InvalidOperationException(SR.Get(SRID.LayoutManager_DeepRecursion, 255));
                } 

                _flags = (VisualFlags)(((uint)_flags & 0x00FFFFFF) | (value << 24)); 
            } 
        }
 

        #endregion VisualChildren

 
        #region VisualParent
 
        ///  
        /// Returns the parent of this Visual.  Parent may be either a Visual or Visual3D.
        ///  
        protected DependencyObject VisualParent
        {
            get
            { 
                VerifyAPIReadOnly();
 
                return InternalVisualParent; 
            }
        } 

        /// 
        /// Identical to VisualParent, except that skips verify access for perf.
        ///  
        internal DependencyObject InternalVisualParent
        { 
            get 
            {
                return _parent; 
            }
        }

        #endregion VisualParent 

        // These 2 method will be REMOVED once Hamid is back and can 
        // explain why Window needs to Bypass layout for setting Flow Direction. 
        // These methods are only called from InternalSetLayoutTransform which is called only from Window
        [FriendAccessAllowed] 
        internal void InternalSetOffsetWorkaround(Vector offset)
        {
            VisualOffset = offset;
        } 
        [FriendAccessAllowed]
        internal void InternalSetTransformWorkaround(Transform transform) 
        { 
            VisualTransform = transform;
        } 

        // -------------------------------------------------------------------
        //
        //   Visual Properties 
        //
        // ------------------------------------------------------------------- 
 
        #region Visual Properties
 
        /// 
        /// Gets or sets the transform of this Visual.
        /// 
        protected internal Transform VisualTransform 
        {
            get 
            { 
                VerifyAPIReadOnly();
 
                return TransformField.GetValue(this);
            }
            protected set
            { 
                VerifyAPIReadWrite(value);
 
                Transform transform = TransformField.GetValue(this); 
                if (transform == value)
                { 
                    return;
                }

                Transform newTransform = value; 

                // Add changed notifications for the new transform if necessary. 
                if (newTransform != null && !newTransform.IsFrozen) 
                {
                    newTransform.Changed += TransformChangedHandler; 
                }

                if (transform != null)
                { 
                    //
                    // Remove changed notifications for the old transform if necessary. 
                    // 

                    if (!transform.IsFrozen) 
                    {
                        transform.Changed -= TransformChangedHandler;
                    }
 
                    //
                    // Disconnect the transform from this visual. 
                    // 

                    DisconnectAttachedResource( 
                        VisualProxyFlags.IsTransformDirty,
                        ((DUCE.IResource)transform));
                }
 
                //
                // Set the new clip and mark it dirty 
                // 

                TransformField.SetValue(this, newTransform); 

                SetFlagsOnAllChannels(true, VisualProxyFlags.IsTransformDirty);

                TransformChanged(/* sender */ null, /* args */ null); 
            }
        } 
 
        /// 
        /// BitmapEffect Property - 
        /// Gets or sets the optional BitmapEffect.  If set, the BitmapEffect will
        /// be applied Visual's rendered content, after which the OpacityMask and/or Opacity
        /// will be applied (if present).
        ///  
        protected internal BitmapEffect VisualBitmapEffect
        { 
            get 
            {
                VerifyAPIReadOnly(); 

                if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect))
                    return BitmapEffectStateField.GetValue(this).BitmapEffect;
 
                return null;
            } 
 
            protected set
            { 
                VerifyAPIReadWrite(value);

                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this);
 
                BitmapEffect bitmapEffect = (bitmapEffectState == null) ? null : bitmapEffectState.BitmapEffect;
                if (bitmapEffect == value) 
                { 
                    return;
                } 

                BitmapEffect newBitmapEffect = value;

                if (newBitmapEffect == null) 
                {
                    Debug.Assert(bitmapEffectState != null); 
                    for (int i = 0; i < _proxy.Count; i++) 
                    {
                        DUCE.Channel channel = _proxy.GetChannel(i); 
                        bitmapEffectState.FreeContent(this, channel);
                    }

                    BitmapEffectStateField.SetValue(this, null); 
                    SetFlags(false, VisualFlags.NodeHasBitmapEffect);
                    SetFlagsOnAllChannels(false, VisualProxyFlags.IsContentConnected); 
                    SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty | 
                                                VisualProxyFlags.IsOpacityDirty |
                                                VisualProxyFlags.IsOpacityMaskDirty | 
                                                VisualProxyFlags.IsEdgeModeDirty);
                }
                else
                { 
                    // if we are adding a bitmap effect to the visual,
                    // we want to disconnect all its children, edgemode and 
                    // opacity/opacity mask from all channels 
                    // The visual's children will no longer be rendered on the
                    // compositor. We render them to a bitmap and apply the 
                    // effect to the bitmap and then set the new bitmap as the
                    // content of the visual.

                    if (bitmapEffectState == null) 
                    {
                        DisconnectBitmapEffectPropertiesOnAllChannels(); 
                        bitmapEffectState = new BitmapEffectVisualState(); 
                        BitmapEffectStateField.SetValue(this, bitmapEffectState);
                    } 

                    bitmapEffectState.BitmapEffect = newBitmapEffect;
                    SetFlags(true, VisualFlags.NodeHasBitmapEffect);
                } 

                // Enable new image effect if necessary. 
                if (newBitmapEffect != null && !newBitmapEffect.IsFrozen) 
                {
                    newBitmapEffect.Changed += BitmapEffectChangedHandler; 
                }

                // Disable old image effect if necessary.
                if (bitmapEffect != null && !bitmapEffect.IsFrozen) 
                {
                    bitmapEffect.Changed -= BitmapEffectChangedHandler; 
                } 

                //Propagate flags -- the handler doesn't care about the arguments, so we can pass in nulls 
                BitmapEffectChanged(/* sender */ null, /* args */ null);
            }
        }
 
        /// 
        /// BitmapEffectInput Property - 
        /// Gets or sets the optional BitmapEffectInput.  If set, the BitmapEffectInput will 
        /// be applied Visual's rendered content, after which the OpacityMask and/or Opacity
        /// will be applied (if present). 
        /// 
        protected internal BitmapEffectInput VisualBitmapEffectInput
        {
            get 
            {
                VerifyAPIReadOnly(); 
                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this); 
                if (bitmapEffectState != null)
                    return bitmapEffectState.BitmapEffectInput; 

                return null;
            }
 
            protected set
            { 
                VerifyAPIReadWrite(); 
                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this);
 
                BitmapEffectInput bitmapEffectInput = (bitmapEffectState == null) ? null : bitmapEffectState.BitmapEffectInput;
                if (bitmapEffectInput == value)
                {
                    return; 
                }
 
                BitmapEffectInput newBitmapEffectInput = value; 

                if (bitmapEffectState == null) 
                {
                    bitmapEffectState = new BitmapEffectVisualState();
                    BitmapEffectStateField.SetValue(this, bitmapEffectState);
                } 

                // Enable new image effect if necessary. 
                if (newBitmapEffectInput != null && !newBitmapEffectInput.IsFrozen) 
                {
                    newBitmapEffectInput.Changed += BitmapEffectInputChangedHandler; 
                }

                // Disable old image effect if necessary.
                if (bitmapEffectInput != null && !bitmapEffectInput.IsFrozen) 
                {
                    bitmapEffectInput.Changed -= BitmapEffectInputChangedHandler; 
                } 

 
                bitmapEffectState.BitmapEffectInput = newBitmapEffectInput;

                //Propagate flags -- the handler doesn't care about the arguments, so we can pass in nulls
                BitmapEffectInputChanged(/* sender */ null, /* args */ null); 
            }
        } 
 

        ///  
        /// Gets or sets the clip of this Visual.
        /// 
        protected internal Geometry VisualClip
        { 
            get
            { 
                VerifyAPIReadOnly(); 

                return ClipField.GetValue(this); 
            }
            protected set
            {
                ChangeVisualClip(value, false /* dontSetWhenClose */); 
            }
        } 
 
        /// 
        ///     Processes changing the clip from the old clip to the new clip. 
        ///     Called from Visual.set_VisualClip and from places that want
        ///     to optimize setting a new clip (like UIElement.ensureClip).
        /// 
        internal void ChangeVisualClip(Geometry newClip, bool dontSetWhenClose) 
        {
            VerifyAPIReadWrite(newClip); 
 
            Geometry oldClip = ClipField.GetValue(this);
            if ((oldClip == newClip) || 
                (dontSetWhenClose && (oldClip != null) && (newClip != null) && oldClip.AreClose(newClip)))
            {
                return;
            } 

            // Add changed notifications for the new clip if necessary. 
            if (newClip != null && !newClip.IsFrozen) 
            {
                newClip.Changed += ClipChangedHandler; 
            }

            if (oldClip != null)
            { 
                //
                // Remove changed notifications for the old clip if necessary. 
                // 

                if (!oldClip.IsFrozen) 
                {
                    oldClip.Changed -= ClipChangedHandler;
                }
 
                //
                // Disconnect the clip from this visual. 
                // 

                DisconnectAttachedResource( 
                    VisualProxyFlags.IsClipDirty,
                    ((DUCE.IResource)oldClip));
            }
 
            //
            // Set the new clip and mark it dirty 
            // 

            ClipField.SetValue(this, newClip); 

            SetFlagsOnAllChannels(true, VisualProxyFlags.IsClipDirty);

            ClipChanged(/* sender */ null, /* args */ null); 
        }
 
        ///  
        /// Gets and sets the offset.
        ///  
        protected internal Vector VisualOffset
        {
            get
            { 
                // VerifyAPIReadOnly(); // Intentionally removed for performance reasons.
                return _offset; 
            } 
            protected set
            { 
                VerifyAPIReadWrite();

                if (value != _offset) // Fuzzy comparison might be better here.
                { 
                    VisualFlags flags;
 
                    _offset = value; 

                    SetFlagsOnAllChannels(true, VisualProxyFlags.IsOffsetDirty); 

                    flags = VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate;

                    // 
                    //
 
 

 


                    if (CheckFlagsOr(VisualFlags.NodeUsesRealizationCaches | VisualFlags.NodeInSubtreeUsesRealizationCaches)
                        && MediaContext.From(Dispatcher).BitmapEffectsUsed) 
                    {
                        SetFlags(true, VisualFlags.NodeRequiresNewRealization); 
                        flags |= VisualFlags.NodeInSubtreeRequiresNewRealization; 
                    }
 
                    PropagateFlags(
                        this,
                        flags,
                        VisualProxyFlags.IsSubtreeDirtyForRender); 
                }
            } 
        } 

        ///  
        /// Gets or sets the opacity of the Visual.
        /// 
        protected internal double VisualOpacity
        { 
            get
            { 
                VerifyAPIReadOnly(); 

                return OpacityCache; 
            }
            protected set
            {
                VerifyAPIReadWrite(); 

                if (OpacityCache == value) 
                { 
                    return;
                } 

                OpacityField.SetValue(this, value);

                // [....]: We need to do more here for animated opacity. 

                SetFlagsOnAllChannels(true, VisualProxyFlags.IsOpacityDirty); 
 
                PropagateFlags(
                    this, 
                    VisualFlags.NodeNeedsBitmapEffectUpdate,
                    VisualProxyFlags.IsSubtreeDirtyForRender);
            }
        } 

        ///  
        /// Gets or sets the EdgeMode of the Visual. 
        /// 
        protected internal EdgeMode VisualEdgeMode 
        {
            get
            {
                VerifyAPIReadOnly(); 

                return EdgeModeCache; 
            } 
            protected set
            { 
                VerifyAPIReadWrite();

                if (EdgeModeCache == value)
                { 
                    return;
                } 
 
                EdgeModeField.SetValue(this, value);
 
                SetFlagsOnAllChannels(true, VisualProxyFlags.IsEdgeModeDirty);

                PropagateFlags(
                    this, 
                    VisualFlags.NodeNeedsBitmapEffectUpdate,
                    VisualProxyFlags.IsSubtreeDirtyForRender); 
            } 
        }
 
        private EdgeMode EdgeModeCache
        {
            get
            { 
                object edgeMode = EdgeModeField.GetValue(this);
 
                if (edgeMode == null) 
                {
                    return EdgeMode.Unspecified; 
                }

                return (EdgeMode)edgeMode;
            } 
        }
 
        ///  
        /// Gets or sets the ImageScalingMode of the Visual.
        ///  
        protected internal BitmapScalingMode VisualBitmapScalingMode
        {
            get
            { 
                VerifyAPIReadOnly();
 
                return BitmapScalingModeCache; 
            }
            protected set 
            {
                VerifyAPIReadWrite();

                if (BitmapScalingModeCache == value) 
                {
                    return; 
                } 

                BitmapScalingModeField.SetValue(this, value); 

                SetFlagsOnAllChannels(true, VisualProxyFlags.IsBitmapScalingModeDirty);

                PropagateFlags( 
                    this,
                    VisualFlags.NodeNeedsBitmapEffectUpdate, 
                    VisualProxyFlags.IsSubtreeDirtyForRender); 
            }
        } 

        private BitmapScalingMode BitmapScalingModeCache
        {
            get 
            {
                object bitmapScalingMode = BitmapScalingModeField.GetValue(this); 
 
                if (bitmapScalingMode == null)
                { 
                    return BitmapScalingMode.Unspecified;
                }

                return (BitmapScalingMode) bitmapScalingMode; 
            }
        } 
 
        /// 
        /// OpacityMask Property - 
        /// Gets or sets the optional OpacityMask.  If set, the Brush's opacity will
        /// be combined multiplicitively with the Visual's rendered content.
        /// 
        protected internal Brush VisualOpacityMask 
        {
            get 
            { 
                VerifyAPIReadOnly();
 
                return OpacityMaskField.GetValue(this);
            }
            protected set
            { 
                VerifyAPIReadWrite(value);
 
                Brush opacityMask = OpacityMaskField.GetValue(this); 
                if (opacityMask == value)
                { 
                    return;
                }

                Brush newOpacityMask = value; 

                // Add changed notifications for the new opacity mask if necessary. 
                if (newOpacityMask != null && !newOpacityMask.IsFrozen) 
                {
                    newOpacityMask.Changed += OpacityMaskChangedHandler; 
                }

                if (opacityMask != null)
                { 
                    //
                    // Remove changed notifications for the old opacity mask if necessary. 
                    // 

                    if (!opacityMask.IsFrozen) 
                    {
                        opacityMask.Changed -= OpacityMaskChangedHandler;
                    }
 
                    //
                    // Disconnect the opacity mask from this visual. 
                    // If the visual has a bitmap effect, the opacity mask is not 
                    // connected
 
                    if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect) == false)
                    {
                        DisconnectAttachedResource(
                            VisualProxyFlags.IsOpacityMaskDirty, 
                            ((DUCE.IResource)opacityMask));
                    } 
                } 

                // 
                // Set the new opacity mask and mark it dirty
                //

                OpacityMaskField.SetValue(this, newOpacityMask); 

                SetFlagsOnAllChannels(true, VisualProxyFlags.IsOpacityMaskDirty); 
 
                OpacityMaskChanged(/* sender */ null, /* args */ null);
            } 
        }


        ///  
        /// Gets or sets X- (vertical) guidelines on this Visual.
        ///  
        protected internal DoubleCollection VisualXSnappingGuidelines 
        {
            get 
            {
                VerifyAPIReadOnly();

                return GuidelinesXField.GetValue(this); 
            }
            protected set 
            { 
                VerifyAPIReadWrite(value);
 
                DoubleCollection guidelines = GuidelinesXField.GetValue(this);
                if (guidelines == value)
                {
                    return; 
                }
 
                DoubleCollection newGuidelines = value; 

                // Add changed notifications for the new guidelines if necessary. 
                if (newGuidelines != null && !newGuidelines.IsFrozen)
                {
                    newGuidelines.Changed += GuidelinesChangedHandler;
                } 

                // Remove changed notifications for the old guidelines if necessary. 
                if (guidelines != null && !guidelines.IsFrozen) 
                {
                    guidelines.Changed -= GuidelinesChangedHandler; 
                }

                GuidelinesXField.SetValue(this, newGuidelines);
 
                GuidelinesChanged(/* sender */ null, /* args */ null);
            } 
        } 

 
        /// 
        /// Gets or sets Y- (horizontal) guidelines of this Visual.
        /// 
        protected internal DoubleCollection VisualYSnappingGuidelines 
        {
            get 
            { 
                VerifyAPIReadOnly();
 
                return GuidelinesYField.GetValue(this);
            }
            protected set
            { 
                VerifyAPIReadWrite(value);
 
                DoubleCollection guidelines = GuidelinesYField.GetValue(this); 
                if (guidelines == value)
                { 
                    return;
                }

                DoubleCollection newGuidelines = value; 

                // Add changed notifications for the new guidelines if necessary. 
                if (newGuidelines != null && !newGuidelines.IsFrozen) 
                {
                    newGuidelines.Changed += GuidelinesChangedHandler; 
                }

                // Remove changed notifications for the old guidelines if necessary.
                if (guidelines != null && !guidelines.IsFrozen) 
                {
                    guidelines.Changed -= GuidelinesChangedHandler; 
                } 

                GuidelinesYField.SetValue(this, newGuidelines); 

                GuidelinesChanged(/* sender */ null, /* args */ null);
            }
        } 

        #endregion Visual Properties 
 
        private double OpacityCache
        { 
            get
            {
                object opacity = OpacityField.GetValue(this);
                if (opacity == null) 
                {
                    return 1.0; 
                } 

                return (double)opacity; 
            }
        }

 

 
        ///  
        /// Disconnects a resource attached to this visual.
        ///  
        internal void DisconnectAttachedResource(
            VisualProxyFlags correspondingFlag,
            DUCE.IResource attachedResource)
        { 
            //
            // We need a special case for the content (corresponding 
            // to the IsContentConnected flag). 
            //
 
            bool needToReleaseContent =
                correspondingFlag == VisualProxyFlags.IsContentConnected;

 
            //
            // Iterate over the channels this visual is being marshaled to 
            // 

            for (int i = 0; i < _proxy.Count; i++) 
            {
                DUCE.Channel channel = _proxy.GetChannel(i);
                VisualProxyFlags flags = _proxy.GetFlags(i);
 
                //
                // See if the corresponding flag is set... 
                // 

                bool correspondingFlagSet = 
                    (flags & correspondingFlag) != 0;


                // 
                // We want to perform an action if IsContentConnected
                // flag is set or a Is*Dirty flag is not set: 
                // 

                if (correspondingFlagSet == needToReleaseContent) 
                {
                    //
                    // Set the flag so that during render we send
                    // update to the compositor. 
                    //
                    SetFlags(channel, true, correspondingFlag); 
 
                    //
                    // Add this resource to the queue for delayed-removal. 
                    //
                    channel.AddToRemoveAndReleaseQueue(
                        null,
                        attachedResource); 

 
                    if (needToReleaseContent) 
                    {
                        // 
                        // Mark the content of this visual as disconnected.
                        //

                        _proxy.SetFlags(i, false, VisualProxyFlags.IsContentConnected); 
                    }
                } 
            } 
        }
 



        ///  
        /// GetDrawing - Returns the Drawing content of this Visual
        ///  
        internal virtual DrawingGroup GetDrawing() 
        {
            VerifyAPIReadOnly(); 

            // Default implementation returns null for Visual's that
            // don't have drawings
            return null; 
        }
 
 

        // ------------------------------------------------------------------- 
        //
        //   Visual Ancestry Relations
        //
        // -------------------------------------------------------------------- 

        #region Visual Ancestry Relations 
 
        /// 
        /// This is called when the parent link of the Visual is changed. 
        /// This method executes important base functionality before calling the
        /// overridable virtual.
        /// 
        /// Old parent or null if the Visual did not have a parent before. 
        internal virtual void FireOnVisualParentChanged(DependencyObject oldParent)
        { 
            // Call the ParentChanged virtual before firing the Ancestor Changed Event 
            OnVisualParentChanged(oldParent);
 
            // Clean up bits when the tree is Cut or Pasted.

            // If we are attaching to a tree then
            // send the bit up if we need to. 
            if(oldParent == null)
            { 
                Debug.Assert(_parent != null, "If oldParent is null, current parent should != null."); 

                if(CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged)) 
                {
                    SetTreeBits(
                        _parent,
                        VisualFlags.SubTreeHoldsAncestorChanged, 
                        VisualFlags.RegisteredForAncestorChanged);
                } 
            } 
            // If we are cutting a sub tree off then
            // clear the bit in the main tree above if we need to. 
            else
            {
                if(CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    ClearTreeBits(
                        oldParent, 
                        VisualFlags.SubTreeHoldsAncestorChanged, 
                        VisualFlags.RegisteredForAncestorChanged);
                } 
            }

            // Fire the Ancestor changed Event on the nodes.
            AncestorChangedEventArgs args = new AncestorChangedEventArgs(this, oldParent); 
            ProcessAncestorChangedNotificationRecursive(this, args);
        } 
 

        ///  
        /// OnVisualParentChanged is called when the parent of the Visual is changed.
        /// 
        /// Old parent or null if the Visual did not have a parent before.
        protected internal virtual void OnVisualParentChanged(DependencyObject oldParent) 
        {
        } 
 
        /// 
        /// OnVisualChildrenChanged is called when the VisualCollection of the Visual is edited. 
        /// 
        protected internal virtual void OnVisualChildrenChanged(
            DependencyObject visualAdded,
            DependencyObject visualRemoved) 
        {
        } 
 

        ///  
        ///   Add removed delegates to the VisualAncenstorChanged Event.
        /// 
        /// 
        ///     This also sets/clears the tree-searching bit up the tree 
        /// 
        internal event AncestorChangedEventHandler VisualAncestorChanged 
        { 
            add
            { 
                AncestorChangedEventHandler newHandler = AncestorChangedEventField.GetValue(this);

                if (newHandler == null)
                { 
                    newHandler = value;
                } 
                else 
                {
                    newHandler += value; 
                }

                AncestorChangedEventField.SetValue(this, newHandler);
 
                SetTreeBits(
                    this, 
                    VisualFlags.SubTreeHoldsAncestorChanged, 
                    VisualFlags.RegisteredForAncestorChanged);
            } 

            remove
            {
                // check that we are Disabling a node that was previously Enabled 
                if(CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged))
                { 
                    ClearTreeBits( 
                        this,
                        VisualFlags.SubTreeHoldsAncestorChanged, 
                        VisualFlags.RegisteredForAncestorChanged);
                }

                // if we are Disabling a Visual that was not Enabled then this 
                // search should fail.  But it is safe to check.
                AncestorChangedEventHandler newHandler = AncestorChangedEventField.GetValue(this); 
 
                if (newHandler != null)
                { 
                    newHandler -= value;

                    if(newHandler == null)
                    { 
                        AncestorChangedEventField.ClearValue(this);
                    } 
                    else 
                    {
                        AncestorChangedEventField.SetValue(this, newHandler); 
                    }
                }
            }
        } 

 
        ///  
        ///     Walks down in the tree for nodes that have AncestorChanged Handlers
        ///     registered and calls them. 
        ///     It uses Flag bits that help it prune the walk.  This should go
        ///     straight to the relevent nodes.
        /// 
        internal static void ProcessAncestorChangedNotificationRecursive(DependencyObject e, AncestorChangedEventArgs args) 
        {
            if (e is Visual3D) 
            { 
                Visual3D.ProcessAncestorChangedNotificationRecursive(e, args);
            } 
            else
            {
                Visual eAsVisual = e as Visual;
 
                // If the flag is not set, then we are Done.
                if(!eAsVisual.CheckFlagsAnd(VisualFlags.SubTreeHoldsAncestorChanged)) 
                { 
                    return;
                } 

                // If there is a handler on this node, then fire it.
                AncestorChangedEventHandler handler = AncestorChangedEventField.GetValue(eAsVisual);
 
                if(handler != null)
                { 
                    handler(eAsVisual, args); 
                }
 
                // Decend into the children.
                int count = eAsVisual.InternalVisual2DOr3DChildrenCount;

                for (int i = 0; i < count; i++) 
                {
                    DependencyObject childVisual = eAsVisual.InternalGet2DOr3DVisualChild(i); 
                    if (childVisual != null) 
                    {
                        ProcessAncestorChangedNotificationRecursive(childVisual, args); 
                    }
                }
            }
        } 

 
        ///  
        /// Returns true if the specified ancestor (this) is really the ancestor of the
        /// given descendant (argument). 
        /// 
        public bool IsAncestorOf(DependencyObject descendant)
        {
            Visual visual; 
            Visual3D visual3D;
 
            VisualTreeUtils.AsNonNullVisual(descendant, out visual, out visual3D); 

            // x86 branch prediction skips the branch on first encounter.  We favor 2D. 
            if(visual3D != null)
            {
                return visual3D.IsDescendantOf(this);
            } 

            return visual.IsDescendantOf(this); 
        } 

        ///  
        /// Returns true if the refernece Visual (this) is a descendant of the argument Visual.
        /// 
        public bool IsDescendantOf(DependencyObject ancestor)
        { 
            if (ancestor == null)
            { 
                throw new ArgumentNullException("ancestor"); 
            }
 
            VisualTreeUtils.EnsureVisual(ancestor);

            // Walk up the parent chain of the descendant until we run out
            // of 2D parents or we find the ancestor. 
            DependencyObject current = this;
 
            while ((current != null) && (current != ancestor)) 
            {
                Visual currentAsVisual = current as Visual; 

                if (currentAsVisual != null)
                {
                    current = currentAsVisual._parent; 
                }
                else 
                { 
                    Visual3D currentAsVisual3D = current as Visual3D;
 
                    if (currentAsVisual3D != null)
                    {
                        current = currentAsVisual3D.InternalVisualParent;
                    } 
                    else
                    { 
                        current = null; 
                    }
                } 
            }

            return current == ancestor;
        } 

 
        ///  
        ///     Walks up the Visual tree setting or clearing the given flags.  Unlike
        ///     PropagateFlags this does not terminate when it reaches node with 
        ///     the flags already set.  It always walks all the way to the root.
        /// 
        internal void SetFlagsToRoot(bool value, VisualFlags flag)
        { 
            Visual current = this;
 
            do 
            {
                current.SetFlags(value, flag); 


                Visual currentParent = current._parent as Visual;
 
                // if the cast to currentParent failed and yet current._parent is not null then
                // we have a 3D element.  Call SetFlagsToRoot on it instead. 
                if (current._parent != null && currentParent == null) 
                {
                    ((Visual3D)current._parent).SetFlagsToRoot(value, flag); 
                    return;
                }

                current = currentParent; 
            }
            while (current != null); 
        } 

 
        /// 
        ///     Finds the first ancestor of the given element which has the given
        ///     flags set.
        ///  
        internal DependencyObject FindFirstAncestorWithFlagsAnd(VisualFlags flag)
        { 
            Visual current = this; 

            do 
            {
                if (current.CheckFlagsAnd(flag))
                {
                    // The other Visual crossed through this Visual's parent chain. Hence this is our 
                    // common ancestor.
                    return current; 
                } 

                DependencyObject parent = current._parent; 

                // first attempt to see if parent is a Visual, in which case we continue the loop.
                // Otherwise see if it's a Visual3D, and call the similar method on it.
                current = parent as Visual; 
                if (current == null)
                { 
                    Visual3D parentAsVisual3D = parent as Visual3D; 
                    if (parentAsVisual3D != null)
                    { 
                        return parentAsVisual3D.FindFirstAncestorWithFlagsAnd(flag);
                    }
                }
            } 
            while (current != null);
 
            return null; 
        }
 

        /// 
        /// Finds the common ancestor of two Visuals.
        ///  
        /// Returns the common ancestor if the Visuals have one or otherwise null.
        /// If the argument is null. 
        public DependencyObject FindCommonVisualAncestor(DependencyObject otherVisual) 
        {
            VerifyAPIReadOnly(otherVisual); 

            if (otherVisual == null)
            {
                throw new System.ArgumentNullException("otherVisual"); 
            }
 
            // Since we can't rely on code running in the CLR, we need to first make sure 
            // that the FindCommonAncestor flag is not set. It is enought to ensure this
            // on one path to the root Visual. 

            //

 

 
            SetFlagsToRoot(false, VisualFlags.FindCommonAncestor); 

            // Walk up the other visual's parent chain and set the FindCommonAncestor flag. 
            VisualTreeUtils.SetFlagsToRoot(otherVisual, true, VisualFlags.FindCommonAncestor);

            // Now see if the other Visual's parent chain crosses our parent chain.
            return FindFirstAncestorWithFlagsAnd(VisualFlags.FindCommonAncestor); 
        }
 
        #endregion Visual Ancestry Relations 

 
        // -------------------------------------------------------------------
        //
        //   Visual-to-Visual Transforms
        // 
        // --------------------------------------------------------------------
 
        #region Visual-to-Visual Transforms 

        ///  
        /// Returns a transform that can be used to transform coordinate from this
        /// node to the specified ancestor.  It allows 3D to be between the 2D nodes.
        /// 
        ///  
        /// If ancestor is null.
        ///  
        ///  
        /// If the ancestor Visual is not a ancestor of Visual.
        ///  
        /// If the Visuals are not connected.
        public GeneralTransform TransformToAncestor(
            Visual ancestor)
        { 
            if (ancestor == null)
            { 
                throw new ArgumentNullException("ancestor"); 
            }
 
            VerifyAPIReadOnly(ancestor);

            return InternalTransformToAncestor(ancestor, false);
        } 

        ///  
        /// Returns a transform that can be used to transform coordinate from this 
        /// node to the specified ancestor.
        ///  
        /// 
        /// If ancestor is null.
        /// 
        ///  
        /// If the ancestor Visual3D is not a ancestor of Visual.
        ///  
        /// If the Visuals are not connected. 
        public GeneralTransform2DTo3D TransformToAncestor(Visual3D ancestor)
        { 
            if (ancestor == null)
            {
                throw new ArgumentNullException("ancestor");
            } 

            VerifyAPIReadOnly(ancestor); 
 
            return InternalTransformToAncestor(ancestor, false);
        } 

        /// 
        /// Returns a transform that can be used to transform coordinates from this
        /// node to the specified descendant, or null if the transform from descendant to "this" 
        /// is non-invertible.  It allows 3D to be between the 2D nodes.
        ///  
        ///  
        /// If the reference Visual is not a ancestor of the descendant Visual.
        ///  
        /// If the descendant argument is null.
        /// If the Visuals are not connected.
        public GeneralTransform TransformToDescendant(Visual descendant)
        { 
            if (descendant == null)
            { 
                throw new ArgumentNullException("descendant"); 
            }
 
            VerifyAPIReadOnly(descendant);

            return descendant.InternalTransformToAncestor(this, true);
        } 

 
        ///  
        /// The returned matrix can be used to transform coordinates from this Visual to
        /// the specified Visual. 
        /// Returns null if no such transform exists due to a non-invertible Transform.
        /// 
        /// If visual is null.
        /// If the Visuals are not connected. 
        public GeneralTransform TransformToVisual(Visual visual)
        { 
            DependencyObject ancestor = FindCommonVisualAncestor(visual); 
            Visual ancestorAsVisual = ancestor as Visual;
 
            if (ancestorAsVisual == null)
            {
                throw new System.InvalidOperationException(SR.Get(SRID.Visual_NoCommonAncestor));
            } 

            GeneralTransform g0; 
            Matrix m0; 

            bool isSimple0 = this.TrySimpleTransformToAncestor(ancestorAsVisual, 
                                                               false,
                                                               out g0,
                                                               out m0);
 
            GeneralTransform g1;
            Matrix m1; 
 
            bool isSimple1 = visual.TrySimpleTransformToAncestor(ancestorAsVisual,
                                                                 true, 
                                                                 out g1,
                                                                 out m1);

            // combine the transforms 
            // if both transforms are simple Matrix transforms, just multiply them and
            // return the result. 
            if (isSimple0 && isSimple1) 
            {
                MatrixUtil.MultiplyMatrix(ref m0, ref m1); 
                MatrixTransform m = new MatrixTransform(m0);
                m.Freeze();
                return m;
            } 

            // Handle the case where 0 is simple and 1 is complex. 
            if (isSimple0) 
            {
                g0 = new MatrixTransform(m0); 
                g0.Freeze();
            }
            else if (isSimple1)
            { 
                g1 = new MatrixTransform(m1);
                g1.Freeze(); 
            } 

            // If inverse was requested, TrySimpleTransformToAncestor can return null 
            // add the transform only if it is not null
            if (g1 != null)
            {
                GeneralTransformGroup group = new GeneralTransformGroup(); 
                group.Children.Add(g0);
                group.Children.Add(g1); 
                group.Freeze(); 
                return group;
            } 

            return g0;
        }
 
        /// 
        /// Returns the transform or the inverse transform between this visual and the specified ancestor. 
        /// If inverse is requested but does not exist (if the transform is not invertible), null is returned. 
        /// 
        /// Ancestor visual. 
        /// Returns inverse if this argument is true.
        private GeneralTransform InternalTransformToAncestor(Visual ancestor, bool inverse)
        {
            GeneralTransform generalTransform; 
            Matrix simpleTransform;
 
            bool isSimple = TrySimpleTransformToAncestor(ancestor, 
                                                         inverse,
                                                         out generalTransform, 
                                                         out simpleTransform);

            if (isSimple)
            { 
                MatrixTransform matrixTransform = new MatrixTransform(simpleTransform);
                matrixTransform.Freeze(); 
                return matrixTransform; 
            }
            else 
            {
                return generalTransform;
            }
        } 

        ///  
        /// Provides the transform or the inverse transform between this visual and the specified ancestor. 
        /// Returns true if the transform is "simple" - in which case the GeneralTransform is null
        /// and the caller should use the Matrix. 
        /// Otherwise, returns false - use the GeneralTransform and ignore the Matrix.
        /// If inverse is requested but not available (if the transform is not invertible), false is
        /// returned and the GeneralTransform is null.
        ///  
        /// Ancestor visual.
        /// Returns inverse if this argument is true. 
        /// The GeneralTransform if this method returns false. 
        /// The Matrix if this method returns true.
        internal bool TrySimpleTransformToAncestor(Visual ancestor, 
                                                                         bool inverse,
                                                                         out GeneralTransform generalTransform,
                                                                         out Matrix simpleTransform)
        { 
            Debug.Assert(ancestor != null);
 
            // flag to indicate if we have a case where we do multile 2D->3D->2D transitions 
            bool embedded2Don3D = false;
 
            DependencyObject g = this;
            Matrix m = Matrix.Identity;

            // Keep this null until it's needed 
            GeneralTransformGroup group = null;
 
            // This while loop will walk up the visual tree until we encounter the ancestor. 
            // As it does so, it will accumulate the descendent->ancestor transform.
            // In most cases, this is simply a matrix, though if we encounter a bitmap effect we 
            // will need to use a general transform group to store the transform.
            // We will accumulate the current transform in a matrix until we encounter a bitmap effect,
            // at which point we will add the matrix's current value and the bitmap effect's transforms
            // to the GeneralTransformGroup and continue to accumulate further transforms in the matrix again. 
            // At the end of this loop, we will have 0 or more transforms in the GeneralTransformGroup
            // and the matrix which, if not identity, should be appended to the GeneralTransformGroup. 
            // If, as is commonly the case, this loop terminates without encountering a bitmap effect 
            // we will simply use the Matrix.
 
            while ((VisualTreeHelper.GetParent(g) != null) && (g != ancestor))
            {
                Visual gAsVisual = g as Visual;
                if (gAsVisual != null) 
                {
                    if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect)) 
                    { 
                        BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this);
                        BitmapEffect effect = bitmapEffectState.BitmapEffect; 

                        // if the BitmapEffect has an affine transformation
                        // add code to just multiply the matrix here to the effects matrix
                        if (effect.IsAffineTransform) 
                        {
                            Matrix cm = effect.GetAffineMatrix(); 
                            MatrixUtil.MultiplyMatrix(ref m, ref cm); 
                        }
                        else 
                        {
                            if (group == null)
                            {
                                group = new GeneralTransformGroup(); 
                            }
 
                            group.Children.Add(new MatrixTransform(m)); 
                            m = Matrix.Identity;
 
                            group.Children.Add(new BitmapEffectGeneralTransform(bitmapEffectState.BitmapEffect,
                                    bitmapEffectState.BitmapEffectInput, false, VisualContentBounds));
                        }
                    } 

                    Transform transform = TransformField.GetValue(gAsVisual); 
                    if (transform != null) 
                    {
                        Matrix cm = transform.Value; 
                        MatrixUtil.MultiplyMatrix(ref m, ref cm);
                    }
                    m.Translate(gAsVisual._offset.X, gAsVisual._offset.Y); // Consider having a bit that indicates that we have a non-null offset.
                    g = gAsVisual._parent; 
                }
                else 
                { 
                    // we just hit a Visual3D - use a GeneralTransform to go from 2D -> 3D -> 2D
                    // and then return to the tree using the 2D parent - the general transform will deal with the 
                    // actual transformation.  This Visual3D also must be a Viewport2DVisual3D since this is the only
                    // Visual3D that can have a 2D child.
                    Viewport2DVisual3D gAsVisual3D = g as Viewport2DVisual3D;
 
                    if (group == null)
                    { 
                        group = new GeneralTransformGroup(); 
                    }
 
                    group.Children.Add(new MatrixTransform(m));
                    m = Matrix.Identity;

                    Visual visualForGenTransform = null; 
                    if (embedded2Don3D)
                    { 
                        visualForGenTransform = gAsVisual3D.Visual; 
                    }
                    else 
                    {
                        visualForGenTransform = this;
                        embedded2Don3D = true;
                    } 

                    group.Children.Add(new GeneralTransform2DTo3DTo2D(gAsVisual3D, visualForGenTransform)); 
 
                    g = VisualTreeHelper.GetContainingVisual2D(gAsVisual3D);
                } 
            }

            if (g != ancestor)
            { 
                throw new System.InvalidOperationException(SR.Get(inverse ? SRID.Visual_NotADescendant : SRID.Visual_NotAnAncestor));
            } 
 
            // At this point, we will have 0 or more transforms in the GeneralTransformGroup
            // and the matrix which, if not identity, should be appended to the GeneralTransformGroup. 
            // If, as is commonly the case, this loop terminates without encountering a bitmap effect
            // we will simply use the Matrix.

            // Assert that a non-null group implies at least one child 
            Debug.Assert((group == null) || (group.Children.Count > 0));
 
            // Do we have a group? 
            if (group != null)
            { 
                if (!m.IsIdentity)
                {
                    group.Children.Add(new MatrixTransform(m));
                } 

                if (inverse) 
                { 
                    group = (GeneralTransformGroup)group.Inverse;
                } 

                // group can be null if it does not have an inverse
                if (group != null)
                { 
                    group.Freeze();
                } 
 
                // Initialize out params
                generalTransform = group; 
                simpleTransform = new Matrix();
                return false; // simple transform failed
            }
            // If not, the entire transform is stored in the matrix 
            else
            { 
                // Initialize out params 
                generalTransform = null;
 
                if (inverse)
                {
                    if (!m.HasInverse)
                    { 
                        simpleTransform = new Matrix();
                        return false; // inversion failed, so simple transform failed. 
                    } 

                    m.Invert(); 
                }

                simpleTransform = m;
                return true; // simple transform succeeded 
            }
        } 
 
        /// 
        /// Returns the transform or the inverse transform between this visual and the specified ancestor. 
        /// If inverse is requested but does not exist (if the transform is not invertible), null is returned.
        /// 
        /// Ancestor visual.
        /// Returns inverse if this argument is true. 
        private GeneralTransform2DTo3D InternalTransformToAncestor(Visual3D ancestor, bool inverse)
        { 
            GeneralTransform2DTo3D transformTo3D = null; 

            if (TrySimpleTransformToAncestor(ancestor, 
                                             out transformTo3D))
            {
                transformTo3D.Freeze();
                return transformTo3D; 
            }
            else 
            { 
                return null;
            } 
        }

        /// 
        /// Provides the transform to go from 2D to 3D. 
        /// 
        /// Ancestor visual. 
        /// The transform to use to go to 3D 
        internal bool TrySimpleTransformToAncestor(Visual3D ancestor,
                                                   out GeneralTransform2DTo3D transformTo3D) 
        {
            Debug.Assert(ancestor != null);

            // get the 3D object that contains this visual 
            // this must be a Viewport2DVisual3D since this is the only 3D class that can contain 2D content as a child
            Viewport2DVisual3D containingVisual3D = VisualTreeHelper.GetContainingVisual3D(this) as Viewport2DVisual3D; 
 
            // if containingVisual3D is null then ancestor is not the ancestor
            if (containingVisual3D == null) 
            {
                throw new System.InvalidOperationException(SR.Get(SRID.Visual_NotAnAncestor));
            }
 
            GeneralTransform transform2D = this.TransformToAncestor(containingVisual3D.Visual);
            GeneralTransform3D transform3D = containingVisual3D.TransformToAncestor(ancestor); 
            transformTo3D = new GeneralTransform2DTo3D(transform2D, containingVisual3D, transform3D); 

            return true; 
        }

        /// 
        /// This method converts a point in the current Visual's coordinate 
        /// system into a point in screen coordinates.
        ///  
        public Point PointToScreen(Point point) 
        {
            VerifyAPIReadOnly(); 

            PresentationSource inputSource = PresentationSource.FromVisual(this);

            if (inputSource == null) 
            {
                throw new InvalidOperationException(SR.Get(SRID.Visual_NoPresentationSource)); 
            } 

            // Translate the point from the visual to the root. 
            GeneralTransform gUp = this.TransformToAncestor(inputSource.RootVisual);
            if (gUp == null || !gUp.TryTransform(point, out point))
            {
                throw new InvalidOperationException(SR.Get(SRID.Visual_CannotTransformPoint)); 
            }
 
            // Translate the point from the root to the screen 
            point = PointUtil.RootToClient(point, inputSource);
            point = PointUtil.ClientToScreen(point, inputSource); 

            return point;
        }
 
        /// 
        /// This method converts a point in screen coordinates into a point 
        /// in the current Visual's coordinate system. 
        /// 
        public Point PointFromScreen(Point point) 
        {
            VerifyAPIReadOnly();

            PresentationSource inputSource = PresentationSource.FromVisual(this); 

            if (inputSource == null) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.Visual_NoPresentationSource));
            } 

            // Translate the point from the screen to the root
            point = PointUtil.ScreenToClient(point, inputSource);
            point = PointUtil.ClientToRoot(point, inputSource); 

            // Translate the point from the root to the visual. 
            GeneralTransform gDown = inputSource.RootVisual.TransformToDescendant(this); 
            if (gDown == null || !gDown.TryTransform(point, out point))
            { 
                throw new InvalidOperationException(SR.Get(SRID.Visual_CannotTransformPoint));
            }

            return point; 
        }
 
        #endregion Visual-to-Visual Transforms 

 

        // --------------------------------------------------------------------
        //
        //   Internal Event Handlers 
        //
        // ------------------------------------------------------------------- 
 
        #region Internal Event Handlers
 
        internal EventHandler ClipChangedHandler
        {
            get
            { 
                return new EventHandler(ClipChanged);
            } 
        } 

        internal void ClipChanged(object sender, EventArgs e) 
        {
            PropagateChangedFlags();
        }
 
        internal EventHandler TransformChangedHandler
        { 
            get 
            {
                return new EventHandler(TransformChanged); 
            }
        }

        internal void TransformChanged(object sender, EventArgs e) 
        {
            PropagateChangedFlags(); 
        } 

        internal EventHandler GuidelinesChangedHandler 
        {
            get
            {
                return new EventHandler(GuidelinesChanged); 
            }
        } 
 
        internal void GuidelinesChanged(object sender, EventArgs e)
        { 
            SetFlagsOnAllChannels(
                true,
                VisualProxyFlags.IsGuidelineCollectionDirty);
 
            PropagateChangedFlags();
        } 
 
        internal EventHandler OpacityMaskChangedHandler
        { 
            get
            {
                return new EventHandler(OpacityMaskChanged);
            } 
        }
 
        internal void OpacityMaskChanged(object sender, EventArgs e) 
        {
            PropagateChangedFlags(); 
        }

        internal EventHandler BitmapEffectChangedHandler
        { 
            get
            { 
                return new EventHandler(BitmapEffectChanged); 
            }
        } 

        internal void BitmapEffectChanged(object sender, EventArgs e)
        {
            SetFlagsOnAllChannels(true, VisualProxyFlags.IsBitmapEffectDirty); 
            PropagateChangedFlags();
        } 
 

        internal EventHandler BitmapEffectInputChangedHandler 
        {
            get
            {
                return new EventHandler(BitmapEffectInputChanged); 
            }
        } 
 
        internal void BitmapEffectInputChanged(object sender, EventArgs e)
        { 
            if (CheckFlagsAnd(VisualFlags.NodeHasBitmapEffect))
            {
                SetFlagsOnAllChannels(true, VisualProxyFlags.IsBitmapEffectDirty);
 
                PropagateFlags(
                    this, 
                    VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate, 
                    VisualProxyFlags.IsSubtreeDirtyForRender);
            } 
        }

        internal EventHandler ContentsChangedHandler
        { 
            get
            { 
                return new EventHandler(ContentsChanged); 
            }
        } 

        internal virtual void ContentsChanged(object sender, EventArgs e)
        {
            PropagateChangedFlags(); 
        }
 
        #endregion Internal Event Handlers 

 

        // --------------------------------------------------------------------
        //
        //   Visual flags manipulation 
        //
        // ------------------------------------------------------------------- 
 
        #region Visual flags manipulation
 
        /// 
        /// SetFlagsOnAllChannels is used to set or unset one
        /// or multiple flags on all channels this visual is
        /// marshaled to. 
        /// 
        internal void SetFlagsOnAllChannels( 
            bool value, 
            VisualProxyFlags flagsToChange)
        { 
            _proxy.SetFlagsOnAllChannels(
                value,
                flagsToChange);
        } 

 
        ///  
        /// SetFlags is used to set or unset one or multiple flags on a given channel.
        ///  
        internal void SetFlags(
            DUCE.Channel channel,
            bool value,
            VisualProxyFlags flagsToChange) 
        {
            _proxy.SetFlags( 
                channel, 
                value,
                flagsToChange); 
        }


        ///  
        /// SetFlags is used to set or unset one or multiple node flags on the node.
        ///  
        internal void SetFlags(bool value, VisualFlags flags) 
        {
            _flags = value ? (_flags | flags) : (_flags & (~flags)); 
        }


        ///  
        /// CheckFlagsOnAllChannels returns true if all flags in
        /// the bitmask flags are set on all channels this visual is 
        /// marshaled to. 
        /// 
        ///  
        /// If there aren't any bits set on the specified flags
        /// the method returns true.
        /// 
        internal bool CheckFlagsOnAllChannels(VisualProxyFlags flagsToCheck) 
        {
            return _proxy.CheckFlagsOnAllChannels(flagsToCheck); 
        } 

 
        /// 
        /// CheckFlagsAnd returns true if all flags in the bitmask flags
        /// are set on a given channel.
        ///  
        /// 
        /// If there aren't any bits set on the specified flags 
        /// the method returns true. 
        /// 
        internal bool CheckFlagsAnd( 
            DUCE.Channel channel,
            VisualProxyFlags flagsToCheck)
        {
            return (_proxy.GetFlags(channel) & flagsToCheck) == flagsToCheck; 
        }
 
 
        /// 
        /// CheckFlagsAnd returns true if all flags in the bitmask flags are set on the node. 
        /// 
        /// If there aren't any bits set on the specified flags the method
        /// returns true
        internal bool CheckFlagsAnd(VisualFlags flags) 
        {
            return (_flags & flags) == flags; 
        } 

        ///  
        /// Checks if any of the specified flags is set on a given channel.
        /// 
        /// 
        /// If there aren't any bits set on the specified flags 
        /// the method returns true.
        ///  
        internal bool CheckFlagsOr( 
            DUCE.Channel channel,
            VisualProxyFlags flagsToCheck) 
        {
            return (_proxy.GetFlags(channel) & flagsToCheck) != VisualProxyFlags.None;
        }
 

        ///  
        /// Checks if any of the specified flags is set on the node. 
        /// 
        /// If there aren't any bits set on the specified flags the method 
        /// returns true
        internal bool CheckFlagsOr(VisualFlags flags)
        {
            return (flags == 0) || ((_flags & flags) > 0); 
        }
 
 
        /// 
        ///     Set a bit in a Visual node and in all its direct ancestors. 
        /// 
        /// The Visual Element
        /// The Flag that marks a sub tree to search
        /// The Flag that marks the node to search for. 
        internal static void SetTreeBits(
            DependencyObject e, 
            VisualFlags treeFlag, 
            VisualFlags nodeFlag)
        { 
            Visual eAsVisual;
            Visual3D eAsVisual3D;

            if (e != null) 
            {
                eAsVisual = e as Visual; 
                if (eAsVisual != null) 
                {
                    eAsVisual.SetFlags(true, nodeFlag); 
                }
                else
                {
                    ((Visual3D)e).SetFlags(true, nodeFlag); 
                }
            } 
 
            while (null!=e)
            { 
                eAsVisual = e as Visual;
                if (eAsVisual != null)
                {
                    // if the bit is already set, then we're done. 
                    if(eAsVisual.CheckFlagsAnd(treeFlag))
                        return; 
 
                    eAsVisual.SetFlags(true, treeFlag);
                } 
                else
                {
                    eAsVisual3D = e as Visual3D;
 
                    // if the bit is already set, then we're done.
                    if(eAsVisual3D.CheckFlagsAnd(treeFlag)) 
                        return; 

                    eAsVisual3D.SetFlags(true, treeFlag); 
                }

                e = VisualTreeHelper.GetParent(e);
            } 
        }
 
 
        /// 
        ///     Clean a bit in a Visual node and in all its direct ancestors; 
        ///     unless the ancestor also has
        /// 
        /// The Visual Element
        /// The Flag that marks a sub tree to search 
        /// The Flag that marks the node to search for.
        internal static void ClearTreeBits( 
            DependencyObject e, 
            VisualFlags treeFlag,
            VisualFlags nodeFlag) 
        {
            Visual eAsVisual;
            Visual3D eAsVisual3D;
 
            // This bit might not be set, but checking costs as much as setting
            // So it is faster to just clear it everytime. 
            if (e != null) 
            {
                eAsVisual = e as Visual; 
                if (eAsVisual != null)
                {
                    eAsVisual.SetFlags(false, nodeFlag);
                } 
                else
                { 
                    ((Visual3D)e).SetFlags(false, nodeFlag); 
                }
            } 

            while (e != null)
            {
                eAsVisual = e as Visual; 
                if (eAsVisual != null)
                { 
                    if(eAsVisual.CheckFlagsAnd(nodeFlag)) 
                    {
                        return;  // Done;   if a parent also has the Node bit set. 
                    }

                    if(DoAnyChildrenHaveABitSet(eAsVisual, treeFlag))
                    { 
                        return;  // Done;   if a other subtrees are set.
                    } 
 
                    eAsVisual.SetFlags(false, treeFlag);
                } 
                else
                {
                    eAsVisual3D = e as Visual3D;
 
                    if(eAsVisual3D.CheckFlagsAnd(nodeFlag))
                    { 
                        return;  // Done;   if a parent also has the Node bit set. 
                    }
 
                    if(Visual3D.DoAnyChildrenHaveABitSet(eAsVisual3D, treeFlag))
                    {
                        return;  // Done;   if a other subtrees are set.
                    } 

                    eAsVisual3D.SetFlags(false, treeFlag); 
                } 

                e = VisualTreeHelper.GetParent(e); 
            }
        }

 
        /// 
        ///     Check all the children for a bit. 
        ///  
        private static bool DoAnyChildrenHaveABitSet(
            Visual pe, 
            VisualFlags flag)
        {

            int count = pe.VisualChildrenCount; 
            for (int i = 0; i < count; i++)
            { 
                Visual v = pe.GetVisualChild(i); 
                if (v != null && v.CheckFlagsAnd(flag))
                { 
                    return true;
                }
            }
 
            return false;
        } 
 

        ///  
        /// Propagates the flags up to the root.
        /// 
        /// 
        /// The walk stops on a node with all of the required flags set. 
        /// 
        internal static void PropagateFlags( 
            Visual e, 
            VisualFlags flags,
            VisualProxyFlags proxyFlags) 
        {
            while ((e != null) &&
                   (!e.CheckFlagsAnd(flags) || !e.CheckFlagsOnAllChannels(proxyFlags)))
            { 
                if (e.CheckFlagsOr(VisualFlags.ShouldPostRender))
                { 
                    MediaContext mctx = MediaContext.From(e.Dispatcher); 

                    if (mctx.Channel != null) 
                    {
                        mctx.PostRender();
                    }
                } 
                else if (e.CheckFlagsAnd(VisualFlags.NodeIsVisualBrushRoot))
                { 
                    // 
                    // For visuals that are root nodes in visual brushes we
                    // need to fire OnChanged on the owning brushes. 
                    //

                    Dictionary visualBrushToChannelsMap =
                        VisualBrushToChannelsMapField.GetValue(e); 

                    Debug.Assert(visualBrushToChannelsMap != null, "Visual brush roots need to have the visual brush to channels map!"); 
 

                    // 
                    // Iterate over the visual brushes and fire the OnChanged event.
                    //

                    foreach (VisualBrush visualBrush in visualBrushToChannelsMap.Keys) 
                    {
                        visualBrush.FireOnChanged(); 
                    } 
                }
 
                e.SetFlags(true, flags);
                e.SetFlagsOnAllChannels(true, proxyFlags);

                if (e._parent == null) 
                {
                    // Stop propagating.  We are at the root of the 2D subtree. 
                    return; 
                }
 
                Visual parentAsVisual = e._parent as Visual;
                if (parentAsVisual == null)
                {
                    // if the parent is not null (saw this with earlier null check) and is not a Visual 
                    // it must be a Visual3D - continue the propagation
                    Visual3D.PropagateFlags((Visual3D)e._parent, flags, proxyFlags); 
                    return; 
                }
 
                e = parentAsVisual;
            }
        }
 
        /// 
        /// Sets the NodeRequiresNewRealization flag on the current node and 
        /// propagates the subtree realizations and dirty flags up to the root 
        /// 
        ///  
        /// The walk stops on a node with all of the required flags set.
        /// 
        internal void PropagateChangedFlags()
        { 
            //
            // Don't always know in advance if node has realizations, so propagate 
            // flags regardless. 
            //
            SetFlags(true, VisualFlags.NodeRequiresNewRealization); 

            PropagateFlags(
                this,
                VisualFlags.IsSubtreeDirtyForPrecompute | VisualFlags.NodeNeedsBitmapEffectUpdate, 
                VisualProxyFlags.IsSubtreeDirtyForRender);
        } 
 
        #endregion Visual flags manipulation
 
#if TRACE
        /// 
        /// Debug variable for counting nodes touched in the
        /// realizations walk 
        /// 
        internal static int MarkVisibleRealizationsCount; 
#endif 

        ///  
        /// This node or a node below it contains a graphness
        /// inducing element
        /// 
        internal bool NodeContainsGraphness 
        {
            get 
            { 
                return CheckFlagsAnd(VisualFlags.NodeOrDescendantIntroducesGraphness);
            } 
        }

        // -------------------------------------------------------------------
        // 
        //   Internal Fields
        // 
        // ------------------------------------------------------------------- 

        #region Internal Fields 

        internal static readonly UncommonField BitmapEffectStateField = new UncommonField();

        internal delegate void AncestorChangedEventHandler(object sender, AncestorChangedEventArgs e); 

        // index in parent child array. no meaning if parent is null. 
        // note that we maintain in debug that the _parentIndex is -1 if the parent is null. 
        internal int _parentIndex;
 
        // ([....]) I think we have to change the API so that we can save
        // here. For now that is good enough.
        internal DependencyObject _parent;
 
        internal VisualProxy _proxy;
 
        #endregion Internal Fields 

 

        // --------------------------------------------------------------------
        //
        //   Private Fields 
        //
        // ------------------------------------------------------------------- 
 
        #region Private Fields
 
        // bbox in inner coordinate space of this node including its children.
        private Rect _bboxSubgraph = Rect.Empty;

        // 
        // Store the visual brushes hold on to this visual. Also store the corresponding
        // number of channel, on which that visual brush holds on to this visual. 
        // 
        private static readonly UncommonField> VisualBrushToChannelsMapField
            = new UncommonField>(); 

        //
        // Store the channels on which visual brushes hold on to this visual. Also store the
        // corresponding number of visual brushes on that channel, holding on to this visual. 
        //
        private static readonly UncommonField> ChannelsToVisualBrushMapField 
            = new UncommonField>(); 

        private static readonly UncommonField ClipField = new UncommonField(); 
        private static readonly UncommonField OpacityField = new UncommonField();
        private static readonly UncommonField OpacityMaskField = new UncommonField();
        private static readonly UncommonField EdgeModeField = new UncommonField();
        private static readonly UncommonField BitmapScalingModeField = new UncommonField(); 

        private static readonly UncommonField TransformField = new UncommonField(); 
 
        private static readonly UncommonField GuidelinesXField = new UncommonField();
        private static readonly UncommonField GuidelinesYField = new UncommonField(); 

        private static readonly UncommonField AncestorChangedEventField
            = new UncommonField();
 
        private Vector _offset;
        private VisualFlags _flags; 
 
        #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