Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / Geometry.cs / 1305600 / 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Parallel.cs
- Coordinator.cs
- DaylightTime.cs
- Helpers.cs
- ScriptingAuthenticationServiceSection.cs
- WebPartZoneBase.cs
- RuntimeResourceSet.cs
- BinHexEncoder.cs
- ScriptComponentDescriptor.cs
- BamlMapTable.cs
- XmlCustomFormatter.cs
- ExtendedPropertyDescriptor.cs
- HtmlInputFile.cs
- PropertyPathConverter.cs
- InputEventArgs.cs
- StyleXamlTreeBuilder.cs
- SignedXml.cs
- GenericIdentity.cs
- PeerResolverElement.cs
- Win32SafeHandles.cs
- ListViewSelectEventArgs.cs
- BrowserDefinition.cs
- FileSystemInfo.cs
- GregorianCalendar.cs
- XPathNavigatorReader.cs
- StructuredTypeEmitter.cs
- BatchParser.cs
- HashCodeCombiner.cs
- XmlName.cs
- WebPartAuthorizationEventArgs.cs
- cookie.cs
- TextElementCollectionHelper.cs
- AutomationPattern.cs
- DataGridViewControlCollection.cs
- SizeAnimationUsingKeyFrames.cs
- XmlEntity.cs
- Rotation3DAnimation.cs
- ColorAnimationUsingKeyFrames.cs
- RuleConditionDialog.Designer.cs
- InternalRelationshipCollection.cs
- SynchronizedDispatch.cs
- MenuCommandService.cs
- BaseCollection.cs
- SqlMethods.cs
- SimpleFileLog.cs
- Condition.cs
- WindowsAltTab.cs
- EpmContentSerializerBase.cs
- XamlStream.cs
- DBCommandBuilder.cs
- VisualStyleTypesAndProperties.cs
- ComponentEvent.cs
- SchemaNotation.cs
- Update.cs
- ExpandCollapsePattern.cs
- ObjectDataSourceDisposingEventArgs.cs
- Int64KeyFrameCollection.cs
- FixedTextSelectionProcessor.cs
- IndexOutOfRangeException.cs
- MaskedTextBoxTextEditor.cs
- GregorianCalendarHelper.cs
- ModelService.cs
- AdCreatedEventArgs.cs
- TagPrefixAttribute.cs
- ProxySimple.cs
- PeerName.cs
- EventItfInfo.cs
- Int32RectConverter.cs
- TableHeaderCell.cs
- Figure.cs
- DelegateArgumentValue.cs
- NativeMethods.cs
- DependencyPropertyDescriptor.cs
- BlockCollection.cs
- SafeNativeMethodsCLR.cs
- TrackingConditionCollection.cs
- AuthorizationPolicyTypeElement.cs
- ConditionalDesigner.cs
- NavigateEvent.cs
- ObservableCollection.cs
- SqlDataSourceCustomCommandEditor.cs
- Base64Stream.cs
- Helper.cs
- XmlKeywords.cs
- CacheSection.cs
- WebPartActionVerb.cs
- WindowsToolbarItemAsMenuItem.cs
- BaseUriHelper.cs
- PingReply.cs
- NetNamedPipeBindingElement.cs
- SchemaLookupTable.cs
- WindowsFormsHost.cs
- TextDecoration.cs
- SetIndexBinder.cs
- SqlException.cs
- Decimal.cs
- ProtectedConfiguration.cs
- ToolStripOverflowButton.cs
- Mappings.cs
- CodeAssignStatement.cs