BitmapEffectDrawingContextWalker.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Core / CSharp / System / Windows / Media / Effects / BitmapEffectDrawingContextWalker.cs / 1 / BitmapEffectDrawingContextWalker.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: BitmapEffectDrawingContextWalker.cs 
//
// Description: This file contains the implementation of BitmapEffectDrawingContextWalker. 
//              This DrawingContextWalker is used to render the commands between 
//              PushEffect and Pop
// 
// History:
//  07/25/2005 : [....] - 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.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Security; 
using System.Security.Permissions;
namespace System.Windows.Media.Effects 
{ 
    class BitmapEffectDrawingContextWalker : DrawingContextWalker
    { 
        /// 
        /// PushType enum - this defines the type of Pushes in a context, so that our
        /// untyped Pops know what to Pop.
        ///  
        private enum PushType
        { 
            Transform, 
            Clip,
            Opacity, 
            OpacityMask,
            BitmapEffect,
            GuidelineSet,
            GuidelineY1, 
            GuidelineY2
        } 
 

        public BitmapEffectDrawingContextWalker() 
        {
            _transform = Matrix.Identity;
            _windowClip = Rect.Empty;
        } 

        public BitmapEffectDrawingContextWalker(Matrix transform, Rect windowClip) 
        { 
            _transform = transform;
            _windowClip = windowClip; 
        }

        /// 
        ///     DrawLine - 
        ///     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)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawLine( 
                        pen,
                        point0,
                        point1);
            } 
        }
 
        ///  
        ///     DrawLine -
        ///     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.  
        ///  Optional AnimationClock for point0. 
        ///  The end Point for the line.  
        ///  Optional AnimationClock for point1.  
        public override void DrawLine(
            Pen pen, 
            Point point0,
            AnimationClock point0Animations,
            Point point1,
            AnimationClock point1Animations) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawLine(
                        pen, 
                        point0,
                        point0Animations,
                        point1,
                        point1Animations); 
            }
 
        } 

        ///  
        ///     DrawRectangle -
        ///     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)
        { 
            if (_effectContext != null)
            {
                _effectContext.Context.DrawRectangle(
                        brush, 
                        pen,
                        rectangle); 
            } 
        }
 
        /// 
        ///     DrawRectangle -
        ///     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. 
        ///  Optional AnimationClock for rectangle.  
        public override void DrawRectangle( 
            Brush brush,
            Pen pen, 
            Rect rectangle,
            AnimationClock rectangleAnimations)
        {
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawRectangle( 
                        brush, 
                        pen,
                        rectangle); 
            }
        }

        ///  
        ///     DrawRoundedRectangle -
        ///     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) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawRoundedRectangle(
                        brush, 
                        pen,
                        rectangle,
                        radiusX,
                        radiusY); 
            }
        } 
 
        /// 
        ///     DrawRoundedRectangle - 
        ///     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. 
        ///  Optional AnimationClock for rectangle.  
        /// 
        ///     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] 
        /// 
        ///  Optional AnimationClock for radiusX.  
        /// 
        ///     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].
        ///  
        ///  Optional AnimationClock for radiusY. 
        public override void DrawRoundedRectangle( 
            Brush brush, 
            Pen pen,
            Rect rectangle, 
            AnimationClock rectangleAnimations,
            Double radiusX,
            AnimationClock radiusXAnimations,
            Double radiusY, 
            AnimationClock radiusYAnimations)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawRoundedRectangle( 
                    brush,
                    pen,
                    rectangle,
                    rectangleAnimations, 
                    radiusX,
                    radiusXAnimations, 
                    radiusY, 
                    radiusYAnimations);
            } 

        }

        ///  
        ///     DrawEllipse -
        ///     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) 
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawEllipse(
                        brush,
                        pen,
                        center, 
                        radiusX,
                        radiusY); 
            } 
        }
 
        /// 
        ///     DrawEllipse -
        ///     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. 
        ///  
        ///  Optional AnimationClock for center. 
        ///  
        ///     The radius in the X dimension of the ellipse.
        ///     The absolute value of the radius provided will be used.
        /// 
        ///  Optional AnimationClock for radiusX.  
        /// 
        ///     The radius in the Y dimension of the ellipse. 
        ///     The absolute value of the radius provided will be used. 
        /// 
        ///  Optional AnimationClock for radiusY.  
        public override void DrawEllipse(
            Brush brush,
            Pen pen,
            Point center, 
            AnimationClock centerAnimations,
            Double radiusX, 
            AnimationClock radiusXAnimations, 
            Double radiusY,
            AnimationClock radiusYAnimations) 
        {
            if (_effectContext != null)
            {
                _effectContext.Context.DrawEllipse( 
                    brush,
                    pen, 
                    center, 
                    centerAnimations,
                    radiusX, 
                    radiusXAnimations,
                    radiusY,
                    radiusYAnimations);
            } 

        } 
 
        /// 
        ///     DrawGeometry - 
        ///     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) 
        {
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawGeometry(
                        brush,
                        pen, 
                        geometry);
            } 
        } 

        ///  
        ///     DrawImage -
        ///     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) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawImage(
                        imageSource, 
                        rectangle);
            }
        }
 
        /// 
        ///     DrawImage - 
        ///     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.
        ///  
        ///  Optional AnimationClock for rectangle.  
        public override void DrawImage(
            ImageSource imageSource, 
            Rect rectangle,
            AnimationClock rectangleAnimations)
        {
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawImage( 
                        imageSource, 
                        rectangle,
                        rectangleAnimations); 
            }
        }

        ///  
        ///     DrawGlyphRun -
        ///     Draw a GlyphRun 
        ///  
        /// 
        ///     Foreground brush to draw the GlyphRun with. 
        /// 
        ///  The GlyphRun to draw.  
        public override void DrawGlyphRun(
            Brush foregroundBrush, 
            GlyphRun glyphRun)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawGlyphRun( 
                        foregroundBrush,
                        glyphRun);
            }
        } 

        ///  
        ///     DrawDrawing - 
        ///     Draw a Drawing by appending a sub-Drawing to the current Drawing.
        ///  
        ///  The drawing to draw. 
        public override void DrawDrawing(
            Drawing drawing)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawDrawing(drawing); 
            }
        } 

        /// 
        ///     DrawVideo -
        ///     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 MediaClock will be fit.
        /// 
        public override void DrawVideo( 
            MediaPlayer player,
            Rect rectangle) 
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawVideo(
                    player,
                    rectangle);
            } 
        }
 
        ///  
        ///     DrawVideo -
        ///     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 MediaClock will be fit. 
        /// 
        ///  Optional AnimationClock for rectangle.  
        public override void DrawVideo(
            MediaPlayer player,
            Rect rectangle,
            AnimationClock rectangleAnimations) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawVideo(
                    player, 
                    rectangle,
                    rectangleAnimations);
            }
        } 

        ///  
        ///     DrawScene3D - 
        ///     Draw a Scene3D (internal object encapsulating a 3D scene)
        ///  
        ///  The Scene3D to draw. 
        internal override void DrawScene3D(
            Scene3D scene3D)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawScene3D(scene3D); 
            }
        } 

        /// 
        ///     PushGuidelineSet -
        ///     Push a set of guidelines which will apply to all drawing operations until the 
        ///     corresponding Pop.
        ///  
        ///  The GuidelineSet to push.  
        public override void PushGuidelineSet(
            GuidelineSet guidelines) 
        {
            if (_effectContext != null)
            {
                _effectContext.Context.PushGuidelineSet(guidelines); 
            }
 
            // Ensure the type stack 
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2);
            }

            _pushTypeStack.Push(PushType.GuidelineSet); 
        }
 
        ///  
        ///     PushGuidelineY1 -
        ///     Explicitly push one horizontal guideline. 
        /// 
        ///  The coordinate of leading guideline. 
        internal override void PushGuidelineY1(
            Double coordinate) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.PushGuidelineY1(coordinate);
            } 

            // Ensure the type stack
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2);
            } 
 
            _pushTypeStack.Push(PushType.GuidelineY1);
        } 

        /// 
        ///     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)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.PushGuidelineY2(leadingCoordinate, 
                                                       offsetToDrivenCoordinate);
            }

            // Ensure the type stack 
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2); 
            }
 
            _pushTypeStack.Push(PushType.GuidelineY2);
        }

        ///  
        /// Push an opacity mask
        ///  
        ///  
        /// The opacity mask
        ///  
        public override void PushOpacityMask(Brush brush)
        {
            if (_effectContext != null)
            { 
                _effectContext.Context.PushOpacityMask(brush);
            } 
            // Ensure the type stack 
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2);
            }

            _pushTypeStack.Push(PushType.OpacityMask); 
        }
 
        ///  
        ///     PushClip -
        ///     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)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.PushClip(clipGeometry); 
            }

            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2); 
            } 

            _pushTypeStack.Push(PushType.Clip); 
        }

        /// 
        ///     PushOpacity - 
        ///     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)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.PushOpacity(opacity); 
            }
 
            // Ensure the type stack
            if (_pushTypeStack == null)
            {
                _pushTypeStack = new Stack(2); 
            }
 
            _pushTypeStack.Push(PushType.Opacity); 
        }
 
        /// 
        ///     PushOpacity -
        ///     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. 
        /// 
        ///  Optional AnimationClock for opacity.  
        public override void PushOpacity(
            Double opacity,
            AnimationClock opacityAnimations)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.PushOpacity( 
                        opacity,
                        opacityAnimations); 
            }

            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2); 
            } 

            _pushTypeStack.Push(PushType.Opacity); 
        }

        /// 
        ///     PushTransform - 
        ///     Push a Transform which will apply to all drawing operations until the corresponding
        ///     Pop. 
        ///  
        ///  The Transform to push. 
        public override void PushTransform( 
            Transform transform)
        {
            if (_effectContext != null)
            { 
                _effectContext.Context.PushTransform(transform);
            } 
 
            // Ensure the transform stack
            if (_transformStack == null) 
            {
                _transformStack = new Stack(2);
            }
 
            // Push the old transform.
            _transformStack.Push(_transform); 
 
            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2);
            }
 
            // Push the transform type
            _pushTypeStack.Push(PushType.Transform); 
 
            Matrix newValue = Matrix.Identity;
 
            // Retrieve the new transform as a matrix if it exists
            if ((transform != null) && !transform.IsIdentity)
            {
                // If the transform is degeneraate, we can skip all instructions until the 
                // corresponding Pop.
                newValue = transform.Value; 
            } 

            // Update the current transform 
            _transform = newValue * _transform;
        }

        ///  
        ///     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) 
        {
 
            // create new context 
            if (_effectContext == null)
            { 
                _effectContext = new BitmapEffectDrawingContextState(effect, effectInput);
            }
            else
            { 
                _effectContext.Context.PushEffect(effect, effectInput);
            } 
 
            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2);
            }
 
            _pushTypeStack.Push(PushType.BitmapEffect);
            _effectStackDepth++; 
        } 

        ///  
        /// Pop
        /// 
        public override void Pop(
            ) 
        {
            // We must have a type stack and it must not be empty. 
            Debug.Assert(_pushTypeStack != null); 
            Debug.Assert(_pushTypeStack.Count > 0);
 
            // Retrieve the PushType to figure out what what this Pop is.
            PushType pushType = _pushTypeStack.Pop();

            switch (pushType) 
            {
                case PushType.Transform: 
                    // We must have a Transform stack and it must not be empty. 
                    Debug.Assert(_transformStack != null);
                    Debug.Assert(_transformStack.Count > 0); 

                    // Restore the transform
                    _transform = _transformStack.Pop();
                    break; 
                case PushType.BitmapEffect:
 
                    Debug.Assert(_effectStackDepth > 0, "We should have pushed an effect first"); 
                    Debug.Assert(_effectContext != null, "We should have created a context");
 
                    _effectStackDepth--;

                    // render only if it is a toplevel effect
                    if (_effectStackDepth == 0) 
                    {
                        _effectContext.Context.Close(); 
                        Matrix worldTransform = _transform; 
                        BitmapSource effectImage = _effectContext.RenderBitmapEffect(ref worldTransform, _windowClip);
                        ImageDrawing drawing = new ImageDrawing(); 

                        if (effectImage != null)
                        {
                            drawing.ImageSource = effectImage; 
                            drawing.Rect = new Rect(0, 0, effectImage.Width, effectImage.Height);
                        } 
 
                        DrawingGroup group = new DrawingGroup();
                        group.Children.Add(drawing); 
                        group.Transform = new MatrixTransform(worldTransform);

                        BitmapEffectDrawing.Drawings.Add(group);
                        BitmapEffectDrawing.WorldTransforms.Add(new MatrixTransform(_transform)); 
                        _effectContext = null;
                    } 
 
                    break;
                default: 
                    // Ignore the rest
                    break;
            }
 
            if (_effectContext != null)
            { 
                _effectContext.Context.Pop(); 
            }
        } 

        internal BitmapEffectDrawing BitmapEffectDrawing
        {
            get 
            {
                if (_bitmapEffectDrawing == null) 
                { 
                    _bitmapEffectDrawing = new BitmapEffectDrawing();
                } 
                return _bitmapEffectDrawing;
            }
        }
 
        #region Private Fields
 
        private BitmapEffectDrawing _bitmapEffectDrawing; 

        // The current local->world Transform as a matrix. 
        private Matrix _transform;

        private Rect _windowClip = Rect.Empty;
 
        // The Type stack for our Push/Pop calls.  This tells whether a given Pop corresponds
        // to a Transform, Clip, etc. 
        private Stack _pushTypeStack; 

        // This stack contains the Matrices encountered during our walk. 
        // The current transform is stored in _transform and not in the Stack.
        private Stack _transformStack;

        // this contains the effect drawing context 
        private BitmapEffectDrawingContextState _effectContext;
        private long _effectStackDepth; 
 
        #endregion
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: BitmapEffectDrawingContextWalker.cs 
//
// Description: This file contains the implementation of BitmapEffectDrawingContextWalker. 
//              This DrawingContextWalker is used to render the commands between 
//              PushEffect and Pop
// 
// History:
//  07/25/2005 : [....] - 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.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Security; 
using System.Security.Permissions;
namespace System.Windows.Media.Effects 
{ 
    class BitmapEffectDrawingContextWalker : DrawingContextWalker
    { 
        /// 
        /// PushType enum - this defines the type of Pushes in a context, so that our
        /// untyped Pops know what to Pop.
        ///  
        private enum PushType
        { 
            Transform, 
            Clip,
            Opacity, 
            OpacityMask,
            BitmapEffect,
            GuidelineSet,
            GuidelineY1, 
            GuidelineY2
        } 
 

        public BitmapEffectDrawingContextWalker() 
        {
            _transform = Matrix.Identity;
            _windowClip = Rect.Empty;
        } 

        public BitmapEffectDrawingContextWalker(Matrix transform, Rect windowClip) 
        { 
            _transform = transform;
            _windowClip = windowClip; 
        }

        /// 
        ///     DrawLine - 
        ///     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)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawLine( 
                        pen,
                        point0,
                        point1);
            } 
        }
 
        ///  
        ///     DrawLine -
        ///     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.  
        ///  Optional AnimationClock for point0. 
        ///  The end Point for the line.  
        ///  Optional AnimationClock for point1.  
        public override void DrawLine(
            Pen pen, 
            Point point0,
            AnimationClock point0Animations,
            Point point1,
            AnimationClock point1Animations) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawLine(
                        pen, 
                        point0,
                        point0Animations,
                        point1,
                        point1Animations); 
            }
 
        } 

        ///  
        ///     DrawRectangle -
        ///     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)
        { 
            if (_effectContext != null)
            {
                _effectContext.Context.DrawRectangle(
                        brush, 
                        pen,
                        rectangle); 
            } 
        }
 
        /// 
        ///     DrawRectangle -
        ///     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. 
        ///  Optional AnimationClock for rectangle.  
        public override void DrawRectangle( 
            Brush brush,
            Pen pen, 
            Rect rectangle,
            AnimationClock rectangleAnimations)
        {
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawRectangle( 
                        brush, 
                        pen,
                        rectangle); 
            }
        }

        ///  
        ///     DrawRoundedRectangle -
        ///     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) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawRoundedRectangle(
                        brush, 
                        pen,
                        rectangle,
                        radiusX,
                        radiusY); 
            }
        } 
 
        /// 
        ///     DrawRoundedRectangle - 
        ///     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. 
        ///  Optional AnimationClock for rectangle.  
        /// 
        ///     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] 
        /// 
        ///  Optional AnimationClock for radiusX.  
        /// 
        ///     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].
        ///  
        ///  Optional AnimationClock for radiusY. 
        public override void DrawRoundedRectangle( 
            Brush brush, 
            Pen pen,
            Rect rectangle, 
            AnimationClock rectangleAnimations,
            Double radiusX,
            AnimationClock radiusXAnimations,
            Double radiusY, 
            AnimationClock radiusYAnimations)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawRoundedRectangle( 
                    brush,
                    pen,
                    rectangle,
                    rectangleAnimations, 
                    radiusX,
                    radiusXAnimations, 
                    radiusY, 
                    radiusYAnimations);
            } 

        }

        ///  
        ///     DrawEllipse -
        ///     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) 
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawEllipse(
                        brush,
                        pen,
                        center, 
                        radiusX,
                        radiusY); 
            } 
        }
 
        /// 
        ///     DrawEllipse -
        ///     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. 
        ///  
        ///  Optional AnimationClock for center. 
        ///  
        ///     The radius in the X dimension of the ellipse.
        ///     The absolute value of the radius provided will be used.
        /// 
        ///  Optional AnimationClock for radiusX.  
        /// 
        ///     The radius in the Y dimension of the ellipse. 
        ///     The absolute value of the radius provided will be used. 
        /// 
        ///  Optional AnimationClock for radiusY.  
        public override void DrawEllipse(
            Brush brush,
            Pen pen,
            Point center, 
            AnimationClock centerAnimations,
            Double radiusX, 
            AnimationClock radiusXAnimations, 
            Double radiusY,
            AnimationClock radiusYAnimations) 
        {
            if (_effectContext != null)
            {
                _effectContext.Context.DrawEllipse( 
                    brush,
                    pen, 
                    center, 
                    centerAnimations,
                    radiusX, 
                    radiusXAnimations,
                    radiusY,
                    radiusYAnimations);
            } 

        } 
 
        /// 
        ///     DrawGeometry - 
        ///     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) 
        {
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawGeometry(
                        brush,
                        pen, 
                        geometry);
            } 
        } 

        ///  
        ///     DrawImage -
        ///     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) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawImage(
                        imageSource, 
                        rectangle);
            }
        }
 
        /// 
        ///     DrawImage - 
        ///     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.
        ///  
        ///  Optional AnimationClock for rectangle.  
        public override void DrawImage(
            ImageSource imageSource, 
            Rect rectangle,
            AnimationClock rectangleAnimations)
        {
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawImage( 
                        imageSource, 
                        rectangle,
                        rectangleAnimations); 
            }
        }

        ///  
        ///     DrawGlyphRun -
        ///     Draw a GlyphRun 
        ///  
        /// 
        ///     Foreground brush to draw the GlyphRun with. 
        /// 
        ///  The GlyphRun to draw.  
        public override void DrawGlyphRun(
            Brush foregroundBrush, 
            GlyphRun glyphRun)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.DrawGlyphRun( 
                        foregroundBrush,
                        glyphRun);
            }
        } 

        ///  
        ///     DrawDrawing - 
        ///     Draw a Drawing by appending a sub-Drawing to the current Drawing.
        ///  
        ///  The drawing to draw. 
        public override void DrawDrawing(
            Drawing drawing)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawDrawing(drawing); 
            }
        } 

        /// 
        ///     DrawVideo -
        ///     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 MediaClock will be fit.
        /// 
        public override void DrawVideo( 
            MediaPlayer player,
            Rect rectangle) 
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawVideo(
                    player,
                    rectangle);
            } 
        }
 
        ///  
        ///     DrawVideo -
        ///     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 MediaClock will be fit. 
        /// 
        ///  Optional AnimationClock for rectangle.  
        public override void DrawVideo(
            MediaPlayer player,
            Rect rectangle,
            AnimationClock rectangleAnimations) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.DrawVideo(
                    player, 
                    rectangle,
                    rectangleAnimations);
            }
        } 

        ///  
        ///     DrawScene3D - 
        ///     Draw a Scene3D (internal object encapsulating a 3D scene)
        ///  
        ///  The Scene3D to draw. 
        internal override void DrawScene3D(
            Scene3D scene3D)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.DrawScene3D(scene3D); 
            }
        } 

        /// 
        ///     PushGuidelineSet -
        ///     Push a set of guidelines which will apply to all drawing operations until the 
        ///     corresponding Pop.
        ///  
        ///  The GuidelineSet to push.  
        public override void PushGuidelineSet(
            GuidelineSet guidelines) 
        {
            if (_effectContext != null)
            {
                _effectContext.Context.PushGuidelineSet(guidelines); 
            }
 
            // Ensure the type stack 
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2);
            }

            _pushTypeStack.Push(PushType.GuidelineSet); 
        }
 
        ///  
        ///     PushGuidelineY1 -
        ///     Explicitly push one horizontal guideline. 
        /// 
        ///  The coordinate of leading guideline. 
        internal override void PushGuidelineY1(
            Double coordinate) 
        {
            if (_effectContext != null) 
            { 
                _effectContext.Context.PushGuidelineY1(coordinate);
            } 

            // Ensure the type stack
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2);
            } 
 
            _pushTypeStack.Push(PushType.GuidelineY1);
        } 

        /// 
        ///     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)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.PushGuidelineY2(leadingCoordinate, 
                                                       offsetToDrivenCoordinate);
            }

            // Ensure the type stack 
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2); 
            }
 
            _pushTypeStack.Push(PushType.GuidelineY2);
        }

        ///  
        /// Push an opacity mask
        ///  
        ///  
        /// The opacity mask
        ///  
        public override void PushOpacityMask(Brush brush)
        {
            if (_effectContext != null)
            { 
                _effectContext.Context.PushOpacityMask(brush);
            } 
            // Ensure the type stack 
            if (_pushTypeStack == null)
            { 
                _pushTypeStack = new Stack(2);
            }

            _pushTypeStack.Push(PushType.OpacityMask); 
        }
 
        ///  
        ///     PushClip -
        ///     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)
        { 
            if (_effectContext != null) 
            {
                _effectContext.Context.PushClip(clipGeometry); 
            }

            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2); 
            } 

            _pushTypeStack.Push(PushType.Clip); 
        }

        /// 
        ///     PushOpacity - 
        ///     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)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.PushOpacity(opacity); 
            }
 
            // Ensure the type stack
            if (_pushTypeStack == null)
            {
                _pushTypeStack = new Stack(2); 
            }
 
            _pushTypeStack.Push(PushType.Opacity); 
        }
 
        /// 
        ///     PushOpacity -
        ///     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. 
        /// 
        ///  Optional AnimationClock for opacity.  
        public override void PushOpacity(
            Double opacity,
            AnimationClock opacityAnimations)
        { 
            if (_effectContext != null)
            { 
                _effectContext.Context.PushOpacity( 
                        opacity,
                        opacityAnimations); 
            }

            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2); 
            } 

            _pushTypeStack.Push(PushType.Opacity); 
        }

        /// 
        ///     PushTransform - 
        ///     Push a Transform which will apply to all drawing operations until the corresponding
        ///     Pop. 
        ///  
        ///  The Transform to push. 
        public override void PushTransform( 
            Transform transform)
        {
            if (_effectContext != null)
            { 
                _effectContext.Context.PushTransform(transform);
            } 
 
            // Ensure the transform stack
            if (_transformStack == null) 
            {
                _transformStack = new Stack(2);
            }
 
            // Push the old transform.
            _transformStack.Push(_transform); 
 
            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2);
            }
 
            // Push the transform type
            _pushTypeStack.Push(PushType.Transform); 
 
            Matrix newValue = Matrix.Identity;
 
            // Retrieve the new transform as a matrix if it exists
            if ((transform != null) && !transform.IsIdentity)
            {
                // If the transform is degeneraate, we can skip all instructions until the 
                // corresponding Pop.
                newValue = transform.Value; 
            } 

            // Update the current transform 
            _transform = newValue * _transform;
        }

        ///  
        ///     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) 
        {
 
            // create new context 
            if (_effectContext == null)
            { 
                _effectContext = new BitmapEffectDrawingContextState(effect, effectInput);
            }
            else
            { 
                _effectContext.Context.PushEffect(effect, effectInput);
            } 
 
            // Ensure the type stack
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2);
            }
 
            _pushTypeStack.Push(PushType.BitmapEffect);
            _effectStackDepth++; 
        } 

        ///  
        /// Pop
        /// 
        public override void Pop(
            ) 
        {
            // We must have a type stack and it must not be empty. 
            Debug.Assert(_pushTypeStack != null); 
            Debug.Assert(_pushTypeStack.Count > 0);
 
            // Retrieve the PushType to figure out what what this Pop is.
            PushType pushType = _pushTypeStack.Pop();

            switch (pushType) 
            {
                case PushType.Transform: 
                    // We must have a Transform stack and it must not be empty. 
                    Debug.Assert(_transformStack != null);
                    Debug.Assert(_transformStack.Count > 0); 

                    // Restore the transform
                    _transform = _transformStack.Pop();
                    break; 
                case PushType.BitmapEffect:
 
                    Debug.Assert(_effectStackDepth > 0, "We should have pushed an effect first"); 
                    Debug.Assert(_effectContext != null, "We should have created a context");
 
                    _effectStackDepth--;

                    // render only if it is a toplevel effect
                    if (_effectStackDepth == 0) 
                    {
                        _effectContext.Context.Close(); 
                        Matrix worldTransform = _transform; 
                        BitmapSource effectImage = _effectContext.RenderBitmapEffect(ref worldTransform, _windowClip);
                        ImageDrawing drawing = new ImageDrawing(); 

                        if (effectImage != null)
                        {
                            drawing.ImageSource = effectImage; 
                            drawing.Rect = new Rect(0, 0, effectImage.Width, effectImage.Height);
                        } 
 
                        DrawingGroup group = new DrawingGroup();
                        group.Children.Add(drawing); 
                        group.Transform = new MatrixTransform(worldTransform);

                        BitmapEffectDrawing.Drawings.Add(group);
                        BitmapEffectDrawing.WorldTransforms.Add(new MatrixTransform(_transform)); 
                        _effectContext = null;
                    } 
 
                    break;
                default: 
                    // Ignore the rest
                    break;
            }
 
            if (_effectContext != null)
            { 
                _effectContext.Context.Pop(); 
            }
        } 

        internal BitmapEffectDrawing BitmapEffectDrawing
        {
            get 
            {
                if (_bitmapEffectDrawing == null) 
                { 
                    _bitmapEffectDrawing = new BitmapEffectDrawing();
                } 
                return _bitmapEffectDrawing;
            }
        }
 
        #region Private Fields
 
        private BitmapEffectDrawing _bitmapEffectDrawing; 

        // The current local->world Transform as a matrix. 
        private Matrix _transform;

        private Rect _windowClip = Rect.Empty;
 
        // The Type stack for our Push/Pop calls.  This tells whether a given Pop corresponds
        // to a Transform, Clip, etc. 
        private Stack _pushTypeStack; 

        // This stack contains the Matrices encountered during our walk. 
        // The current transform is stored in _transform and not in the Stack.
        private Stack _transformStack;

        // this contains the effect drawing context 
        private BitmapEffectDrawingContextState _effectContext;
        private long _effectStackDepth; 
 
        #endregion
    } 
}

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