RenderData.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 / RenderData.cs / 1 / RenderData.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: RenderData.cs 
//
// Description: This file contains the implementation of RenderData. 
//              A RenderData is the backing store for a Drawing or the contents 
//              of a Visual.  It contains a data stream which is a byte array
//              containing renderdata instructions and an array of dependent resource. 
//
// History:
//  03/30/2004 : adsmith - Created it.
// 
//---------------------------------------------------------------------------
 
using MS.Internal; 
using MS.Utility;
using System; 
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization; 
using System.Diagnostics;
using System.Runtime.InteropServices; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Media.Animation; 
using System.Windows.Media.Composition;
using System.Windows.Media.Imaging;
using System.Windows.Media.Effects;
using System.Security; 
using System.Security.Permissions;
namespace System.Windows.Media 
{ 
    /// 
    /// RenderData 
    /// A RenderData is the backing store for a Drawing or the contents
    /// of a Visual.  It contains a data stream which is a byte array
    /// containing renderdata instructions and an array of dependent resource.
    /// 
    /// NOTE: RenderData is a not a fully functional Freezable
    ///  
    internal partial class RenderData : Freezable, DUCE.IResource, IDrawingContent 
    {
        ///  
        /// Default constructor.
        /// 
        internal RenderData()
        { 
            // RenderData is a transient object that does not want to participate
            // as the InheritanceContext of any of its dependents.  (It can be 
            // the Freezable context.) 
            CanBeInheritanceContext = false;
        } 

        /// 
        /// RenderData flags definition.
        ///  
        [System.Flags]
        internal enum Flags : uint 
        { 
            HasStaticContentRequiringRealizations = 0x1,
            HasDynamicContentRequiringRealizations = 0x2, 
            ContentIntroducesGraphness = 0x4,
        }

        ///  
        /// CheckFlagsAnd returns true if all flags in the bitmask flags are set.
        ///  
        /// If there aren't any bits set on the specified flags the method 
        /// returns true
        private bool CheckFlagsAnd(Flags flags) 
        {
            return (_flags & flags) == flags;
        }
 
        /// 
        /// CheckFlagsOr returns true if any of the flags in the bitmask flags is set. 
        ///  
        /// If there aren't any bits set on the specified flags the method
        /// returns true 
        private bool CheckFlagsOr(Flags flags)
        {
            return (flags == 0) || ((_flags & flags) > 0);
        } 

        ///  
        /// SetFlags is used to set or unset a flag. 
        /// 
        private void SetFlags(bool value, Flags f) 
        {
            _flags = value ? (_flags | f) : (_flags & (~f));
        }
 
        /// 
        /// RecordHeader - This struct is the header for each record entry 
        ///  
        internal struct RecordHeader
        { 
            public int Size;
            public MILCMD Id;
        }
 
        private enum PushType
        { 
            BitmapEffect, 
            Other
        } 

        /// 
        /// WriteDataRecord - writes a data record in the form of "size - id - data"
        /// The Length of the data packed is "size" - (2 * sizeof(int)). 
        /// Note that the cbRecordSize param is *only* the size of the record itself.  The Size
        /// written to the stream will be larger (by sizeof(RecordHeader)) because it includes the size 
        /// itself and the id. 
        /// 
        ///  MILCMD - the record id  
        /// 
        ///   byte* pointing to at least cbRecordSize bytes which will be copied to the stream.
        /// 
        ///  int - the size, in bytes, of pbRecord. Must be >= 0.  
        /// 
        ///     Critical: This code has unsafe code and dereferences a pointer 
        ///  
        [SecurityCritical]
        public unsafe void WriteDataRecord(MILCMD id, 
                                           byte* pbRecord,
                                           int cbRecordSize)
        {
            Debug.Assert(cbRecordSize >= 0); 

            // The records must always be padded to be QWORD aligned. 
            Debug.Assert((_curOffset % 8) == 0); 
            Debug.Assert((cbRecordSize % 8) == 0);
            Debug.Assert((sizeof(RecordHeader) % 8) == 0); 

            int totalSize, newOffset;
            checked
            { 
                totalSize = cbRecordSize + sizeof(RecordHeader);
                newOffset = _curOffset + totalSize; 
            } 

            // Do we need to increase the buffer size? 
            // Yes, if there's no buffer or if the buffer is too small.
            if ((_buffer == null) || (newOffset > _buffer.Length))
            {
                EnsureBuffer(newOffset); 
            }
 
            // At this point, _buffer must be non-null and 
            // _buffer.Length must be >= newOffset
            Debug.Assert((_buffer != null) && (_buffer.Length >= newOffset)); 

            // Also, because pinning a 0-length buffer fails, we assert this too.
            Debug.Assert(_buffer.Length > 0);
 
            RecordHeader header;
 
            header.Size = totalSize; 
            header.Id = id;
 
            Marshal.Copy((IntPtr)(&header), this._buffer, _curOffset, sizeof(RecordHeader));
            Marshal.Copy((IntPtr)pbRecord, this._buffer, _curOffset + sizeof(RecordHeader), cbRecordSize);

            _curOffset += totalSize; 

            // don't update if we don't have any effects or 
            // we already have pushed at least one effect on the stack 
            if (_effectDataResource != null && BitmapEffectStackDepth == 0)
            { 
                _effectDataResource.UpdateDataSize(id, totalSize);
            }
        }
 

 
        #region IDrawingContent 

        ///  
        /// Returns the bounding box occupied by the content
        /// 
        /// 
        /// Bounding box occupied by the content 
        /// 
        public Rect GetContentBounds(BoundsDrawingContextWalker ctx) 
        { 
            Debug.Assert(ctx != null);
 
            DrawingContextWalk(ctx);
            return ctx.Bounds;
        }
 
        /// 
        /// Forward the current value of the content to the DrawingContextWalker 
        /// methods. 
        /// 
        ///  DrawingContextWalker to forward content to.  
        public void WalkContent(DrawingContextWalker walker)
        {
            DrawingContextWalk(walker);
        } 

        ///  
        /// Determines whether or not a point exists within the content 
        /// 
        ///  Point to hit-test for.  
        /// 
        /// 'true' if the point exists within the content, 'false' otherwise
        /// 
        public bool HitTestPoint(Point point) 
        {
            HitTestDrawingContextWalker ctx = new HitTestWithPointDrawingContextWalker(point); 
 
            DrawingContextWalk(ctx);
 
            return ctx.IsHit;
        }

        ///  
        /// Hit-tests a geometry against this content
        ///  
        ///  PathGeometry to hit-test for.  
        /// 
        /// IntersectionDetail describing the result of the hit-test 
        /// 
        public IntersectionDetail HitTestGeometry(PathGeometry geometry)
        {
            HitTestDrawingContextWalker ctx = 
                new HitTestWithGeometryDrawingContextWalker(geometry);
 
            DrawingContextWalk(ctx); 

            return ctx.IntersectionDetail; 
        }

        protected override Freezable CreateInstanceCore()
        { 
            return new RenderData();
        } 
 
        // We don't need to call ReadPreamble() because this is an internal class.
        // Plus, the extra VerifyAccess() calls might be an issue. 
        //
        // We don't need to call WritePreamble() because this cannot be frozen
        // (FreezeCore always returns false)
        // 
        // We don't need to call WritePostscript() because we only care if children
        // below us change. 
        // 
        // About the calls to Invariant.Assert(false)... we're only implementing
        // Freezable to hook up parent pointers from the children Freezables 
        // to the RenderData. RenderData should never be cloned or frozen and
        // the class is internal so we'll just put in some Asserts to make sure
        // we don't do it in the future.
 
        protected override void CloneCore(Freezable source)
        { 
            Invariant.Assert(false); 
        }
 
        protected override void CloneCurrentValueCore(Freezable source)
        {
            Invariant.Assert(false);
        } 

        protected override bool FreezeCore(bool isChecking) 
        { 
            return false;
        } 

        protected override void GetAsFrozenCore(Freezable source)
        {
            Invariant.Assert(false); 
        }
 
        protected override void GetCurrentValueAsFrozenCore(Freezable source) 
        {
            Invariant.Assert(false); 
        }

        /// 
        /// Propagates an event handler to Freezables and AnimationClockResources 
        /// referenced by the content.
        ///  
        ///  Event handler to propagate  
        ///  'true' to add the handler, 'false' to remove it 
        public void PropagateChangedHandler(EventHandler handler, bool adding) 
        {
            Debug.Assert(!this.IsFrozen);

            if (adding) 
            {
                this.Changed += handler; 
            } 
            else
            { 
                this.Changed -= handler;
            }

            for (int i = 0, count = _dependentResources.Count; i < count; i++) 
            {
                Freezable freezableResource = _dependentResources[i] as Freezable; 
                if (freezableResource != null) 
                {
                    // Ideally, we would call OFPC(null, freezable) in AddDependentResource 
                    // but RenderData never removes resources so nothing would ever remove
                    // the context pointer. Fortunately, content calls PropagateChangedHandler
                    // when it cares and when it stops caring about its resources. Thus, we'll
                    // do all context hookup here. 
                    if (adding)
                    { 
                        OnFreezablePropertyChanged(null, freezableResource); 
                    }
                    else 
                    {
                        OnFreezablePropertyChanged(freezableResource, null);
                    }
                } 
                else
                { 
                    // If it's not a Freezable it may be an AnimationClockResource, which we 
                    // also need to handle.
                    AnimationClockResource clockResource = _dependentResources[i] as AnimationClockResource; 

                    if (clockResource != null)
                    {
                        // if it is a clock, it better not be a Freezable too or we'll 
                        // end up firing the handler twice
                        Debug.Assert(_dependentResources[i] as Freezable == null); 
 
                        clockResource.PropagateChangedHandlersCore(handler, adding);
                    } 
                }
            }
        }
 
        /// 
        /// Walks the dictionary of resources and precomputes them. 
        ///  
        void IDrawingContent.PrecomputeContent()
        { 
            MediaContext mc = MediaContext.From(Dispatcher);

            bool graphness = false;
 
            for (int i = 0, count = _dependentResources.Count; i < count; i++)
            { 
                Animatable a = _dependentResources[i] as Animatable; 
                if (a != null)
                { 
                    a.Precompute();

                    if (a.RequiresRealizationUpdates)
                    { 
                        HasDynamicContentRequiringRealizations |= true;
                        graphness |= a.CanIntroduceGraphness(); 
                    } 
                }
            } 
            SetFlags(graphness, Flags.ContentIntroducesGraphness);
        }

        ///  
        /// True iff the render data requires realization updates.
        ///  
        bool IDrawingContent.ContentRequiresRealizationUpdates 
        {
            get { return HasStaticContentRequiringRealizations || HasDynamicContentRequiringRealizations; } 
        }

        /// 
        /// True if this content can introduce graphness. 
        /// 
        ///  
        /// There are two ways to introduce graphness in renderdata. 
        /// the ContentIntroducesGraphness flag means that somewhere
        /// in the _dependentResources array is a resource that requires 
        /// realization updates and can introduce graphness to the scene,
        /// such as a VisualBrush or DrawingBrush.
        /// 
        bool IDrawingContent.ContentIntroducesGraphness 
        {
            get 
            { 
                return CheckFlagsOr(Flags.ContentIntroducesGraphness);
            } 
        }

        /// 
        /// Performs a realization update for the current render data. 
        /// 
        /// The render context. 
        public void UpdateRealizations(RealizationContext realizationContext) 
        {
            DrawingContextWalk(realizationContext.DrawingContextWalker); 

            if (_effectDataResource != null)
            {
                if (_effectDataResource.BitmapEffectDrawing.ScheduleForUpdates) 
                {
                    BitmapEffectRenderDataContent content = new BitmapEffectRenderDataContent(this, realizationContext); 
                    realizationContext.ScheduleForRealizationsUpdate(content); 
                    _effectDataResource.BitmapEffectDrawing.ScheduleForUpdates = false;
                } 

                _effectDataResource.BitmapEffectDrawing.UpdateRealizations(realizationContext);
            }
        } 

        ///  
        /// HasStaticContentRequiringRealizations 
        /// 
        internal bool HasStaticContentRequiringRealizations 
        {
            get
            {
                return CheckFlagsAnd(Flags.HasStaticContentRequiringRealizations); 
            }
 
            set 
            {
                SetFlags(value, Flags.HasStaticContentRequiringRealizations); 
            }
        }

        ///  
        /// HasDynamicContentRequiringRealizations
        ///  
        internal bool HasDynamicContentRequiringRealizations 
        {
            get 
            {
                return CheckFlagsAnd(Flags.HasDynamicContentRequiringRealizations);
            }
 
            set
            { 
                SetFlags(value, Flags.HasDynamicContentRequiringRealizations); 
            }
        } 

        /// 
        /// Returns the stack depth for the last top level effect that was pushed
        /// If no effects are currently on the stack, returns 0 
        /// 
        internal int BitmapEffectStackDepth 
        { 
            get
            { 
                if (_effectDataResource == null)
                {
                    return 0;
                } 

                return _effectDataResource.BitmapEffectStackDepth; 
            } 

            set 
            {
                //if this is the first time create it
                if (_effectDataResource == null)
                { 
                    _effectDataResource = new BitmapEffectRenderDataResource();
 
                    // set the DataSize to be the current offset 
                    // we want to add all commands up until the first PushEffect
                    _effectDataResource.DataSize = _curOffset; 
                }

                _effectDataResource.BitmapEffectStackDepth = value;
            } 
        }
 
 
        /// 
        /// keep track where on the stack, the effect was pushed 
        /// we do this only for top level effects
        /// 
        /// 
        internal void BeginTopLevelBitmapEffect(int stackDepth) 
        {
            BitmapEffectStackDepth = stackDepth; 
 
            // we have a new top level effect
            _effectDataResource.TopLevelEffects++; 

            HasStaticContentRequiringRealizations = true;
        }
 
        /// 
        /// Reset the stack depth 
        ///  
        internal void EndTopLevelBitmapEffect()
        { 
            BitmapEffectStackDepth = 0;
        }

        ///  
        /// Returns the size of the renderdata
        ///  
        public int DataSize 
        {
            get 
            {
                if (_effectDataResource == null)
                {
                    return _curOffset; 
                }
                else 
                { 
                    return _effectDataResource.DataSize;
                } 
            }
        }

        #endregion IDrawingContent 

        #region DUCE 
 
        DUCE.ResourceHandle DUCE.IResource.AddRefOnChannel(DUCE.Channel channel)
        { 
            using (CompositionEngineLock.Acquire())
            {
                // AddRef'ing or Releasing the renderdata itself doesn't propgate through the dependents,
                // unless our ref goes from or to 0.  This is why we have this if statement guarding 
                // the inner loop.
                if (_duceResource.CreateOrAddRefOnChannel(channel, DUCE.ResourceType.TYPE_RENDERDATA)) 
                { 
                    // First we AddRefOnChannel each of the dependent resources,
                    // then we update our own. 
                    for (int i = 0; i < _dependentResources.Count; i++)
                    {

                        DUCE.IResource resource = _dependentResources[i] as DUCE.IResource; 

                        if (resource != null) 
                        { 
                            resource.AddRefOnChannel(channel);
                        } 
                    }

                    if (_effectDataResource != null)
                    { 
                        _effectDataResource.CreateBitmapEffectResources(channel);
                    } 
 
                    UpdateResource(channel);
                } 

                return _duceResource.GetHandle(channel);
            }
        } 

        void DUCE.IResource.ReleaseOnChannel(DUCE.Channel channel) 
        { 
            using (CompositionEngineLock.Acquire())
            { 
                Debug.Assert(_duceResource.IsOnChannel(channel));

                // AddRef'ing or Releasing the renderdata itself doesn't propgate through the dependents,
                // unless our ref goes from or to 0.  This is why we have this if statement guarding 
                // the inner loop.
                if (_duceResource.ReleaseOnChannel(channel)) 
                { 
                    for (int i = 0; i < _dependentResources.Count; i++)
                    { 
                        DUCE.IResource resource = _dependentResources[i] as DUCE.IResource;

                        if (resource != null)
                        { 
                            resource.ReleaseOnChannel(channel);
                        } 
                    } 

                    if (_effectDataResource != null) 
                    {
                        _effectDataResource.ReleaseBitmapEffectResources(channel);
                    }
                } 
            }
        } 
 
        DUCE.ResourceHandle DUCE.IResource.GetHandle(DUCE.Channel channel)
        { 
            DUCE.ResourceHandle handle;

            // Reconsider the need for this lock when removing the MultiChannelResource.
            using (CompositionEngineLock.Acquire()) 
            {
                // This method is a short cut and must only be called while the ref count 
                // of this resource on this channel is non-zero.  Thus we assert that this 
                // resource is already on this channel.
                Debug.Assert(_duceResource.IsOnChannel(channel)); 

                handle = _duceResource.GetHandle(channel);
            }
 
            return handle;
        } 
 
        int DUCE.IResource.GetChannelCount()
        { 
            return _duceResource.GetChannelCount();
        }

        DUCE.Channel DUCE.IResource.GetChannel(int index) 
        {
            return _duceResource.GetChannel(index); 
        } 

        ///  
        /// This is only implemented by Visual and Visual3D.
        /// 
        void DUCE.IResource.RemoveChildFromParent(DUCE.IResource parent, DUCE.Channel channel)
        { 
            throw new NotImplementedException();
        } 
 
        /// 
        /// This is only implemented by Visual and Visual3D. 
        /// 
        DUCE.ResourceHandle DUCE.IResource.Get3DHandle(DUCE.Channel channel)
        {
            throw new NotImplementedException(); 
        }
        #endregion DUCE 
 
        public uint AddDependentResource(Object o)
        { 
            // Append the resource to the internal array.
            if (o == null)
            {
                return 0; 
            }
            else 
            { 
                return (uint)(_dependentResources.Add(o) + 1);
            } 
        }

        #region Internal Resource Methods
 
        private void UpdateResource(DUCE.Channel channel)
        { 
            Debug.Assert(_duceResource.IsOnChannel(channel)); 

            MarshalToDUCE(channel); 
        }

        #endregion Internal Resource Methods
 
        #region Private Methods
 
        ///  
        /// EnsureBuffer - this method ensures that the capacity is at least equal to cbRequiredSize.
        ///  
        ///  int - the new minimum size required.  Must be >= 0. 
        private void EnsureBuffer(int cbRequiredSize)
        {
            Debug.Assert(cbRequiredSize >= 0); 

            // If we don't have a buffer, this is easy: we simply allocate a new one of the appropriate size. 
            if (_buffer == null) 
            {
                _buffer = new byte[cbRequiredSize]; 
            }
            else
            {
                // For efficiency, we shouldn't have been called if there's already enough room 
                Debug.Assert(_buffer.Length < cbRequiredSize);
 
                // The new size will be 1.5 x the previous size, or the min size required (whichever is larger) 
                // We perform the 1.5x math by taking 2x of the length and subtracting 0.5x the length because
                // the 2x and 0.5x can be figured via shifts.  This is ~2x faster than performing the floating 
                // point math.
                int newSize = Math.Max((_buffer.Length << 1) - (_buffer.Length >> 1), cbRequiredSize);

                // This is a double-check against the math above - if newSize isn't at least cbRequiredSize, 
                // this growth function is broken.
                Debug.Assert(newSize >= cbRequiredSize); 
 
                byte[] _newBuffer = new byte[newSize];
 
                _buffer.CopyTo(_newBuffer, 0);

                _buffer = _newBuffer;
            } 
        }
 
        ///  
        /// DependentLookup - given an index into the dependent resource array,
        /// we return null if the index is 0, else we return the dependent at index - 1. 
        /// 
        ///  uint - 1-based index into the dependent array, 0 means "no lookup". 
        private object DependentLookup(uint index)
        { 
            Debug.Assert(index <= (uint)Int32.MaxValue);
 
            if (index == 0) 
            {
                return null; 
            }

            Debug.Assert(_dependentResources.Count >= index);
 
            return _dependentResources[(int)index - 1];
        } 
 
        /// 
        /// Update the DrawingGroup resource for each bitmap effect 
        /// 
        internal void ExecuteBitmapEffectRealizationUpdates(DUCE.Channel channel)
        {
            Debug.Assert(_effectDataResource != null); 
            _effectDataResource.UpdateBitmapEffectResources(this, channel);
        } 
 
        #endregion Private Methods
 
        #region Private Fields

        // The buffer into which the renderdata is written
        private byte[] _buffer; 

        // The offset of the beginning of the next record 
        // We ensure that the types in our instruction structs are correctly aligned wrt. their 
        // size for read/write access, assuming that the instruction struct sits at an 8-byte
        // boundary.  Thus _curOffset must always be at an 8-byte boundary to begin writing 
        // an instruction.
        private int _curOffset;

        private FrugalStructList _dependentResources = new FrugalStructList(); 

        private BitmapEffectRenderDataResource _effectDataResource; 
        // DUCE resource 
        private DUCE.MultiChannelResource _duceResource = new DUCE.MultiChannelResource();
 
        private Flags _flags;

        #endregion Private Fields
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: RenderData.cs 
//
// Description: This file contains the implementation of RenderData. 
//              A RenderData is the backing store for a Drawing or the contents 
//              of a Visual.  It contains a data stream which is a byte array
//              containing renderdata instructions and an array of dependent resource. 
//
// History:
//  03/30/2004 : adsmith - Created it.
// 
//---------------------------------------------------------------------------
 
using MS.Internal; 
using MS.Utility;
using System; 
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization; 
using System.Diagnostics;
using System.Runtime.InteropServices; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Media.Animation; 
using System.Windows.Media.Composition;
using System.Windows.Media.Imaging;
using System.Windows.Media.Effects;
using System.Security; 
using System.Security.Permissions;
namespace System.Windows.Media 
{ 
    /// 
    /// RenderData 
    /// A RenderData is the backing store for a Drawing or the contents
    /// of a Visual.  It contains a data stream which is a byte array
    /// containing renderdata instructions and an array of dependent resource.
    /// 
    /// NOTE: RenderData is a not a fully functional Freezable
    ///  
    internal partial class RenderData : Freezable, DUCE.IResource, IDrawingContent 
    {
        ///  
        /// Default constructor.
        /// 
        internal RenderData()
        { 
            // RenderData is a transient object that does not want to participate
            // as the InheritanceContext of any of its dependents.  (It can be 
            // the Freezable context.) 
            CanBeInheritanceContext = false;
        } 

        /// 
        /// RenderData flags definition.
        ///  
        [System.Flags]
        internal enum Flags : uint 
        { 
            HasStaticContentRequiringRealizations = 0x1,
            HasDynamicContentRequiringRealizations = 0x2, 
            ContentIntroducesGraphness = 0x4,
        }

        ///  
        /// CheckFlagsAnd returns true if all flags in the bitmask flags are set.
        ///  
        /// If there aren't any bits set on the specified flags the method 
        /// returns true
        private bool CheckFlagsAnd(Flags flags) 
        {
            return (_flags & flags) == flags;
        }
 
        /// 
        /// CheckFlagsOr returns true if any of the flags in the bitmask flags is set. 
        ///  
        /// If there aren't any bits set on the specified flags the method
        /// returns true 
        private bool CheckFlagsOr(Flags flags)
        {
            return (flags == 0) || ((_flags & flags) > 0);
        } 

        ///  
        /// SetFlags is used to set or unset a flag. 
        /// 
        private void SetFlags(bool value, Flags f) 
        {
            _flags = value ? (_flags | f) : (_flags & (~f));
        }
 
        /// 
        /// RecordHeader - This struct is the header for each record entry 
        ///  
        internal struct RecordHeader
        { 
            public int Size;
            public MILCMD Id;
        }
 
        private enum PushType
        { 
            BitmapEffect, 
            Other
        } 

        /// 
        /// WriteDataRecord - writes a data record in the form of "size - id - data"
        /// The Length of the data packed is "size" - (2 * sizeof(int)). 
        /// Note that the cbRecordSize param is *only* the size of the record itself.  The Size
        /// written to the stream will be larger (by sizeof(RecordHeader)) because it includes the size 
        /// itself and the id. 
        /// 
        ///  MILCMD - the record id  
        /// 
        ///   byte* pointing to at least cbRecordSize bytes which will be copied to the stream.
        /// 
        ///  int - the size, in bytes, of pbRecord. Must be >= 0.  
        /// 
        ///     Critical: This code has unsafe code and dereferences a pointer 
        ///  
        [SecurityCritical]
        public unsafe void WriteDataRecord(MILCMD id, 
                                           byte* pbRecord,
                                           int cbRecordSize)
        {
            Debug.Assert(cbRecordSize >= 0); 

            // The records must always be padded to be QWORD aligned. 
            Debug.Assert((_curOffset % 8) == 0); 
            Debug.Assert((cbRecordSize % 8) == 0);
            Debug.Assert((sizeof(RecordHeader) % 8) == 0); 

            int totalSize, newOffset;
            checked
            { 
                totalSize = cbRecordSize + sizeof(RecordHeader);
                newOffset = _curOffset + totalSize; 
            } 

            // Do we need to increase the buffer size? 
            // Yes, if there's no buffer or if the buffer is too small.
            if ((_buffer == null) || (newOffset > _buffer.Length))
            {
                EnsureBuffer(newOffset); 
            }
 
            // At this point, _buffer must be non-null and 
            // _buffer.Length must be >= newOffset
            Debug.Assert((_buffer != null) && (_buffer.Length >= newOffset)); 

            // Also, because pinning a 0-length buffer fails, we assert this too.
            Debug.Assert(_buffer.Length > 0);
 
            RecordHeader header;
 
            header.Size = totalSize; 
            header.Id = id;
 
            Marshal.Copy((IntPtr)(&header), this._buffer, _curOffset, sizeof(RecordHeader));
            Marshal.Copy((IntPtr)pbRecord, this._buffer, _curOffset + sizeof(RecordHeader), cbRecordSize);

            _curOffset += totalSize; 

            // don't update if we don't have any effects or 
            // we already have pushed at least one effect on the stack 
            if (_effectDataResource != null && BitmapEffectStackDepth == 0)
            { 
                _effectDataResource.UpdateDataSize(id, totalSize);
            }
        }
 

 
        #region IDrawingContent 

        ///  
        /// Returns the bounding box occupied by the content
        /// 
        /// 
        /// Bounding box occupied by the content 
        /// 
        public Rect GetContentBounds(BoundsDrawingContextWalker ctx) 
        { 
            Debug.Assert(ctx != null);
 
            DrawingContextWalk(ctx);
            return ctx.Bounds;
        }
 
        /// 
        /// Forward the current value of the content to the DrawingContextWalker 
        /// methods. 
        /// 
        ///  DrawingContextWalker to forward content to.  
        public void WalkContent(DrawingContextWalker walker)
        {
            DrawingContextWalk(walker);
        } 

        ///  
        /// Determines whether or not a point exists within the content 
        /// 
        ///  Point to hit-test for.  
        /// 
        /// 'true' if the point exists within the content, 'false' otherwise
        /// 
        public bool HitTestPoint(Point point) 
        {
            HitTestDrawingContextWalker ctx = new HitTestWithPointDrawingContextWalker(point); 
 
            DrawingContextWalk(ctx);
 
            return ctx.IsHit;
        }

        ///  
        /// Hit-tests a geometry against this content
        ///  
        ///  PathGeometry to hit-test for.  
        /// 
        /// IntersectionDetail describing the result of the hit-test 
        /// 
        public IntersectionDetail HitTestGeometry(PathGeometry geometry)
        {
            HitTestDrawingContextWalker ctx = 
                new HitTestWithGeometryDrawingContextWalker(geometry);
 
            DrawingContextWalk(ctx); 

            return ctx.IntersectionDetail; 
        }

        protected override Freezable CreateInstanceCore()
        { 
            return new RenderData();
        } 
 
        // We don't need to call ReadPreamble() because this is an internal class.
        // Plus, the extra VerifyAccess() calls might be an issue. 
        //
        // We don't need to call WritePreamble() because this cannot be frozen
        // (FreezeCore always returns false)
        // 
        // We don't need to call WritePostscript() because we only care if children
        // below us change. 
        // 
        // About the calls to Invariant.Assert(false)... we're only implementing
        // Freezable to hook up parent pointers from the children Freezables 
        // to the RenderData. RenderData should never be cloned or frozen and
        // the class is internal so we'll just put in some Asserts to make sure
        // we don't do it in the future.
 
        protected override void CloneCore(Freezable source)
        { 
            Invariant.Assert(false); 
        }
 
        protected override void CloneCurrentValueCore(Freezable source)
        {
            Invariant.Assert(false);
        } 

        protected override bool FreezeCore(bool isChecking) 
        { 
            return false;
        } 

        protected override void GetAsFrozenCore(Freezable source)
        {
            Invariant.Assert(false); 
        }
 
        protected override void GetCurrentValueAsFrozenCore(Freezable source) 
        {
            Invariant.Assert(false); 
        }

        /// 
        /// Propagates an event handler to Freezables and AnimationClockResources 
        /// referenced by the content.
        ///  
        ///  Event handler to propagate  
        ///  'true' to add the handler, 'false' to remove it 
        public void PropagateChangedHandler(EventHandler handler, bool adding) 
        {
            Debug.Assert(!this.IsFrozen);

            if (adding) 
            {
                this.Changed += handler; 
            } 
            else
            { 
                this.Changed -= handler;
            }

            for (int i = 0, count = _dependentResources.Count; i < count; i++) 
            {
                Freezable freezableResource = _dependentResources[i] as Freezable; 
                if (freezableResource != null) 
                {
                    // Ideally, we would call OFPC(null, freezable) in AddDependentResource 
                    // but RenderData never removes resources so nothing would ever remove
                    // the context pointer. Fortunately, content calls PropagateChangedHandler
                    // when it cares and when it stops caring about its resources. Thus, we'll
                    // do all context hookup here. 
                    if (adding)
                    { 
                        OnFreezablePropertyChanged(null, freezableResource); 
                    }
                    else 
                    {
                        OnFreezablePropertyChanged(freezableResource, null);
                    }
                } 
                else
                { 
                    // If it's not a Freezable it may be an AnimationClockResource, which we 
                    // also need to handle.
                    AnimationClockResource clockResource = _dependentResources[i] as AnimationClockResource; 

                    if (clockResource != null)
                    {
                        // if it is a clock, it better not be a Freezable too or we'll 
                        // end up firing the handler twice
                        Debug.Assert(_dependentResources[i] as Freezable == null); 
 
                        clockResource.PropagateChangedHandlersCore(handler, adding);
                    } 
                }
            }
        }
 
        /// 
        /// Walks the dictionary of resources and precomputes them. 
        ///  
        void IDrawingContent.PrecomputeContent()
        { 
            MediaContext mc = MediaContext.From(Dispatcher);

            bool graphness = false;
 
            for (int i = 0, count = _dependentResources.Count; i < count; i++)
            { 
                Animatable a = _dependentResources[i] as Animatable; 
                if (a != null)
                { 
                    a.Precompute();

                    if (a.RequiresRealizationUpdates)
                    { 
                        HasDynamicContentRequiringRealizations |= true;
                        graphness |= a.CanIntroduceGraphness(); 
                    } 
                }
            } 
            SetFlags(graphness, Flags.ContentIntroducesGraphness);
        }

        ///  
        /// True iff the render data requires realization updates.
        ///  
        bool IDrawingContent.ContentRequiresRealizationUpdates 
        {
            get { return HasStaticContentRequiringRealizations || HasDynamicContentRequiringRealizations; } 
        }

        /// 
        /// True if this content can introduce graphness. 
        /// 
        ///  
        /// There are two ways to introduce graphness in renderdata. 
        /// the ContentIntroducesGraphness flag means that somewhere
        /// in the _dependentResources array is a resource that requires 
        /// realization updates and can introduce graphness to the scene,
        /// such as a VisualBrush or DrawingBrush.
        /// 
        bool IDrawingContent.ContentIntroducesGraphness 
        {
            get 
            { 
                return CheckFlagsOr(Flags.ContentIntroducesGraphness);
            } 
        }

        /// 
        /// Performs a realization update for the current render data. 
        /// 
        /// The render context. 
        public void UpdateRealizations(RealizationContext realizationContext) 
        {
            DrawingContextWalk(realizationContext.DrawingContextWalker); 

            if (_effectDataResource != null)
            {
                if (_effectDataResource.BitmapEffectDrawing.ScheduleForUpdates) 
                {
                    BitmapEffectRenderDataContent content = new BitmapEffectRenderDataContent(this, realizationContext); 
                    realizationContext.ScheduleForRealizationsUpdate(content); 
                    _effectDataResource.BitmapEffectDrawing.ScheduleForUpdates = false;
                } 

                _effectDataResource.BitmapEffectDrawing.UpdateRealizations(realizationContext);
            }
        } 

        ///  
        /// HasStaticContentRequiringRealizations 
        /// 
        internal bool HasStaticContentRequiringRealizations 
        {
            get
            {
                return CheckFlagsAnd(Flags.HasStaticContentRequiringRealizations); 
            }
 
            set 
            {
                SetFlags(value, Flags.HasStaticContentRequiringRealizations); 
            }
        }

        ///  
        /// HasDynamicContentRequiringRealizations
        ///  
        internal bool HasDynamicContentRequiringRealizations 
        {
            get 
            {
                return CheckFlagsAnd(Flags.HasDynamicContentRequiringRealizations);
            }
 
            set
            { 
                SetFlags(value, Flags.HasDynamicContentRequiringRealizations); 
            }
        } 

        /// 
        /// Returns the stack depth for the last top level effect that was pushed
        /// If no effects are currently on the stack, returns 0 
        /// 
        internal int BitmapEffectStackDepth 
        { 
            get
            { 
                if (_effectDataResource == null)
                {
                    return 0;
                } 

                return _effectDataResource.BitmapEffectStackDepth; 
            } 

            set 
            {
                //if this is the first time create it
                if (_effectDataResource == null)
                { 
                    _effectDataResource = new BitmapEffectRenderDataResource();
 
                    // set the DataSize to be the current offset 
                    // we want to add all commands up until the first PushEffect
                    _effectDataResource.DataSize = _curOffset; 
                }

                _effectDataResource.BitmapEffectStackDepth = value;
            } 
        }
 
 
        /// 
        /// keep track where on the stack, the effect was pushed 
        /// we do this only for top level effects
        /// 
        /// 
        internal void BeginTopLevelBitmapEffect(int stackDepth) 
        {
            BitmapEffectStackDepth = stackDepth; 
 
            // we have a new top level effect
            _effectDataResource.TopLevelEffects++; 

            HasStaticContentRequiringRealizations = true;
        }
 
        /// 
        /// Reset the stack depth 
        ///  
        internal void EndTopLevelBitmapEffect()
        { 
            BitmapEffectStackDepth = 0;
        }

        ///  
        /// Returns the size of the renderdata
        ///  
        public int DataSize 
        {
            get 
            {
                if (_effectDataResource == null)
                {
                    return _curOffset; 
                }
                else 
                { 
                    return _effectDataResource.DataSize;
                } 
            }
        }

        #endregion IDrawingContent 

        #region DUCE 
 
        DUCE.ResourceHandle DUCE.IResource.AddRefOnChannel(DUCE.Channel channel)
        { 
            using (CompositionEngineLock.Acquire())
            {
                // AddRef'ing or Releasing the renderdata itself doesn't propgate through the dependents,
                // unless our ref goes from or to 0.  This is why we have this if statement guarding 
                // the inner loop.
                if (_duceResource.CreateOrAddRefOnChannel(channel, DUCE.ResourceType.TYPE_RENDERDATA)) 
                { 
                    // First we AddRefOnChannel each of the dependent resources,
                    // then we update our own. 
                    for (int i = 0; i < _dependentResources.Count; i++)
                    {

                        DUCE.IResource resource = _dependentResources[i] as DUCE.IResource; 

                        if (resource != null) 
                        { 
                            resource.AddRefOnChannel(channel);
                        } 
                    }

                    if (_effectDataResource != null)
                    { 
                        _effectDataResource.CreateBitmapEffectResources(channel);
                    } 
 
                    UpdateResource(channel);
                } 

                return _duceResource.GetHandle(channel);
            }
        } 

        void DUCE.IResource.ReleaseOnChannel(DUCE.Channel channel) 
        { 
            using (CompositionEngineLock.Acquire())
            { 
                Debug.Assert(_duceResource.IsOnChannel(channel));

                // AddRef'ing or Releasing the renderdata itself doesn't propgate through the dependents,
                // unless our ref goes from or to 0.  This is why we have this if statement guarding 
                // the inner loop.
                if (_duceResource.ReleaseOnChannel(channel)) 
                { 
                    for (int i = 0; i < _dependentResources.Count; i++)
                    { 
                        DUCE.IResource resource = _dependentResources[i] as DUCE.IResource;

                        if (resource != null)
                        { 
                            resource.ReleaseOnChannel(channel);
                        } 
                    } 

                    if (_effectDataResource != null) 
                    {
                        _effectDataResource.ReleaseBitmapEffectResources(channel);
                    }
                } 
            }
        } 
 
        DUCE.ResourceHandle DUCE.IResource.GetHandle(DUCE.Channel channel)
        { 
            DUCE.ResourceHandle handle;

            // Reconsider the need for this lock when removing the MultiChannelResource.
            using (CompositionEngineLock.Acquire()) 
            {
                // This method is a short cut and must only be called while the ref count 
                // of this resource on this channel is non-zero.  Thus we assert that this 
                // resource is already on this channel.
                Debug.Assert(_duceResource.IsOnChannel(channel)); 

                handle = _duceResource.GetHandle(channel);
            }
 
            return handle;
        } 
 
        int DUCE.IResource.GetChannelCount()
        { 
            return _duceResource.GetChannelCount();
        }

        DUCE.Channel DUCE.IResource.GetChannel(int index) 
        {
            return _duceResource.GetChannel(index); 
        } 

        ///  
        /// This is only implemented by Visual and Visual3D.
        /// 
        void DUCE.IResource.RemoveChildFromParent(DUCE.IResource parent, DUCE.Channel channel)
        { 
            throw new NotImplementedException();
        } 
 
        /// 
        /// This is only implemented by Visual and Visual3D. 
        /// 
        DUCE.ResourceHandle DUCE.IResource.Get3DHandle(DUCE.Channel channel)
        {
            throw new NotImplementedException(); 
        }
        #endregion DUCE 
 
        public uint AddDependentResource(Object o)
        { 
            // Append the resource to the internal array.
            if (o == null)
            {
                return 0; 
            }
            else 
            { 
                return (uint)(_dependentResources.Add(o) + 1);
            } 
        }

        #region Internal Resource Methods
 
        private void UpdateResource(DUCE.Channel channel)
        { 
            Debug.Assert(_duceResource.IsOnChannel(channel)); 

            MarshalToDUCE(channel); 
        }

        #endregion Internal Resource Methods
 
        #region Private Methods
 
        ///  
        /// EnsureBuffer - this method ensures that the capacity is at least equal to cbRequiredSize.
        ///  
        ///  int - the new minimum size required.  Must be >= 0. 
        private void EnsureBuffer(int cbRequiredSize)
        {
            Debug.Assert(cbRequiredSize >= 0); 

            // If we don't have a buffer, this is easy: we simply allocate a new one of the appropriate size. 
            if (_buffer == null) 
            {
                _buffer = new byte[cbRequiredSize]; 
            }
            else
            {
                // For efficiency, we shouldn't have been called if there's already enough room 
                Debug.Assert(_buffer.Length < cbRequiredSize);
 
                // The new size will be 1.5 x the previous size, or the min size required (whichever is larger) 
                // We perform the 1.5x math by taking 2x of the length and subtracting 0.5x the length because
                // the 2x and 0.5x can be figured via shifts.  This is ~2x faster than performing the floating 
                // point math.
                int newSize = Math.Max((_buffer.Length << 1) - (_buffer.Length >> 1), cbRequiredSize);

                // This is a double-check against the math above - if newSize isn't at least cbRequiredSize, 
                // this growth function is broken.
                Debug.Assert(newSize >= cbRequiredSize); 
 
                byte[] _newBuffer = new byte[newSize];
 
                _buffer.CopyTo(_newBuffer, 0);

                _buffer = _newBuffer;
            } 
        }
 
        ///  
        /// DependentLookup - given an index into the dependent resource array,
        /// we return null if the index is 0, else we return the dependent at index - 1. 
        /// 
        ///  uint - 1-based index into the dependent array, 0 means "no lookup". 
        private object DependentLookup(uint index)
        { 
            Debug.Assert(index <= (uint)Int32.MaxValue);
 
            if (index == 0) 
            {
                return null; 
            }

            Debug.Assert(_dependentResources.Count >= index);
 
            return _dependentResources[(int)index - 1];
        } 
 
        /// 
        /// Update the DrawingGroup resource for each bitmap effect 
        /// 
        internal void ExecuteBitmapEffectRealizationUpdates(DUCE.Channel channel)
        {
            Debug.Assert(_effectDataResource != null); 
            _effectDataResource.UpdateBitmapEffectResources(this, channel);
        } 
 
        #endregion Private Methods
 
        #region Private Fields

        // The buffer into which the renderdata is written
        private byte[] _buffer; 

        // The offset of the beginning of the next record 
        // We ensure that the types in our instruction structs are correctly aligned wrt. their 
        // size for read/write access, assuming that the instruction struct sits at an 8-byte
        // boundary.  Thus _curOffset must always be at an 8-byte boundary to begin writing 
        // an instruction.
        private int _curOffset;

        private FrugalStructList _dependentResources = new FrugalStructList(); 

        private BitmapEffectRenderDataResource _effectDataResource; 
        // DUCE resource 
        private DUCE.MultiChannelResource _duceResource = new DUCE.MultiChannelResource();
 
        private Flags _flags;

        #endregion Private Fields
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

                        

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