BoundsDrawingContextWalker.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / BoundsDrawingContextWalker.cs / 1 / BoundsDrawingContextWalker.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: BoundsDrawingContextWalker.cs 
//
// Description: This file contains the implementation of BoundsDrawingContextWalker. 
//              This DrawingContextWalker is used to perform bounds calculations 
//              on renderdata.
// 
// History:
//  04/15/2004 : adsmith - Created it.
//
//--------------------------------------------------------------------------- 

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;
using System.Windows.Media.Media3D;
using System.Security;
using System.Security.Permissions; 
namespace System.Windows.Media
{ 
    ///  
    /// BoundsDrawingContextWalker - a DrawingContextWalker which will calculate the bounds
    /// of the contents of a render data. 
    /// 
    internal class BoundsDrawingContextWalker : 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, 
            Guidelines,
            BitmapEffect 
        } 

        ///  
        /// Constructor for BoundsDrawingContextWalker
        /// 
        public BoundsDrawingContextWalker()
        { 
            _bounds = Rect.Empty;
            _transform = Matrix.Identity; 
        } 

        public Rect Bounds 
        {
            get
            {
                return _bounds; 
            }
        } 
 
        #region Static Drawing Context Methods
 
        /// 
        ///     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 (Pen.ContributesToBounds(pen))
            { 
                // _bounds is always in "world" space 
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = LineGeometry.GetBoundsHelper( 
                    pen,
                    _transform, // world transform
                    point0,
                    point1, 
                    Matrix.Identity, // geometry transform
                    Geometry.StandardFlatteningTolerance, 
                    ToleranceType.Absolute 
                    );
 
                AddTransformedBounds(ref geometryBounds);
            }
        }
 
        /// 
        ///     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 ((brush != null) || Pen.ContributesToBounds(pen)) 
            { 
                // _bounds is always in "world" space
                // So, we need to transform the geometry to world to bound it 
                Rect geometryBounds = RectangleGeometry.GetBoundsHelper(
                    pen,
                    _transform, // world transform
                    rectangle, 
                    0.0,
                    0.0, 
                    Matrix.Identity, // geometry transform 
                    Geometry.StandardFlatteningTolerance,
                    ToleranceType.Absolute 
                    );

                AddTransformedBounds(ref geometryBounds);
            } 
        }
 
        ///  
        ///     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 ((brush != null) || Pen.ContributesToBounds(pen)) 
            {
                // _bounds is always in "world" space
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = RectangleGeometry.GetBoundsHelper( 
                    pen,
                    _transform, // world transform 
                    rectangle, 
                    radiusX,
                    radiusY, 
                    Matrix.Identity, // geometry transform
                    Geometry.StandardFlatteningTolerance,
                    ToleranceType.Absolute
                    ); 

                AddTransformedBounds(ref geometryBounds); 
            } 
        }
 
        /// 
        ///     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 ((brush != null) || Pen.ContributesToBounds(pen))
            { 
                // _bounds is always in "world" space 
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = EllipseGeometry.GetBoundsHelper( 
                    pen,
                    _transform, // world transform
                    center,
                    radiusX, 
                    radiusY,
                    Matrix.Identity, // geometry transform 
                    Geometry.StandardFlatteningTolerance, 
                    ToleranceType.Absolute
                    ); 

                AddTransformedBounds(ref geometryBounds);
            }
        } 

        ///  
        ///     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 ((geometry != null) && ((brush != null) || Pen.ContributesToBounds(pen))) 
            {
                // _bounds is always in "world" space 
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = geometry.GetBoundsInternal(pen, _transform);

                AddTransformedBounds(ref geometryBounds); 
            }
        } 
 
        /// 
        ///     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 BitmapSource to draw.  
        ///  
        ///     The Rect into which the BitmapSource will be fit.
        ///  
        public override void DrawImage(
            ImageSource imageSource,
            Rect rectangle)
        { 
            if (imageSource != null)
            { 
                AddBounds(ref 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 MediaPlayer will be fit.
        /// 
        public override void DrawVideo( 
            MediaPlayer video,
            Rect rectangle) 
        { 
            if (video != null)
            { 
                AddBounds(ref rectangle);
            }
        }
 
        /// 
        /// Draw a GlyphRun. 
        ///  
        /// Foreground brush to draw GlyphRun with. 
        ///  The GlyphRun to draw.  
        public override void DrawGlyphRun(Brush foregroundBrush, GlyphRun glyphRun)
        {
            if ((foregroundBrush != null) && (glyphRun != null))
            { 
                // The InkBoundingBox + the Origin produce the true InkBoundingBox.
                Rect rectangle = glyphRun.ComputeInkBoundingBox(); 
 
                if (!rectangle.IsEmpty)
                { 
                    rectangle.Offset((Vector)glyphRun.BaselineOrigin);
                    AddBounds(ref rectangle);
                }
            } 
        }
 
        ///  
        ///     PushOpacityMask -
        ///     Push an opacity mask, which will apply to all drawing primitives until the 
        ///     corresponding Pop call.
        /// 
        ///  Brush for opacity mask. 
        public override void PushOpacityMask( 
            Brush brush)
        { 
            // Push the opacity type 
            PushTypeStack(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 we have an old clip, push the old clip onto the stack.
            if (_haveClip)
            { 
                // Ensure the clip stack
                if (_clipStack == null) 
                { 
                    _clipStack = new Stack(2);
                } 

                _clipStack.Push(_clip);
            }
 
            // Push the clip type
            PushTypeStack(PushType.Clip); 
 
            if (clipGeometry != null)
            { 
                // Since _clip is a value type, we need to know whether we have a clip or not.
                // If not, we can assert that the initial value is present (Rect.Empty).
                // We should also now set the _haveClip flag.
                if (!_haveClip) 
                {
                    _haveClip = true; 
                    _clip = clipGeometry.GetBoundsInternal(null /* pen */, _transform); 
                }
                else 
                {
                    // update current clip
                    _clip.Intersect(clipGeometry.GetBoundsInternal(null /* pen */, _transform));
                } 
            }
        } 
 
        /// 
        ///     DrawScene3D - 
        ///     Draw a Scene3D (internal object encapsulating a 3D scene)
        /// 
        ///  The Scene3D to draw. 
        internal override void DrawScene3D( 
            Scene3D scene3D)
        { 
            // 
            // NTRAID#Longhorn-1456260-2006/01/10-milesc
            // This bounds calculation does not match unmanaged code 
            //

            if (scene3D != null)
            { 
                Rect bounds = scene3D.Viewport;
                AddBounds(ref bounds); 
            } 
        }
 
        /// 
        ///     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)
        {
            // Push the opacity type
            PushTypeStack(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)
        { 
            // Ensure the transform stack 
            if (_transformStack == null)
            { 
                _transformStack = new Stack(2);
            }

            // Push the old transform. 
            _transformStack.Push(_transform);
 
            // Push the transform type 
            PushTypeStack(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;
        } 

        ///  
        ///     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)
        { 
            // Push the guidelines type 
            PushTypeStack(PushType.Guidelines);
 
            // Nothing else to do. Guidelines are not used,
            // so we only need to register Push() type in order to treat
            // Pop() properly.
        } 

        ///  
        ///     PushGuidelineY1 - 
        ///     Explicitly push one horizontal guideline.
        ///  
        ///  The coordinate of leading guideline. 
        internal override void PushGuidelineY1(
            Double coordinate)
        { 
            // Push the guidelines type
            PushTypeStack(PushType.Guidelines); 
 
            // Nothing else to do. Guidelines are not used,
            // so we only need to register Push() type in order to treat 
            // Pop() properly.
        }

        ///  
        ///     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) 
        {
            // Push the guidelines type 
            PushTypeStack(PushType.Guidelines);

            // Nothing else to do. Guidelines are not used,
            // so we only need to register Push() type in order to treat 
            // Pop() properly.
        } 
 
        /// 
        ///     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)
        { 
            // Ensure the type stack
            PushTypeStack(PushType.BitmapEffect);

            // Ensure the effect stack 
            if (_effectDataStack == null)
            { 
                _effectDataStack = new Stack(); 
            }
 
            // Ensure the transform stack
            if (_transformStack == null)
            {
                _transformStack = new Stack(2); 
            }
 
            // Ensure the bounds stack 
            if (_boundsStack == null)
            { 
                _boundsStack = new Stack();
            }

            if (effectInput == null) 
            {
                effectInput = new BitmapEffectInput(); 
            } 

            _effectDataStack.Push(new BitmapEffectInputData(effect, effectInput)); 

            // save the current bounds and reset them
            _boundsStack.Push(_bounds);
            _bounds = Rect.Empty; 

            // save the current transform and reset it to identity. 
            _transformStack.Push(_transform); 
            _transform = Matrix.Identity;
        } 


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

                    // Restore the clip, if there's one to restore
                    if ((_clipStack != null) &&
                        (_clipStack.Count > 0)) 
                    {
                        _clip = _clipStack.Pop(); 
                    } 
                    else
                    { 
                        // If the _clipStack was empty or null, then we no longer have a clip.
                        _haveClip = false;
                    }
 
                    break;
                case PushType.BitmapEffect: 
                    // we must have an effect, transform and bound stacks 
                    // and they must not be empty
                    Debug.Assert(_effectDataStack != null); 
                    Debug.Assert(_effectDataStack.Count > 0);
                    Debug.Assert(_transformStack != null);
                    Debug.Assert(_transformStack.Count > 0);
                    Debug.Assert(_boundsStack != null); 
                    Debug.Assert(_boundsStack.Count > 0);
 
                    // pop the effect 
                    BitmapEffectInputData data = _effectDataStack.Pop();
 
                    // apply the effect to the bounds
                    Rect effectBounds = (data.BitmapEffect == null) ? _bounds :
                                            data.BitmapEffect.TransformRect(
                                                data.BitmapEffectInput, 
                                                _bounds,
                                                false /*fInverse*/); 
 
                    // pop the current transform
                    _transform = _transformStack.Pop(); 

                    // pop the current bounds
                    _bounds = _boundsStack.Pop();
 
                    // add the combined bounds between the pusheffect and pop
                    // instructions 
                    AddBounds(ref effectBounds); 
                    break;
                default: 
                    // Ignore the rest
                    break;
            }
        } 

        #endregion Static Drawing Context Methods 
 
        #region Private Methods
 
        /// 
        /// AddBounds - Unions the non-transformed bounds which are
        /// local to the current Drawing operation with the
        /// aggregate bounds of other Drawing operations encountered 
        /// during this walk.
        ///  
        ///  
        ///     In:  The bounds of the geometry to union in the coordinate
        ///          space of the current Drawing operations 
        ///     Out: The transformed and clipped bounds of the geometry
        ///          in the coordinate space of the top-level Drawing
        ///          operation.
        ///  
        private void AddBounds(ref Rect bounds)
        { 
            // _bounds is always in "world" space 
            // So, we need to transform the Rect to world to bound it
            if (!_transform.IsIdentity) 
            {
                MatrixUtil.TransformRect(ref bounds, ref _transform);
            }
 
            AddTransformedBounds(ref bounds);
        } 
 
        /// 
        /// AddTransformedBounds - Unions bounds which have been transformed 
        /// into the top-level Drawing operation with the aggregate bounds of
        /// other Drawing operations encountered during this walk.
        /// 
        ///  
        ///     In:  The bounds of the geometry to union in the coordinate
        ///          space of the current Drawing operations 
        ///     Out: The transformed and clipped bounds of the geometry 
        ///          in the coordinate space of the top-level Drawing
        ///          operation. 
        /// 
        private void AddTransformedBounds(ref Rect bounds)
        {
            if (DoubleUtil.RectHasNaN(bounds)) 
            {
                // We set the bounds to infinity if it has NaN 
                bounds.X = Double.NegativeInfinity; 
                bounds.Y = Double.NegativeInfinity;
                bounds.Width = Double.PositiveInfinity; 
                bounds.Height = Double.PositiveInfinity;
            }

            if (_haveClip) 
            {
                bounds.Intersect(_clip); 
            } 

            _bounds.Union(bounds); 
        }

        /// 
        /// Ensure the type stack exists, and store given push type there. 
        /// 
        /// the push type to store 
        private void PushTypeStack(PushType pushType) 
        {
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2);
            }
 
            _pushTypeStack.Push(pushType);
        } 
 
        /// 
        /// Ensure that the state is clear and is good for next use. 
        /// 
        internal void ClearState()
        {
            _boundsStack = null; 
            _clip = Rect.Empty;
            _bounds = Rect.Empty; 
            _haveClip = false; 
            _transform = new Matrix();
            _pushTypeStack = null; 
            _transformStack = null;
            _effectDataStack = null;
            _clipStack = null;
        } 

        #endregion Private Methods 
 
        // The accumulated bounds, in world space
        private Rect _bounds; 

        // This stack contains the bounds gathered during our walk.
        // The current bounds are stored in _bounds
        private Stack _boundsStack; 

        // The current clip in world space, if _haveClip is true.  Otherwise, this 
        // variable may hold random rects (stuff left over from previously pop'ed clipped) 
        private Rect _clip;
 
        // States whether or not we have a clip (because Rect isn't nullable).
        private bool _haveClip;

        // The current local->world Transform as a matrix. 
        private Matrix _transform;
 
        // 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 Matricies encountered during our walk.
        // The current transform is stored in _transform and not in the Stack.
        private Stack _transformStack; 

        private Stack _effectDataStack; 
 
        // This stack contains the clip rects encountered during our walk.
        // The current clip is stored in _clip and not in the Stack. 
        private Stack _clipStack;
    }
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// File: BoundsDrawingContextWalker.cs 
//
// Description: This file contains the implementation of BoundsDrawingContextWalker. 
//              This DrawingContextWalker is used to perform bounds calculations 
//              on renderdata.
// 
// History:
//  04/15/2004 : adsmith - Created it.
//
//--------------------------------------------------------------------------- 

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;
using System.Windows.Media.Media3D;
using System.Security;
using System.Security.Permissions; 
namespace System.Windows.Media
{ 
    ///  
    /// BoundsDrawingContextWalker - a DrawingContextWalker which will calculate the bounds
    /// of the contents of a render data. 
    /// 
    internal class BoundsDrawingContextWalker : 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, 
            Guidelines,
            BitmapEffect 
        } 

        ///  
        /// Constructor for BoundsDrawingContextWalker
        /// 
        public BoundsDrawingContextWalker()
        { 
            _bounds = Rect.Empty;
            _transform = Matrix.Identity; 
        } 

        public Rect Bounds 
        {
            get
            {
                return _bounds; 
            }
        } 
 
        #region Static Drawing Context Methods
 
        /// 
        ///     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 (Pen.ContributesToBounds(pen))
            { 
                // _bounds is always in "world" space 
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = LineGeometry.GetBoundsHelper( 
                    pen,
                    _transform, // world transform
                    point0,
                    point1, 
                    Matrix.Identity, // geometry transform
                    Geometry.StandardFlatteningTolerance, 
                    ToleranceType.Absolute 
                    );
 
                AddTransformedBounds(ref geometryBounds);
            }
        }
 
        /// 
        ///     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 ((brush != null) || Pen.ContributesToBounds(pen)) 
            { 
                // _bounds is always in "world" space
                // So, we need to transform the geometry to world to bound it 
                Rect geometryBounds = RectangleGeometry.GetBoundsHelper(
                    pen,
                    _transform, // world transform
                    rectangle, 
                    0.0,
                    0.0, 
                    Matrix.Identity, // geometry transform 
                    Geometry.StandardFlatteningTolerance,
                    ToleranceType.Absolute 
                    );

                AddTransformedBounds(ref geometryBounds);
            } 
        }
 
        ///  
        ///     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 ((brush != null) || Pen.ContributesToBounds(pen)) 
            {
                // _bounds is always in "world" space
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = RectangleGeometry.GetBoundsHelper( 
                    pen,
                    _transform, // world transform 
                    rectangle, 
                    radiusX,
                    radiusY, 
                    Matrix.Identity, // geometry transform
                    Geometry.StandardFlatteningTolerance,
                    ToleranceType.Absolute
                    ); 

                AddTransformedBounds(ref geometryBounds); 
            } 
        }
 
        /// 
        ///     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 ((brush != null) || Pen.ContributesToBounds(pen))
            { 
                // _bounds is always in "world" space 
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = EllipseGeometry.GetBoundsHelper( 
                    pen,
                    _transform, // world transform
                    center,
                    radiusX, 
                    radiusY,
                    Matrix.Identity, // geometry transform 
                    Geometry.StandardFlatteningTolerance, 
                    ToleranceType.Absolute
                    ); 

                AddTransformedBounds(ref geometryBounds);
            }
        } 

        ///  
        ///     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 ((geometry != null) && ((brush != null) || Pen.ContributesToBounds(pen))) 
            {
                // _bounds is always in "world" space 
                // So, we need to transform the geometry to world to bound it
                Rect geometryBounds = geometry.GetBoundsInternal(pen, _transform);

                AddTransformedBounds(ref geometryBounds); 
            }
        } 
 
        /// 
        ///     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 BitmapSource to draw.  
        ///  
        ///     The Rect into which the BitmapSource will be fit.
        ///  
        public override void DrawImage(
            ImageSource imageSource,
            Rect rectangle)
        { 
            if (imageSource != null)
            { 
                AddBounds(ref 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 MediaPlayer will be fit.
        /// 
        public override void DrawVideo( 
            MediaPlayer video,
            Rect rectangle) 
        { 
            if (video != null)
            { 
                AddBounds(ref rectangle);
            }
        }
 
        /// 
        /// Draw a GlyphRun. 
        ///  
        /// Foreground brush to draw GlyphRun with. 
        ///  The GlyphRun to draw.  
        public override void DrawGlyphRun(Brush foregroundBrush, GlyphRun glyphRun)
        {
            if ((foregroundBrush != null) && (glyphRun != null))
            { 
                // The InkBoundingBox + the Origin produce the true InkBoundingBox.
                Rect rectangle = glyphRun.ComputeInkBoundingBox(); 
 
                if (!rectangle.IsEmpty)
                { 
                    rectangle.Offset((Vector)glyphRun.BaselineOrigin);
                    AddBounds(ref rectangle);
                }
            } 
        }
 
        ///  
        ///     PushOpacityMask -
        ///     Push an opacity mask, which will apply to all drawing primitives until the 
        ///     corresponding Pop call.
        /// 
        ///  Brush for opacity mask. 
        public override void PushOpacityMask( 
            Brush brush)
        { 
            // Push the opacity type 
            PushTypeStack(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 we have an old clip, push the old clip onto the stack.
            if (_haveClip)
            { 
                // Ensure the clip stack
                if (_clipStack == null) 
                { 
                    _clipStack = new Stack(2);
                } 

                _clipStack.Push(_clip);
            }
 
            // Push the clip type
            PushTypeStack(PushType.Clip); 
 
            if (clipGeometry != null)
            { 
                // Since _clip is a value type, we need to know whether we have a clip or not.
                // If not, we can assert that the initial value is present (Rect.Empty).
                // We should also now set the _haveClip flag.
                if (!_haveClip) 
                {
                    _haveClip = true; 
                    _clip = clipGeometry.GetBoundsInternal(null /* pen */, _transform); 
                }
                else 
                {
                    // update current clip
                    _clip.Intersect(clipGeometry.GetBoundsInternal(null /* pen */, _transform));
                } 
            }
        } 
 
        /// 
        ///     DrawScene3D - 
        ///     Draw a Scene3D (internal object encapsulating a 3D scene)
        /// 
        ///  The Scene3D to draw. 
        internal override void DrawScene3D( 
            Scene3D scene3D)
        { 
            // 
            // NTRAID#Longhorn-1456260-2006/01/10-milesc
            // This bounds calculation does not match unmanaged code 
            //

            if (scene3D != null)
            { 
                Rect bounds = scene3D.Viewport;
                AddBounds(ref bounds); 
            } 
        }
 
        /// 
        ///     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)
        {
            // Push the opacity type
            PushTypeStack(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)
        { 
            // Ensure the transform stack 
            if (_transformStack == null)
            { 
                _transformStack = new Stack(2);
            }

            // Push the old transform. 
            _transformStack.Push(_transform);
 
            // Push the transform type 
            PushTypeStack(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;
        } 

        ///  
        ///     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)
        { 
            // Push the guidelines type 
            PushTypeStack(PushType.Guidelines);
 
            // Nothing else to do. Guidelines are not used,
            // so we only need to register Push() type in order to treat
            // Pop() properly.
        } 

        ///  
        ///     PushGuidelineY1 - 
        ///     Explicitly push one horizontal guideline.
        ///  
        ///  The coordinate of leading guideline. 
        internal override void PushGuidelineY1(
            Double coordinate)
        { 
            // Push the guidelines type
            PushTypeStack(PushType.Guidelines); 
 
            // Nothing else to do. Guidelines are not used,
            // so we only need to register Push() type in order to treat 
            // Pop() properly.
        }

        ///  
        ///     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) 
        {
            // Push the guidelines type 
            PushTypeStack(PushType.Guidelines);

            // Nothing else to do. Guidelines are not used,
            // so we only need to register Push() type in order to treat 
            // Pop() properly.
        } 
 
        /// 
        ///     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)
        { 
            // Ensure the type stack
            PushTypeStack(PushType.BitmapEffect);

            // Ensure the effect stack 
            if (_effectDataStack == null)
            { 
                _effectDataStack = new Stack(); 
            }
 
            // Ensure the transform stack
            if (_transformStack == null)
            {
                _transformStack = new Stack(2); 
            }
 
            // Ensure the bounds stack 
            if (_boundsStack == null)
            { 
                _boundsStack = new Stack();
            }

            if (effectInput == null) 
            {
                effectInput = new BitmapEffectInput(); 
            } 

            _effectDataStack.Push(new BitmapEffectInputData(effect, effectInput)); 

            // save the current bounds and reset them
            _boundsStack.Push(_bounds);
            _bounds = Rect.Empty; 

            // save the current transform and reset it to identity. 
            _transformStack.Push(_transform); 
            _transform = Matrix.Identity;
        } 


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

                    // Restore the clip, if there's one to restore
                    if ((_clipStack != null) &&
                        (_clipStack.Count > 0)) 
                    {
                        _clip = _clipStack.Pop(); 
                    } 
                    else
                    { 
                        // If the _clipStack was empty or null, then we no longer have a clip.
                        _haveClip = false;
                    }
 
                    break;
                case PushType.BitmapEffect: 
                    // we must have an effect, transform and bound stacks 
                    // and they must not be empty
                    Debug.Assert(_effectDataStack != null); 
                    Debug.Assert(_effectDataStack.Count > 0);
                    Debug.Assert(_transformStack != null);
                    Debug.Assert(_transformStack.Count > 0);
                    Debug.Assert(_boundsStack != null); 
                    Debug.Assert(_boundsStack.Count > 0);
 
                    // pop the effect 
                    BitmapEffectInputData data = _effectDataStack.Pop();
 
                    // apply the effect to the bounds
                    Rect effectBounds = (data.BitmapEffect == null) ? _bounds :
                                            data.BitmapEffect.TransformRect(
                                                data.BitmapEffectInput, 
                                                _bounds,
                                                false /*fInverse*/); 
 
                    // pop the current transform
                    _transform = _transformStack.Pop(); 

                    // pop the current bounds
                    _bounds = _boundsStack.Pop();
 
                    // add the combined bounds between the pusheffect and pop
                    // instructions 
                    AddBounds(ref effectBounds); 
                    break;
                default: 
                    // Ignore the rest
                    break;
            }
        } 

        #endregion Static Drawing Context Methods 
 
        #region Private Methods
 
        /// 
        /// AddBounds - Unions the non-transformed bounds which are
        /// local to the current Drawing operation with the
        /// aggregate bounds of other Drawing operations encountered 
        /// during this walk.
        ///  
        ///  
        ///     In:  The bounds of the geometry to union in the coordinate
        ///          space of the current Drawing operations 
        ///     Out: The transformed and clipped bounds of the geometry
        ///          in the coordinate space of the top-level Drawing
        ///          operation.
        ///  
        private void AddBounds(ref Rect bounds)
        { 
            // _bounds is always in "world" space 
            // So, we need to transform the Rect to world to bound it
            if (!_transform.IsIdentity) 
            {
                MatrixUtil.TransformRect(ref bounds, ref _transform);
            }
 
            AddTransformedBounds(ref bounds);
        } 
 
        /// 
        /// AddTransformedBounds - Unions bounds which have been transformed 
        /// into the top-level Drawing operation with the aggregate bounds of
        /// other Drawing operations encountered during this walk.
        /// 
        ///  
        ///     In:  The bounds of the geometry to union in the coordinate
        ///          space of the current Drawing operations 
        ///     Out: The transformed and clipped bounds of the geometry 
        ///          in the coordinate space of the top-level Drawing
        ///          operation. 
        /// 
        private void AddTransformedBounds(ref Rect bounds)
        {
            if (DoubleUtil.RectHasNaN(bounds)) 
            {
                // We set the bounds to infinity if it has NaN 
                bounds.X = Double.NegativeInfinity; 
                bounds.Y = Double.NegativeInfinity;
                bounds.Width = Double.PositiveInfinity; 
                bounds.Height = Double.PositiveInfinity;
            }

            if (_haveClip) 
            {
                bounds.Intersect(_clip); 
            } 

            _bounds.Union(bounds); 
        }

        /// 
        /// Ensure the type stack exists, and store given push type there. 
        /// 
        /// the push type to store 
        private void PushTypeStack(PushType pushType) 
        {
            if (_pushTypeStack == null) 
            {
                _pushTypeStack = new Stack(2);
            }
 
            _pushTypeStack.Push(pushType);
        } 
 
        /// 
        /// Ensure that the state is clear and is good for next use. 
        /// 
        internal void ClearState()
        {
            _boundsStack = null; 
            _clip = Rect.Empty;
            _bounds = Rect.Empty; 
            _haveClip = false; 
            _transform = new Matrix();
            _pushTypeStack = null; 
            _transformStack = null;
            _effectDataStack = null;
            _clipStack = null;
        } 

        #endregion Private Methods 
 
        // The accumulated bounds, in world space
        private Rect _bounds; 

        // This stack contains the bounds gathered during our walk.
        // The current bounds are stored in _bounds
        private Stack _boundsStack; 

        // The current clip in world space, if _haveClip is true.  Otherwise, this 
        // variable may hold random rects (stuff left over from previously pop'ed clipped) 
        private Rect _clip;
 
        // States whether or not we have a clip (because Rect isn't nullable).
        private bool _haveClip;

        // The current local->world Transform as a matrix. 
        private Matrix _transform;
 
        // 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 Matricies encountered during our walk.
        // The current transform is stored in _transform and not in the Stack.
        private Stack _transformStack; 

        private Stack _effectDataStack; 
 
        // This stack contains the clip rects encountered during our walk.
        // The current clip is stored in _clip and not in the Stack. 
        private Stack _clipStack;
    }
}
 

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