RealizationDrawingContextWalker.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

                            //------------------------------------------------------------------------------ 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: RealizationDrawingContextWalker.cs 
//
// Description: 
//   This file contains the implementation of RealizationDrawingContextWalker. 
//   This DrawingContextWalker is used to perform realization updates on
//   render data. 
//
//-----------------------------------------------------------------------------

namespace System.Windows.Media 
{
    using MS.Internal; 
 
    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.Effects;
    using System.Windows.Media.Imaging;

 
    /// 
    /// RealizationDrawingContextWalker - a DrawingContextWalker which will 
    /// update realizations of the contents of the render data. 
    /// 
    internal class RealizationDrawingContextWalker : DrawingContextWalker 
    {
        //---------------------------------------------------------------------
        //
        //  Internal Constructors 
        //
        //--------------------------------------------------------------------- 
 
        #region Internal Constructors
 
        /// 
        /// Constructor for BoundsDrawingContextWalker
        /// 
        /// The render context. 
        internal RealizationDrawingContextWalker(RealizationContext ctx)
        { 
            Debug.Assert(ctx != null); 

            _ctx = ctx; 
            _operationTypeStack = new Stack(2);
            _opacityMaskBoundsStack = new Stack(2);
            _opacityMaskBrushStack = new Stack(2);
            _opacityMaskMatrixStack = new MatrixStack(); 
            _opacityMaskRect = Rect.Empty;
            _opacityMaskAccumulate = 0; 
        } 

        #endregion Internal Constructors 



        //---------------------------------------------------------------------- 
        //
        //  Public Methods 
        // 
        //---------------------------------------------------------------------
 
        #region Public Methods

        /// 
        /// Push a clip region, which will apply to all drawing primitives 
        /// until the corresponding Pop call.
        ///  
        ///  
        /// The Geometry to which we will clip.
        ///  
        public override void PushClip(Geometry clipGeometry)
        {
            // Ignore the clip value.
            _operationTypeStack.Push(OperationType.Clip); 
        }
 
 
        /// 
        /// Push an opacity mask 
        /// 
        /// 
        /// The opacity mask
        ///  
        public override void PushOpacityMask(Brush brush)
        { 
            _operationTypeStack.Push(OperationType.OpacityMask); 
            _opacityMaskBoundsStack.Push(_opacityMaskRect);
            _opacityMaskRect = Rect.Empty; 
            _opacityMaskAccumulate++;
            _opacityMaskBrushStack.Push(brush);
            _opacityMaskMatrixStack.Push(Transform.Identity, /* combine */ false);
        } 

        private void PopOpacityMask() 
        { 
            Debug.Assert(_opacityMaskBoundsStack.Count > 0);
            Debug.Assert(_opacityMaskBrushStack.Count > 0); 
            Brush brush = _opacityMaskBrushStack.Pop();
            if (brush != null)
            {
                brush.UpdateRealizations(_opacityMaskRect,  _ctx); 
            }
            _opacityMaskRect = Rect.Union(_opacityMaskRect, _opacityMaskBoundsStack.Pop()); 
            _opacityMaskAccumulate--; 
        }
 
        private void TransformAndUnionOpacityMaskBounds(Rect bounds)
        {
            Rect r = Rect.Transform(bounds, _opacityMaskMatrixStack.Peek());
            _opacityMaskRect.Union(r); 
            return;
        } 
 
        /// 
        /// Push an opacity which will blend the composite of all drawing 
        /// primitives added until the corresponding Pop call.
        /// 
        /// 
        /// The opacity with which to blend - 0 is transparent, 1 is opaque. 
        /// 
        public override void PushOpacity(Double opacity) 
        { 
            // Ignore the opacity value.
            _operationTypeStack.Push(OperationType.Opacity); 
        }


        ///  
        /// Push a Transform which will apply to all drawing operations
        /// until the corresponding Pop. 
        ///  
        /// The Transform to push.
        public override void PushTransform(Transform transform) 
        {
            // Retrieve the new transform as a matrix if it exists.
            if (transform != null && !transform.IsIdentity)
            { 
                // Push the operation type.
                _operationTypeStack.Push(OperationType.Transform); 
 
                // Push the valid transform on the stack.
                _ctx.TransformStack.Push(transform, /* combine */ true); 
                _opacityMaskMatrixStack.Push(transform, /* combine */ true);
            }
            else
            { 
                // Do not store identity (or null) transforms on the transform stack.
                _operationTypeStack.Push(OperationType.InvalidOrIrrelevantTransform); 
            } 
        }
 
        /// 
        ///     PushEffect -
        ///     Push a BitmapEffect which will apply to all drawing operations until the
        ///     corresponding Pop. 
        /// 
        ///  The BitmapEffect to push.  
        ///  The BitmapEffectInput.  
        public override void PushEffect(
            BitmapEffect effect, 
            BitmapEffectInput effectInput)
        {
            _operationTypeStack.Push(OperationType.BitmapEffect);
            pushedEffects++; 
        }
 
        ///  
        ///     PushGuidelineSet -
        ///     Push a set of guidelines which should be applied 
        ///     to all drawing operations until the
        ///     corresponding Pop.
        /// 
        ///  The GuidelineSet to push.  
        public override void PushGuidelineSet(
            GuidelineSet guidelines) 
        { 
            // Ignore the guidelines value.
            _operationTypeStack.Push(OperationType.Guidelines); 
        }

        /// 
        ///     PushGuidelineY1 - 
        ///     Explicitly push one horizontal guideline.
        ///  
        ///  The coordinate of leading guideline.  
        internal override void PushGuidelineY1(
            Double coordinate) 
        {
            // Ignore the guidelines values.
            _operationTypeStack.Push(OperationType.Guidelines);
        } 

 
        ///  
        ///     PushGuidelineY2 -
        ///     Explicitly push a pair of horizontal guidelines. 
        /// 
        /// 
        ///     The coordinate of leading guideline.
        ///  
        /// 
        ///     The offset from leading guideline to driven guideline. 
        ///  
        internal override void PushGuidelineY2(
            Double leadingCoordinate, 
            Double offsetToDrivenCoordinate)
        {
            // Ignore the guidelines values.
            _operationTypeStack.Push(OperationType.Guidelines); 
        }
 
 
        /// 
        /// Pops a transform/clip/opacity change from the stack. 
        /// 
        public override void Pop()
        {
            // We must have a type stack and it must not be empty. 
            Debug.Assert(_operationTypeStack != null);
            Debug.Assert(_operationTypeStack.Count > 0); 
 
            // Retrieve the OperationType to figure out what what this Pop is.
            OperationType operationType = _operationTypeStack.Pop(); 

            switch (operationType)
            {
                case OperationType.Transform: 
                    // Restore the previous transform
                    _ctx.TransformStack.Pop(); 
                    _opacityMaskMatrixStack.Pop(); 
                    break;
                case OperationType.BitmapEffect: 
                    pushedEffects--;
                    break;
                case OperationType.OpacityMask:
                    PopOpacityMask(); 
                    break;
                default: 
                    // Do nothing for the 'not stored' operation types 
                    Debug.Assert(operationType == OperationType.Clip ||
                                 operationType == OperationType.Opacity || 
                                 operationType == OperationType.Guidelines ||
                                 operationType == OperationType.InvalidOrIrrelevantTransform ||
                                 operationType == OperationType.BitmapEffect);
                    break; 
            }
        } 
 

 
        /// 
        /// Draws a line with the specified pen. Note that this API does not
        /// accept a Brush, as there is no area to fill.
        ///  
        /// The Pen with which to stroke the line.
        /// The start Point for the line. 
        /// The end Point for the line. 
        public override void DrawLine(
            Pen pen, 
            Point point0,
            Point point1)
        {
            // skip realization updates if there is an effect on the stack 
            // we will do this at a later time
            if (pushedEffects > 0) 
            { 
                return;
            } 

            if (pen != null)
            {
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, null); 
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates;
 
                if (    requiresRealizationUpdates 
                    ||  _opacityMaskAccumulate > 0)
                { 
                    Rect fillBounds = Rect.Empty;

                    // This is the union of the geometry and the stroke.
                    Rect strokeBounds = LineGeometry.GetBoundsHelper( 
                        pen,
                        Matrix.Identity, // world transform 
                        point0, 
                        point1,
                        Matrix.Identity, // geometry transform 
                        Geometry.StandardFlatteningTolerance,
                        ToleranceType.Absolute
                        );
 
                    if (_opacityMaskAccumulate > 0)
                    { 
                        TransformAndUnionOpacityMaskBounds(strokeBounds); 
                    }
 
                    if (requiresRealizationUpdates)
                    {
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx);
                    } 
                }
            } 
        } 

 
        /// 
        /// Draw a rectangle with the provided Brush and/or Pen.
        /// If both the Brush and Pen are null this call is a no-op.
        ///  
        /// 
        /// The Brush with which to fill the rectangle. 
        /// This is optional, and can be null, in which case no fill is performed. 
        /// 
        ///  
        /// The Pen with which to stroke the rectangle.
        /// This is optional, and can be null, in which case no stroke is performed.
        /// 
        /// The Rect to fill and/or stroke. 
        public override void DrawRectangle(
            Brush brush, 
            Pen pen, 
            Rect rectangle)
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time
            if (pushedEffects > 0)
            { 
                return;
            } 
 
            if (pen != null || brush != null)
            { 
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush);
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates;

                if (requiresRealizationUpdates || _opacityMaskAccumulate > 0) 
                {
                    Rect fillBounds = Rect.Empty; 
                    Rect strokeBounds = Rect.Empty; 

                    if (brush != null) 
                    {
                        fillBounds = RectangleGeometry.GetBoundsHelper(
                            null,
                            Matrix.Identity, // world transform 
                            rectangle,
                            0, 
                            0, 
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            );
                    }
 
                    if (pen != null)
                    { 
                        // This is the union of the geometry and the stroke. 
                        strokeBounds = RectangleGeometry.GetBoundsHelper(
                            pen, 
                            Matrix.Identity, // world transform
                            rectangle,
                            0,
                            0, 
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute 
                            );
                    } 

                    if (_opacityMaskAccumulate > 0)
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds); 
                    }
 
                    if (requiresRealizationUpdates) 
                    {
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                    }
                }
            }
        } 

 
        ///  
        /// Draw a rounded rectangle with the provided Brush and/or Pen.
        /// If both the Brush and Pen are null this call is a no-op. 
        /// 
        /// 
        /// The Brush with which to fill the rectangle.
        /// This is optional, and can be null, in which case no fill is performed. 
        /// 
        ///  
        /// The Pen with which to stroke the rectangle. 
        /// This is optional, and can be null, in which case no stroke is performed.
        ///  
        /// The Rect to fill and/or stroke.
        /// 
        /// The radius in the X dimension of the rounded corners of this
        /// rounded Rect.  This value will be clamped to the range [0..rectangle.Width/2] 
        /// 
        ///  
        /// The radius in the Y dimension of the rounded corners of this 
        /// rounded Rect.  This value will be clamped to the range [0..rectangle.Height/2].
        ///  
        public override void DrawRoundedRectangle(
            Brush brush,
            Pen pen,
            Rect rectangle, 
            Double radiusX,
            Double radiusY) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            if (!rectangle.IsEmpty && (pen != null || brush != null)) 
            { 
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush);
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates; 

                if (requiresRealizationUpdates || _opacityMaskAccumulate > 0)
                {
                    Rect fillBounds = Rect.Empty; 
                    Rect strokeBounds = Rect.Empty;
 
                    if (brush != null) 
                    {
                        fillBounds = RectangleGeometry.GetBoundsHelper( 
                            null,
                            Matrix.Identity, // world transform
                            rectangle,
                            radiusX, 
                            radiusY,
                            Matrix.Identity, // geometry transform 
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    }

                    if (pen != null)
                    { 
                        // This is the union of the geometry and the stroke.
                        strokeBounds = RectangleGeometry.GetBoundsHelper( 
                            pen, 
                            Matrix.Identity, // world transform
                            rectangle, 
                            radiusX,
                            radiusY,
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    } 

                    if (_opacityMaskAccumulate > 0) 
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds);
                    }
 
                    if (requiresRealizationUpdates)
                    { 
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                    }
                } 
            }
        }

 
        /// 
        /// Draw an ellipse with the provided Brush and/or Pen. 
        /// If both the Brush and Pen are null this call is a no-op. 
        /// 
        ///  
        /// The Brush with which to fill the ellipse.
        /// This is optional, and can be null, in which case no fill is performed.
        /// 
        ///  
        /// The Pen with which to stroke the ellipse.
        /// This is optional, and can be null, in which case no stroke is performed. 
        ///  
        /// 
        /// The center of the ellipse to fill and/or stroke. 
        /// 
        /// 
        /// The radius in the X dimension of the ellipse.
        /// The absolute value of the radius provided will be used. 
        /// 
        ///  
        /// The radius in the Y dimension of the ellipse. 
        /// The absolute value of the radius provided will be used.
        ///  
        public override void DrawEllipse(
            Brush brush,
            Pen pen,
            Point center, 
            Double radiusX,
            Double radiusY) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            if (pen != null || brush != null) 
            { 
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush);
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates; 

                Rect fillBounds = Rect.Empty;
                Rect strokeBounds = Rect.Empty;
 
                if (requiresRealizationUpdates || _opacityMaskAccumulate > 0)
                { 
                    if (brush != null) 
                    {
                        fillBounds = EllipseGeometry.GetBoundsHelper( 
                            null,
                            Matrix.Identity, // world transform
                            center,
                            radiusX, 
                            radiusY,
                            Matrix.Identity, // geometry transform 
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    }

                    if (pen != null)
                    { 
                        // This is the union of the geometry and the stroke.
                        strokeBounds = EllipseGeometry.GetBoundsHelper( 
                            pen, 
                            Matrix.Identity, // world transform
                            center, 
                            radiusX,
                            radiusY,
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    } 

                    if (_opacityMaskAccumulate > 0) 
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds);
                    }
 
                    if (requiresRealizationUpdates)
                    { 
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                    }
                } 
            }
        }

 
        /// 
        /// Draw a Geometry with the provided Brush and/or Pen. 
        /// If both the Brush and Pen are null this call is a no-op. 
        /// 
        ///  
        /// The Brush with which to fill the Geometry.
        /// This is optional, and can be null, in which case no fill is performed.
        /// 
        ///  
        /// The Pen with which to stroke the Geometry.
        /// This is optional, and can be null, in which case no stroke is performed. 
        ///  
        /// The Geometry to fill and/or stroke.
        public override void DrawGeometry( 
            Brush brush,
            Pen pen,
            Geometry geometry)
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0) 
            {
                return; 
            }

            if (geometry != null &&
                (pen != null || brush != null)) 
            {
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush); 
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates; 

                if (requiresRealizationUpdates  || _opacityMaskAccumulate > 0) 
                {
                    Rect fillBounds = Rect.Empty;
                    Rect strokeBounds = Rect.Empty;
 
                    if (brush != null)
                    { 
                        fillBounds = geometry.GetBoundsInternal(null, Matrix.Identity); 
                    }
 
                    if (pen != null)
                    {
                        // This is the union of the geometry and the stroke.
                        strokeBounds = geometry.GetBoundsInternal(pen, Matrix.Identity); 
                    }
 
                    if (_opacityMaskAccumulate > 0) 
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds); 
                    }

                    if (requiresRealizationUpdates)
                    { 
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx);
                    } 
                } 
            }
        } 


        /// 
        /// Draw an Image into the region specified by the Rect. 
        /// The Image will potentially be stretched and distorted to fit the Rect.
        /// For more fine grained control, consider filling a Rect with an ImageBrush via 
        /// DrawRectangle. 
        /// 
        /// The ImageSource to draw. 
        /// 
        /// The Rect into which the ImageSource will be fit.
        /// 
        public override void DrawImage( 
            ImageSource imageSource,
            Rect rectangle) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            DrawingImage di = imageSource as DrawingImage; 
            if (di != null && di.Drawing != null) 
            {
                Drawing drawing = di.Drawing; 

                if (drawing.RequiresRealizationUpdates || _opacityMaskAccumulate > 0)
                {
                    Rect drawingBounds = drawing.Bounds; 

                    if (_opacityMaskAccumulate > 0) 
                    { 
                        TransformAndUnionOpacityMaskBounds(drawingBounds);
                    } 

                    if (drawing.RequiresRealizationUpdates &&
                        !DoubleUtil.AreClose(drawingBounds.Width, 0) &&
                        !DoubleUtil.AreClose(drawingBounds.Height, 0)) 
                    {
                        Matrix scale = Matrix.CreateScaling( 
                            rectangle.Width / drawingBounds.Width, 
                            rectangle.Height / drawingBounds.Height);
 
                        _ctx.TransformStack.Push(ref scale, true);

                        // Update realizations inside the drawing graph.
                        drawing.UpdateRealizations(_ctx); 

                        _ctx.TransformStack.Pop(); 
                    } 
                }
            } 
        }


        ///  
        /// Draw a Video into the region specified by the Rect. The Video will
        /// potentially be stretched and distorted to fit the Rect. For more 
        /// fine grained control, consider filling a Rect with an VideoBrush 
        /// via DrawRectangle.
        ///  
        /// The MediaPlayer to draw.
        /// 
        /// The Rect into which the MediaPlayer will be fit.
        ///  
        public override void DrawVideo(
            MediaPlayer video, 
            Rect rectangle) 
        {
            // Do nothing. 
        }


        ///  
        /// Draw a GlyphRun.
        ///  
        /// Foreground brush to draw GlyphRun with.  
        ///  The GlyphRun to draw. 
        public override void DrawGlyphRun(Brush foregroundBrush, GlyphRun glyphRun) 
        {
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time
            if (pushedEffects > 0) 
            {
                return; 
            } 

            if (glyphRun != null && 
                foregroundBrush != null)
            {
                RealizationBrushHelper helper = new RealizationBrushHelper(null, foregroundBrush);
 
                if (helper.NeedsRealizationUpdates || _opacityMaskAccumulate > 0)
                { 
                    Rect strokeBounds = Rect.Empty; 
                    Rect fillBounds = glyphRun.ComputeInkBoundingBox();
                    if (!fillBounds.IsEmpty) 
                    {
                        Point baselineOrigin = glyphRun.BaselineOrigin;
                        fillBounds.X += baselineOrigin.X;
                        fillBounds.Y += baselineOrigin.Y; 

                        if (_opacityMaskAccumulate > 0) 
                        { 
                            TransformAndUnionOpacityMaskBounds(fillBounds);
                        } 

                        if (helper.NeedsRealizationUpdates)
                        {
                            helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// DrawDrawing is being overriden here to invoke the spezialized realization walk
        /// on Drawings. 
        /// 
        public override void DrawDrawing(Drawing drawing) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            if (drawing != null) 
            { 
                drawing.UpdateRealizations(_ctx);
            } 
        }

        #endregion Public Methods
 
        internal RealizationContext Context
        { 
            get { return _ctx; } 
        }
        //---------------------------------------------------------------------- 
        //
        //  Private Fields
        //
        //---------------------------------------------------------------------- 

        #region Private Fields 
 
        // The current realization context.
        private readonly RealizationContext _ctx; 

        // The Type stack for our Push/Pop calls.  This tells whether a given
        // Pop corresponds to a Transform, Clip, etc.
        private readonly Stack _operationTypeStack; 

        private Stack _opacityMaskBoundsStack; 
        private int _opacityMaskAccumulate; 
        private Rect _opacityMaskRect;
        private Stack _opacityMaskBrushStack; 
        private MatrixStack _opacityMaskMatrixStack;

        int pushedEffects;
        #endregion Private Fields 

 
        //--------------------------------------------------------------------- 
        //
        //  Private Types 
        //
        //----------------------------------------------------------------------

        #region Private Types 

        ///  
        /// OperationType enum - this defines the type of Pushes in a context, 
        /// so that our untyped Pops know what to Pop.
        ///  
        private enum OperationType
        {
            Transform,
            InvalidOrIrrelevantTransform, 
            Clip,
            Opacity, 
            OpacityMask, 
            Guidelines,
            BitmapEffect 
        }

        #endregion Private Types
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: RealizationDrawingContextWalker.cs 
//
// Description: 
//   This file contains the implementation of RealizationDrawingContextWalker. 
//   This DrawingContextWalker is used to perform realization updates on
//   render data. 
//
//-----------------------------------------------------------------------------

namespace System.Windows.Media 
{
    using MS.Internal; 
 
    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.Effects;
    using System.Windows.Media.Imaging;

 
    /// 
    /// RealizationDrawingContextWalker - a DrawingContextWalker which will 
    /// update realizations of the contents of the render data. 
    /// 
    internal class RealizationDrawingContextWalker : DrawingContextWalker 
    {
        //---------------------------------------------------------------------
        //
        //  Internal Constructors 
        //
        //--------------------------------------------------------------------- 
 
        #region Internal Constructors
 
        /// 
        /// Constructor for BoundsDrawingContextWalker
        /// 
        /// The render context. 
        internal RealizationDrawingContextWalker(RealizationContext ctx)
        { 
            Debug.Assert(ctx != null); 

            _ctx = ctx; 
            _operationTypeStack = new Stack(2);
            _opacityMaskBoundsStack = new Stack(2);
            _opacityMaskBrushStack = new Stack(2);
            _opacityMaskMatrixStack = new MatrixStack(); 
            _opacityMaskRect = Rect.Empty;
            _opacityMaskAccumulate = 0; 
        } 

        #endregion Internal Constructors 



        //---------------------------------------------------------------------- 
        //
        //  Public Methods 
        // 
        //---------------------------------------------------------------------
 
        #region Public Methods

        /// 
        /// Push a clip region, which will apply to all drawing primitives 
        /// until the corresponding Pop call.
        ///  
        ///  
        /// The Geometry to which we will clip.
        ///  
        public override void PushClip(Geometry clipGeometry)
        {
            // Ignore the clip value.
            _operationTypeStack.Push(OperationType.Clip); 
        }
 
 
        /// 
        /// Push an opacity mask 
        /// 
        /// 
        /// The opacity mask
        ///  
        public override void PushOpacityMask(Brush brush)
        { 
            _operationTypeStack.Push(OperationType.OpacityMask); 
            _opacityMaskBoundsStack.Push(_opacityMaskRect);
            _opacityMaskRect = Rect.Empty; 
            _opacityMaskAccumulate++;
            _opacityMaskBrushStack.Push(brush);
            _opacityMaskMatrixStack.Push(Transform.Identity, /* combine */ false);
        } 

        private void PopOpacityMask() 
        { 
            Debug.Assert(_opacityMaskBoundsStack.Count > 0);
            Debug.Assert(_opacityMaskBrushStack.Count > 0); 
            Brush brush = _opacityMaskBrushStack.Pop();
            if (brush != null)
            {
                brush.UpdateRealizations(_opacityMaskRect,  _ctx); 
            }
            _opacityMaskRect = Rect.Union(_opacityMaskRect, _opacityMaskBoundsStack.Pop()); 
            _opacityMaskAccumulate--; 
        }
 
        private void TransformAndUnionOpacityMaskBounds(Rect bounds)
        {
            Rect r = Rect.Transform(bounds, _opacityMaskMatrixStack.Peek());
            _opacityMaskRect.Union(r); 
            return;
        } 
 
        /// 
        /// Push an opacity which will blend the composite of all drawing 
        /// primitives added until the corresponding Pop call.
        /// 
        /// 
        /// The opacity with which to blend - 0 is transparent, 1 is opaque. 
        /// 
        public override void PushOpacity(Double opacity) 
        { 
            // Ignore the opacity value.
            _operationTypeStack.Push(OperationType.Opacity); 
        }


        ///  
        /// Push a Transform which will apply to all drawing operations
        /// until the corresponding Pop. 
        ///  
        /// The Transform to push.
        public override void PushTransform(Transform transform) 
        {
            // Retrieve the new transform as a matrix if it exists.
            if (transform != null && !transform.IsIdentity)
            { 
                // Push the operation type.
                _operationTypeStack.Push(OperationType.Transform); 
 
                // Push the valid transform on the stack.
                _ctx.TransformStack.Push(transform, /* combine */ true); 
                _opacityMaskMatrixStack.Push(transform, /* combine */ true);
            }
            else
            { 
                // Do not store identity (or null) transforms on the transform stack.
                _operationTypeStack.Push(OperationType.InvalidOrIrrelevantTransform); 
            } 
        }
 
        /// 
        ///     PushEffect -
        ///     Push a BitmapEffect which will apply to all drawing operations until the
        ///     corresponding Pop. 
        /// 
        ///  The BitmapEffect to push.  
        ///  The BitmapEffectInput.  
        public override void PushEffect(
            BitmapEffect effect, 
            BitmapEffectInput effectInput)
        {
            _operationTypeStack.Push(OperationType.BitmapEffect);
            pushedEffects++; 
        }
 
        ///  
        ///     PushGuidelineSet -
        ///     Push a set of guidelines which should be applied 
        ///     to all drawing operations until the
        ///     corresponding Pop.
        /// 
        ///  The GuidelineSet to push.  
        public override void PushGuidelineSet(
            GuidelineSet guidelines) 
        { 
            // Ignore the guidelines value.
            _operationTypeStack.Push(OperationType.Guidelines); 
        }

        /// 
        ///     PushGuidelineY1 - 
        ///     Explicitly push one horizontal guideline.
        ///  
        ///  The coordinate of leading guideline.  
        internal override void PushGuidelineY1(
            Double coordinate) 
        {
            // Ignore the guidelines values.
            _operationTypeStack.Push(OperationType.Guidelines);
        } 

 
        ///  
        ///     PushGuidelineY2 -
        ///     Explicitly push a pair of horizontal guidelines. 
        /// 
        /// 
        ///     The coordinate of leading guideline.
        ///  
        /// 
        ///     The offset from leading guideline to driven guideline. 
        ///  
        internal override void PushGuidelineY2(
            Double leadingCoordinate, 
            Double offsetToDrivenCoordinate)
        {
            // Ignore the guidelines values.
            _operationTypeStack.Push(OperationType.Guidelines); 
        }
 
 
        /// 
        /// Pops a transform/clip/opacity change from the stack. 
        /// 
        public override void Pop()
        {
            // We must have a type stack and it must not be empty. 
            Debug.Assert(_operationTypeStack != null);
            Debug.Assert(_operationTypeStack.Count > 0); 
 
            // Retrieve the OperationType to figure out what what this Pop is.
            OperationType operationType = _operationTypeStack.Pop(); 

            switch (operationType)
            {
                case OperationType.Transform: 
                    // Restore the previous transform
                    _ctx.TransformStack.Pop(); 
                    _opacityMaskMatrixStack.Pop(); 
                    break;
                case OperationType.BitmapEffect: 
                    pushedEffects--;
                    break;
                case OperationType.OpacityMask:
                    PopOpacityMask(); 
                    break;
                default: 
                    // Do nothing for the 'not stored' operation types 
                    Debug.Assert(operationType == OperationType.Clip ||
                                 operationType == OperationType.Opacity || 
                                 operationType == OperationType.Guidelines ||
                                 operationType == OperationType.InvalidOrIrrelevantTransform ||
                                 operationType == OperationType.BitmapEffect);
                    break; 
            }
        } 
 

 
        /// 
        /// Draws a line with the specified pen. Note that this API does not
        /// accept a Brush, as there is no area to fill.
        ///  
        /// The Pen with which to stroke the line.
        /// The start Point for the line. 
        /// The end Point for the line. 
        public override void DrawLine(
            Pen pen, 
            Point point0,
            Point point1)
        {
            // skip realization updates if there is an effect on the stack 
            // we will do this at a later time
            if (pushedEffects > 0) 
            { 
                return;
            } 

            if (pen != null)
            {
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, null); 
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates;
 
                if (    requiresRealizationUpdates 
                    ||  _opacityMaskAccumulate > 0)
                { 
                    Rect fillBounds = Rect.Empty;

                    // This is the union of the geometry and the stroke.
                    Rect strokeBounds = LineGeometry.GetBoundsHelper( 
                        pen,
                        Matrix.Identity, // world transform 
                        point0, 
                        point1,
                        Matrix.Identity, // geometry transform 
                        Geometry.StandardFlatteningTolerance,
                        ToleranceType.Absolute
                        );
 
                    if (_opacityMaskAccumulate > 0)
                    { 
                        TransformAndUnionOpacityMaskBounds(strokeBounds); 
                    }
 
                    if (requiresRealizationUpdates)
                    {
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx);
                    } 
                }
            } 
        } 

 
        /// 
        /// Draw a rectangle with the provided Brush and/or Pen.
        /// If both the Brush and Pen are null this call is a no-op.
        ///  
        /// 
        /// The Brush with which to fill the rectangle. 
        /// This is optional, and can be null, in which case no fill is performed. 
        /// 
        ///  
        /// The Pen with which to stroke the rectangle.
        /// This is optional, and can be null, in which case no stroke is performed.
        /// 
        /// The Rect to fill and/or stroke. 
        public override void DrawRectangle(
            Brush brush, 
            Pen pen, 
            Rect rectangle)
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time
            if (pushedEffects > 0)
            { 
                return;
            } 
 
            if (pen != null || brush != null)
            { 
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush);
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates;

                if (requiresRealizationUpdates || _opacityMaskAccumulate > 0) 
                {
                    Rect fillBounds = Rect.Empty; 
                    Rect strokeBounds = Rect.Empty; 

                    if (brush != null) 
                    {
                        fillBounds = RectangleGeometry.GetBoundsHelper(
                            null,
                            Matrix.Identity, // world transform 
                            rectangle,
                            0, 
                            0, 
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            );
                    }
 
                    if (pen != null)
                    { 
                        // This is the union of the geometry and the stroke. 
                        strokeBounds = RectangleGeometry.GetBoundsHelper(
                            pen, 
                            Matrix.Identity, // world transform
                            rectangle,
                            0,
                            0, 
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute 
                            );
                    } 

                    if (_opacityMaskAccumulate > 0)
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds); 
                    }
 
                    if (requiresRealizationUpdates) 
                    {
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                    }
                }
            }
        } 

 
        ///  
        /// Draw a rounded rectangle with the provided Brush and/or Pen.
        /// If both the Brush and Pen are null this call is a no-op. 
        /// 
        /// 
        /// The Brush with which to fill the rectangle.
        /// This is optional, and can be null, in which case no fill is performed. 
        /// 
        ///  
        /// The Pen with which to stroke the rectangle. 
        /// This is optional, and can be null, in which case no stroke is performed.
        ///  
        /// The Rect to fill and/or stroke.
        /// 
        /// The radius in the X dimension of the rounded corners of this
        /// rounded Rect.  This value will be clamped to the range [0..rectangle.Width/2] 
        /// 
        ///  
        /// The radius in the Y dimension of the rounded corners of this 
        /// rounded Rect.  This value will be clamped to the range [0..rectangle.Height/2].
        ///  
        public override void DrawRoundedRectangle(
            Brush brush,
            Pen pen,
            Rect rectangle, 
            Double radiusX,
            Double radiusY) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            if (!rectangle.IsEmpty && (pen != null || brush != null)) 
            { 
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush);
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates; 

                if (requiresRealizationUpdates || _opacityMaskAccumulate > 0)
                {
                    Rect fillBounds = Rect.Empty; 
                    Rect strokeBounds = Rect.Empty;
 
                    if (brush != null) 
                    {
                        fillBounds = RectangleGeometry.GetBoundsHelper( 
                            null,
                            Matrix.Identity, // world transform
                            rectangle,
                            radiusX, 
                            radiusY,
                            Matrix.Identity, // geometry transform 
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    }

                    if (pen != null)
                    { 
                        // This is the union of the geometry and the stroke.
                        strokeBounds = RectangleGeometry.GetBoundsHelper( 
                            pen, 
                            Matrix.Identity, // world transform
                            rectangle, 
                            radiusX,
                            radiusY,
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    } 

                    if (_opacityMaskAccumulate > 0) 
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds);
                    }
 
                    if (requiresRealizationUpdates)
                    { 
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                    }
                } 
            }
        }

 
        /// 
        /// Draw an ellipse with the provided Brush and/or Pen. 
        /// If both the Brush and Pen are null this call is a no-op. 
        /// 
        ///  
        /// The Brush with which to fill the ellipse.
        /// This is optional, and can be null, in which case no fill is performed.
        /// 
        ///  
        /// The Pen with which to stroke the ellipse.
        /// This is optional, and can be null, in which case no stroke is performed. 
        ///  
        /// 
        /// The center of the ellipse to fill and/or stroke. 
        /// 
        /// 
        /// The radius in the X dimension of the ellipse.
        /// The absolute value of the radius provided will be used. 
        /// 
        ///  
        /// The radius in the Y dimension of the ellipse. 
        /// The absolute value of the radius provided will be used.
        ///  
        public override void DrawEllipse(
            Brush brush,
            Pen pen,
            Point center, 
            Double radiusX,
            Double radiusY) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            if (pen != null || brush != null) 
            { 
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush);
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates; 

                Rect fillBounds = Rect.Empty;
                Rect strokeBounds = Rect.Empty;
 
                if (requiresRealizationUpdates || _opacityMaskAccumulate > 0)
                { 
                    if (brush != null) 
                    {
                        fillBounds = EllipseGeometry.GetBoundsHelper( 
                            null,
                            Matrix.Identity, // world transform
                            center,
                            radiusX, 
                            radiusY,
                            Matrix.Identity, // geometry transform 
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    }

                    if (pen != null)
                    { 
                        // This is the union of the geometry and the stroke.
                        strokeBounds = EllipseGeometry.GetBoundsHelper( 
                            pen, 
                            Matrix.Identity, // world transform
                            center, 
                            radiusX,
                            radiusY,
                            Matrix.Identity, // geometry transform
                            Geometry.StandardFlatteningTolerance, 
                            ToleranceType.Absolute
                            ); 
                    } 

                    if (_opacityMaskAccumulate > 0) 
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds);
                    }
 
                    if (requiresRealizationUpdates)
                    { 
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                    }
                } 
            }
        }

 
        /// 
        /// Draw a Geometry with the provided Brush and/or Pen. 
        /// If both the Brush and Pen are null this call is a no-op. 
        /// 
        ///  
        /// The Brush with which to fill the Geometry.
        /// This is optional, and can be null, in which case no fill is performed.
        /// 
        ///  
        /// The Pen with which to stroke the Geometry.
        /// This is optional, and can be null, in which case no stroke is performed. 
        ///  
        /// The Geometry to fill and/or stroke.
        public override void DrawGeometry( 
            Brush brush,
            Pen pen,
            Geometry geometry)
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0) 
            {
                return; 
            }

            if (geometry != null &&
                (pen != null || brush != null)) 
            {
                RealizationBrushHelper helper = new RealizationBrushHelper(pen, brush); 
                bool requiresRealizationUpdates = helper.NeedsRealizationUpdates; 

                if (requiresRealizationUpdates  || _opacityMaskAccumulate > 0) 
                {
                    Rect fillBounds = Rect.Empty;
                    Rect strokeBounds = Rect.Empty;
 
                    if (brush != null)
                    { 
                        fillBounds = geometry.GetBoundsInternal(null, Matrix.Identity); 
                    }
 
                    if (pen != null)
                    {
                        // This is the union of the geometry and the stroke.
                        strokeBounds = geometry.GetBoundsInternal(pen, Matrix.Identity); 
                    }
 
                    if (_opacityMaskAccumulate > 0) 
                    {
                        TransformAndUnionOpacityMaskBounds(pen != null ? strokeBounds : fillBounds); 
                    }

                    if (requiresRealizationUpdates)
                    { 
                        helper.UpdateRealizations(strokeBounds, fillBounds, _ctx);
                    } 
                } 
            }
        } 


        /// 
        /// Draw an Image into the region specified by the Rect. 
        /// The Image will potentially be stretched and distorted to fit the Rect.
        /// For more fine grained control, consider filling a Rect with an ImageBrush via 
        /// DrawRectangle. 
        /// 
        /// The ImageSource to draw. 
        /// 
        /// The Rect into which the ImageSource will be fit.
        /// 
        public override void DrawImage( 
            ImageSource imageSource,
            Rect rectangle) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            DrawingImage di = imageSource as DrawingImage; 
            if (di != null && di.Drawing != null) 
            {
                Drawing drawing = di.Drawing; 

                if (drawing.RequiresRealizationUpdates || _opacityMaskAccumulate > 0)
                {
                    Rect drawingBounds = drawing.Bounds; 

                    if (_opacityMaskAccumulate > 0) 
                    { 
                        TransformAndUnionOpacityMaskBounds(drawingBounds);
                    } 

                    if (drawing.RequiresRealizationUpdates &&
                        !DoubleUtil.AreClose(drawingBounds.Width, 0) &&
                        !DoubleUtil.AreClose(drawingBounds.Height, 0)) 
                    {
                        Matrix scale = Matrix.CreateScaling( 
                            rectangle.Width / drawingBounds.Width, 
                            rectangle.Height / drawingBounds.Height);
 
                        _ctx.TransformStack.Push(ref scale, true);

                        // Update realizations inside the drawing graph.
                        drawing.UpdateRealizations(_ctx); 

                        _ctx.TransformStack.Pop(); 
                    } 
                }
            } 
        }


        ///  
        /// Draw a Video into the region specified by the Rect. The Video will
        /// potentially be stretched and distorted to fit the Rect. For more 
        /// fine grained control, consider filling a Rect with an VideoBrush 
        /// via DrawRectangle.
        ///  
        /// The MediaPlayer to draw.
        /// 
        /// The Rect into which the MediaPlayer will be fit.
        ///  
        public override void DrawVideo(
            MediaPlayer video, 
            Rect rectangle) 
        {
            // Do nothing. 
        }


        ///  
        /// Draw a GlyphRun.
        ///  
        /// Foreground brush to draw GlyphRun with.  
        ///  The GlyphRun to draw. 
        public override void DrawGlyphRun(Brush foregroundBrush, GlyphRun glyphRun) 
        {
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time
            if (pushedEffects > 0) 
            {
                return; 
            } 

            if (glyphRun != null && 
                foregroundBrush != null)
            {
                RealizationBrushHelper helper = new RealizationBrushHelper(null, foregroundBrush);
 
                if (helper.NeedsRealizationUpdates || _opacityMaskAccumulate > 0)
                { 
                    Rect strokeBounds = Rect.Empty; 
                    Rect fillBounds = glyphRun.ComputeInkBoundingBox();
                    if (!fillBounds.IsEmpty) 
                    {
                        Point baselineOrigin = glyphRun.BaselineOrigin;
                        fillBounds.X += baselineOrigin.X;
                        fillBounds.Y += baselineOrigin.Y; 

                        if (_opacityMaskAccumulate > 0) 
                        { 
                            TransformAndUnionOpacityMaskBounds(fillBounds);
                        } 

                        if (helper.NeedsRealizationUpdates)
                        {
                            helper.UpdateRealizations(strokeBounds, fillBounds, _ctx); 
                        }
                    } 
                } 
            }
        } 

        /// 
        /// DrawDrawing is being overriden here to invoke the spezialized realization walk
        /// on Drawings. 
        /// 
        public override void DrawDrawing(Drawing drawing) 
        { 
            // skip realization updates if there is an effect on the stack
            // we will do this at a later time 
            if (pushedEffects > 0)
            {
                return;
            } 

            if (drawing != null) 
            { 
                drawing.UpdateRealizations(_ctx);
            } 
        }

        #endregion Public Methods
 
        internal RealizationContext Context
        { 
            get { return _ctx; } 
        }
        //---------------------------------------------------------------------- 
        //
        //  Private Fields
        //
        //---------------------------------------------------------------------- 

        #region Private Fields 
 
        // The current realization context.
        private readonly RealizationContext _ctx; 

        // The Type stack for our Push/Pop calls.  This tells whether a given
        // Pop corresponds to a Transform, Clip, etc.
        private readonly Stack _operationTypeStack; 

        private Stack _opacityMaskBoundsStack; 
        private int _opacityMaskAccumulate; 
        private Rect _opacityMaskRect;
        private Stack _opacityMaskBrushStack; 
        private MatrixStack _opacityMaskMatrixStack;

        int pushedEffects;
        #endregion Private Fields 

 
        //--------------------------------------------------------------------- 
        //
        //  Private Types 
        //
        //----------------------------------------------------------------------

        #region Private Types 

        ///  
        /// OperationType enum - this defines the type of Pushes in a context, 
        /// so that our untyped Pops know what to Pop.
        ///  
        private enum OperationType
        {
            Transform,
            InvalidOrIrrelevantTransform, 
            Clip,
            Opacity, 
            OpacityMask, 
            Guidelines,
            BitmapEffect 
        }

        #endregion Private Types
    } 
}

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