Visual.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / Visual.cs / 3 / 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.IsEffectDirty
            | 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); 
        }
 
        /// 
        /// 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.
        ///
        /// NTRAID#Longhorn-111639-2007/07/05-kurtb:
        /// This is needed since MIL and the managed size differ about how big content bounds are 
        /// WPF considers geometric bounds (i.e. it will union in points) while MIL considers anything
        /// with zero area to be empty.  This poses problems when looking for the exact size of a 
        /// VisualBrush. 
        /// 
        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. 
        ///
        /// NTRAID#Longhorn-111639-2007/07/05-kurtb:
        /// This is needed since MIL and the managed size differ about how big content bounds are
        /// WPF considers geometric bounds (i.e. it will union in points) while MIL considers anything 
        /// with zero area to be empty.  This poses problems when looking for the exact size of a
        /// VisualBrush. 
        ///  
        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.NodeHasEffect))
            {
                Rect effectBounds;
 
                Effect effect = EffectField.GetValue(this);
                if (effect != null) 
                { 
                    // The Effect always deals in unit bounds, so transform the
                    // unit rect and then map back into the world space bounds 
                    // defined by bboxSubgraph.

                    Rect unitBounds = new Rect(0,0,1,1);
                    Rect unitTransformedBounds = effect.EffectMapping.TransformBounds(unitBounds); 

                    Point topLeft = Effect.UnitToWorld(unitTransformedBounds.TopLeft, bboxSubgraph); 
                    Point bottomRight = Effect.UnitToWorld(unitTransformedBounds.BottomRight, bboxSubgraph); 

                    effectBounds = new Rect(topLeft, bottomRight); 
                }
                else
                {
                    Debug.Assert(BitmapEffectStateField.GetValue(this) != null); 
                    effectBounds = BitmapEffectStateField.GetValue(this).GetBounds(bboxSubgraph);
                    if (renderBounds && IsEmptyRenderBounds(ref effectBounds /* ref for perf - not modified */)) 
                    { 
                        effectBounds = Rect.Empty;
                    } 
                }

                bboxSubgraph.Union(effectBounds);
            } 

            // 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 
        ///
        /// NTRAID#Longhorn-111639-2007/07/05-kurtb:
        /// See above CalculateSubgraphBounds* methods for more detail.  This helper method
        /// goes with them. 
        /// 
        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
                if (CheckFlagsAnd(ctx.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. 
                //
 
                //
                // NTRAID#Longhorn-1964653-2007/04/19-jordanpa:
                // RenderTargetBitmap and BitmapEffects use synchronous channels. If a
                // node on the synchronous channel is the root of a VisualBrush from another 
                // channel, then the node will never be deleted. Instead we really need to
                // check if the node is the root of a VisualBrush _on the same channel_. 
                // This check is more expensive so we'll leave the faster check first to avoid 
                // the more expensive check which isn't necessary most of the time.
                // 
                // If the node is the root of a VisualBrush and the VisualBrush is one of
                // the node's children then a cycle is created. All of the nodes on the
                // cycle will leak. On [....] channels, this is particularly bad because
                // the user doesn't know about the [....] channel and has no control over it. 
                // We have a queue of [....] channels that are reused and leaking can lead
                // to conflicts on channel reuse resulting in a crash. 
                // 
                // *** DANGER *** Fortunately, as of today, tree structure on a [....] channel is
                // never manipulated. The tree gets built, the tree gets drawn, and the tree gets 
                // released. Because of this, we can just always delete. In the future if that
                // changes, the isSynchronous check here will cause a problem. *** DANGER ***
                //
                // The bug representing the outstanding cyle leak issue is 1981551 
                //
 
                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);
                    } 

                    Effect effect = EffectField.GetValue(this); 
                    if ((effect != null) 
                        && (!CheckFlagsAnd(channel, VisualProxyFlags.IsEffectDirty)))
                    { 
                        ((DUCE.IResource)effect).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 (!NodeHasLegacyBitmapEffect) 
                    {
                        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 [....] 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) 
                {
                    // 
                    // Add the visual to the remove and release queue. 
                    //
                    // The visual used to be released immediately, but it was causing problems where 
                    // the visual had children who were being removed from it, so there was a command
                    // referring to the visual in the channel's remove and release queue. When Render
                    // came around, it looked up the handle for the visual to make the remove command,
                    // except the visual didn't have a handle anymore because it was released 
                    // immediately here. For more details see Dev10 453126.
                    // 
                    channel.AddToRemoveAndReleaseQueue( 
                        null,
                        this); 
                }
            }
        }
 
        #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
                        // 
#pragma warning disable 0618 
                        if (VisualBitmapEffect != null)
#pragma warning restore 0618 
                        {
                            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 (NodeHasLegacyBitmapEffect) 
                        {
                            // 
                            // 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);
                    UpdateEffect(channel, handle, flags, isOnChannel); 
                    UpdateGuidelines(channel, handle, flags, isOnChannel);

                    // if we have a legacy BitmapEffect, mark the effect as dirty
                    // we will render the rest of the visual during 
                    // the realization pass
                    if (NodeHasLegacyBitmapEffect) 
                    { 

                        // 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 bitmap effect. 
        ///  
        /// 
        ///  
        /// 
        /// The Visual exists on channel.
        private void UpdateEffect(DUCE.Channel channel,
                                     DUCE.ResourceHandle handle, 
                                     VisualProxyFlags flags,
                                     bool isOnChannel) 
        { 
            // Bitmap Effect  --------------------------------------------------------------------------------
 
            if ((flags & VisualProxyFlags.IsEffectDirty) != 0)
            {
                Effect effect = EffectField.GetValue(this);
 
                if (effect != null)
                { 
                    // 
                    // Set the new effect resource on the visual.
                    // If effect is null we don't need to do this. 
                    // Also note that the old effect was disconnected
                    // in the Effect property setter.
                    //
 
                    DUCE.CompositionNode.SetEffect(
                        handle, 
                        ((DUCE.IResource)effect).AddRefOnChannel(channel), 
                        channel);
                } 
                else if (isOnChannel) /* effect == null */
                {
                    DUCE.CompositionNode.SetEffect(
                        handle, 
                        DUCE.ResourceHandle.Null,
                        channel); 
                } 
                SetFlags(channel, false, VisualProxyFlags.IsEffectDirty);
            } 
        }


 
        /// 
        /// 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;
 
            bool isChildrenZOrderDirty = CheckFlagsAnd(channel, VisualProxyFlags.IsChildrenZOrderDirty); 
            int childCount = VisualChildrenCount;
 
            //
            // If the visual children have been re-ordered, enqueue a packet to RemoveAllChildren,
            // then reinsert all the children.  The parent visual will release the children when
            // the RemoveAllChildren packet, but the managed visuals will still have references 
            // to them so that they won't be destructed and recreated.
            // 
            if (isChildrenZOrderDirty) 
            {
                DUCE.CompositionNode.RemoveAllChildren( 
                    handle,
                    channel);
            }
 
            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 or that the ZOrder 
                    // of the children has changed.
                    // 
                    if (child.IsOnChannel(channel)) 
                    {
                        bool isConnectedToParent = child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent); 

                        if (!isConnectedToParent || isChildrenZOrderDirty)
                        {
                            DUCE.CompositionNode.InsertChildAt( 
                                handle,
                                ((DUCE.IResource)child).GetHandle(channel), 
                                connectedChildIndex, 
                                channel);
 
                            child.SetFlags(
                                channel,
                                true,
                                VisualProxyFlags.IsConnectedToParent); 
                        }
 
                        connectedChildIndex++; 
                    }
                } 
            }

            SetFlags(channel, false, VisualProxyFlags.IsChildrenZOrderDirty);
        } 

 
        ///  
        /// Marks the visible realizations in this visual graph.
        ///  
        /// The realization context.
        /// 
        /// 
        internal void MarkVisibleRealizations(RealizationContext ctx) 
        {
            Debug.Assert(IsOnChannel(ctx.Channel)); 
 
            if (    CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches)
                 || NodeHasLegacyBitmapEffect) 
            {
                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_MVR 
                    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 (NodeHasLegacyBitmapEffect)
                    { 
                        // 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.IsOnChannel(ctx.Channel));
 
                    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.NodeHasEffect)) 
                { 
                    Effect imageEffect = EffectField.GetValue(this);
                    if (imageEffect != null) 
                    {
                        GeneralTransform effectHitTestInverse = imageEffect.EffectMapping.Inverse;

                        // only do work if the transform isn't the identity transform 
                        if (effectHitTestInverse != Transform.Identity)
                        { 
                            bool ok = false; 

                            // Convert to unit space 
                            Point? unitHitPoint = Effect.WorldToUnit(originalHitPoint, _bboxSubgraph);
                            if (unitHitPoint != null)
                            {
                                Point transformedPt = new Point(); 

                                // Do the transform 
 
                                ok = effectHitTestInverse.TryTransform(unitHitPoint.Value, out transformedPt);
                                if (ok) 
                                {
                                    // Convert back to world space
                                    hitPoint = Effect.UnitToWorld(transformedPt, _bboxSubgraph);
                                } 
                            }
 
                            if (!ok) 
                            {
                                return HitTestResultBehavior.Continue; 
                            }
                        }
                    }
                    else 
                    {
                        Debug.Assert(BitmapEffectStateField.GetValue(this) != null); 
                        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.NodeHasEffect))
            { 
                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this);
                if (bitmapEffectState != null)
                {
                    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(); 
                        // Note that the below likely should be VisualDescendantBounds, but we're not modifying this 
                        // code now that legacy BitmapEffects are obsolete.
                        group.Children.Add(new BitmapEffectGeneralTransform(bitmapEffectState.BitmapEffect, 
                                                                            bitmapEffectState.BitmapEffectInput, false, VisualContentBounds));
                    }
                }
                else 
                {
                    Effect effect = EffectField.GetValue(this); 
                    GeneralTransform gt = effect.CoerceToUnitSpaceGeneralTransform( 
                        effect.EffectMapping,
                        VisualDescendantBounds); 

                    Transform affineTransform = gt.AffineTransform;
                    if (affineTransform != null)
                    { 
                        Matrix cm = affineTransform.Value;
                        MatrixUtil.MultiplyMatrix(ref m, ref cm); 
                    } 
                    else
                    { 
                        group = new GeneralTransformGroup();
                        group.Children.Add(gt);
                    }
                } 
            }
 
            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 | VisualProxyFlags.IsChildrenZOrderDirty);

            //
 
            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); 
            }
        } 

        /// 
        /// Gets or sets the Effect of this Visual.
        ///  
        protected internal Effect VisualEffect
        { 
            get 
            {
                VerifyAPIReadOnly(); 

                return VisualEffectInternal;
            }
            protected set 
            {
                VerifyAPIReadWrite(value); 
 
                // Legacy BitmapEffects and new Effects cannot be mixed because the new image effect
                // pipeline may be used to emulate a legacy BitmapEffect. 
                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);
                if (bed != null)
                {
                    if (value != null) // UIElement has a tendency to set a lot of properties to null even if it 
                                       // never set a property to a different value in the first place.
                    { 
                        // If a BitmapEffect is set, the user cannot set an Effect, since 
                        // mixing of legacy BitmapEffects is not allowed with Effects.
                        throw new Exception(SR.Get(SRID.Effect_CombinedLegacyAndNew)); 
                    }
                    else
                    {
                        return; 
                    }
                } 
 
                VisualEffectInternal = value;
 
            }
        }

        ///  
        /// Internal accessor to image effect property that gets or sets the Effect of this Visual.
        /// The internal accessor is used by the VisualBitmapEffect emulation layer to avoid some of the 
        /// compatibility checks in the protected VisualEffect property. 
        /// 
        internal Effect VisualEffectInternal 
        {
            get
            {
                // Legacy BitmapEffects and new Effects cannot be mixed because the new image effect 
                // pipeline may be used to emulate a legacy BitmapEffect. Therefore, if a BitmapEffect is
                // assigned to this node, the Effect is conceptually not set and null must be returned 
                // from this getter. If no BitmapEffect is set on this node, the Effect has been provided 
                // by the user and therefore the Effect is returned.
 
                if (NodeHasLegacyBitmapEffect)
                {
                    return null;
                } 
                else
                { 
                    return EffectField.GetValue(this); 
                }
            } 

            set
            {
                Effect imageEffect = EffectField.GetValue(this); 
                if (imageEffect == value)
                { 
                    return; 
                }
 
                Effect newEffect = value;

                // Add changed notifications for the new Effect if necessary.
                if (newEffect != null && !newEffect.IsFrozen) 
                {
                    newEffect.Changed += EffectChangedHandler; 
                } 

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

                    if (!imageEffect.IsFrozen) 
                    { 
                        imageEffect.Changed -= EffectChangedHandler;
                    } 

                    //
                    // Disconnect the Effect from this visual.
                    // 

                    DisconnectAttachedResource( 
                        VisualProxyFlags.IsEffectDirty, 
                        ((DUCE.IResource)imageEffect));
                } 

                //
                // Set the new effect and mark it dirty
                // 

                SetFlags(newEffect != null, VisualFlags.NodeHasEffect); 
 
                EffectField.SetValue(this, newEffect);
 
                SetFlagsOnAllChannels(true, VisualProxyFlags.IsEffectDirty);

                EffectChanged(/* 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).
        /// 
        [Obsolete(MS.Internal.Media.VisualTreeUtils.BitmapEffectObsoleteMessage)] 
        protected internal BitmapEffect VisualBitmapEffect
        { 
            get 
            {
                VerifyAPIReadOnly(); 

                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);

                if (bed != null) 
                {
                    return bed.BitmapEffect; 
                } 
                else
                { 
                    return null;
                }
            }
 
            protected set
            { 
                VerifyAPIReadWrite(value); 

                // 
                // Figure out if a image effect has been provided by the user. If so, calling this API is illegal
                // since new Effects and legacy BitmapEffects cannot be mixed.

                Effect imageEffect = EffectField.GetValue(this); 
                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);
                if (   (bed == null) 
                    && (imageEffect != null)) 

                { 
                    if (value != null) // Allowing incoming value of null because UIElements tend
                                       // to aggressively set this property to null even if it has never been set.
                    {
                        // If no BitmapEffect is set and an Effect is set, the Effect has been 
                        // provided by the user and not by emulation. Since mixing of legacy
                        // BitmapEffects is not allowed with Effects, setting a BitmapEffect is illegal. 
                        throw new Exception(SR.Get(SRID.Effect_CombinedLegacyAndNew)); 
                    }
                    else 
                    {
                        return;
                    }
                } 

 
                // 
                // To enable emulation of the legacy effects on top of the new effects pipeline, store the
                // bitmap effect information in our staging uncommon field: UserProvidedBitmapEffectData. 

                BitmapEffect oldBitmapEffect = (bed == null) ? null : bed.BitmapEffect;
                if (oldBitmapEffect == value) // If new and old value are the same, this set call can be treated as a no-op.
                { 
                    return;
                } 
 
                BitmapEffect newBitmapEffect = value;
 
                if (newBitmapEffect == null)
                {
                    Debug.Assert(bed != null, "Must be non-null because otherwise the code would have earlied out where new value is compared against old value.");
                    // The following line of code will effectively set the BitmapEffectInput property to null. This is strange behavior for WPF properties, but follows the 
                    // original BitmapEffects implementation.
                    UserProvidedBitmapEffectData.SetValue(this, null); 
                } 
                else
                { 
                    if (bed == null)
                    {
                        bed = new BitmapEffectData();
                        UserProvidedBitmapEffectData.SetValue(this, bed); 
                    }
 
                    bed.BitmapEffect = newBitmapEffect; 
                }
 
                if (newBitmapEffect != null && !newBitmapEffect.IsFrozen)
                {
                    newBitmapEffect.Changed += new EventHandler(BitmapEffectEmulationChanged);
                } 
                if (oldBitmapEffect != null && !oldBitmapEffect.IsFrozen)
                { 
                    oldBitmapEffect.Changed -= new EventHandler(BitmapEffectEmulationChanged); 
                }
 
                // Notify about the bitmap effect changes to configure the new emulation.
                BitmapEffectEmulationChanged(/* 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).
        /// 
        [Obsolete(MS.Internal.Media.VisualTreeUtils.BitmapEffectObsoleteMessage)] 
        protected internal BitmapEffectInput VisualBitmapEffectInput
        { 
            get 
            {
                VerifyAPIReadOnly(); 

                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);

                if (bed != null) 
                {
                    return bed.BitmapEffectInput; 
                } 
                else
                { 
                    return null;
                }
            }
 
            protected set
            { 
                VerifyAPIReadWrite(value); 

                // 
                // Figure out if a image effect has been provided by the user. If so, calling this API is illegal
                // sinc new Effects and legacy BitmapEffects cannot be mixed.

                Effect imageEffect = EffectField.GetValue(this); 
                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);
                if ((bed == null) && (imageEffect != null)) 
                { 
                    if (value != null) // Allowing null because parser and UIElement tend to set this property to null
                                       // even if it has never been set to non-null. 
                    {
                        // If no BitmapEffect is set and an Effect is set, the Effect has been
                        // provided by the user. Since mixing of legacy BitmapEffects is not allowed with
                        // Effects, setting a BitmapEffect is illegal. 
                        throw new Exception(SR.Get(SRID.Effect_CombinedLegacyAndNew));
                    } 
                    else 
                    {
                        return; 
                    }
                }

 
                //
                // To enable emulation of the legacy effects on top of the new effects pipeline, store the 
                // bitmap effect input information in our staging uncommon field: UserProvidedBitmapEffectData. 

                BitmapEffectInput oldBitmapEffectInput = (bed == null) ? null : bed.BitmapEffectInput; 
                BitmapEffectInput newBitmapEffectInput = value;

                if (oldBitmapEffectInput == newBitmapEffectInput) // If new and old value are the same, this set call can be treated as a no-op.
                { 
                    return;
                } 
 
                // Make sure there is a BitmapEffectData instance allocated.
                if (bed == null) 
                {
                    bed = new BitmapEffectData();
                    UserProvidedBitmapEffectData.SetValue(this, bed);
                } 

                bed.BitmapEffectInput = newBitmapEffectInput; 
 

                if (newBitmapEffectInput != null && !newBitmapEffectInput.IsFrozen) 
                {
                    newBitmapEffectInput.Changed += new EventHandler(BitmapEffectEmulationChanged);
                }
                if (oldBitmapEffectInput != null && !oldBitmapEffectInput.IsFrozen) 
                {
                    oldBitmapEffectInput.Changed -= new EventHandler(BitmapEffectEmulationChanged); 
                } 

                // Notify about the bitmap effect changes to configure the new emulation. 
                BitmapEffectEmulationChanged(/* sender */ null, /* args */ null);
            }
        }
 

        //  
        // This handler reconfigures the bitmap effects pipeline whenever anything changes. It is 
        // responsible for figuring out if a legacy effect can be emulated on the new pipeline or
        // not. 
        // 
        internal void BitmapEffectEmulationChanged(object sender, EventArgs e)
        {
            BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this); 
            BitmapEffect currentBitmapEffect = (bed == null) ? null : bed.BitmapEffect;
            BitmapEffectInput currentBitmapEffectInput = (bed == null) ? null : bed.BitmapEffectInput; 
 
            // Note that when this method is called, a legacy BitmapEffect has been set or reset on
            // the Visual by the user. The next step is to try to emulate the effect in case the current 
            // effect is non null or reset the emulation layer if the user has set the effect to null.

            if (currentBitmapEffect == null)
            { 
                // This means the effect has been disconnected from this Visual. Setting the internal
                // bitmap effect property and the image effect property to null to disconnect all the 
                // effects. The Effect property needs to be set to null because the effect might 
                // be emulated.
                VisualBitmapEffectInternal = null; 
                VisualBitmapEffectInputInternal = null;
                VisualEffectInternal = null;
            }
            else if (currentBitmapEffectInput != null) 
            {
                // If a BitmapEffectInput is specified, make sure the legacy effect is not being 
                // emulated using the Effect pipeline since the new pipeline does not support 
                // BitmapEffecInputs.
                VisualEffectInternal = null; 
                VisualBitmapEffectInternal = currentBitmapEffect;
                VisualBitmapEffectInputInternal = currentBitmapEffectInput;
            }
            else if (RenderCapability.IsShaderEffectSoftwareRenderingSupported && 
                    currentBitmapEffect.CanBeEmulatedUsingEffectPipeline() &&
                    (!CheckFlagsAnd(VisualFlags.BitmapEffectEmulationDisabled))) 
            { 
                // If we can emulate the effect switch to emulating it.
                VisualBitmapEffectInternal = null; 
                VisualBitmapEffectInputInternal = null;
                VisualEffectInternal = currentBitmapEffect.GetEmulatingEffect();
            }
            else 
            {
                // Cannot emulate the effect, using legacy pipeline. 
                VisualEffectInternal = null; 
                VisualBitmapEffectInputInternal = null;
                VisualBitmapEffectInternal = currentBitmapEffect; 
            }

        }
 
        /// 
        /// Used by the test team to disable bitmap effect emulation for testing purposes. 
        ///  
        internal bool BitmapEffectEmulationDisabled
        { 
            get
            {
                return CheckFlagsAnd(VisualFlags.BitmapEffectEmulationDisabled);
            } 
            set
            { 
                if (value != CheckFlagsAnd(VisualFlags.BitmapEffectEmulationDisabled)) 
                {
                    SetFlags(value, VisualFlags.BitmapEffectEmulationDisabled); 

                    // Notify about the bitmap effect changes to configure the new emulation.
                    BitmapEffectEmulationChanged(/* sender */ null, /* args */ null);
                } 
            }
        } 
 
        /// 
        /// Internal accessor to BitmapEffect property that gets or sets the BitmapEffect of this Visual. 
        /// The internal accessor is used by the VisualBitmapEffect emulation layer to avoid some of the
        /// compatibility checks in the protected VisualBitmapEffect property.
        /// 
        internal BitmapEffect VisualBitmapEffectInternal 
        {
            get 
            { 
                VerifyAPIReadOnly();
 
                if (NodeHasLegacyBitmapEffect)
                {
                    return BitmapEffectStateField.GetValue(this).BitmapEffect;
                } 
                else
                { 
                    return null; 
                }
            } 

            set
            {
                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.NodeHasEffect); 
                    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; 

                    Debug.Assert(EffectField.GetValue(this) == null, "Not expecting both BitmapEffect and Effect to be set on the same node"); 
                    SetFlags(true, VisualFlags.NodeHasEffect); 
                }
 
                // 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);
            } 
        } 

        ///  
        /// Internal accessor to BitmapEffectInput property that gets or sets the BitmapEffectInput of this Visual.
        /// The internal accessor is used by the VisualBitmapEffect emulation layer to avoid some of the
        /// compatibility checks in the protected VisualBitmapEffectInput property.
        ///  
        internal BitmapEffectInput VisualBitmapEffectInputInternal
        { 
            get 
            {
                VerifyAPIReadOnly(); 
                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this);
                if (bitmapEffectState != null)
                    return bitmapEffectState.BitmapEffectInput;
 
                return null;
            } 
 
            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;
 
                    // 
                    // NTRAID#Longhorn-1611281-2006/04/14-bedej:
                    // If this node or subtree has realizations, and there are bitmap effects in the 
                    // scene, we need to propagate the change flag so that we can produce new realizations
                    // for those bitmap effects. This means that adding bitmap effects will regress
                    // performance by producing unnecessary glyph realizations.
                    // 

                    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);
 
                // GSchneid: 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 (!NodeHasLegacyBitmapEffect) 
                    {
                        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 (gAsVisual.CheckFlagsAnd(VisualFlags.NodeHasEffect)) 
                    {
                        // Only check for Effect, not legacy BitmapEffect.  Previous
                        // version had an incorrect BitmapEffect implementation
                        // here, and there's no need to improve on our 
                        // BitmapEffect implementation if it didn't work
                        // before. 
 
                        Effect imageEffect = EffectField.GetValue(gAsVisual);
                        if (imageEffect != null) 
                        {
                            GeneralTransform gt = imageEffect.CoerceToUnitSpaceGeneralTransform(
                                imageEffect.EffectMapping,
                                gAsVisual.VisualDescendantBounds); 

                            Transform affineTransform = gt.AffineTransform; 
                            if (affineTransform != null) 
                            {
                                Matrix cm = affineTransform.Value; 
                                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(gt); 
                            }
                        } 
                    } 

                    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 EffectChangedHandler 
        {
            get 
            { 
                return new EventHandler(EffectChanged);
            } 
        }

        internal void EffectChanged(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 (NodeHasLegacyBitmapEffect) 
            {
                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); 
        }
 
 
        private bool NodeHasLegacyBitmapEffect
        { 
            get
            {
                // NodeHasEffect flag is overloaded for both legacy
                // BitmapEffects and the newer Effects 
                return
                    CheckFlagsAnd(VisualFlags.NodeHasEffect) && 
                    BitmapEffectStateField.GetValue(this) != null; 
            }
        } 


        #endregion Visual flags manipulation
 
#if TRACE_MVR
        ///  
        /// 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;
 
        // (GSchneid) 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 EffectField = new UncommonField();

        private static readonly UncommonField GuidelinesXField = new UncommonField(); 
        private static readonly UncommonField GuidelinesYField = new UncommonField();
 
        private static readonly UncommonField AncestorChangedEventField 
            = new UncommonField();
 
        private static readonly UncommonField UserProvidedBitmapEffectData = 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.
//------------------------------------------------------------------------------ 
//
// 
//    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.IsEffectDirty
            | 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); 
        }
 
        /// 
        /// 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.
        ///
        /// NTRAID#Longhorn-111639-2007/07/05-kurtb:
        /// This is needed since MIL and the managed size differ about how big content bounds are 
        /// WPF considers geometric bounds (i.e. it will union in points) while MIL considers anything
        /// with zero area to be empty.  This poses problems when looking for the exact size of a 
        /// VisualBrush. 
        /// 
        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. 
        ///
        /// NTRAID#Longhorn-111639-2007/07/05-kurtb:
        /// This is needed since MIL and the managed size differ about how big content bounds are
        /// WPF considers geometric bounds (i.e. it will union in points) while MIL considers anything 
        /// with zero area to be empty.  This poses problems when looking for the exact size of a
        /// VisualBrush. 
        ///  
        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.NodeHasEffect))
            {
                Rect effectBounds;
 
                Effect effect = EffectField.GetValue(this);
                if (effect != null) 
                { 
                    // The Effect always deals in unit bounds, so transform the
                    // unit rect and then map back into the world space bounds 
                    // defined by bboxSubgraph.

                    Rect unitBounds = new Rect(0,0,1,1);
                    Rect unitTransformedBounds = effect.EffectMapping.TransformBounds(unitBounds); 

                    Point topLeft = Effect.UnitToWorld(unitTransformedBounds.TopLeft, bboxSubgraph); 
                    Point bottomRight = Effect.UnitToWorld(unitTransformedBounds.BottomRight, bboxSubgraph); 

                    effectBounds = new Rect(topLeft, bottomRight); 
                }
                else
                {
                    Debug.Assert(BitmapEffectStateField.GetValue(this) != null); 
                    effectBounds = BitmapEffectStateField.GetValue(this).GetBounds(bboxSubgraph);
                    if (renderBounds && IsEmptyRenderBounds(ref effectBounds /* ref for perf - not modified */)) 
                    { 
                        effectBounds = Rect.Empty;
                    } 
                }

                bboxSubgraph.Union(effectBounds);
            } 

            // 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 
        ///
        /// NTRAID#Longhorn-111639-2007/07/05-kurtb:
        /// See above CalculateSubgraphBounds* methods for more detail.  This helper method
        /// goes with them. 
        /// 
        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
                if (CheckFlagsAnd(ctx.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. 
                //
 
                //
                // NTRAID#Longhorn-1964653-2007/04/19-jordanpa:
                // RenderTargetBitmap and BitmapEffects use synchronous channels. If a
                // node on the synchronous channel is the root of a VisualBrush from another 
                // channel, then the node will never be deleted. Instead we really need to
                // check if the node is the root of a VisualBrush _on the same channel_. 
                // This check is more expensive so we'll leave the faster check first to avoid 
                // the more expensive check which isn't necessary most of the time.
                // 
                // If the node is the root of a VisualBrush and the VisualBrush is one of
                // the node's children then a cycle is created. All of the nodes on the
                // cycle will leak. On [....] channels, this is particularly bad because
                // the user doesn't know about the [....] channel and has no control over it. 
                // We have a queue of [....] channels that are reused and leaking can lead
                // to conflicts on channel reuse resulting in a crash. 
                // 
                // *** DANGER *** Fortunately, as of today, tree structure on a [....] channel is
                // never manipulated. The tree gets built, the tree gets drawn, and the tree gets 
                // released. Because of this, we can just always delete. In the future if that
                // changes, the isSynchronous check here will cause a problem. *** DANGER ***
                //
                // The bug representing the outstanding cyle leak issue is 1981551 
                //
 
                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);
                    } 

                    Effect effect = EffectField.GetValue(this); 
                    if ((effect != null) 
                        && (!CheckFlagsAnd(channel, VisualProxyFlags.IsEffectDirty)))
                    { 
                        ((DUCE.IResource)effect).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 (!NodeHasLegacyBitmapEffect) 
                    {
                        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 [....] 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) 
                {
                    // 
                    // Add the visual to the remove and release queue. 
                    //
                    // The visual used to be released immediately, but it was causing problems where 
                    // the visual had children who were being removed from it, so there was a command
                    // referring to the visual in the channel's remove and release queue. When Render
                    // came around, it looked up the handle for the visual to make the remove command,
                    // except the visual didn't have a handle anymore because it was released 
                    // immediately here. For more details see Dev10 453126.
                    // 
                    channel.AddToRemoveAndReleaseQueue( 
                        null,
                        this); 
                }
            }
        }
 
        #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
                        // 
#pragma warning disable 0618 
                        if (VisualBitmapEffect != null)
#pragma warning restore 0618 
                        {
                            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 (NodeHasLegacyBitmapEffect) 
                        {
                            // 
                            // 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);
                    UpdateEffect(channel, handle, flags, isOnChannel); 
                    UpdateGuidelines(channel, handle, flags, isOnChannel);

                    // if we have a legacy BitmapEffect, mark the effect as dirty
                    // we will render the rest of the visual during 
                    // the realization pass
                    if (NodeHasLegacyBitmapEffect) 
                    { 

                        // 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 bitmap effect. 
        ///  
        /// 
        ///  
        /// 
        /// The Visual exists on channel.
        private void UpdateEffect(DUCE.Channel channel,
                                     DUCE.ResourceHandle handle, 
                                     VisualProxyFlags flags,
                                     bool isOnChannel) 
        { 
            // Bitmap Effect  --------------------------------------------------------------------------------
 
            if ((flags & VisualProxyFlags.IsEffectDirty) != 0)
            {
                Effect effect = EffectField.GetValue(this);
 
                if (effect != null)
                { 
                    // 
                    // Set the new effect resource on the visual.
                    // If effect is null we don't need to do this. 
                    // Also note that the old effect was disconnected
                    // in the Effect property setter.
                    //
 
                    DUCE.CompositionNode.SetEffect(
                        handle, 
                        ((DUCE.IResource)effect).AddRefOnChannel(channel), 
                        channel);
                } 
                else if (isOnChannel) /* effect == null */
                {
                    DUCE.CompositionNode.SetEffect(
                        handle, 
                        DUCE.ResourceHandle.Null,
                        channel); 
                } 
                SetFlags(channel, false, VisualProxyFlags.IsEffectDirty);
            } 
        }


 
        /// 
        /// 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;
 
            bool isChildrenZOrderDirty = CheckFlagsAnd(channel, VisualProxyFlags.IsChildrenZOrderDirty); 
            int childCount = VisualChildrenCount;
 
            //
            // If the visual children have been re-ordered, enqueue a packet to RemoveAllChildren,
            // then reinsert all the children.  The parent visual will release the children when
            // the RemoveAllChildren packet, but the managed visuals will still have references 
            // to them so that they won't be destructed and recreated.
            // 
            if (isChildrenZOrderDirty) 
            {
                DUCE.CompositionNode.RemoveAllChildren( 
                    handle,
                    channel);
            }
 
            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 or that the ZOrder 
                    // of the children has changed.
                    // 
                    if (child.IsOnChannel(channel)) 
                    {
                        bool isConnectedToParent = child.CheckFlagsAnd(channel, VisualProxyFlags.IsConnectedToParent); 

                        if (!isConnectedToParent || isChildrenZOrderDirty)
                        {
                            DUCE.CompositionNode.InsertChildAt( 
                                handle,
                                ((DUCE.IResource)child).GetHandle(channel), 
                                connectedChildIndex, 
                                channel);
 
                            child.SetFlags(
                                channel,
                                true,
                                VisualProxyFlags.IsConnectedToParent); 
                        }
 
                        connectedChildIndex++; 
                    }
                } 
            }

            SetFlags(channel, false, VisualProxyFlags.IsChildrenZOrderDirty);
        } 

 
        ///  
        /// Marks the visible realizations in this visual graph.
        ///  
        /// The realization context.
        /// 
        /// 
        internal void MarkVisibleRealizations(RealizationContext ctx) 
        {
            Debug.Assert(IsOnChannel(ctx.Channel)); 
 
            if (    CheckFlagsAnd(VisualFlags.NodeInSubtreeUsesRealizationCaches)
                 || NodeHasLegacyBitmapEffect) 
            {
                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_MVR 
                    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 (NodeHasLegacyBitmapEffect)
                    { 
                        // 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.IsOnChannel(ctx.Channel));
 
                    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.NodeHasEffect)) 
                { 
                    Effect imageEffect = EffectField.GetValue(this);
                    if (imageEffect != null) 
                    {
                        GeneralTransform effectHitTestInverse = imageEffect.EffectMapping.Inverse;

                        // only do work if the transform isn't the identity transform 
                        if (effectHitTestInverse != Transform.Identity)
                        { 
                            bool ok = false; 

                            // Convert to unit space 
                            Point? unitHitPoint = Effect.WorldToUnit(originalHitPoint, _bboxSubgraph);
                            if (unitHitPoint != null)
                            {
                                Point transformedPt = new Point(); 

                                // Do the transform 
 
                                ok = effectHitTestInverse.TryTransform(unitHitPoint.Value, out transformedPt);
                                if (ok) 
                                {
                                    // Convert back to world space
                                    hitPoint = Effect.UnitToWorld(transformedPt, _bboxSubgraph);
                                } 
                            }
 
                            if (!ok) 
                            {
                                return HitTestResultBehavior.Continue; 
                            }
                        }
                    }
                    else 
                    {
                        Debug.Assert(BitmapEffectStateField.GetValue(this) != null); 
                        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.NodeHasEffect))
            { 
                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this);
                if (bitmapEffectState != null)
                {
                    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(); 
                        // Note that the below likely should be VisualDescendantBounds, but we're not modifying this 
                        // code now that legacy BitmapEffects are obsolete.
                        group.Children.Add(new BitmapEffectGeneralTransform(bitmapEffectState.BitmapEffect, 
                                                                            bitmapEffectState.BitmapEffectInput, false, VisualContentBounds));
                    }
                }
                else 
                {
                    Effect effect = EffectField.GetValue(this); 
                    GeneralTransform gt = effect.CoerceToUnitSpaceGeneralTransform( 
                        effect.EffectMapping,
                        VisualDescendantBounds); 

                    Transform affineTransform = gt.AffineTransform;
                    if (affineTransform != null)
                    { 
                        Matrix cm = affineTransform.Value;
                        MatrixUtil.MultiplyMatrix(ref m, ref cm); 
                    } 
                    else
                    { 
                        group = new GeneralTransformGroup();
                        group.Children.Add(gt);
                    }
                } 
            }
 
            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 | VisualProxyFlags.IsChildrenZOrderDirty);

            //
 
            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); 
            }
        } 

        /// 
        /// Gets or sets the Effect of this Visual.
        ///  
        protected internal Effect VisualEffect
        { 
            get 
            {
                VerifyAPIReadOnly(); 

                return VisualEffectInternal;
            }
            protected set 
            {
                VerifyAPIReadWrite(value); 
 
                // Legacy BitmapEffects and new Effects cannot be mixed because the new image effect
                // pipeline may be used to emulate a legacy BitmapEffect. 
                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);
                if (bed != null)
                {
                    if (value != null) // UIElement has a tendency to set a lot of properties to null even if it 
                                       // never set a property to a different value in the first place.
                    { 
                        // If a BitmapEffect is set, the user cannot set an Effect, since 
                        // mixing of legacy BitmapEffects is not allowed with Effects.
                        throw new Exception(SR.Get(SRID.Effect_CombinedLegacyAndNew)); 
                    }
                    else
                    {
                        return; 
                    }
                } 
 
                VisualEffectInternal = value;
 
            }
        }

        ///  
        /// Internal accessor to image effect property that gets or sets the Effect of this Visual.
        /// The internal accessor is used by the VisualBitmapEffect emulation layer to avoid some of the 
        /// compatibility checks in the protected VisualEffect property. 
        /// 
        internal Effect VisualEffectInternal 
        {
            get
            {
                // Legacy BitmapEffects and new Effects cannot be mixed because the new image effect 
                // pipeline may be used to emulate a legacy BitmapEffect. Therefore, if a BitmapEffect is
                // assigned to this node, the Effect is conceptually not set and null must be returned 
                // from this getter. If no BitmapEffect is set on this node, the Effect has been provided 
                // by the user and therefore the Effect is returned.
 
                if (NodeHasLegacyBitmapEffect)
                {
                    return null;
                } 
                else
                { 
                    return EffectField.GetValue(this); 
                }
            } 

            set
            {
                Effect imageEffect = EffectField.GetValue(this); 
                if (imageEffect == value)
                { 
                    return; 
                }
 
                Effect newEffect = value;

                // Add changed notifications for the new Effect if necessary.
                if (newEffect != null && !newEffect.IsFrozen) 
                {
                    newEffect.Changed += EffectChangedHandler; 
                } 

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

                    if (!imageEffect.IsFrozen) 
                    { 
                        imageEffect.Changed -= EffectChangedHandler;
                    } 

                    //
                    // Disconnect the Effect from this visual.
                    // 

                    DisconnectAttachedResource( 
                        VisualProxyFlags.IsEffectDirty, 
                        ((DUCE.IResource)imageEffect));
                } 

                //
                // Set the new effect and mark it dirty
                // 

                SetFlags(newEffect != null, VisualFlags.NodeHasEffect); 
 
                EffectField.SetValue(this, newEffect);
 
                SetFlagsOnAllChannels(true, VisualProxyFlags.IsEffectDirty);

                EffectChanged(/* 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).
        /// 
        [Obsolete(MS.Internal.Media.VisualTreeUtils.BitmapEffectObsoleteMessage)] 
        protected internal BitmapEffect VisualBitmapEffect
        { 
            get 
            {
                VerifyAPIReadOnly(); 

                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);

                if (bed != null) 
                {
                    return bed.BitmapEffect; 
                } 
                else
                { 
                    return null;
                }
            }
 
            protected set
            { 
                VerifyAPIReadWrite(value); 

                // 
                // Figure out if a image effect has been provided by the user. If so, calling this API is illegal
                // since new Effects and legacy BitmapEffects cannot be mixed.

                Effect imageEffect = EffectField.GetValue(this); 
                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);
                if (   (bed == null) 
                    && (imageEffect != null)) 

                { 
                    if (value != null) // Allowing incoming value of null because UIElements tend
                                       // to aggressively set this property to null even if it has never been set.
                    {
                        // If no BitmapEffect is set and an Effect is set, the Effect has been 
                        // provided by the user and not by emulation. Since mixing of legacy
                        // BitmapEffects is not allowed with Effects, setting a BitmapEffect is illegal. 
                        throw new Exception(SR.Get(SRID.Effect_CombinedLegacyAndNew)); 
                    }
                    else 
                    {
                        return;
                    }
                } 

 
                // 
                // To enable emulation of the legacy effects on top of the new effects pipeline, store the
                // bitmap effect information in our staging uncommon field: UserProvidedBitmapEffectData. 

                BitmapEffect oldBitmapEffect = (bed == null) ? null : bed.BitmapEffect;
                if (oldBitmapEffect == value) // If new and old value are the same, this set call can be treated as a no-op.
                { 
                    return;
                } 
 
                BitmapEffect newBitmapEffect = value;
 
                if (newBitmapEffect == null)
                {
                    Debug.Assert(bed != null, "Must be non-null because otherwise the code would have earlied out where new value is compared against old value.");
                    // The following line of code will effectively set the BitmapEffectInput property to null. This is strange behavior for WPF properties, but follows the 
                    // original BitmapEffects implementation.
                    UserProvidedBitmapEffectData.SetValue(this, null); 
                } 
                else
                { 
                    if (bed == null)
                    {
                        bed = new BitmapEffectData();
                        UserProvidedBitmapEffectData.SetValue(this, bed); 
                    }
 
                    bed.BitmapEffect = newBitmapEffect; 
                }
 
                if (newBitmapEffect != null && !newBitmapEffect.IsFrozen)
                {
                    newBitmapEffect.Changed += new EventHandler(BitmapEffectEmulationChanged);
                } 
                if (oldBitmapEffect != null && !oldBitmapEffect.IsFrozen)
                { 
                    oldBitmapEffect.Changed -= new EventHandler(BitmapEffectEmulationChanged); 
                }
 
                // Notify about the bitmap effect changes to configure the new emulation.
                BitmapEffectEmulationChanged(/* 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).
        /// 
        [Obsolete(MS.Internal.Media.VisualTreeUtils.BitmapEffectObsoleteMessage)] 
        protected internal BitmapEffectInput VisualBitmapEffectInput
        { 
            get 
            {
                VerifyAPIReadOnly(); 

                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);

                if (bed != null) 
                {
                    return bed.BitmapEffectInput; 
                } 
                else
                { 
                    return null;
                }
            }
 
            protected set
            { 
                VerifyAPIReadWrite(value); 

                // 
                // Figure out if a image effect has been provided by the user. If so, calling this API is illegal
                // sinc new Effects and legacy BitmapEffects cannot be mixed.

                Effect imageEffect = EffectField.GetValue(this); 
                BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this);
                if ((bed == null) && (imageEffect != null)) 
                { 
                    if (value != null) // Allowing null because parser and UIElement tend to set this property to null
                                       // even if it has never been set to non-null. 
                    {
                        // If no BitmapEffect is set and an Effect is set, the Effect has been
                        // provided by the user. Since mixing of legacy BitmapEffects is not allowed with
                        // Effects, setting a BitmapEffect is illegal. 
                        throw new Exception(SR.Get(SRID.Effect_CombinedLegacyAndNew));
                    } 
                    else 
                    {
                        return; 
                    }
                }

 
                //
                // To enable emulation of the legacy effects on top of the new effects pipeline, store the 
                // bitmap effect input information in our staging uncommon field: UserProvidedBitmapEffectData. 

                BitmapEffectInput oldBitmapEffectInput = (bed == null) ? null : bed.BitmapEffectInput; 
                BitmapEffectInput newBitmapEffectInput = value;

                if (oldBitmapEffectInput == newBitmapEffectInput) // If new and old value are the same, this set call can be treated as a no-op.
                { 
                    return;
                } 
 
                // Make sure there is a BitmapEffectData instance allocated.
                if (bed == null) 
                {
                    bed = new BitmapEffectData();
                    UserProvidedBitmapEffectData.SetValue(this, bed);
                } 

                bed.BitmapEffectInput = newBitmapEffectInput; 
 

                if (newBitmapEffectInput != null && !newBitmapEffectInput.IsFrozen) 
                {
                    newBitmapEffectInput.Changed += new EventHandler(BitmapEffectEmulationChanged);
                }
                if (oldBitmapEffectInput != null && !oldBitmapEffectInput.IsFrozen) 
                {
                    oldBitmapEffectInput.Changed -= new EventHandler(BitmapEffectEmulationChanged); 
                } 

                // Notify about the bitmap effect changes to configure the new emulation. 
                BitmapEffectEmulationChanged(/* sender */ null, /* args */ null);
            }
        }
 

        //  
        // This handler reconfigures the bitmap effects pipeline whenever anything changes. It is 
        // responsible for figuring out if a legacy effect can be emulated on the new pipeline or
        // not. 
        // 
        internal void BitmapEffectEmulationChanged(object sender, EventArgs e)
        {
            BitmapEffectData bed = UserProvidedBitmapEffectData.GetValue(this); 
            BitmapEffect currentBitmapEffect = (bed == null) ? null : bed.BitmapEffect;
            BitmapEffectInput currentBitmapEffectInput = (bed == null) ? null : bed.BitmapEffectInput; 
 
            // Note that when this method is called, a legacy BitmapEffect has been set or reset on
            // the Visual by the user. The next step is to try to emulate the effect in case the current 
            // effect is non null or reset the emulation layer if the user has set the effect to null.

            if (currentBitmapEffect == null)
            { 
                // This means the effect has been disconnected from this Visual. Setting the internal
                // bitmap effect property and the image effect property to null to disconnect all the 
                // effects. The Effect property needs to be set to null because the effect might 
                // be emulated.
                VisualBitmapEffectInternal = null; 
                VisualBitmapEffectInputInternal = null;
                VisualEffectInternal = null;
            }
            else if (currentBitmapEffectInput != null) 
            {
                // If a BitmapEffectInput is specified, make sure the legacy effect is not being 
                // emulated using the Effect pipeline since the new pipeline does not support 
                // BitmapEffecInputs.
                VisualEffectInternal = null; 
                VisualBitmapEffectInternal = currentBitmapEffect;
                VisualBitmapEffectInputInternal = currentBitmapEffectInput;
            }
            else if (RenderCapability.IsShaderEffectSoftwareRenderingSupported && 
                    currentBitmapEffect.CanBeEmulatedUsingEffectPipeline() &&
                    (!CheckFlagsAnd(VisualFlags.BitmapEffectEmulationDisabled))) 
            { 
                // If we can emulate the effect switch to emulating it.
                VisualBitmapEffectInternal = null; 
                VisualBitmapEffectInputInternal = null;
                VisualEffectInternal = currentBitmapEffect.GetEmulatingEffect();
            }
            else 
            {
                // Cannot emulate the effect, using legacy pipeline. 
                VisualEffectInternal = null; 
                VisualBitmapEffectInputInternal = null;
                VisualBitmapEffectInternal = currentBitmapEffect; 
            }

        }
 
        /// 
        /// Used by the test team to disable bitmap effect emulation for testing purposes. 
        ///  
        internal bool BitmapEffectEmulationDisabled
        { 
            get
            {
                return CheckFlagsAnd(VisualFlags.BitmapEffectEmulationDisabled);
            } 
            set
            { 
                if (value != CheckFlagsAnd(VisualFlags.BitmapEffectEmulationDisabled)) 
                {
                    SetFlags(value, VisualFlags.BitmapEffectEmulationDisabled); 

                    // Notify about the bitmap effect changes to configure the new emulation.
                    BitmapEffectEmulationChanged(/* sender */ null, /* args */ null);
                } 
            }
        } 
 
        /// 
        /// Internal accessor to BitmapEffect property that gets or sets the BitmapEffect of this Visual. 
        /// The internal accessor is used by the VisualBitmapEffect emulation layer to avoid some of the
        /// compatibility checks in the protected VisualBitmapEffect property.
        /// 
        internal BitmapEffect VisualBitmapEffectInternal 
        {
            get 
            { 
                VerifyAPIReadOnly();
 
                if (NodeHasLegacyBitmapEffect)
                {
                    return BitmapEffectStateField.GetValue(this).BitmapEffect;
                } 
                else
                { 
                    return null; 
                }
            } 

            set
            {
                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.NodeHasEffect); 
                    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; 

                    Debug.Assert(EffectField.GetValue(this) == null, "Not expecting both BitmapEffect and Effect to be set on the same node"); 
                    SetFlags(true, VisualFlags.NodeHasEffect); 
                }
 
                // 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);
            } 
        } 

        ///  
        /// Internal accessor to BitmapEffectInput property that gets or sets the BitmapEffectInput of this Visual.
        /// The internal accessor is used by the VisualBitmapEffect emulation layer to avoid some of the
        /// compatibility checks in the protected VisualBitmapEffectInput property.
        ///  
        internal BitmapEffectInput VisualBitmapEffectInputInternal
        { 
            get 
            {
                VerifyAPIReadOnly(); 
                BitmapEffectVisualState bitmapEffectState = BitmapEffectStateField.GetValue(this);
                if (bitmapEffectState != null)
                    return bitmapEffectState.BitmapEffectInput;
 
                return null;
            } 
 
            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;
 
                    // 
                    // NTRAID#Longhorn-1611281-2006/04/14-bedej:
                    // If this node or subtree has realizations, and there are bitmap effects in the 
                    // scene, we need to propagate the change flag so that we can produce new realizations
                    // for those bitmap effects. This means that adding bitmap effects will regress
                    // performance by producing unnecessary glyph realizations.
                    // 

                    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);
 
                // GSchneid: 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 (!NodeHasLegacyBitmapEffect) 
                    {
                        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 (gAsVisual.CheckFlagsAnd(VisualFlags.NodeHasEffect)) 
                    {
                        // Only check for Effect, not legacy BitmapEffect.  Previous
                        // version had an incorrect BitmapEffect implementation
                        // here, and there's no need to improve on our 
                        // BitmapEffect implementation if it didn't work
                        // before. 
 
                        Effect imageEffect = EffectField.GetValue(gAsVisual);
                        if (imageEffect != null) 
                        {
                            GeneralTransform gt = imageEffect.CoerceToUnitSpaceGeneralTransform(
                                imageEffect.EffectMapping,
                                gAsVisual.VisualDescendantBounds); 

                            Transform affineTransform = gt.AffineTransform; 
                            if (affineTransform != null) 
                            {
                                Matrix cm = affineTransform.Value; 
                                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(gt); 
                            }
                        } 
                    } 

                    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 EffectChangedHandler 
        {
            get 
            { 
                return new EventHandler(EffectChanged);
            } 
        }

        internal void EffectChanged(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 (NodeHasLegacyBitmapEffect) 
            {
                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); 
        }
 
 
        private bool NodeHasLegacyBitmapEffect
        { 
            get
            {
                // NodeHasEffect flag is overloaded for both legacy
                // BitmapEffects and the newer Effects 
                return
                    CheckFlagsAnd(VisualFlags.NodeHasEffect) && 
                    BitmapEffectStateField.GetValue(this) != null; 
            }
        } 


        #endregion Visual flags manipulation
 
#if TRACE_MVR
        ///  
        /// 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;
 
        // (GSchneid) 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 EffectField = new UncommonField();

        private static readonly UncommonField GuidelinesXField = new UncommonField(); 
        private static readonly UncommonField GuidelinesYField = new UncommonField();
 
        private static readonly UncommonField AncestorChangedEventField 
            = new UncommonField();
 
        private static readonly UncommonField UserProvidedBitmapEffectData = 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