RenderData.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Media / RenderData.cs / 2 / 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 : [....] - 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,
            ContentContainsMultiuseGlyphruns = 0x8,
        }
 
        /// 
        /// 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);
            bool multipleParentGlyphruns = false; 

            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 there are glyph runs contained within this resource we need to notify them
                    // that there is now one more or less renderdata using them as a resource. This is
                    // so we can detect when multiple sets of renderdata are using the same glyph run
                    // as this creates a multiple path scenario 
                    //
                    if (CheckFlagsAnd(Flags.HasStaticContentRequiringRealizations)) 
                    { 
                        GlyphRun glyphRun = _dependentResources[i] as GlyphRun;
 
                        if (glyphRun != null)
                        {
                            if (adding)
                            { 
                                glyphRun.IncrementParentCount();
                            } 
                            else 
                            {
                                glyphRun.DecrementParentCount(); 
                            }
                            multipleParentGlyphruns |= glyphRun.HasMultipleParents;
                        }
                    } 

                    // 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); 
                    }
                } 
            }
            SetFlags(multipleParentGlyphruns, Flags.ContentContainsMultiuseGlyphruns);
        }
 
        /// 
        /// 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. The ContentContainsMultiuseGlyphruns
        /// flag means that there is a GlyphRun in this renderdata which is also
        /// used again by this or another renderdata, causing another graphness 
        /// scenario.
        ///  
        bool IDrawingContent.ContentIntroducesGraphness 
        {
            get 
            {
                return CheckFlagsOr(Flags.ContentIntroducesGraphness | Flags.ContentContainsMultiuseGlyphruns);
            }
        } 

        ///  
        /// 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.
                        

                        

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