Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / System / Windows / Media / ByteStreamGeometryContext.cs / 1 / ByteStreamGeometryContext.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // This class is used by the StreamGeometry class to generate an inlined, // flattened geometry stream. // //--------------------------------------------------------------------------- using MS.Utility; using MS.Internal; using MS.Internal.PresentationCore; using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Composition; using System.Windows.Media.Effects; using System.Windows.Media.Imaging; using System.Windows.Media.Media3D; using System.Diagnostics; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using System.Security; using System.Security.Permissions; namespace System.Windows.Media { ////// ByteStreamGeometryContext /// internal class ByteStreamGeometryContext : CapacityStreamGeometryContext { #region Constructors ////// Creates a geometry stream context. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] internal ByteStreamGeometryContext() { // For now, we just write this into the stream. We'll update its fields as we go. MIL_PATHGEOMETRY tempPath = new MIL_PATHGEOMETRY(); unsafe { AppendData((byte*)&tempPath, sizeof(MIL_PATHGEOMETRY)); // Initialize the size to include the MIL_PATHGEOMETRY itself // All other fields are intentionally left as 0; _currentPathGeometryData.Size = (uint)sizeof(MIL_PATHGEOMETRY); } } #endregion Constructors #region Public Methods ////// Closes the StreamContext and flushes the content. /// Afterwards the StreamContext can not be used anymore. /// This call does not require all Push calls to have been Popped. /// ////// This call is illegal if this object has already been closed or disposed. /// public override void Close() { VerifyApi(); ((IDisposable)this).Dispose(); } ////// BeginFigure - Start a new figure. /// ////// Critical - it has an unsafe block /// PublicOK - This function takes the address of a stack variable. /// [SecurityCritical] public override void BeginFigure(Point startPoint, bool isFilled, bool isClosed) { VerifyApi(); // Don't forget to close out the previous segment/figure FinishFigure(); // Remember the location - we set this only after successful allocation in case it throws // and we're re-entered. int oldOffset = _currOffset; MIL_PATHFIGURE tempFigure; unsafe { AppendData((byte*)&tempFigure, sizeof(MIL_PATHFIGURE)); } _currentPathFigureDataOffset = oldOffset; _currentPathFigureData.StartPoint = startPoint; _currentPathFigureData.Flags |= isFilled ? MilPathFigureFlags.IsFillable : 0; _currentPathFigureData.Flags |= isClosed ? MilPathFigureFlags.IsClosed : 0; _currentPathFigureData.BackSize = _lastFigureSize; _currentPathFigureData.Size = (UInt32)(_currOffset - _currentPathFigureDataOffset); } ////// LineTo - append a LineTo to the current figure. /// public override void LineTo(Point point, bool isStroked, bool isSmoothJoin) { VerifyApi(); _scratchForLine[0] = point; GenericPolyTo(_scratchForLine, isStroked, isSmoothJoin, false /* does not have curves */, 1 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyLine); } ////// QuadraticBezierTo - append a QuadraticBezierTo to the current figure. /// public override void QuadraticBezierTo(Point point1, Point point2, bool isStroked, bool isSmoothJoin) { VerifyApi(); _scratchForQuadraticBezier[0] = point1; _scratchForQuadraticBezier[1] = point2; GenericPolyTo(_scratchForQuadraticBezier, isStroked, isSmoothJoin, true /* has curves */, 2 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier); } ////// BezierTo - apply a BezierTo to the current figure. /// public override void BezierTo(Point point1, Point point2, Point point3, bool isStroked, bool isSmoothJoin) { VerifyApi(); _scratchForBezier[0] = point1; _scratchForBezier[1] = point2; _scratchForBezier[2] = point3; GenericPolyTo(_scratchForBezier, isStroked, isSmoothJoin, true /* has curves */, 3 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyBezier); } ////// PolyLineTo - append a PolyLineTo to the current figure. /// public override void PolyLineTo(IListpoints, bool isStroked, bool isSmoothJoin) { VerifyApi(); GenericPolyTo(points, isStroked, isSmoothJoin, false /* does not have curves */, 1 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyLine); } /// /// PolyQuadraticBezierTo - append a PolyQuadraticBezierTo to the current figure. /// public override void PolyQuadraticBezierTo(IListpoints, bool isStroked, bool isSmoothJoin) { VerifyApi(); GenericPolyTo(points, isStroked, isSmoothJoin, true /* has curves */, 2 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier); } /// /// PolyBezierTo - append a PolyBezierTo to the current figure. /// public override void PolyBezierTo(IListpoints, bool isStroked, bool isSmoothJoin) { VerifyApi(); GenericPolyTo(points, isStroked, isSmoothJoin, true /* has curves */, 3 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyBezier); } /// /// ArcTo - append an ArcTo to the current figure. /// ////// Critical - it has an unsafe block /// PublicOk - This function takes the address of a stack variable. /// [SecurityCritical] public override void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked, bool isSmoothJoin) { VerifyApi(); if (_currentPathFigureDataOffset == -1) { throw new InvalidOperationException(SR.Get(SRID.StreamGeometry_NeedBeginFigure)); } FinishSegment(); MIL_SEGMENT_ARC arcToSegment = new MIL_SEGMENT_ARC(); arcToSegment.Type = MIL_SEGMENT_TYPE.MilSegmentArc; arcToSegment.Flags |= isStroked ? 0 : MILCoreSegFlags.SegIsAGap; arcToSegment.Flags |= isSmoothJoin ? MILCoreSegFlags.SegSmoothJoin : 0; arcToSegment.Flags |= MILCoreSegFlags.SegIsCurved; arcToSegment.BackSize = _lastSegmentSize; arcToSegment.Point = point; arcToSegment.Size = size; arcToSegment.XRotation = rotationAngle; arcToSegment.LargeArc = (uint)(isLargeArc ? 1 : 0); arcToSegment.Sweep = (uint)(sweepDirection == SweepDirection.Clockwise ? 1 : 0); int offsetToArcToSegment = _currOffset; unsafe { AppendData((byte*)(&arcToSegment), sizeof(MIL_SEGMENT_ARC)); _lastSegmentSize = (UInt32)sizeof(MIL_SEGMENT_ARC); } // Update the current path figure data _currentPathFigureData.Flags |= isStroked ? 0 : MilPathFigureFlags.HasGaps; _currentPathFigureData.Flags |= MilPathFigureFlags.HasCurves; _currentPathFigureData.Count++; // Always keep the OffsetToLastSegment and Size accurate _currentPathFigureData.Size = (UInt32)(_currOffset - _currentPathFigureDataOffset); _currentPathFigureData.OffsetToLastSegment = (UInt32)(offsetToArcToSegment - _currentPathFigureDataOffset); } #endregion Public Methods #region Internal Methods ////// GetData - Retrieves the data stream built by this Context. /// internal byte[] GetData() { ShrinkToFit(); return _chunkList[0]; } override internal void SetClosedState(bool isClosed) { if (_currentPathFigureDataOffset == -1) { throw new InvalidOperationException(SR.Get(SRID.StreamGeometry_NeedBeginFigure)); } // Clear out the IsClosed flag, then set it as appropriate. _currentPathFigureData.Flags &= ~MilPathFigureFlags.IsClosed; _currentPathFigureData.Flags |= isClosed ? MilPathFigureFlags.IsClosed : 0; } #endregion Internal Methods #region Private Methods ////// This verifies that the API can be called at this time. /// private void VerifyApi() { VerifyAccess(); if (_disposed) { throw new ObjectDisposedException("ByteStreamGeometryContext"); } } ////// CloseCore - This method is implemented by derived classes to hand off the content /// to its eventual destination. /// protected virtual void CloseCore(byte[] geometryData) {} ////// This is the same as the Close call: /// Closes the Context and flushes the content. /// Afterwards the Context can not be used anymore. /// This call does not require all Push calls to have been Popped. /// ////// This call is illegal if this object has already been closed or disposed. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] internal override void DisposeCore() { if (!_disposed) { FinishFigure(); unsafe { // We have to have at least this much data already in the stream checked { Debug.Assert(sizeof(MIL_PATHGEOMETRY) <= _currOffset); Debug.Assert(_currentPathGeometryData.Size == (uint)_currOffset); } fixed (MIL_PATHGEOMETRY* pCurrentPathGeometryData = &_currentPathGeometryData) { OverwriteData((byte *)pCurrentPathGeometryData, 0, sizeof(MIL_PATHGEOMETRY)); } } ShrinkToFit(); CloseCore(_chunkList[0]); _disposed = true; } } ////// ReadData - reads data from a specified location in the buffer /// /// /// byte* pointing to at least cbDataSize bytes into which will be copied the desired data /// /// int - the offset, in bytes, of the requested data. Must be >= 0. /// int - the size, in bytes, of the requested data. Must be >= 0. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void ReadData(byte* pbData, int bufferOffset, int cbDataSize) { Invariant.Assert(cbDataSize >= 0); Invariant.Assert(bufferOffset >= 0); // // checked { Invariant.Assert(_currOffset >= bufferOffset+cbDataSize); } ReadWriteData(true /* reading */, pbData, cbDataSize, 0, ref bufferOffset); } ////// OverwriteData - overwrite data in the buffer. /// /// /// byte* pointing to at least cbDataSize bytes which will be copied to the stream. /// /// int - the offset, in bytes, at which the data should be writen. Must be >= 0. /// int - the size, in bytes, of pbData. Must be >= 0. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void OverwriteData(byte* pbData, int bufferOffset, int cbDataSize) { Invariant.Assert(cbDataSize >= 0); checked { int newOffset = bufferOffset + cbDataSize; Invariant.Assert(newOffset <= _currOffset); } ReadWriteData(false /* writing */, pbData, cbDataSize, 0, ref bufferOffset); } ////// AppendData - append data to the buffer. /// /// /// byte* pointing to at least cbDataSize bytes which will be copied to the stream. /// /// int - the size, in bytes, of pbData. Must be >= 0. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void AppendData(byte* pbData, int cbDataSize) { Invariant.Assert(cbDataSize >= 0); int newOffset; checked { newOffset = _currOffset + cbDataSize; } if (_chunkList.Count == 0) { _chunkList.Add(new byte[c_defaultChunkSize]); } ReadWriteData(false /* writing */, pbData, cbDataSize, _chunkList.Count-1, ref _currChunkOffset); _currOffset = newOffset; } ////// ShrinkToFit - Shrink the data to fit in exactly one chunk /// ////// Critical: This code has unsafe code and dereferences a pointer /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] internal void ShrinkToFit() { Debug.Assert(_chunkList.Count != 0); if (_chunkList.Count > 1 || _chunkList[0].Length != _currOffset) { byte [] buffer = new byte[_currOffset]; unsafe { fixed (byte *pbData = buffer) { ReadData(pbData, 0, _currOffset); } _chunkList = new FrugalStructList(); _chunkList.Add(buffer); } } } /// /// ReadWriteData - read from/write to buffer. /// /// bool - is the buffer read from or written to? /// /// byte* pointing to at least cbDataSize bytes which will be copied to/from the stream. /// /// int - the size, in bytes, of pbData. Must be >= 0. /// the current chunk to start writing to/reading from /// in/out: the current position in the current chunk. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void ReadWriteData(bool reading, byte* pbData, int cbDataSize, int currentChunk, ref int bufferOffset) { Invariant.Assert(cbDataSize >= 0); // Skip past irrelevant chunks while (bufferOffset > _chunkList[currentChunk].Length) { bufferOffset -= _chunkList[currentChunk].Length; currentChunk++; } // Arithmetic should be checked by the caller (AppendData or OverwriteData) while (cbDataSize > 0) { int cbDataForThisChunk = Math.Min(cbDataSize, _chunkList[currentChunk].Length - bufferOffset); if (cbDataForThisChunk > 0) { // At this point, _buffer must be non-null and // _buffer.Length must be >= newOffset Invariant.Assert((_chunkList[currentChunk] != null) && (_chunkList[currentChunk].Length >= bufferOffset + cbDataForThisChunk)); // Also, because pinning a 0-length buffer fails, we assert this too. Invariant.Assert(_chunkList[currentChunk].Length > 0); if (reading) { Marshal.Copy(_chunkList[currentChunk], bufferOffset, (IntPtr)pbData, cbDataForThisChunk); } else { Marshal.Copy((IntPtr)pbData, _chunkList[currentChunk], bufferOffset, cbDataForThisChunk); } cbDataSize -= cbDataForThisChunk; pbData += cbDataForThisChunk; bufferOffset += cbDataForThisChunk; } if (cbDataSize > 0) { checked {currentChunk++;} if (_chunkList.Count == currentChunk) { Invariant.Assert(!reading); // Exponential growth early on. Later, linear growth. int newChunkSize = Math.Min(2*_chunkList[_chunkList.Count-1].Length, c_maxChunkSize); _chunkList.Add(new byte[newChunkSize]); } bufferOffset = 0; } } } ////// FinishFigure - called to completed any outstanding Figure which may be present. /// If there is one, we write its data into the stream at the appropriate offset /// and update the path's flags/size/figure count/etc based on this Figure. /// After this call, a new figure needs to be started for any segment-building APIs /// to be legal. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] private void FinishFigure() { if (_currentPathFigureDataOffset != -1) { FinishSegment(); unsafe { // We have to have at least this much data already in the stream checked { Debug.Assert(_currentPathFigureDataOffset + sizeof(MIL_PATHFIGURE) <= _currOffset); } fixed (MIL_PATHFIGURE* pCurrentPathFigureData = &_currentPathFigureData) { OverwriteData((byte *)pCurrentPathFigureData, _currentPathFigureDataOffset, sizeof(MIL_PATHFIGURE)); } } _currentPathGeometryData.Flags |= ((_currentPathFigureData.Flags & MilPathFigureFlags.HasCurves) != 0) ? MilPathGeometryFlags.HasCurves : 0; _currentPathGeometryData.Flags |= ((_currentPathFigureData.Flags & MilPathFigureFlags.HasGaps) != 0) ? MilPathGeometryFlags.HasGaps : 0; _currentPathGeometryData.Flags |= ((_currentPathFigureData.Flags & MilPathFigureFlags.IsFillable) == 0) ? MilPathGeometryFlags.HasHollows : 0; _currentPathGeometryData.FigureCount++; _currentPathGeometryData.Size = (UInt32)(_currOffset); _lastFigureSize = _currentPathFigureData.Size; // Initialize _currentPathFigureData (this really just 0's out the memory) _currentPathFigureDataOffset = -1; _currentPathFigureData = new MIL_PATHFIGURE(); // We must also clear _lastSegmentSize, since there is now no "last segment" _lastSegmentSize = 0; } } ////// FinishSegment - called to completed any outstanding Segment which may be present. /// If there is one, we write its data into the stream at the appropriate offset /// and update the figure's flags/size/segment count/etc based on this Segment. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] private void FinishSegment() { if (_currentPolySegmentDataOffset != -1) { unsafe { // We have to have at least this much data already in the stream checked { Debug.Assert(_currentPolySegmentDataOffset + sizeof(MIL_SEGMENT_POLY) <= _currOffset); } fixed (MIL_SEGMENT_POLY* pCurrentPolySegmentData = &_currentPolySegmentData) { OverwriteData((byte *)pCurrentPolySegmentData, _currentPolySegmentDataOffset, sizeof(MIL_SEGMENT_POLY)); } _lastSegmentSize = (UInt32)(sizeof(MIL_SEGMENT_POLY) + (sizeof(Point) * _currentPolySegmentData.Count)); } // Update the current path figure data if ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsAGap) != 0) { _currentPathFigureData.Flags |= MilPathFigureFlags.HasGaps; } if ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsCurved) != 0) { _currentPathFigureData.Flags |= MilPathFigureFlags.HasCurves; } _currentPathFigureData.Count++; // Always keep the OffsetToLastSegment and Size accurate _currentPathFigureData.Size = (UInt32)(_currOffset - _currentPathFigureDataOffset); _currentPathFigureData.OffsetToLastSegment = (UInt32)(_currentPolySegmentDataOffset - _currentPathFigureDataOffset); // Initialize _currentPolySegmentData (this really just 0's out the memory) _currentPolySegmentDataOffset = -1; _currentPolySegmentData = new MIL_SEGMENT_POLY(); } } ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] private void GenericPolyTo(IListpoints, bool isStroked, bool isSmoothJoin, bool hasCurves, int pointCountMultiple, MIL_SEGMENT_TYPE segmentType) { if (_currentPathFigureDataOffset == -1) { throw new InvalidOperationException(SR.Get(SRID.StreamGeometry_NeedBeginFigure)); } if (points == null) { return; } int count = points.Count; count -= count % pointCountMultiple; if (count <= 0) { return; } // Do we need to finish the old segment? // Yes, if there is an old segment and if its type or flags are different from // the new segment. if ( (_currentPolySegmentDataOffset != -1) && ( (_currentPolySegmentData.Type != segmentType) || ( ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsAGap) == 0) != isStroked ) || ( ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegSmoothJoin) != 0) != isSmoothJoin ) ) ) { FinishSegment(); } // Do we need to start a new segment? if (_currentPolySegmentDataOffset == -1) { MIL_SEGMENT_POLY tempSegment; int oldOffset = _currOffset; unsafe { AppendData((byte*)&tempSegment, sizeof(MIL_SEGMENT_POLY)); } _currentPolySegmentDataOffset = oldOffset; _currentPolySegmentData.Type = segmentType; _currentPolySegmentData.Flags |= isStroked ? 0 : MILCoreSegFlags.SegIsAGap; _currentPolySegmentData.Flags |= hasCurves ? MILCoreSegFlags.SegIsCurved : 0; _currentPolySegmentData.Flags |= isSmoothJoin ? MILCoreSegFlags.SegSmoothJoin : 0; _currentPolySegmentData.BackSize = _lastSegmentSize; } // Assert that everything is ready to go Debug.Assert((_currentPolySegmentDataOffset != -1) && (_currentPolySegmentData.Type == segmentType) && (((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsAGap) == 0) == isStroked) && (((_currentPolySegmentData.Flags & MILCoreSegFlags.SegSmoothJoin) != 0) == isSmoothJoin)); for (int i = 0; i < count; i++) { Point p = points[i]; unsafe { AppendData((byte*)&p, sizeof(Point)); } _currentPolySegmentData.Count++; } } #endregion Private Methods #region Fields private bool _disposed; private int _currChunkOffset; FrugalStructList _chunkList; private int _currOffset; private MIL_PATHGEOMETRY _currentPathGeometryData; private MIL_PATHFIGURE _currentPathFigureData; private int _currentPathFigureDataOffset = -1; private MIL_SEGMENT_POLY _currentPolySegmentData; private int _currentPolySegmentDataOffset = -1; private UInt32 _lastSegmentSize = 0; private UInt32 _lastFigureSize = 0; private Point[] _scratchForLine = new Point[1]; private Point[] _scratchForQuadraticBezier = new Point[2]; private Point[] _scratchForBezier = new Point[3]; private const int c_defaultChunkSize = 2*1024; private const int c_maxChunkSize = 1024*1024; #endregion Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // // Copyright (C) Microsoft Corporation. All rights reserved. // // // This class is used by the StreamGeometry class to generate an inlined, // flattened geometry stream. // //--------------------------------------------------------------------------- using MS.Utility; using MS.Internal; using MS.Internal.PresentationCore; using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows.Threading; using System.Windows; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Composition; using System.Windows.Media.Effects; using System.Windows.Media.Imaging; using System.Windows.Media.Media3D; using System.Diagnostics; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using System.Security; using System.Security.Permissions; namespace System.Windows.Media { ////// ByteStreamGeometryContext /// internal class ByteStreamGeometryContext : CapacityStreamGeometryContext { #region Constructors ////// Creates a geometry stream context. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] internal ByteStreamGeometryContext() { // For now, we just write this into the stream. We'll update its fields as we go. MIL_PATHGEOMETRY tempPath = new MIL_PATHGEOMETRY(); unsafe { AppendData((byte*)&tempPath, sizeof(MIL_PATHGEOMETRY)); // Initialize the size to include the MIL_PATHGEOMETRY itself // All other fields are intentionally left as 0; _currentPathGeometryData.Size = (uint)sizeof(MIL_PATHGEOMETRY); } } #endregion Constructors #region Public Methods ////// Closes the StreamContext and flushes the content. /// Afterwards the StreamContext can not be used anymore. /// This call does not require all Push calls to have been Popped. /// ////// This call is illegal if this object has already been closed or disposed. /// public override void Close() { VerifyApi(); ((IDisposable)this).Dispose(); } ////// BeginFigure - Start a new figure. /// ////// Critical - it has an unsafe block /// PublicOK - This function takes the address of a stack variable. /// [SecurityCritical] public override void BeginFigure(Point startPoint, bool isFilled, bool isClosed) { VerifyApi(); // Don't forget to close out the previous segment/figure FinishFigure(); // Remember the location - we set this only after successful allocation in case it throws // and we're re-entered. int oldOffset = _currOffset; MIL_PATHFIGURE tempFigure; unsafe { AppendData((byte*)&tempFigure, sizeof(MIL_PATHFIGURE)); } _currentPathFigureDataOffset = oldOffset; _currentPathFigureData.StartPoint = startPoint; _currentPathFigureData.Flags |= isFilled ? MilPathFigureFlags.IsFillable : 0; _currentPathFigureData.Flags |= isClosed ? MilPathFigureFlags.IsClosed : 0; _currentPathFigureData.BackSize = _lastFigureSize; _currentPathFigureData.Size = (UInt32)(_currOffset - _currentPathFigureDataOffset); } ////// LineTo - append a LineTo to the current figure. /// public override void LineTo(Point point, bool isStroked, bool isSmoothJoin) { VerifyApi(); _scratchForLine[0] = point; GenericPolyTo(_scratchForLine, isStroked, isSmoothJoin, false /* does not have curves */, 1 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyLine); } ////// QuadraticBezierTo - append a QuadraticBezierTo to the current figure. /// public override void QuadraticBezierTo(Point point1, Point point2, bool isStroked, bool isSmoothJoin) { VerifyApi(); _scratchForQuadraticBezier[0] = point1; _scratchForQuadraticBezier[1] = point2; GenericPolyTo(_scratchForQuadraticBezier, isStroked, isSmoothJoin, true /* has curves */, 2 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier); } ////// BezierTo - apply a BezierTo to the current figure. /// public override void BezierTo(Point point1, Point point2, Point point3, bool isStroked, bool isSmoothJoin) { VerifyApi(); _scratchForBezier[0] = point1; _scratchForBezier[1] = point2; _scratchForBezier[2] = point3; GenericPolyTo(_scratchForBezier, isStroked, isSmoothJoin, true /* has curves */, 3 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyBezier); } ////// PolyLineTo - append a PolyLineTo to the current figure. /// public override void PolyLineTo(IListpoints, bool isStroked, bool isSmoothJoin) { VerifyApi(); GenericPolyTo(points, isStroked, isSmoothJoin, false /* does not have curves */, 1 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyLine); } /// /// PolyQuadraticBezierTo - append a PolyQuadraticBezierTo to the current figure. /// public override void PolyQuadraticBezierTo(IListpoints, bool isStroked, bool isSmoothJoin) { VerifyApi(); GenericPolyTo(points, isStroked, isSmoothJoin, true /* has curves */, 2 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyQuadraticBezier); } /// /// PolyBezierTo - append a PolyBezierTo to the current figure. /// public override void PolyBezierTo(IListpoints, bool isStroked, bool isSmoothJoin) { VerifyApi(); GenericPolyTo(points, isStroked, isSmoothJoin, true /* has curves */, 3 /* pointCountMultiple */, MIL_SEGMENT_TYPE.MilSegmentPolyBezier); } /// /// ArcTo - append an ArcTo to the current figure. /// ////// Critical - it has an unsafe block /// PublicOk - This function takes the address of a stack variable. /// [SecurityCritical] public override void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection, bool isStroked, bool isSmoothJoin) { VerifyApi(); if (_currentPathFigureDataOffset == -1) { throw new InvalidOperationException(SR.Get(SRID.StreamGeometry_NeedBeginFigure)); } FinishSegment(); MIL_SEGMENT_ARC arcToSegment = new MIL_SEGMENT_ARC(); arcToSegment.Type = MIL_SEGMENT_TYPE.MilSegmentArc; arcToSegment.Flags |= isStroked ? 0 : MILCoreSegFlags.SegIsAGap; arcToSegment.Flags |= isSmoothJoin ? MILCoreSegFlags.SegSmoothJoin : 0; arcToSegment.Flags |= MILCoreSegFlags.SegIsCurved; arcToSegment.BackSize = _lastSegmentSize; arcToSegment.Point = point; arcToSegment.Size = size; arcToSegment.XRotation = rotationAngle; arcToSegment.LargeArc = (uint)(isLargeArc ? 1 : 0); arcToSegment.Sweep = (uint)(sweepDirection == SweepDirection.Clockwise ? 1 : 0); int offsetToArcToSegment = _currOffset; unsafe { AppendData((byte*)(&arcToSegment), sizeof(MIL_SEGMENT_ARC)); _lastSegmentSize = (UInt32)sizeof(MIL_SEGMENT_ARC); } // Update the current path figure data _currentPathFigureData.Flags |= isStroked ? 0 : MilPathFigureFlags.HasGaps; _currentPathFigureData.Flags |= MilPathFigureFlags.HasCurves; _currentPathFigureData.Count++; // Always keep the OffsetToLastSegment and Size accurate _currentPathFigureData.Size = (UInt32)(_currOffset - _currentPathFigureDataOffset); _currentPathFigureData.OffsetToLastSegment = (UInt32)(offsetToArcToSegment - _currentPathFigureDataOffset); } #endregion Public Methods #region Internal Methods ////// GetData - Retrieves the data stream built by this Context. /// internal byte[] GetData() { ShrinkToFit(); return _chunkList[0]; } override internal void SetClosedState(bool isClosed) { if (_currentPathFigureDataOffset == -1) { throw new InvalidOperationException(SR.Get(SRID.StreamGeometry_NeedBeginFigure)); } // Clear out the IsClosed flag, then set it as appropriate. _currentPathFigureData.Flags &= ~MilPathFigureFlags.IsClosed; _currentPathFigureData.Flags |= isClosed ? MilPathFigureFlags.IsClosed : 0; } #endregion Internal Methods #region Private Methods ////// This verifies that the API can be called at this time. /// private void VerifyApi() { VerifyAccess(); if (_disposed) { throw new ObjectDisposedException("ByteStreamGeometryContext"); } } ////// CloseCore - This method is implemented by derived classes to hand off the content /// to its eventual destination. /// protected virtual void CloseCore(byte[] geometryData) {} ////// This is the same as the Close call: /// Closes the Context and flushes the content. /// Afterwards the Context can not be used anymore. /// This call does not require all Push calls to have been Popped. /// ////// This call is illegal if this object has already been closed or disposed. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] internal override void DisposeCore() { if (!_disposed) { FinishFigure(); unsafe { // We have to have at least this much data already in the stream checked { Debug.Assert(sizeof(MIL_PATHGEOMETRY) <= _currOffset); Debug.Assert(_currentPathGeometryData.Size == (uint)_currOffset); } fixed (MIL_PATHGEOMETRY* pCurrentPathGeometryData = &_currentPathGeometryData) { OverwriteData((byte *)pCurrentPathGeometryData, 0, sizeof(MIL_PATHGEOMETRY)); } } ShrinkToFit(); CloseCore(_chunkList[0]); _disposed = true; } } ////// ReadData - reads data from a specified location in the buffer /// /// /// byte* pointing to at least cbDataSize bytes into which will be copied the desired data /// /// int - the offset, in bytes, of the requested data. Must be >= 0. /// int - the size, in bytes, of the requested data. Must be >= 0. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void ReadData(byte* pbData, int bufferOffset, int cbDataSize) { Invariant.Assert(cbDataSize >= 0); Invariant.Assert(bufferOffset >= 0); // // checked { Invariant.Assert(_currOffset >= bufferOffset+cbDataSize); } ReadWriteData(true /* reading */, pbData, cbDataSize, 0, ref bufferOffset); } ////// OverwriteData - overwrite data in the buffer. /// /// /// byte* pointing to at least cbDataSize bytes which will be copied to the stream. /// /// int - the offset, in bytes, at which the data should be writen. Must be >= 0. /// int - the size, in bytes, of pbData. Must be >= 0. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void OverwriteData(byte* pbData, int bufferOffset, int cbDataSize) { Invariant.Assert(cbDataSize >= 0); checked { int newOffset = bufferOffset + cbDataSize; Invariant.Assert(newOffset <= _currOffset); } ReadWriteData(false /* writing */, pbData, cbDataSize, 0, ref bufferOffset); } ////// AppendData - append data to the buffer. /// /// /// byte* pointing to at least cbDataSize bytes which will be copied to the stream. /// /// int - the size, in bytes, of pbData. Must be >= 0. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void AppendData(byte* pbData, int cbDataSize) { Invariant.Assert(cbDataSize >= 0); int newOffset; checked { newOffset = _currOffset + cbDataSize; } if (_chunkList.Count == 0) { _chunkList.Add(new byte[c_defaultChunkSize]); } ReadWriteData(false /* writing */, pbData, cbDataSize, _chunkList.Count-1, ref _currChunkOffset); _currOffset = newOffset; } ////// ShrinkToFit - Shrink the data to fit in exactly one chunk /// ////// Critical: This code has unsafe code and dereferences a pointer /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] internal void ShrinkToFit() { Debug.Assert(_chunkList.Count != 0); if (_chunkList.Count > 1 || _chunkList[0].Length != _currOffset) { byte [] buffer = new byte[_currOffset]; unsafe { fixed (byte *pbData = buffer) { ReadData(pbData, 0, _currOffset); } _chunkList = new FrugalStructList(); _chunkList.Add(buffer); } } } /// /// ReadWriteData - read from/write to buffer. /// /// bool - is the buffer read from or written to? /// /// byte* pointing to at least cbDataSize bytes which will be copied to/from the stream. /// /// int - the size, in bytes, of pbData. Must be >= 0. /// the current chunk to start writing to/reading from /// in/out: the current position in the current chunk. ////// Critical: This code has unsafe code and dereferences a pointer /// [SecurityCritical] private unsafe void ReadWriteData(bool reading, byte* pbData, int cbDataSize, int currentChunk, ref int bufferOffset) { Invariant.Assert(cbDataSize >= 0); // Skip past irrelevant chunks while (bufferOffset > _chunkList[currentChunk].Length) { bufferOffset -= _chunkList[currentChunk].Length; currentChunk++; } // Arithmetic should be checked by the caller (AppendData or OverwriteData) while (cbDataSize > 0) { int cbDataForThisChunk = Math.Min(cbDataSize, _chunkList[currentChunk].Length - bufferOffset); if (cbDataForThisChunk > 0) { // At this point, _buffer must be non-null and // _buffer.Length must be >= newOffset Invariant.Assert((_chunkList[currentChunk] != null) && (_chunkList[currentChunk].Length >= bufferOffset + cbDataForThisChunk)); // Also, because pinning a 0-length buffer fails, we assert this too. Invariant.Assert(_chunkList[currentChunk].Length > 0); if (reading) { Marshal.Copy(_chunkList[currentChunk], bufferOffset, (IntPtr)pbData, cbDataForThisChunk); } else { Marshal.Copy((IntPtr)pbData, _chunkList[currentChunk], bufferOffset, cbDataForThisChunk); } cbDataSize -= cbDataForThisChunk; pbData += cbDataForThisChunk; bufferOffset += cbDataForThisChunk; } if (cbDataSize > 0) { checked {currentChunk++;} if (_chunkList.Count == currentChunk) { Invariant.Assert(!reading); // Exponential growth early on. Later, linear growth. int newChunkSize = Math.Min(2*_chunkList[_chunkList.Count-1].Length, c_maxChunkSize); _chunkList.Add(new byte[newChunkSize]); } bufferOffset = 0; } } } ////// FinishFigure - called to completed any outstanding Figure which may be present. /// If there is one, we write its data into the stream at the appropriate offset /// and update the path's flags/size/figure count/etc based on this Figure. /// After this call, a new figure needs to be started for any segment-building APIs /// to be legal. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] private void FinishFigure() { if (_currentPathFigureDataOffset != -1) { FinishSegment(); unsafe { // We have to have at least this much data already in the stream checked { Debug.Assert(_currentPathFigureDataOffset + sizeof(MIL_PATHFIGURE) <= _currOffset); } fixed (MIL_PATHFIGURE* pCurrentPathFigureData = &_currentPathFigureData) { OverwriteData((byte *)pCurrentPathFigureData, _currentPathFigureDataOffset, sizeof(MIL_PATHFIGURE)); } } _currentPathGeometryData.Flags |= ((_currentPathFigureData.Flags & MilPathFigureFlags.HasCurves) != 0) ? MilPathGeometryFlags.HasCurves : 0; _currentPathGeometryData.Flags |= ((_currentPathFigureData.Flags & MilPathFigureFlags.HasGaps) != 0) ? MilPathGeometryFlags.HasGaps : 0; _currentPathGeometryData.Flags |= ((_currentPathFigureData.Flags & MilPathFigureFlags.IsFillable) == 0) ? MilPathGeometryFlags.HasHollows : 0; _currentPathGeometryData.FigureCount++; _currentPathGeometryData.Size = (UInt32)(_currOffset); _lastFigureSize = _currentPathFigureData.Size; // Initialize _currentPathFigureData (this really just 0's out the memory) _currentPathFigureDataOffset = -1; _currentPathFigureData = new MIL_PATHFIGURE(); // We must also clear _lastSegmentSize, since there is now no "last segment" _lastSegmentSize = 0; } } ////// FinishSegment - called to completed any outstanding Segment which may be present. /// If there is one, we write its data into the stream at the appropriate offset /// and update the figure's flags/size/segment count/etc based on this Segment. /// ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] private void FinishSegment() { if (_currentPolySegmentDataOffset != -1) { unsafe { // We have to have at least this much data already in the stream checked { Debug.Assert(_currentPolySegmentDataOffset + sizeof(MIL_SEGMENT_POLY) <= _currOffset); } fixed (MIL_SEGMENT_POLY* pCurrentPolySegmentData = &_currentPolySegmentData) { OverwriteData((byte *)pCurrentPolySegmentData, _currentPolySegmentDataOffset, sizeof(MIL_SEGMENT_POLY)); } _lastSegmentSize = (UInt32)(sizeof(MIL_SEGMENT_POLY) + (sizeof(Point) * _currentPolySegmentData.Count)); } // Update the current path figure data if ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsAGap) != 0) { _currentPathFigureData.Flags |= MilPathFigureFlags.HasGaps; } if ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsCurved) != 0) { _currentPathFigureData.Flags |= MilPathFigureFlags.HasCurves; } _currentPathFigureData.Count++; // Always keep the OffsetToLastSegment and Size accurate _currentPathFigureData.Size = (UInt32)(_currOffset - _currentPathFigureDataOffset); _currentPathFigureData.OffsetToLastSegment = (UInt32)(_currentPolySegmentDataOffset - _currentPathFigureDataOffset); // Initialize _currentPolySegmentData (this really just 0's out the memory) _currentPolySegmentDataOffset = -1; _currentPolySegmentData = new MIL_SEGMENT_POLY(); } } ////// Critical - it has an unsafe block /// TreatAsSafe - manipulating a buffer is considered safe /// [SecurityCritical, SecurityTreatAsSafe] private void GenericPolyTo(IListpoints, bool isStroked, bool isSmoothJoin, bool hasCurves, int pointCountMultiple, MIL_SEGMENT_TYPE segmentType) { if (_currentPathFigureDataOffset == -1) { throw new InvalidOperationException(SR.Get(SRID.StreamGeometry_NeedBeginFigure)); } if (points == null) { return; } int count = points.Count; count -= count % pointCountMultiple; if (count <= 0) { return; } // Do we need to finish the old segment? // Yes, if there is an old segment and if its type or flags are different from // the new segment. if ( (_currentPolySegmentDataOffset != -1) && ( (_currentPolySegmentData.Type != segmentType) || ( ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsAGap) == 0) != isStroked ) || ( ((_currentPolySegmentData.Flags & MILCoreSegFlags.SegSmoothJoin) != 0) != isSmoothJoin ) ) ) { FinishSegment(); } // Do we need to start a new segment? if (_currentPolySegmentDataOffset == -1) { MIL_SEGMENT_POLY tempSegment; int oldOffset = _currOffset; unsafe { AppendData((byte*)&tempSegment, sizeof(MIL_SEGMENT_POLY)); } _currentPolySegmentDataOffset = oldOffset; _currentPolySegmentData.Type = segmentType; _currentPolySegmentData.Flags |= isStroked ? 0 : MILCoreSegFlags.SegIsAGap; _currentPolySegmentData.Flags |= hasCurves ? MILCoreSegFlags.SegIsCurved : 0; _currentPolySegmentData.Flags |= isSmoothJoin ? MILCoreSegFlags.SegSmoothJoin : 0; _currentPolySegmentData.BackSize = _lastSegmentSize; } // Assert that everything is ready to go Debug.Assert((_currentPolySegmentDataOffset != -1) && (_currentPolySegmentData.Type == segmentType) && (((_currentPolySegmentData.Flags & MILCoreSegFlags.SegIsAGap) == 0) == isStroked) && (((_currentPolySegmentData.Flags & MILCoreSegFlags.SegSmoothJoin) != 0) == isSmoothJoin)); for (int i = 0; i < count; i++) { Point p = points[i]; unsafe { AppendData((byte*)&p, sizeof(Point)); } _currentPolySegmentData.Count++; } } #endregion Private Methods #region Fields private bool _disposed; private int _currChunkOffset; FrugalStructList _chunkList; private int _currOffset; private MIL_PATHGEOMETRY _currentPathGeometryData; private MIL_PATHFIGURE _currentPathFigureData; private int _currentPathFigureDataOffset = -1; private MIL_SEGMENT_POLY _currentPolySegmentData; private int _currentPolySegmentDataOffset = -1; private UInt32 _lastSegmentSize = 0; private UInt32 _lastFigureSize = 0; private Point[] _scratchForLine = new Point[1]; private Point[] _scratchForQuadraticBezier = new Point[2]; private Point[] _scratchForBezier = new Point[3]; private const int c_defaultChunkSize = 2*1024; private const int c_maxChunkSize = 1024*1024; #endregion Fields } } // 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
- DataRowView.cs
- GeneratedCodeAttribute.cs
- ScriptManager.cs
- InputLangChangeRequestEvent.cs
- BaseTreeIterator.cs
- Stream.cs
- connectionpool.cs
- DataGridTable.cs
- BoundField.cs
- LogStream.cs
- MediaSystem.cs
- ListMarkerSourceInfo.cs
- ErrorLog.cs
- IndentTextWriter.cs
- GeneratedContractType.cs
- Operand.cs
- DecimalKeyFrameCollection.cs
- AtlasWeb.Designer.cs
- ToolboxCategory.cs
- DispatchWrapper.cs
- KeyValueConfigurationElement.cs
- COAUTHINFO.cs
- BooleanFunctions.cs
- WebHttpDispatchOperationSelector.cs
- BitmapPalette.cs
- Light.cs
- XmlDesignerDataSourceView.cs
- DefaultValueAttribute.cs
- TraceFilter.cs
- HtmlAnchor.cs
- AccessorTable.cs
- BrowserCapabilitiesFactory.cs
- SiteMapNodeItemEventArgs.cs
- WebPartCloseVerb.cs
- ServerType.cs
- DeclaredTypeValidatorAttribute.cs
- AssociationSet.cs
- SpanIndex.cs
- CreateRefExpr.cs
- PerformanceCounterCategory.cs
- WebPartTransformer.cs
- DataObject.cs
- TrustManagerMoreInformation.cs
- FixedSOMPageElement.cs
- UnhandledExceptionEventArgs.cs
- TemplateApplicationHelper.cs
- WhitespaceRuleReader.cs
- SafeHandles.cs
- WindowsGraphicsCacheManager.cs
- EventLog.cs
- FlowDocumentPaginator.cs
- XhtmlBasicValidationSummaryAdapter.cs
- XsltSettings.cs
- Publisher.cs
- ViewRendering.cs
- MetadataWorkspace.cs
- StringValueSerializer.cs
- SystemWebExtensionsSectionGroup.cs
- ToolStripItemDataObject.cs
- UpDownBaseDesigner.cs
- FunctionDefinition.cs
- DbModificationCommandTree.cs
- BindingBase.cs
- ErrorTableItemStyle.cs
- RuntimeVariableList.cs
- FilterableAttribute.cs
- CompilationRelaxations.cs
- StatusBar.cs
- EpmSyndicationContentSerializer.cs
- DrawingGroup.cs
- EmulateRecognizeCompletedEventArgs.cs
- RunWorkerCompletedEventArgs.cs
- HMACSHA384.cs
- SafeLibraryHandle.cs
- DbDataReader.cs
- DBConnectionString.cs
- XmlSchemaAnnotation.cs
- DataBindingCollectionEditor.cs
- ApplicationManager.cs
- PrintEvent.cs
- securitycriticaldataClass.cs
- ContractCodeDomInfo.cs
- DataGridViewRowsAddedEventArgs.cs
- DesignerTextBoxAdapter.cs
- WebRequestModuleElementCollection.cs
- PackageDigitalSignatureManager.cs
- CompositeDesignerAccessibleObject.cs
- InstanceNameConverter.cs
- DataGridLinkButton.cs
- ErrorHandlingAcceptor.cs
- StrongName.cs
- SessionIDManager.cs
- XmlNullResolver.cs
- QualifiedId.cs
- VerificationException.cs
- CodeAttributeArgument.cs
- KeyValuePairs.cs
- RadialGradientBrush.cs
- _ConnectStream.cs
- DataMisalignedException.cs