Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Media / PathGeometry.cs / 1 / PathGeometry.cs
//---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // Description: Implementation of the class PathGeometry // //--------------------------------------------------------------------------- using System; using MS.Internal; using MS.Internal.PresentationCore; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Diagnostics; using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Text; using System.Globalization; using System.Windows.Media; using System.Windows.Media.Composition; using System.Windows; using System.Text.RegularExpressions; using System.Windows.Media.Animation; using System.Windows.Markup; using System.Windows.Converters; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using MS.Win32; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using UnsafeNativeMethods=MS.Win32.PresentationCore.UnsafeNativeMethods; namespace System.Windows.Media { #region PathGeometryInternalFlags [System.Flags] internal enum PathGeometryInternalFlags { None = 0x0, Invalid = 0x1, Dirty = 0x2, BoundsValid = 0x4 } #endregion #region PathGeometry ////// PathGeometry /// [ContentProperty("Figures")] public sealed partial class PathGeometry : Geometry { #region Constructors ////// /// public PathGeometry() { } ////// Constructor /// /// A collection of figures public PathGeometry(IEnumerablefigures) { if (figures != null) { foreach (PathFigure item in figures) { Figures.Add(item); } } else { throw new ArgumentNullException("figures"); } SetDirty(); } /// /// Constructor /// /// A collection of figures /// The fill rule (OddEven or NonZero) /// A transformation to apply to the input public PathGeometry(IEnumerablefigures, FillRule fillRule, Transform transform) { Transform = transform; if (ValidateEnums.IsFillRuleValid(fillRule)) { FillRule = fillRule; if (figures != null) { foreach (PathFigure item in figures) { Figures.Add(item); } } else { throw new ArgumentNullException("figures"); } SetDirty(); } } /// /// Static "CreateFromGeometry" method which creates a new PathGeometry from the Geometry specified. /// /// /// Geometry - The Geometry which will be used as the basis for the newly created /// PathGeometry. The new Geometry will be based on the current value of all properties. /// public static PathGeometry CreateFromGeometry(Geometry geometry) { if (geometry == null) { return null; } return geometry.GetAsPathGeometry(); } ////// Static method which parses a PathGeometryData and makes calls into the provided context sink. /// This can be used to build a PathGeometry, for readback, etc. /// ////// Critical - calls code that performs an elevation. /// TreatAsSafe - This method reads from a pinned byte array. /// [SecurityCritical, SecurityTreatAsSafe] internal static void ParsePathGeometryData(PathGeometryData pathData, CapacityStreamGeometryContext ctx) { if (pathData.IsEmpty()) { return; } unsafe { int currentOffset = 0; fixed (byte* pbData = pathData.SerializedData) { // This assert is a logical correctness test Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_PATHGEOMETRY)); // ... while this assert tests "physical" correctness (i.e. are we running out of buffer). Invariant.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_PATHGEOMETRY)); MIL_PATHGEOMETRY *pPathGeometry = (MIL_PATHGEOMETRY*)pbData; // Move the current offset to after the Path's data currentOffset += sizeof(MIL_PATHGEOMETRY); // Are there any Figures to add? if (pPathGeometry->FigureCount > 0) { // Allocate the correct number of Figures up front ctx.SetFigureCount((int)pPathGeometry->FigureCount); // ... and iterate on the Figures. for (int i = 0; i < pPathGeometry->FigureCount; i++) { // We only expect well-formed data, but we should assert that we're not reading // too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_PATHFIGURE)); MIL_PATHFIGURE *pPathFigure = (MIL_PATHFIGURE*)(pbData + currentOffset); // Move the current offset to the after of the Figure's data currentOffset += sizeof(MIL_PATHFIGURE); ctx.BeginFigure(pPathFigure->StartPoint, ((pPathFigure->Flags & PathFigureFlags.IsFillable) != 0), ((pPathFigure->Flags & PathFigureFlags.IsClosed) != 0)); if (pPathFigure->Count > 0) { // Allocate the correct number of Segments up front ctx.SetSegmentCount((int)pPathFigure->Count); // ... and iterate on the Segments. for (int j = 0; j < pPathFigure->Count; j++) { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT)); MIL_SEGMENT *pSegment = (MIL_SEGMENT*)(pbData + currentOffset); switch (pSegment->Type) { case MIL_SEGMENT_TYPE.MilSegmentLine: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_LINE)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_LINE)); MIL_SEGMENT_LINE *pSegmentLine = (MIL_SEGMENT_LINE*)(pbData + currentOffset); ctx.LineTo(pSegmentLine->Point, ((pSegmentLine->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentLine->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_LINE); } break; case MIL_SEGMENT_TYPE.MilSegmentBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_BEZIER)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_BEZIER)); MIL_SEGMENT_BEZIER *pSegmentBezier = (MIL_SEGMENT_BEZIER*)(pbData + currentOffset); ctx.BezierTo(pSegmentBezier->Point1, pSegmentBezier->Point2, pSegmentBezier->Point3, ((pSegmentBezier->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentBezier->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_BEZIER); } break; case MIL_SEGMENT_TYPE.MilSegmentQuadraticBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_QUADRATICBEZIER)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_QUADRATICBEZIER)); MIL_SEGMENT_QUADRATICBEZIER *pSegmentQuadraticBezier = (MIL_SEGMENT_QUADRATICBEZIER*)(pbData + currentOffset); ctx.QuadraticBezierTo(pSegmentQuadraticBezier->Point1, pSegmentQuadraticBezier->Point2, ((pSegmentQuadraticBezier->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentQuadraticBezier->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_QUADRATICBEZIER); } break; case MIL_SEGMENT_TYPE.MilSegmentArc: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_ARC)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_ARC)); MIL_SEGMENT_ARC *pSegmentArc = (MIL_SEGMENT_ARC*)(pbData + currentOffset); ctx.ArcTo(pSegmentArc->Point, pSegmentArc->Size, pSegmentArc->XRotation, (pSegmentArc->LargeArc != 0), (pSegmentArc->Sweep == 0) ? SweepDirection.Counterclockwise : SweepDirection.Clockwise, ((pSegmentArc->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentArc->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); currentOffset += sizeof(MIL_SEGMENT_ARC); } break; case MIL_SEGMENT_TYPE.MilSegmentPolyLine: case MIL_SEGMENT_TYPE.MilSegmentPolyBezier: case MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier: { // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_POLY)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_POLY)); MIL_SEGMENT_POLY *pSegmentPoly = (MIL_SEGMENT_POLY*)(pbData + currentOffset); Debug.Assert(pSegmentPoly->Count <= Int32.MaxValue); if (pSegmentPoly->Count > 0) { Listpoints = new List ((int)pSegmentPoly->Count); // We only expect well-formed data, but we should assert that we're not reading too much data. Debug.Assert(pathData.SerializedData.Length >= currentOffset + sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point)); Debug.Assert(pathData.Size >= currentOffset + sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point)); Point* pPoint = (Point*)(pbData + currentOffset + sizeof(MIL_SEGMENT_POLY)); for (uint k = 0; k < pSegmentPoly->Count; k++) { points.Add(*pPoint); pPoint++; } switch (pSegment->Type) { case MIL_SEGMENT_TYPE.MilSegmentPolyLine: ctx.PolyLineTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; case MIL_SEGMENT_TYPE.MilSegmentPolyBezier: ctx.PolyBezierTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; case MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier: ctx.PolyQuadraticBezierTo(points, ((pSegmentPoly->Flags & MILCoreSegFlags.SegIsAGap) == 0), ((pSegmentPoly->Flags & MILCoreSegFlags.SegSmoothJoin) != 0)); break; } } currentOffset += sizeof(MIL_SEGMENT_POLY) + (int)pSegmentPoly->Count * sizeof(Point); } break; #if DEBUG case MIL_SEGMENT_TYPE.MilSegmentNone: throw new System.InvalidOperationException(); default: throw new System.InvalidOperationException(); #endif } } } } } } } } #endregion /// /// Implementation of protected override void OnChanged() { SetDirty(); base.OnChanged(); } #region GetTransformedFigureCollection internal override PathFigureCollection GetTransformedFigureCollection(Transform transform) { // Combine the transform argument with the internal transform Matrix matrix = GetCombinedMatrix(transform); // Get the figure collection PathFigureCollection result; if (matrix.IsIdentity) { // There is no need to transform, return the figure collection result = Figures; if (result == null) { result = new PathFigureCollection(); } } else { // Return a transformed copy of the figure collection result = new PathFigureCollection(); PathFigureCollection figures = Figures; int count = figures != null ? figures.Count : 0; for (int i = 0; i < count; ++i) { PathFigure figure = figures.Internal_GetItem(i); result.Add(figure.GetTransformedCopy(matrix)); } } Debug.Assert(result != null); return result; } #endregion #region PathFigure/Geometry ///Freezable.OnChanged . ////// /// public void AddGeometry(Geometry geometry) { if (geometry == null) { throw new System.ArgumentNullException("geometry"); } if (geometry.IsEmpty()) { return; } PathFigureCollection figureCollection = geometry.GetPathFigureCollection(); Debug.Assert(figureCollection != null); PathFigureCollection figures = Figures; if (figures == null) { figures = Figures = new PathFigureCollection(); } for (int i = 0; i < figureCollection.Count; ++i) { figures.Add(figureCollection.Internal_GetItem(i)); } } #endregion #region FigureList class ////// List of figures, populated by callbacks from unmanaged code /// internal class FigureList { ////// Constructor /// internal FigureList() { _figures = new PathFigureCollection(); } ////// Figures - the array of figures /// internal PathFigureCollection Figures { get { return _figures; } } #endregion FigureList class ////// Callback method, used for adding a figure to the list /// /// /// The figure is filled /// /// /// The figure is closed /// /// /// The array of the figure's defining points /// /// /// The size of the points array /// /// /// The array of the figure's defining segment types /// /// /// The size of the types array /// ////// Critical: This code is critical because it is an unsafe code block /// [SecurityCritical] internal unsafe void AddFigureToList(bool isFilled, bool isClosed, MIL_2DPOINTF* pPoints, UInt32 pointCount, byte* pSegTypes, UInt32 segmentCount) { if (pointCount >=1 && segmentCount >= 1) { PathFigure figure = new PathFigure(); figure.IsFilled = isFilled; figure.StartPoint = new Point(pPoints->X, pPoints->Y); int pointIndex = 1; int sameSegCount = 0; for (int segIndex=0; segIndexpointCount) { throw new System.InvalidOperationException(SR.Get(SRID.PathGeometry_InternalReadBackError)); } if (sameSegCount>1) { PointCollection ptCollection = new PointCollection(); for (int i=0; i pointCount) { throw new System.InvalidOperationException(SR.Get(SRID.PathGeometry_InternalReadBackError)); } if (sameSegCount>1) { PointCollection ptCollection = new PointCollection(); for (int i=0; i /// The array of figures /// internal PathFigureCollection _figures; }; internal unsafe delegate void AddFigureToListDelegate(bool isFilled, bool isClosed, MIL_2DPOINTF *pPoints, UInt32 pointCount, byte *pTypes, UInt32 typeCount); #region GetPointAtFractionLength /// /// ////// Critical - calls MilUtility_GetPointAtLengthFraction that performs an elevation. /// PublicOK - This computes the location of the point x% along the way of a path (and its direction). /// Progress is normalized between 0 and 1. This math is considered safe. /// [SecurityCritical] public void GetPointAtFractionLength( double progress, out Point point, out Point tangent) { if (IsEmpty()) { point = new Point(); tangent = new Point(); return; } unsafe { PathGeometryData pathData = GetPathGeometryData(); fixed (byte *pbPathData = pathData.SerializedData) { Debug.Assert(pbPathData != (byte*)0); HRESULT.Check(MilCoreApi.MilUtility_GetPointAtLengthFraction( &pathData.Matrix, pathData.FillRule, pbPathData, pathData.Size, progress, out point, out tangent)); } } } #endregion #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 ////// Critical - calls code that perfoms an elevation ( MilUtility_PathGeometryCombine ) /// TreatAsSafe - the net effect of this function is to return a new PathGeometry given a transform and a combine operation. /// Considered safe. /// /// Although we call code within an unsafe block - managed objects are used to construct the unmanaged data. /// unsafe code will have to be reviewed /// [SecurityCritical, SecurityTreatAsSafe] internal static PathGeometry InternalCombine( Geometry geometry1, Geometry geometry2, GeometryCombineMode mode, Transform transform, double tolerance, ToleranceType type) { PathGeometry resultGeometry = null; unsafe { MIL_MATRIX3X2D matrix = CompositionResourceManager.TransformToMIL_MATRIX3X2D(transform); PathGeometryData data1 = geometry1.GetPathGeometryData(); PathGeometryData data2 = geometry2.GetPathGeometryData(); fixed (byte* pPathData1 = data1.SerializedData) { Debug.Assert(pPathData1 != (byte*)0); fixed (byte* pPathData2 = data2.SerializedData) { Debug.Assert(pPathData2 != (byte*)0); FillRule fillRule = FillRule.Nonzero; FigureList list = new FigureList(); int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryCombine( &matrix, &data1.Matrix, data1.FillRule, pPathData1, data1.Size, &data2.Matrix, data2.FillRule, pPathData2, data2.Size, tolerance, type == ToleranceType.Relative, new AddFigureToListDelegate(list.AddFigureToList), mode, out fillRule); if (hr == (int)MILErrors.MILERR_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; } #endregion Combine ////// Remove all figures /// #region Clear public void Clear() { PathFigureCollection figures = Figures; if (figures != null) { figures.Clear(); } } #endregion #region Bounds ////// Gets the bounds of this PathGeometry as an axis-aligned bounding box /// public override Rect Bounds { get { ReadPreamble(); if (IsEmpty()) { return Rect.Empty; } else { if ((_flags & PathGeometryInternalFlags.BoundsValid) == 0) { // Update the cached bounds _bounds = GetPathBoundsAsRB( GetPathGeometryData(), null, // pen Matrix.Identity, StandardFlatteningTolerance, ToleranceType.Absolute, false); // Do not skip non-fillable figures _flags |= PathGeometryInternalFlags.BoundsValid; } return _bounds.AsRect; } } } ////// Gets the bounds of this PathGeometry as an axis-aligned bounding box with pen and/or transform /// internal static Rect GetPathBounds( PathGeometryData pathData, Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type, bool skipHollows) { if (pathData.IsEmpty()) { return Rect.Empty; } else { MIL_RECTD_RB bounds = PathGeometry.GetPathBoundsAsRB( pathData, pen, worldMatrix, tolerance, type, skipHollows); return bounds.AsRect; } } ////// Gets the bounds of this PathGeometry as an axis-aligned bounding box with pen and/or transform /// /// This function should not be called with a PathGeometryData that's known to be empty, since MIL_RECTD_RB /// does not offer a standard way of representing this. /// ////// Critical as this code performs an elevation ( SUC on MilUtility_PathGeometryBounds) /// TreatAsSafe - the net effect of this function is to return a rect for the Path's bounds. Considered safe. /// although we call code within an unsafe block - managed objects are used to construct the unmanaged data. /// [SecurityCritical, SecurityTreatAsSafe] internal static MIL_RECTD_RB GetPathBoundsAsRB( PathGeometryData pathData, Pen pen, Matrix worldMatrix, double tolerance, ToleranceType type, bool skipHollows) { // This method can't handle the empty geometry case, as it's impossible for us to // return Rect.Empty. Callers should do their own check. Debug.Assert(!pathData.IsEmpty()); 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); } MIL_MATRIX3X2D worldMatrix3X2 = CompositionResourceManager.MatrixToMIL_MATRIX3X2D(ref worldMatrix); fixed (byte *pbPathData = pathData.SerializedData) { MIL_RECTD_RB bounds; Debug.Assert(pbPathData != (byte*)0); fixed (double *pDashArray = dashArray) { int hr = UnsafeNativeMethods.MilCoreApi.MilUtility_PathGeometryBounds( (pen == null) ? null : &penData, pDashArray, &worldMatrix3X2, pathData.FillRule, pbPathData, pathData.Size, &pathData.Matrix, tolerance, type == ToleranceType.Relative, skipHollows, &bounds ); if (hr == (int)MILErrors.MILERR_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 // (NaN will get transformed into Rect.Empty higher up). bounds = MIL_RECTD_RB.NaN; } else { HRESULT.Check(hr); } } return bounds; } } } #endregion #region HitTestWithPathGeometry ////// Critical as this calls a method that elevates (MilUtility_PathGeometryHitTestPathGeometry) /// TreatAsSafe - net effect of this is to checking the relationship between two geometries. So it's considered safe. /// [SecurityCritical, SecurityTreatAsSafe] internal static IntersectionDetail HitTestWithPathGeometry( Geometry geometry1, Geometry geometry2, double tolerance, ToleranceType type) { IntersectionDetail detail = IntersectionDetail.NotCalculated; unsafe { PathGeometryData data1 = geometry1.GetPathGeometryData(); PathGeometryData data2 = geometry2.GetPathGeometryData(); fixed (byte *pbPathData1 = data1.SerializedData) { Debug.Assert(pbPathData1 != (byte*)0); fixed (byte *pbPathData2 = data2.SerializedData) { Debug.Assert(pbPathData2 != (byte*)0); int hr = MilCoreApi.MilUtility_PathGeometryHitTestPathGeometry( &data1.Matrix, data1.FillRule, pbPathData1, data1.Size, &data2.Matrix, data2.FillRule, pbPathData2, data2.Size, tolerance, type == ToleranceType.Relative, &detail); if (hr == (int)MILErrors.MILERR_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. detail = IntersectionDetail.Empty; } else { HRESULT.Check(hr); } } } } Debug.Assert(detail != IntersectionDetail.NotCalculated); return detail; } #endregion #region IsEmpty ////// Returns true if this geometry is empty /// public override bool IsEmpty() { PathFigureCollection figures = Figures; return (figures == null) || (figures.Count <= 0); } #endregion ////// Returns true if this geometry may have curved segments /// public override bool MayHaveCurves() { PathFigureCollection figures = Figures; int count = (figures != null) ? figures.Count : 0; for (int i=0; i/// GetAsPathGeometry - return a PathGeometry version of this Geometry /// internal override PathGeometry GetAsPathGeometry() { return CloneCurrentValue(); } /// /// Creates a string representation of this object based on the format string /// and IFormatProvider passed in. /// If the provider is null, the CurrentCulture is used. /// See the documentation for IFormattable for more information. /// ////// A string representation of this object. /// internal override string ConvertToString(string format, IFormatProvider provider) { PathFigureCollection figures = Figures; FillRule fillRule = FillRule; string figuresString = String.Empty; if (figures != null) { figuresString = figures.ConvertToString(format, provider); } if (fillRule != FillRule.EvenOdd) { return "F1" + figuresString; } else { return figuresString; } } internal void SetDirty() { _flags = PathGeometryInternalFlags.Dirty; } ////// GetPathGeometryData - returns a struct which contains this Geometry represented /// as a path geometry's serialized format. /// internal override PathGeometryData GetPathGeometryData() { PathGeometryData data = new PathGeometryData(); data.FillRule = FillRule; data.Matrix = CompositionResourceManager.TransformToMIL_MATRIX3X2D(Transform); if (IsObviouslyEmpty()) { return Geometry.GetEmptyPathGeometryData(); } ByteStreamGeometryContext ctx = new ByteStreamGeometryContext(); PathFigureCollection figures = Figures; int figureCount = figures == null ? 0 : figures.Count; for (int i = 0; i < figureCount; i++) { figures.Internal_GetItem(i).SerializeData(ctx); } ctx.Close(); data.SerializedData = ctx.GetData(); return data; } ////// Critical: This code accesses unsafe code blocks /// TreatAsSafe: This code does is safe to call and calling a channel with pointers is ok /// [SecurityCritical,SecurityTreatAsSafe] private void ManualUpdateResource(DUCE.Channel channel, bool skipOnChannelCheck) { // If we're told we can skip the channel check, then we must be on channel Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel)); if (skipOnChannelCheck || _duceResource.IsOnChannel(channel)) { checked { Transform vTransform = Transform; // Obtain handles for properties that implement DUCE.IResource DUCE.ResourceHandle hTransform; if (vTransform == null || Object.ReferenceEquals(vTransform, Transform.Identity) ) { hTransform = DUCE.ResourceHandle.Null; } else { hTransform = ((DUCE.IResource)vTransform).GetHandle(channel); } DUCE.MILCMD_PATHGEOMETRY data; data.Type = MILCMD.MilCmdPathGeometry; data.Handle = _duceResource.GetHandle(channel); data.hTransform = hTransform; data.FillRule = FillRule; PathGeometryData pathData = GetPathGeometryData(); data.FiguresSize = pathData.Size; unsafe { channel.BeginCommand( (byte*)&data, sizeof(DUCE.MILCMD_PATHGEOMETRY), (int)data.FiguresSize ); fixed (byte *pPathData = pathData.SerializedData) { channel.AppendCommandData(pPathData, (int)data.FiguresSize); } } channel.EndCommand(); } } } internal override void TransformPropertyChangedHook(DependencyPropertyChangedEventArgs e) { // PathGeometry caches the transformed bounds. We hook the changed event // on the Transformed bounds so we can clear the cache. if ((_flags & PathGeometryInternalFlags.BoundsValid) != 0) { SetDirty(); // The UCE slave already has a notifier registered on its transform to // invalidate its cache. No need to call InvalidateResource() here to // marshal the MIL_PATHGEOMETRY.Flags. } } internal void FiguresPropertyChangedHook(DependencyPropertyChangedEventArgs e) { // This is necessary to invalidate the cached bounds. SetDirty(); } #endregion #region Data internal PathGeometryInternalFlags _flags = PathGeometryInternalFlags.None; internal MIL_RECTD_RB _bounds; // Cached Bounds #endregion } #endregion } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DelegatingStream.cs
- FileStream.cs
- EmptyReadOnlyDictionaryInternal.cs
- XhtmlCssHandler.cs
- mediaclock.cs
- CryptoProvider.cs
- LineVisual.cs
- ComponentChangedEvent.cs
- validationstate.cs
- Type.cs
- BaseResourcesBuildProvider.cs
- TimeSpanMinutesConverter.cs
- ToolStripItemImageRenderEventArgs.cs
- TextDecoration.cs
- CommandLineParser.cs
- ModelServiceImpl.cs
- ExpressionBindings.cs
- StackSpiller.Generated.cs
- Lease.cs
- LabelTarget.cs
- CodeNamespace.cs
- QuaternionAnimation.cs
- Calendar.cs
- TextModifierScope.cs
- ItemCheckEvent.cs
- SspiSecurityTokenParameters.cs
- IProvider.cs
- WeakReferenceKey.cs
- TypeKeyValue.cs
- WebServiceTypeData.cs
- AssemblyNameProxy.cs
- ControlCachePolicy.cs
- EventLog.cs
- DoubleUtil.cs
- Number.cs
- InvalidDataException.cs
- DesignerVerbCollection.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- PagesChangedEventArgs.cs
- CommandID.cs
- MethodCallTranslator.cs
- TypeContext.cs
- ResourcePermissionBase.cs
- MiniModule.cs
- DictionaryMarkupSerializer.cs
- DES.cs
- SqlParameterCollection.cs
- SendActivityDesigner.cs
- PolyBezierSegment.cs
- SkipStoryboardToFill.cs
- RequestQueue.cs
- SettingsSavedEventArgs.cs
- TextWriterTraceListener.cs
- SessionStateSection.cs
- TimeSpanValidator.cs
- BevelBitmapEffect.cs
- FillBehavior.cs
- SortKey.cs
- WindowsComboBox.cs
- HttpCachePolicy.cs
- WebPartVerb.cs
- BinaryWriter.cs
- XmlSchemaType.cs
- AtomMaterializerLog.cs
- HostingEnvironment.cs
- LateBoundBitmapDecoder.cs
- Point3DCollection.cs
- NotCondition.cs
- DataListCommandEventArgs.cs
- CompositeControl.cs
- DbDataReader.cs
- GAC.cs
- PointLightBase.cs
- SerialPort.cs
- FirstMatchCodeGroup.cs
- MailMessageEventArgs.cs
- DisableDpiAwarenessAttribute.cs
- ColumnBinding.cs
- PerformanceCounterLib.cs
- XmlExpressionDumper.cs
- MarginsConverter.cs
- ScrollChrome.cs
- CompilerWrapper.cs
- Quaternion.cs
- ClientConfigurationSystem.cs
- DataGridViewCheckBoxCell.cs
- ReadOnlyDataSource.cs
- ByteViewer.cs
- StatusBarItem.cs
- PropertyGeneratedEventArgs.cs
- TCEAdapterGenerator.cs
- MsmqReceiveParameters.cs
- VScrollProperties.cs
- PolicyImporterElement.cs
- CheckBoxBaseAdapter.cs
- PointLightBase.cs
- SHA256.cs
- Logging.cs
- EntityObject.cs
- Accessors.cs