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

                            //---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: Implementation of the class Geometry 
//
// History: 
// 
//---------------------------------------------------------------------------
 
using System;
using MS.Internal;
using MS.Win32.PresentationCore;
using System.ComponentModel; 
using System.ComponentModel.Design.Serialization;
using System.Diagnostics; 
using System.Reflection; 
using System.Collections;
using System.Globalization; 
using System.Security;
using System.Windows.Media;
using System.Windows.Media.Composition;
using System.Windows; 
using System.Text.RegularExpressions;
using System.Windows.Media.Animation; 
using System.Runtime.InteropServices; 
using System.Windows.Markup;
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;

namespace System.Windows.Media
{ 
    #region Geometry
    ///  
    /// This is the base class for all Geometry classes.  A geometry has bounds, 
    /// can be used to clip, fill or stroke.
    ///  
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
    public abstract partial class Geometry : Animatable, DUCE.IResource
    {
        #region Constructors 

        internal Geometry() 
        { 
        }
 
        #endregion

        #region Public properties
        ///  
        ///     Singleton empty model.
        ///  
        public static Geometry Empty 
        {
            get 
            {
                return s_empty;
            }
        } 

        ///  
        /// Gets the bounds of this Geometry as an axis-aligned bounding box 
        /// 
        public virtual Rect Bounds 
        {
            get
            {
                return PathGeometry.GetPathBounds( 
                    GetPathGeometryData(),
                    null,   // pen 
                    Matrix.Identity, 
                    StandardFlatteningTolerance,
                    ToleranceType.Absolute, 
                    false); // Do not skip non-fillable figures
            }
        }
 
        /// 
        /// Standard error tolerance (0.25) used for polygonal approximation of curved segments 
        ///  
        public static double StandardFlatteningTolerance
        { 
            get
            {
                return c_tolerance;
            } 
        }
 
        #endregion Public properties 

        #region GetRenderBounds 
        /// 
        /// Returns the axis-aligned bounding rectangle when stroked with a pen.
        /// 
        /// The pen 
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute 
        public virtual Rect GetRenderBounds(Pen pen, double tolerance, ToleranceType type) 
        {
            ReadPreamble(); 

            Matrix matrix = Matrix.Identity;
            return GetBoundsInternal(pen, matrix, tolerance, type);
        } 

        ///  
        /// Returns the axis-aligned bounding rectangle when stroked with a pen. 
        /// 
        /// The pen 
        public Rect GetRenderBounds(Pen pen)
        {
            ReadPreamble();
 
            Matrix matrix = Matrix.Identity;
            return GetBoundsInternal(pen, matrix, StandardFlatteningTolerance, ToleranceType.Absolute); 
        } 

        #endregion GetRenderBounds 


        #region Internal Methods
 
        /// 
        ///     Used to optimize Visual.ChangeVisualClip. This is not meant 
        ///     to be used generically since not all geometries implement 
        ///     the method (currently only RectangleGeometry is implemented).
        ///  
        internal virtual bool AreClose(Geometry geometry)
        {
           return false;
        } 

        ///  
        /// Returns the axis-aligned bounding rectangle when stroked with a pen, after applying 
        /// the supplied transform (if non-null).
        ///  
        internal virtual Rect GetBoundsInternal(Pen pen, Matrix matrix, double tolerance, ToleranceType type)
        {
            if (IsObviouslyEmpty())
            { 
                return Rect.Empty;
            } 
 
            PathGeometryData pathData = GetPathGeometryData();
 
            return PathGeometry.GetPathBounds(
                pathData,
                pen,
                matrix, 
                tolerance,
                type, 
                true); /* skip hollows */ 
        }
 
        /// 
        /// Returns the axis-aligned bounding rectangle when stroked with a pen, after applying
        /// the supplied transform (if non-null).
        ///  
        internal Rect GetBoundsInternal(Pen pen, Matrix matrix)
        { 
            return GetBoundsInternal(pen, matrix, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 

        /// 
        /// Critical - it does an elevation in calling MilUtility_PolygonBounds and is unsafe
        ///  
        [SecurityCritical]
        internal unsafe static Rect GetBoundsHelper( 
            Pen pen, 
            Matrix *pWorldMatrix,
            Point* pPoints, 
            byte *pTypes,
            uint pointCount,
            uint segmentCount,
            Matrix *pGeometryMatrix, 
            double tolerance,
            ToleranceType type, 
            bool fSkipHollows) 
        {
            MIL_PEN_DATA penData; 
            double[] dashArray = null;

            // If the pen contributes to the bounds, populate the CMD struct
            bool fPenContributesToBounds = Pen.ContributesToBounds(pen); 

            if (fPenContributesToBounds) 
            { 
                pen.GetBasicPenData(&penData, out dashArray);
            } 

            MilMatrix3x2D geometryMatrix;
            if (pGeometryMatrix != null)
            { 
                geometryMatrix = CompositionResourceManager.MatrixToMilMatrix3x2D(ref (*pGeometryMatrix));
            } 
 
            Debug.Assert(pWorldMatrix != null);
            MilMatrix3x2D worldMatrix = 
                CompositionResourceManager.MatrixToMilMatrix3x2D(ref (*pWorldMatrix));

            Rect bounds;
 
            fixed (double *pDashArray = dashArray)
            { 
                int hr = MilCoreApi.MilUtility_PolygonBounds( 
                    &worldMatrix,
                    (fPenContributesToBounds) ? &penData : null, 
                    (dashArray == null) ? null : pDashArray,
                    pPoints,
                    pTypes,
                    pointCount, 
                    segmentCount,
                    (pGeometryMatrix == null) ? null : &geometryMatrix, 
                    tolerance, 
                    type == ToleranceType.Relative,
                    fSkipHollows, 
                    &bounds
                );

                if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                {
                    // When we encounter NaNs in the renderer, we absorb the error and draw 
                    // nothing. To be consistent, we report that the geometry has empty bounds. 
                    bounds = Rect.Empty;
                } 
                else
                {
                    HRESULT.Check(hr);
                } 
            }
 
            return bounds; 
        }
 
        internal virtual void TransformPropertyChangedHook(DependencyPropertyChangedEventArgs e)
        {
            // Do nothing here -- Overriden by PathGeometry to clear cached bounds.
        } 

        internal Geometry GetTransformedCopy(Transform transform) 
        { 
            Geometry copy = Clone();
            Transform internalTransform = Transform; 

            if (transform != null && !transform.IsIdentity)
            {
                if (internalTransform == null || internalTransform.IsIdentity) 
                {
                    copy.Transform = transform; 
                } 
                else
                { 
                    copy.Transform = new MatrixTransform(internalTransform.Value * transform.Value);
                }
            }
 
            return copy;
        } 
 
        #endregion Internal Methods
 
        /// 
        /// ShouldSerializeTransform - this is called by the serializer to determine whether or not to
        /// serialize the Transform property.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeTransform() 
        { 
            Transform transform = Transform;
            return transform != null && !(transform.IsIdentity); 
        }

        #region Public Methods
 
        /// 
        /// Gets the area of this geometry 
        /// The computational error tolerance 
        /// The way the error tolerance will be interpreted - relative or absolute
        ///  
        ///
        /// Critical as this calls a method that elevates (MilUtility_GeometryGetArea)
        /// TreatAsSafe - net effect of this is to calculate the area of a geometry, so it's considered safe.
        /// 
        [SecurityCritical]
        public virtual double GetArea(double tolerance, ToleranceType type) 
        { 
            ReadPreamble();
 
            if (IsObviouslyEmpty())
            {
                return 0;
            } 

            PathGeometryData pathData = GetPathGeometryData(); 
 
            if (pathData.IsEmpty())
            { 
                return 0;
            }

            double area; 

            unsafe 
            { 
                // Call the core method on the path data
                fixed (byte* pbPathData = pathData.SerializedData) 
                {
                    Debug.Assert(pbPathData != (byte*)0);

                    int hr = MilCoreApi.MilUtility_GeometryGetArea( 
                        pathData.FillRule,
                        pbPathData, 
                        pathData.Size, 
                        &pathData.Matrix,
                        tolerance, 
                        type == ToleranceType.Relative,
                        &area);

                    if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                    {
                        // When we encounter NaNs in the renderer, we absorb the error and draw 
                        // nothing. To be consistent, we report that the geometry has 0 area. 
                        area = 0.0;
                    } 
                    else
                    {
                        HRESULT.Check(hr);
                    } 
                }
            } 
 
            return area;
        } 

        /// 
        /// Gets the area of this geometry
        ///  
        public double GetArea()
        { 
            return GetArea(StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 
        /// 
        /// Returns true if this geometry is empty
        /// 
        public abstract bool IsEmpty(); 

        ///  
        /// Returns true if this geometry may have curved segments 
        /// 
        public abstract bool MayHaveCurves(); 

        #endregion Public Methods

        #region Hit Testing 
        /// 
        /// Returns true if point is inside the fill region defined by this geometry. 
        ///  
        /// The point tested for containment
        /// Acceptable margin of error in distance computation 
        /// The way the error tolerance will be interpreted - relative or absolute
        public bool FillContains(Point hitPoint, double tolerance, ToleranceType type)
        {
            return ContainsInternal(null, hitPoint, tolerance, type); 
        }
 
        ///  
        /// Returns true if point is inside the fill region defined by this geometry.
        ///  
        /// The point tested for containment
        public bool FillContains(Point hitPoint)
        {
            return ContainsInternal(null, hitPoint, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 
        ///  
        /// Returns true if point is inside the stroke of a pen on this geometry.
        ///  
        /// The pen used to define the stroke
        /// The point tested for containment
        /// Acceptable margin of error in distance computation
        /// The way the error tolerance will be interpreted - relative or absolute 
        public bool StrokeContains(Pen pen, Point hitPoint, double tolerance, ToleranceType type)
        { 
            if (pen == null) 
            {
                return false; 
            }

            return ContainsInternal(pen, hitPoint, tolerance, type);
        } 

        ///  
        /// Returns true if point is inside the stroke of a pen on this geometry. 
        /// 
        /// The pen used to define the stroke 
        /// The point tested for containment
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute
        ///  
        /// Critical - as this does an elevation in calling MilUtility_PathGeometryHitTest.
        /// TreatAsSafe - as this doesn't expose anything sensitive. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal virtual bool ContainsInternal(Pen pen, Point hitPoint, double tolerance, ToleranceType type) 
        {
            if (IsObviouslyEmpty())
            {
                return false; 
            }
 
            PathGeometryData pathData = GetPathGeometryData(); 

            if (pathData.IsEmpty()) 
            {
                return false;
            }
 
            bool contains = false;
 
            unsafe 
            {
                MIL_PEN_DATA penData; 
                double[] dashArray = null;

                // If we have a pen, populate the CMD struct
                if (pen != null) 
                {
                    pen.GetBasicPenData(&penData, out dashArray); 
                } 

                fixed (byte* pbPathData = pathData.SerializedData) 
                {
                    Debug.Assert(pbPathData != (byte*)0);

                    fixed (double * dashArrayFixed = dashArray) 
                    {
                        int hr = MilCoreApi.MilUtility_PathGeometryHitTest( 
                                &pathData.Matrix, 
                                (pen == null) ? null : &penData,
                                dashArrayFixed, 
                                pathData.FillRule,
                                pbPathData,
                                pathData.Size,
                                tolerance, 
                                type == ToleranceType.Relative,
                                &hitPoint, 
                                out contains); 

                        if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                        {
                            // When we encounter NaNs in the renderer, we absorb the error and draw
                            // nothing. To be consistent, we report that the geometry is never hittable.
                            contains = false; 
                        }
                        else 
                        { 
                            HRESULT.Check(hr);
                        } 
                    }
                }
            }
 
            return contains;
        } 
 
        /// 
        /// Helper method to be used by derived implementations of ContainsInternal. 
        /// 
        /// 
        /// Critical - Accepts pointers, does an elevation in calling MilUtility_PolygonHitTest.
        ///  
        [SecurityCritical]
        internal unsafe bool ContainsInternal(Pen pen, Point hitPoint, double tolerance, ToleranceType type, 
                                                Point *pPoints, uint pointCount, byte *pTypes, uint typeCount) 
        {
            bool contains = false; 

            MilMatrix3x2D matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform);

            MIL_PEN_DATA penData; 
            double[] dashArray = null;
 
            if (pen != null) 
            {
                pen.GetBasicPenData(&penData, out dashArray); 
            }

            fixed (double *dashArrayFixed = dashArray)
            { 
                int hr = MilCoreApi.MilUtility_PolygonHitTest(
                        &matrix, 
                        (pen == null) ? null : &penData, 
                        dashArrayFixed,
                        pPoints, 
                        pTypes,
                        pointCount,
                        typeCount,
                        tolerance, 
                        type == ToleranceType.Relative,
                        &hitPoint, 
                        out contains); 

                if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                {
                    // When we encounter NaNs in the renderer, we absorb the error and draw
                    // nothing. To be consistent, we report that the geometry is never hittable.
                    contains = false; 
                }
                else 
                { 
                    HRESULT.Check(hr);
                } 
            }

            return contains;
        } 

        ///  
        /// Returns true if point is inside the stroke of a pen on this geometry. 
        /// 
        /// The pen used to define the stroke 
        /// The point tested for containment
        public bool StrokeContains(Pen pen, Point hitPoint)
        {
            return StrokeContains(pen, hitPoint, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 
        ///  
        /// Returns true if a given geometry is contained inside this geometry.
        ///  
        /// The geometry tested for containment
        /// Acceptable margin of error in distance computation
        /// The way the error tolerance will be interpreted - relative or absolute
        public bool FillContains(Geometry geometry, double tolerance, ToleranceType type) 
        {
            IntersectionDetail detail = FillContainsWithDetail(geometry, tolerance, type); 
 
            return (detail == IntersectionDetail.FullyContains);
        } 

        /// 
        /// Returns true if a given geometry is contained inside this geometry.
        ///  
        /// The geometry tested for containment
        public bool FillContains(Geometry geometry) 
        { 
            return FillContains(geometry, StandardFlatteningTolerance, ToleranceType.Absolute);
        } 

        /// 
        /// Returns true if a given geometry is inside this geometry.
        /// The geometry to test for containment in this Geometry 
        /// Acceptable margin of error in distance computation
        /// The way the error tolerance will be interpreted - relative or absolute 
        ///  
        public virtual IntersectionDetail FillContainsWithDetail(Geometry geometry, double tolerance, ToleranceType type)
        { 
            ReadPreamble();

            if (IsObviouslyEmpty() || geometry == null || geometry.IsObviouslyEmpty())
            { 
                return IntersectionDetail.Empty;
            } 
 
            return PathGeometry.HitTestWithPathGeometry(this, geometry, tolerance, type);
        } 


        /// 
        /// Returns if geometry is inside this geometry. 
        /// The geometry to test for containment in this Geometry
        ///  
        public IntersectionDetail FillContainsWithDetail(Geometry geometry) 
        {
            return FillContainsWithDetail(geometry, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }

        /// 
        /// Returns if a given geometry is inside the stroke defined by a given pen on this geometry. 
        /// The pen
        /// The geometry to test for containment in this Geometry 
        /// Acceptable margin of error in distance computation 
        /// The way the error tolerance will be interpreted - relative or absolute
        ///  
        public IntersectionDetail StrokeContainsWithDetail(Pen pen, Geometry geometry, double tolerance, ToleranceType type)
        {
            if (IsObviouslyEmpty() || geometry == null || geometry.IsObviouslyEmpty() || pen == null)
            { 
                return IntersectionDetail.Empty;
            } 
 
            PathGeometry pathGeometry1 = GetWidenedPathGeometry(pen);
 
            return PathGeometry.HitTestWithPathGeometry(pathGeometry1, geometry, tolerance, type);
        }

        ///  
        /// Returns if a given geometry is inside the stroke defined by a given pen on this geometry.
        /// The pen 
        /// The geometry to test for containment in this Geometry 
        /// 
        public IntersectionDetail StrokeContainsWithDetail(Pen pen, Geometry geometry) 
        {
            return StrokeContainsWithDetail(pen, geometry, StandardFlatteningTolerance, ToleranceType.Absolute);
        }
 
        #endregion
 
        #region Geometric Flatten 

        ///  
        /// Approximate this geometry with a polygonal PathGeometry
        /// 
        /// The approximation error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute 
        /// Returns the polygonal approximation as a PathGeometry.
        /// 
        ///     Critical - calls code that performs an elevation. 
        ///     PublicOK - net effect of this code is to create an "flattened" shape from the current one.
        ///                          to "flatten" means to approximate with polygons. 
        ///                             ( in effect creating a different flavor of this shape from this one).
        ///                          Considered safe.
        ///
        [SecurityCritical] 
        public virtual PathGeometry GetFlattenedPathGeometry(double tolerance, ToleranceType type)
        { 
            ReadPreamble(); 

            if (IsObviouslyEmpty()) 
            {
                return new PathGeometry();
            }
 
            PathGeometryData pathData = GetPathGeometryData();
 
            if (pathData.IsEmpty()) 
            {
                return new PathGeometry(); 
            }

            PathGeometry resultGeometry = null;
 
            unsafe
            { 
                fixed (byte *pbPathData = pathData.SerializedData) 
                {
                    Debug.Assert(pbPathData != (byte*)0); 

                    FillRule fillRule = FillRule.Nonzero;

                    PathGeometry.FigureList list = new PathGeometry.FigureList(); 

                    int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryFlatten( 
                        &pathData.Matrix, 
                        pathData.FillRule,
                        pbPathData, 
                        pathData.Size,
                        tolerance,
                        type == ToleranceType.Relative,
                        new PathGeometry.AddFigureToListDelegate(list.AddFigureToList), 
                        out fillRule);
 
                    if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                    {
                        // When we encounter NaNs in the renderer, we absorb the error and draw 
                        // nothing. To be consistent, we return an empty geometry.
                        resultGeometry = new PathGeometry();
                    }
                    else 
                    {
                        HRESULT.Check(hr); 
 
                        resultGeometry = new PathGeometry(list.Figures, fillRule, null);
                    } 
                }

                return resultGeometry;
            } 
        }
 
        ///  
        /// Approximate this geometry with a polygonal PathGeometry
        ///  
        /// Returns the polygonal approximation as a PathGeometry.
        public PathGeometry GetFlattenedPathGeometry()
        {
            // Use the default tolerance interpreted as absolute 
            return GetFlattenedPathGeometry(StandardFlatteningTolerance, ToleranceType.Absolute);
        } 
 
        #endregion Flatten
 
        #region Geometric Widen

        /// 
        /// Create the contour of the stroke defined by given pen when it draws this path 
        /// 
        /// The pen used for stroking this path 
        /// The computational error tolerance 
        /// The way the error tolerance will be interpreted - relative or absolute
        /// Returns the contour as a PathGeometry. 
        ///
        /// Critical as this calls a method that elevates ( SUC on PathGeometryWiden).
        /// PublicOK - net effect of this is to create a new PathGeometry "widened" with a new pen.
        ///                      To "widen" a path is what we do internally when we draw a path with a pen: we generate the contour of the stroke and then fill it. 
        ///                         The exposed method returns that contour as a PathGeometry.
        ///                         In effect we're creating a different flavor of the current shape from this one. 
        /// 
        ///                      Considered safe.
        /// 
        [SecurityCritical]
        public virtual PathGeometry GetWidenedPathGeometry(Pen pen, double tolerance, ToleranceType type)
        {
            ReadPreamble(); 

            if (pen == null) 
            { 
                throw new System.ArgumentNullException("pen");
            } 

            if (IsObviouslyEmpty())
            {
                return new PathGeometry(); 
            }
 
            PathGeometryData pathData = GetPathGeometryData(); 

            if (pathData.IsEmpty()) 
            {
                return new PathGeometry();
            }
 
            PathGeometry resultGeometry = null;
 
            unsafe 
            {
                MIL_PEN_DATA penData; 
                double[] dashArray = null;

                pen.GetBasicPenData(&penData, out dashArray);
 
                fixed (byte *pbPathData = pathData.SerializedData)
                { 
                    Debug.Assert(pbPathData != (byte*)0); 

                    FillRule fillRule = FillRule.Nonzero; 

                    PathGeometry.FigureList list = new PathGeometry.FigureList();

                    // The handle to the pDashArray, if we have one. 
                    // Since the dash array is optional, we may not need to Free it.
                    GCHandle handle = new GCHandle(); 
 
                    // Pin the pDashArray, if we have one.
                    if (dashArray != null) 
                    {
                        handle = GCHandle.Alloc(dashArray, GCHandleType.Pinned);
                    }
 
                    try
                    { 
                        int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryWiden( 
                            &penData,
                            (dashArray == null) ? null : (double*)handle.AddrOfPinnedObject(), 
                            &pathData.Matrix,
                            pathData.FillRule,
                            pbPathData,
                            pathData.Size, 
                            tolerance,
                            type == ToleranceType.Relative, 
                            new PathGeometry.AddFigureToListDelegate(list.AddFigureToList), 
                            out fillRule);
 
                        if (hr == (int)MILErrors.WGXERR_BADNUMBER)
                        {
                            // When we encounter NaNs in the renderer, we absorb the error and draw
                            // nothing. To be consistent, we return an empty geometry. 
                            resultGeometry = new PathGeometry();
                        } 
                        else 
                        {
                            HRESULT.Check(hr); 

                            resultGeometry = new PathGeometry(list.Figures, fillRule, null);
                        }
                    } 
                    finally
                    { 
                        if (handle.IsAllocated) 
                        {
                            handle.Free(); 
                        }
                    }

                } 

                return resultGeometry; 
            } 
        }
 
        /// 
        /// Create the contour of the stroke defined by given pen when it draws this path
        /// 
        /// The pen used for stroking this path 
        /// Returns the contour as a PathGeometry.
        public PathGeometry GetWidenedPathGeometry(Pen pen) 
        { 
            // Use the default tolerance interpreted as absolute
            return GetWidenedPathGeometry(pen, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }

        #endregion Widen
 
        #region Combine
 
        ///  
        /// Returns the result of a Boolean combination of two Geometry objects.
        ///  
        /// The first Geometry object
        /// The second Geometry object
        /// The mode in which the objects will be combined
        /// A transformation to apply to the result, or null 
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute 
        public static PathGeometry Combine( 
            Geometry geometry1,
            Geometry geometry2, 
            GeometryCombineMode mode,
            Transform transform,
            double tolerance,
            ToleranceType type) 
        {
            return PathGeometry.InternalCombine(geometry1, geometry2, mode, transform, tolerance, type); 
        } 

        ///  
        /// Returns the result of a Boolean combination of two Geometry objects.
        /// 
        /// The first Geometry object
        /// The second Geometry object 
        /// The mode in which the objects will be combined
        /// A transformation to apply to the result, or null 
        public static PathGeometry Combine( 
            Geometry geometry1,
            Geometry geometry2, 
            GeometryCombineMode mode,
            Transform transform)
        {
            return PathGeometry.InternalCombine( 
                geometry1,
                geometry2, 
                mode, 
                transform,
                Geometry.StandardFlatteningTolerance, 
                ToleranceType.Absolute);
        }

        #endregion Combine 

        #region Outline 
 
        /// 
        /// Get a simplified contour of the filled region of this PathGeometry 
        /// 
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute
        /// Returns an equivalent geometry, properly oriented with no self-intersections. 
        /// 
        /// Critical - as this calls GetGlyphs() which is critical. 
        /// Safe - as this doesn't expose font information but just gives out a Geometry. 
        /// 
        [SecurityCritical] 
        public virtual PathGeometry GetOutlinedPathGeometry(double tolerance, ToleranceType type)
        {
            ReadPreamble();
 
            if (IsObviouslyEmpty())
            { 
                return new PathGeometry(); 
            }
 
            PathGeometryData pathData = GetPathGeometryData();

            if (pathData.IsEmpty())
            { 
                return new PathGeometry();
            } 
 
            PathGeometry resultGeometry = null;
 
            unsafe
            {
                fixed (byte* pbPathData = pathData.SerializedData)
                { 
                    Invariant.Assert(pbPathData != (byte*)0);
 
                    FillRule fillRule = FillRule.Nonzero; 
                    PathGeometry.FigureList list = new PathGeometry.FigureList();
 
                    int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryOutline(
                        &pathData.Matrix,
                        pathData.FillRule,
                        pbPathData, 
                        pathData.Size,
                        tolerance, 
                        type == ToleranceType.Relative, 
                        new PathGeometry.AddFigureToListDelegate(list.AddFigureToList),
                        out fillRule); 

                    if (hr == (int)MILErrors.WGXERR_BADNUMBER)
                    {
                        // When we encounter NaNs in the renderer, we absorb the error and draw 
                        // nothing. To be consistent, we return an empty geometry.
                        resultGeometry = new PathGeometry(); 
                    } 
                    else
                    { 
                        HRESULT.Check(hr);

                        resultGeometry = new PathGeometry(list.Figures, fillRule, null);
                    } 
                }
            } 
 
            return resultGeometry;
        } 

        /// 
        /// Get a simplified contour of the filled region of this PathGeometry
        ///  
        /// Returns an equivalent geometry, properly oriented with no self-intersections.
        public PathGeometry GetOutlinedPathGeometry() 
        { 
            return GetOutlinedPathGeometry(StandardFlatteningTolerance, ToleranceType.Absolute);
        } 

        #endregion Outline

        #region Internal 

        internal abstract PathGeometry GetAsPathGeometry(); 
 
        /// 
        /// GetPathGeometryData - returns a struct which contains this Geometry represented 
        /// as a path geometry's serialized format.
        /// 
        internal abstract PathGeometryData GetPathGeometryData();
 
        internal PathFigureCollection GetPathFigureCollection()
        { 
            return GetTransformedFigureCollection(null); 
        }
 
        // Get the combination of the internal transform with a given transform.
        // Return true if the result is nontrivial.
        internal Matrix GetCombinedMatrix(Transform transform)
        { 
            Matrix matrix = Matrix.Identity;
            Transform internalTransform = Transform; 
 
            if (internalTransform != null && !internalTransform.IsIdentity)
            { 
                matrix = internalTransform.Value;

                if (transform != null && !transform.IsIdentity)
                { 
                    matrix *= transform.Value;
                } 
            } 
            else if (transform != null && !transform.IsIdentity)
            { 
                matrix = transform.Value;
            }

            return matrix; 
        }
 
        internal abstract PathFigureCollection GetTransformedFigureCollection(Transform transform); 

        // This method is used for eliminating unnecessary work when the geometry is obviously empty. 
        // For most Geometry types the definite IsEmpty() query is just as cheap.  The exceptions will
        // be CombinedGeometry and GeometryGroup.
        internal virtual bool IsObviouslyEmpty() { return IsEmpty(); }
 
        /// 
        /// Can serialize "this" to a string 
        ///  
        internal virtual bool CanSerializeToString()
        { 
            return false;
        }

        internal struct PathGeometryData 
        {
            /// 
            /// Critical as this has an unsafe block. 
            /// TreatAsSafe - net effect is simply to read data.
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            internal bool IsEmpty()
            {
                if ((SerializedData == null) || (SerializedData.Length <= 0)) 
                {
                    return true; 
                } 

                unsafe 
                {
                    fixed (byte *pbPathData = SerializedData)
                    {
                        MIL_PATHGEOMETRY* pPathGeometry = (MIL_PATHGEOMETRY*)pbPathData; 

                        return pPathGeometry->FigureCount <= 0; 
                    } 
                }
            } 

            internal FillRule FillRule;
            internal MilMatrix3x2D Matrix;
            internal byte[] SerializedData; 

            ///  
            ///     Critical: Manipulates unsafe code 
            ///     TreatAsSafe - net effect is simply to read data.
            ///  
            internal uint Size
            {
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                {
                    if ((SerializedData == null) || (SerializedData.Length <= 0)) 
                    { 
                        return 0;
                    } 

                    unsafe
                    {
                        fixed (byte *pbPathData = SerializedData) 
                        {
                            MIL_PATHGEOMETRY* pPathGeometryData = (MIL_PATHGEOMETRY*)pbPathData; 
                            uint size = pPathGeometryData == null ? 0 : pPathGeometryData->Size; 

                            Invariant.Assert(size <= (uint)SerializedData.Length); 

                            return size;
                        }
                    } 
                }
            } 
        } 

        internal static PathGeometryData GetEmptyPathGeometryData() 
        {
            return s_emptyPathGeometryData;
        }
 
        #endregion Internal
 
        #region Private 

        /// 
        /// Critical as this has an unsafe block.
        /// TreatAsSafe - This allocates a buffer locally and writes to it.
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private static PathGeometryData MakeEmptyPathGeometryData()
        { 
            PathGeometryData data = new PathGeometryData(); 
            data.FillRule = FillRule.EvenOdd;
            data.Matrix = CompositionResourceManager.MatrixToMilMatrix3x2D(Matrix.Identity); 

            unsafe
            {
                int size = sizeof(MIL_PATHGEOMETRY); 

                data.SerializedData = new byte[size]; 
 
                fixed (byte *pbData = data.SerializedData)
                { 
                    MIL_PATHGEOMETRY *pPathGeometry = (MIL_PATHGEOMETRY*)pbData;

                    // implicitly set pPathGeometry->Flags = 0;
                    pPathGeometry->FigureCount = 0; 
                    pPathGeometry->Size = (UInt32)size;
                } 
            } 

            return data; 
        }

        private static Geometry MakeEmptyGeometry()
        { 
            Geometry empty = new StreamGeometry();
            empty.Freeze(); 
            return empty; 
        }
 
        private const double c_tolerance = 0.25;

        private static Geometry s_empty = MakeEmptyGeometry();
        private static PathGeometryData s_emptyPathGeometryData = MakeEmptyPathGeometryData(); 
        #endregion Private
    } 
    #endregion 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------------- 
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Description: Implementation of the class Geometry 
//
// History: 
// 
//---------------------------------------------------------------------------
 
using System;
using MS.Internal;
using MS.Win32.PresentationCore;
using System.ComponentModel; 
using System.ComponentModel.Design.Serialization;
using System.Diagnostics; 
using System.Reflection; 
using System.Collections;
using System.Globalization; 
using System.Security;
using System.Windows.Media;
using System.Windows.Media.Composition;
using System.Windows; 
using System.Text.RegularExpressions;
using System.Windows.Media.Animation; 
using System.Runtime.InteropServices; 
using System.Windows.Markup;
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;

namespace System.Windows.Media
{ 
    #region Geometry
    ///  
    /// This is the base class for all Geometry classes.  A geometry has bounds, 
    /// can be used to clip, fill or stroke.
    ///  
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
    public abstract partial class Geometry : Animatable, DUCE.IResource
    {
        #region Constructors 

        internal Geometry() 
        { 
        }
 
        #endregion

        #region Public properties
        ///  
        ///     Singleton empty model.
        ///  
        public static Geometry Empty 
        {
            get 
            {
                return s_empty;
            }
        } 

        ///  
        /// Gets the bounds of this Geometry as an axis-aligned bounding box 
        /// 
        public virtual Rect Bounds 
        {
            get
            {
                return PathGeometry.GetPathBounds( 
                    GetPathGeometryData(),
                    null,   // pen 
                    Matrix.Identity, 
                    StandardFlatteningTolerance,
                    ToleranceType.Absolute, 
                    false); // Do not skip non-fillable figures
            }
        }
 
        /// 
        /// Standard error tolerance (0.25) used for polygonal approximation of curved segments 
        ///  
        public static double StandardFlatteningTolerance
        { 
            get
            {
                return c_tolerance;
            } 
        }
 
        #endregion Public properties 

        #region GetRenderBounds 
        /// 
        /// Returns the axis-aligned bounding rectangle when stroked with a pen.
        /// 
        /// The pen 
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute 
        public virtual Rect GetRenderBounds(Pen pen, double tolerance, ToleranceType type) 
        {
            ReadPreamble(); 

            Matrix matrix = Matrix.Identity;
            return GetBoundsInternal(pen, matrix, tolerance, type);
        } 

        ///  
        /// Returns the axis-aligned bounding rectangle when stroked with a pen. 
        /// 
        /// The pen 
        public Rect GetRenderBounds(Pen pen)
        {
            ReadPreamble();
 
            Matrix matrix = Matrix.Identity;
            return GetBoundsInternal(pen, matrix, StandardFlatteningTolerance, ToleranceType.Absolute); 
        } 

        #endregion GetRenderBounds 


        #region Internal Methods
 
        /// 
        ///     Used to optimize Visual.ChangeVisualClip. This is not meant 
        ///     to be used generically since not all geometries implement 
        ///     the method (currently only RectangleGeometry is implemented).
        ///  
        internal virtual bool AreClose(Geometry geometry)
        {
           return false;
        } 

        ///  
        /// Returns the axis-aligned bounding rectangle when stroked with a pen, after applying 
        /// the supplied transform (if non-null).
        ///  
        internal virtual Rect GetBoundsInternal(Pen pen, Matrix matrix, double tolerance, ToleranceType type)
        {
            if (IsObviouslyEmpty())
            { 
                return Rect.Empty;
            } 
 
            PathGeometryData pathData = GetPathGeometryData();
 
            return PathGeometry.GetPathBounds(
                pathData,
                pen,
                matrix, 
                tolerance,
                type, 
                true); /* skip hollows */ 
        }
 
        /// 
        /// Returns the axis-aligned bounding rectangle when stroked with a pen, after applying
        /// the supplied transform (if non-null).
        ///  
        internal Rect GetBoundsInternal(Pen pen, Matrix matrix)
        { 
            return GetBoundsInternal(pen, matrix, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 

        /// 
        /// Critical - it does an elevation in calling MilUtility_PolygonBounds and is unsafe
        ///  
        [SecurityCritical]
        internal unsafe static Rect GetBoundsHelper( 
            Pen pen, 
            Matrix *pWorldMatrix,
            Point* pPoints, 
            byte *pTypes,
            uint pointCount,
            uint segmentCount,
            Matrix *pGeometryMatrix, 
            double tolerance,
            ToleranceType type, 
            bool fSkipHollows) 
        {
            MIL_PEN_DATA penData; 
            double[] dashArray = null;

            // If the pen contributes to the bounds, populate the CMD struct
            bool fPenContributesToBounds = Pen.ContributesToBounds(pen); 

            if (fPenContributesToBounds) 
            { 
                pen.GetBasicPenData(&penData, out dashArray);
            } 

            MilMatrix3x2D geometryMatrix;
            if (pGeometryMatrix != null)
            { 
                geometryMatrix = CompositionResourceManager.MatrixToMilMatrix3x2D(ref (*pGeometryMatrix));
            } 
 
            Debug.Assert(pWorldMatrix != null);
            MilMatrix3x2D worldMatrix = 
                CompositionResourceManager.MatrixToMilMatrix3x2D(ref (*pWorldMatrix));

            Rect bounds;
 
            fixed (double *pDashArray = dashArray)
            { 
                int hr = MilCoreApi.MilUtility_PolygonBounds( 
                    &worldMatrix,
                    (fPenContributesToBounds) ? &penData : null, 
                    (dashArray == null) ? null : pDashArray,
                    pPoints,
                    pTypes,
                    pointCount, 
                    segmentCount,
                    (pGeometryMatrix == null) ? null : &geometryMatrix, 
                    tolerance, 
                    type == ToleranceType.Relative,
                    fSkipHollows, 
                    &bounds
                );

                if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                {
                    // When we encounter NaNs in the renderer, we absorb the error and draw 
                    // nothing. To be consistent, we report that the geometry has empty bounds. 
                    bounds = Rect.Empty;
                } 
                else
                {
                    HRESULT.Check(hr);
                } 
            }
 
            return bounds; 
        }
 
        internal virtual void TransformPropertyChangedHook(DependencyPropertyChangedEventArgs e)
        {
            // Do nothing here -- Overriden by PathGeometry to clear cached bounds.
        } 

        internal Geometry GetTransformedCopy(Transform transform) 
        { 
            Geometry copy = Clone();
            Transform internalTransform = Transform; 

            if (transform != null && !transform.IsIdentity)
            {
                if (internalTransform == null || internalTransform.IsIdentity) 
                {
                    copy.Transform = transform; 
                } 
                else
                { 
                    copy.Transform = new MatrixTransform(internalTransform.Value * transform.Value);
                }
            }
 
            return copy;
        } 
 
        #endregion Internal Methods
 
        /// 
        /// ShouldSerializeTransform - this is called by the serializer to determine whether or not to
        /// serialize the Transform property.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeTransform() 
        { 
            Transform transform = Transform;
            return transform != null && !(transform.IsIdentity); 
        }

        #region Public Methods
 
        /// 
        /// Gets the area of this geometry 
        /// The computational error tolerance 
        /// The way the error tolerance will be interpreted - relative or absolute
        ///  
        ///
        /// Critical as this calls a method that elevates (MilUtility_GeometryGetArea)
        /// TreatAsSafe - net effect of this is to calculate the area of a geometry, so it's considered safe.
        /// 
        [SecurityCritical]
        public virtual double GetArea(double tolerance, ToleranceType type) 
        { 
            ReadPreamble();
 
            if (IsObviouslyEmpty())
            {
                return 0;
            } 

            PathGeometryData pathData = GetPathGeometryData(); 
 
            if (pathData.IsEmpty())
            { 
                return 0;
            }

            double area; 

            unsafe 
            { 
                // Call the core method on the path data
                fixed (byte* pbPathData = pathData.SerializedData) 
                {
                    Debug.Assert(pbPathData != (byte*)0);

                    int hr = MilCoreApi.MilUtility_GeometryGetArea( 
                        pathData.FillRule,
                        pbPathData, 
                        pathData.Size, 
                        &pathData.Matrix,
                        tolerance, 
                        type == ToleranceType.Relative,
                        &area);

                    if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                    {
                        // When we encounter NaNs in the renderer, we absorb the error and draw 
                        // nothing. To be consistent, we report that the geometry has 0 area. 
                        area = 0.0;
                    } 
                    else
                    {
                        HRESULT.Check(hr);
                    } 
                }
            } 
 
            return area;
        } 

        /// 
        /// Gets the area of this geometry
        ///  
        public double GetArea()
        { 
            return GetArea(StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 
        /// 
        /// Returns true if this geometry is empty
        /// 
        public abstract bool IsEmpty(); 

        ///  
        /// Returns true if this geometry may have curved segments 
        /// 
        public abstract bool MayHaveCurves(); 

        #endregion Public Methods

        #region Hit Testing 
        /// 
        /// Returns true if point is inside the fill region defined by this geometry. 
        ///  
        /// The point tested for containment
        /// Acceptable margin of error in distance computation 
        /// The way the error tolerance will be interpreted - relative or absolute
        public bool FillContains(Point hitPoint, double tolerance, ToleranceType type)
        {
            return ContainsInternal(null, hitPoint, tolerance, type); 
        }
 
        ///  
        /// Returns true if point is inside the fill region defined by this geometry.
        ///  
        /// The point tested for containment
        public bool FillContains(Point hitPoint)
        {
            return ContainsInternal(null, hitPoint, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 
        ///  
        /// Returns true if point is inside the stroke of a pen on this geometry.
        ///  
        /// The pen used to define the stroke
        /// The point tested for containment
        /// Acceptable margin of error in distance computation
        /// The way the error tolerance will be interpreted - relative or absolute 
        public bool StrokeContains(Pen pen, Point hitPoint, double tolerance, ToleranceType type)
        { 
            if (pen == null) 
            {
                return false; 
            }

            return ContainsInternal(pen, hitPoint, tolerance, type);
        } 

        ///  
        /// Returns true if point is inside the stroke of a pen on this geometry. 
        /// 
        /// The pen used to define the stroke 
        /// The point tested for containment
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute
        ///  
        /// Critical - as this does an elevation in calling MilUtility_PathGeometryHitTest.
        /// TreatAsSafe - as this doesn't expose anything sensitive. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal virtual bool ContainsInternal(Pen pen, Point hitPoint, double tolerance, ToleranceType type) 
        {
            if (IsObviouslyEmpty())
            {
                return false; 
            }
 
            PathGeometryData pathData = GetPathGeometryData(); 

            if (pathData.IsEmpty()) 
            {
                return false;
            }
 
            bool contains = false;
 
            unsafe 
            {
                MIL_PEN_DATA penData; 
                double[] dashArray = null;

                // If we have a pen, populate the CMD struct
                if (pen != null) 
                {
                    pen.GetBasicPenData(&penData, out dashArray); 
                } 

                fixed (byte* pbPathData = pathData.SerializedData) 
                {
                    Debug.Assert(pbPathData != (byte*)0);

                    fixed (double * dashArrayFixed = dashArray) 
                    {
                        int hr = MilCoreApi.MilUtility_PathGeometryHitTest( 
                                &pathData.Matrix, 
                                (pen == null) ? null : &penData,
                                dashArrayFixed, 
                                pathData.FillRule,
                                pbPathData,
                                pathData.Size,
                                tolerance, 
                                type == ToleranceType.Relative,
                                &hitPoint, 
                                out contains); 

                        if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                        {
                            // When we encounter NaNs in the renderer, we absorb the error and draw
                            // nothing. To be consistent, we report that the geometry is never hittable.
                            contains = false; 
                        }
                        else 
                        { 
                            HRESULT.Check(hr);
                        } 
                    }
                }
            }
 
            return contains;
        } 
 
        /// 
        /// Helper method to be used by derived implementations of ContainsInternal. 
        /// 
        /// 
        /// Critical - Accepts pointers, does an elevation in calling MilUtility_PolygonHitTest.
        ///  
        [SecurityCritical]
        internal unsafe bool ContainsInternal(Pen pen, Point hitPoint, double tolerance, ToleranceType type, 
                                                Point *pPoints, uint pointCount, byte *pTypes, uint typeCount) 
        {
            bool contains = false; 

            MilMatrix3x2D matrix = CompositionResourceManager.TransformToMilMatrix3x2D(Transform);

            MIL_PEN_DATA penData; 
            double[] dashArray = null;
 
            if (pen != null) 
            {
                pen.GetBasicPenData(&penData, out dashArray); 
            }

            fixed (double *dashArrayFixed = dashArray)
            { 
                int hr = MilCoreApi.MilUtility_PolygonHitTest(
                        &matrix, 
                        (pen == null) ? null : &penData, 
                        dashArrayFixed,
                        pPoints, 
                        pTypes,
                        pointCount,
                        typeCount,
                        tolerance, 
                        type == ToleranceType.Relative,
                        &hitPoint, 
                        out contains); 

                if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                {
                    // When we encounter NaNs in the renderer, we absorb the error and draw
                    // nothing. To be consistent, we report that the geometry is never hittable.
                    contains = false; 
                }
                else 
                { 
                    HRESULT.Check(hr);
                } 
            }

            return contains;
        } 

        ///  
        /// Returns true if point is inside the stroke of a pen on this geometry. 
        /// 
        /// The pen used to define the stroke 
        /// The point tested for containment
        public bool StrokeContains(Pen pen, Point hitPoint)
        {
            return StrokeContains(pen, hitPoint, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }
 
        ///  
        /// Returns true if a given geometry is contained inside this geometry.
        ///  
        /// The geometry tested for containment
        /// Acceptable margin of error in distance computation
        /// The way the error tolerance will be interpreted - relative or absolute
        public bool FillContains(Geometry geometry, double tolerance, ToleranceType type) 
        {
            IntersectionDetail detail = FillContainsWithDetail(geometry, tolerance, type); 
 
            return (detail == IntersectionDetail.FullyContains);
        } 

        /// 
        /// Returns true if a given geometry is contained inside this geometry.
        ///  
        /// The geometry tested for containment
        public bool FillContains(Geometry geometry) 
        { 
            return FillContains(geometry, StandardFlatteningTolerance, ToleranceType.Absolute);
        } 

        /// 
        /// Returns true if a given geometry is inside this geometry.
        /// The geometry to test for containment in this Geometry 
        /// Acceptable margin of error in distance computation
        /// The way the error tolerance will be interpreted - relative or absolute 
        ///  
        public virtual IntersectionDetail FillContainsWithDetail(Geometry geometry, double tolerance, ToleranceType type)
        { 
            ReadPreamble();

            if (IsObviouslyEmpty() || geometry == null || geometry.IsObviouslyEmpty())
            { 
                return IntersectionDetail.Empty;
            } 
 
            return PathGeometry.HitTestWithPathGeometry(this, geometry, tolerance, type);
        } 


        /// 
        /// Returns if geometry is inside this geometry. 
        /// The geometry to test for containment in this Geometry
        ///  
        public IntersectionDetail FillContainsWithDetail(Geometry geometry) 
        {
            return FillContainsWithDetail(geometry, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }

        /// 
        /// Returns if a given geometry is inside the stroke defined by a given pen on this geometry. 
        /// The pen
        /// The geometry to test for containment in this Geometry 
        /// Acceptable margin of error in distance computation 
        /// The way the error tolerance will be interpreted - relative or absolute
        ///  
        public IntersectionDetail StrokeContainsWithDetail(Pen pen, Geometry geometry, double tolerance, ToleranceType type)
        {
            if (IsObviouslyEmpty() || geometry == null || geometry.IsObviouslyEmpty() || pen == null)
            { 
                return IntersectionDetail.Empty;
            } 
 
            PathGeometry pathGeometry1 = GetWidenedPathGeometry(pen);
 
            return PathGeometry.HitTestWithPathGeometry(pathGeometry1, geometry, tolerance, type);
        }

        ///  
        /// Returns if a given geometry is inside the stroke defined by a given pen on this geometry.
        /// The pen 
        /// The geometry to test for containment in this Geometry 
        /// 
        public IntersectionDetail StrokeContainsWithDetail(Pen pen, Geometry geometry) 
        {
            return StrokeContainsWithDetail(pen, geometry, StandardFlatteningTolerance, ToleranceType.Absolute);
        }
 
        #endregion
 
        #region Geometric Flatten 

        ///  
        /// Approximate this geometry with a polygonal PathGeometry
        /// 
        /// The approximation error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute 
        /// Returns the polygonal approximation as a PathGeometry.
        /// 
        ///     Critical - calls code that performs an elevation. 
        ///     PublicOK - net effect of this code is to create an "flattened" shape from the current one.
        ///                          to "flatten" means to approximate with polygons. 
        ///                             ( in effect creating a different flavor of this shape from this one).
        ///                          Considered safe.
        ///
        [SecurityCritical] 
        public virtual PathGeometry GetFlattenedPathGeometry(double tolerance, ToleranceType type)
        { 
            ReadPreamble(); 

            if (IsObviouslyEmpty()) 
            {
                return new PathGeometry();
            }
 
            PathGeometryData pathData = GetPathGeometryData();
 
            if (pathData.IsEmpty()) 
            {
                return new PathGeometry(); 
            }

            PathGeometry resultGeometry = null;
 
            unsafe
            { 
                fixed (byte *pbPathData = pathData.SerializedData) 
                {
                    Debug.Assert(pbPathData != (byte*)0); 

                    FillRule fillRule = FillRule.Nonzero;

                    PathGeometry.FigureList list = new PathGeometry.FigureList(); 

                    int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryFlatten( 
                        &pathData.Matrix, 
                        pathData.FillRule,
                        pbPathData, 
                        pathData.Size,
                        tolerance,
                        type == ToleranceType.Relative,
                        new PathGeometry.AddFigureToListDelegate(list.AddFigureToList), 
                        out fillRule);
 
                    if (hr == (int)MILErrors.WGXERR_BADNUMBER) 
                    {
                        // When we encounter NaNs in the renderer, we absorb the error and draw 
                        // nothing. To be consistent, we return an empty geometry.
                        resultGeometry = new PathGeometry();
                    }
                    else 
                    {
                        HRESULT.Check(hr); 
 
                        resultGeometry = new PathGeometry(list.Figures, fillRule, null);
                    } 
                }

                return resultGeometry;
            } 
        }
 
        ///  
        /// Approximate this geometry with a polygonal PathGeometry
        ///  
        /// Returns the polygonal approximation as a PathGeometry.
        public PathGeometry GetFlattenedPathGeometry()
        {
            // Use the default tolerance interpreted as absolute 
            return GetFlattenedPathGeometry(StandardFlatteningTolerance, ToleranceType.Absolute);
        } 
 
        #endregion Flatten
 
        #region Geometric Widen

        /// 
        /// Create the contour of the stroke defined by given pen when it draws this path 
        /// 
        /// The pen used for stroking this path 
        /// The computational error tolerance 
        /// The way the error tolerance will be interpreted - relative or absolute
        /// Returns the contour as a PathGeometry. 
        ///
        /// Critical as this calls a method that elevates ( SUC on PathGeometryWiden).
        /// PublicOK - net effect of this is to create a new PathGeometry "widened" with a new pen.
        ///                      To "widen" a path is what we do internally when we draw a path with a pen: we generate the contour of the stroke and then fill it. 
        ///                         The exposed method returns that contour as a PathGeometry.
        ///                         In effect we're creating a different flavor of the current shape from this one. 
        /// 
        ///                      Considered safe.
        /// 
        [SecurityCritical]
        public virtual PathGeometry GetWidenedPathGeometry(Pen pen, double tolerance, ToleranceType type)
        {
            ReadPreamble(); 

            if (pen == null) 
            { 
                throw new System.ArgumentNullException("pen");
            } 

            if (IsObviouslyEmpty())
            {
                return new PathGeometry(); 
            }
 
            PathGeometryData pathData = GetPathGeometryData(); 

            if (pathData.IsEmpty()) 
            {
                return new PathGeometry();
            }
 
            PathGeometry resultGeometry = null;
 
            unsafe 
            {
                MIL_PEN_DATA penData; 
                double[] dashArray = null;

                pen.GetBasicPenData(&penData, out dashArray);
 
                fixed (byte *pbPathData = pathData.SerializedData)
                { 
                    Debug.Assert(pbPathData != (byte*)0); 

                    FillRule fillRule = FillRule.Nonzero; 

                    PathGeometry.FigureList list = new PathGeometry.FigureList();

                    // The handle to the pDashArray, if we have one. 
                    // Since the dash array is optional, we may not need to Free it.
                    GCHandle handle = new GCHandle(); 
 
                    // Pin the pDashArray, if we have one.
                    if (dashArray != null) 
                    {
                        handle = GCHandle.Alloc(dashArray, GCHandleType.Pinned);
                    }
 
                    try
                    { 
                        int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryWiden( 
                            &penData,
                            (dashArray == null) ? null : (double*)handle.AddrOfPinnedObject(), 
                            &pathData.Matrix,
                            pathData.FillRule,
                            pbPathData,
                            pathData.Size, 
                            tolerance,
                            type == ToleranceType.Relative, 
                            new PathGeometry.AddFigureToListDelegate(list.AddFigureToList), 
                            out fillRule);
 
                        if (hr == (int)MILErrors.WGXERR_BADNUMBER)
                        {
                            // When we encounter NaNs in the renderer, we absorb the error and draw
                            // nothing. To be consistent, we return an empty geometry. 
                            resultGeometry = new PathGeometry();
                        } 
                        else 
                        {
                            HRESULT.Check(hr); 

                            resultGeometry = new PathGeometry(list.Figures, fillRule, null);
                        }
                    } 
                    finally
                    { 
                        if (handle.IsAllocated) 
                        {
                            handle.Free(); 
                        }
                    }

                } 

                return resultGeometry; 
            } 
        }
 
        /// 
        /// Create the contour of the stroke defined by given pen when it draws this path
        /// 
        /// The pen used for stroking this path 
        /// Returns the contour as a PathGeometry.
        public PathGeometry GetWidenedPathGeometry(Pen pen) 
        { 
            // Use the default tolerance interpreted as absolute
            return GetWidenedPathGeometry(pen, StandardFlatteningTolerance, ToleranceType.Absolute); 
        }

        #endregion Widen
 
        #region Combine
 
        ///  
        /// Returns the result of a Boolean combination of two Geometry objects.
        ///  
        /// The first Geometry object
        /// The second Geometry object
        /// The mode in which the objects will be combined
        /// A transformation to apply to the result, or null 
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute 
        public static PathGeometry Combine( 
            Geometry geometry1,
            Geometry geometry2, 
            GeometryCombineMode mode,
            Transform transform,
            double tolerance,
            ToleranceType type) 
        {
            return PathGeometry.InternalCombine(geometry1, geometry2, mode, transform, tolerance, type); 
        } 

        ///  
        /// Returns the result of a Boolean combination of two Geometry objects.
        /// 
        /// The first Geometry object
        /// The second Geometry object 
        /// The mode in which the objects will be combined
        /// A transformation to apply to the result, or null 
        public static PathGeometry Combine( 
            Geometry geometry1,
            Geometry geometry2, 
            GeometryCombineMode mode,
            Transform transform)
        {
            return PathGeometry.InternalCombine( 
                geometry1,
                geometry2, 
                mode, 
                transform,
                Geometry.StandardFlatteningTolerance, 
                ToleranceType.Absolute);
        }

        #endregion Combine 

        #region Outline 
 
        /// 
        /// Get a simplified contour of the filled region of this PathGeometry 
        /// 
        /// The computational error tolerance
        /// The way the error tolerance will be interpreted - relative or absolute
        /// Returns an equivalent geometry, properly oriented with no self-intersections. 
        /// 
        /// Critical - as this calls GetGlyphs() which is critical. 
        /// Safe - as this doesn't expose font information but just gives out a Geometry. 
        /// 
        [SecurityCritical] 
        public virtual PathGeometry GetOutlinedPathGeometry(double tolerance, ToleranceType type)
        {
            ReadPreamble();
 
            if (IsObviouslyEmpty())
            { 
                return new PathGeometry(); 
            }
 
            PathGeometryData pathData = GetPathGeometryData();

            if (pathData.IsEmpty())
            { 
                return new PathGeometry();
            } 
 
            PathGeometry resultGeometry = null;
 
            unsafe
            {
                fixed (byte* pbPathData = pathData.SerializedData)
                { 
                    Invariant.Assert(pbPathData != (byte*)0);
 
                    FillRule fillRule = FillRule.Nonzero; 
                    PathGeometry.FigureList list = new PathGeometry.FigureList();
 
                    int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryOutline(
                        &pathData.Matrix,
                        pathData.FillRule,
                        pbPathData, 
                        pathData.Size,
                        tolerance, 
                        type == ToleranceType.Relative, 
                        new PathGeometry.AddFigureToListDelegate(list.AddFigureToList),
                        out fillRule); 

                    if (hr == (int)MILErrors.WGXERR_BADNUMBER)
                    {
                        // When we encounter NaNs in the renderer, we absorb the error and draw 
                        // nothing. To be consistent, we return an empty geometry.
                        resultGeometry = new PathGeometry(); 
                    } 
                    else
                    { 
                        HRESULT.Check(hr);

                        resultGeometry = new PathGeometry(list.Figures, fillRule, null);
                    } 
                }
            } 
 
            return resultGeometry;
        } 

        /// 
        /// Get a simplified contour of the filled region of this PathGeometry
        ///  
        /// Returns an equivalent geometry, properly oriented with no self-intersections.
        public PathGeometry GetOutlinedPathGeometry() 
        { 
            return GetOutlinedPathGeometry(StandardFlatteningTolerance, ToleranceType.Absolute);
        } 

        #endregion Outline

        #region Internal 

        internal abstract PathGeometry GetAsPathGeometry(); 
 
        /// 
        /// GetPathGeometryData - returns a struct which contains this Geometry represented 
        /// as a path geometry's serialized format.
        /// 
        internal abstract PathGeometryData GetPathGeometryData();
 
        internal PathFigureCollection GetPathFigureCollection()
        { 
            return GetTransformedFigureCollection(null); 
        }
 
        // Get the combination of the internal transform with a given transform.
        // Return true if the result is nontrivial.
        internal Matrix GetCombinedMatrix(Transform transform)
        { 
            Matrix matrix = Matrix.Identity;
            Transform internalTransform = Transform; 
 
            if (internalTransform != null && !internalTransform.IsIdentity)
            { 
                matrix = internalTransform.Value;

                if (transform != null && !transform.IsIdentity)
                { 
                    matrix *= transform.Value;
                } 
            } 
            else if (transform != null && !transform.IsIdentity)
            { 
                matrix = transform.Value;
            }

            return matrix; 
        }
 
        internal abstract PathFigureCollection GetTransformedFigureCollection(Transform transform); 

        // This method is used for eliminating unnecessary work when the geometry is obviously empty. 
        // For most Geometry types the definite IsEmpty() query is just as cheap.  The exceptions will
        // be CombinedGeometry and GeometryGroup.
        internal virtual bool IsObviouslyEmpty() { return IsEmpty(); }
 
        /// 
        /// Can serialize "this" to a string 
        ///  
        internal virtual bool CanSerializeToString()
        { 
            return false;
        }

        internal struct PathGeometryData 
        {
            /// 
            /// Critical as this has an unsafe block. 
            /// TreatAsSafe - net effect is simply to read data.
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            internal bool IsEmpty()
            {
                if ((SerializedData == null) || (SerializedData.Length <= 0)) 
                {
                    return true; 
                } 

                unsafe 
                {
                    fixed (byte *pbPathData = SerializedData)
                    {
                        MIL_PATHGEOMETRY* pPathGeometry = (MIL_PATHGEOMETRY*)pbPathData; 

                        return pPathGeometry->FigureCount <= 0; 
                    } 
                }
            } 

            internal FillRule FillRule;
            internal MilMatrix3x2D Matrix;
            internal byte[] SerializedData; 

            ///  
            ///     Critical: Manipulates unsafe code 
            ///     TreatAsSafe - net effect is simply to read data.
            ///  
            internal uint Size
            {
                [SecurityCritical, SecurityTreatAsSafe]
                get 
                {
                    if ((SerializedData == null) || (SerializedData.Length <= 0)) 
                    { 
                        return 0;
                    } 

                    unsafe
                    {
                        fixed (byte *pbPathData = SerializedData) 
                        {
                            MIL_PATHGEOMETRY* pPathGeometryData = (MIL_PATHGEOMETRY*)pbPathData; 
                            uint size = pPathGeometryData == null ? 0 : pPathGeometryData->Size; 

                            Invariant.Assert(size <= (uint)SerializedData.Length); 

                            return size;
                        }
                    } 
                }
            } 
        } 

        internal static PathGeometryData GetEmptyPathGeometryData() 
        {
            return s_emptyPathGeometryData;
        }
 
        #endregion Internal
 
        #region Private 

        /// 
        /// Critical as this has an unsafe block.
        /// TreatAsSafe - This allocates a buffer locally and writes to it.
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private static PathGeometryData MakeEmptyPathGeometryData()
        { 
            PathGeometryData data = new PathGeometryData(); 
            data.FillRule = FillRule.EvenOdd;
            data.Matrix = CompositionResourceManager.MatrixToMilMatrix3x2D(Matrix.Identity); 

            unsafe
            {
                int size = sizeof(MIL_PATHGEOMETRY); 

                data.SerializedData = new byte[size]; 
 
                fixed (byte *pbData = data.SerializedData)
                { 
                    MIL_PATHGEOMETRY *pPathGeometry = (MIL_PATHGEOMETRY*)pbData;

                    // implicitly set pPathGeometry->Flags = 0;
                    pPathGeometry->FigureCount = 0; 
                    pPathGeometry->Size = (UInt32)size;
                } 
            } 

            return data; 
        }

        private static Geometry MakeEmptyGeometry()
        { 
            Geometry empty = new StreamGeometry();
            empty.Freeze(); 
            return empty; 
        }
 
        private const double c_tolerance = 0.25;

        private static Geometry s_empty = MakeEmptyGeometry();
        private static PathGeometryData s_emptyPathGeometryData = MakeEmptyPathGeometryData(); 
        #endregion Private
    } 
    #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