Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / ByteStreamGeometryContext.cs / 1305600 / 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(IList points, 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(IList points, 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(IList points, 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(IList points,
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(IList points, 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(IList points, 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(IList points, 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(IList points,
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
- BordersPage.cs
- TemplateControlBuildProvider.cs
- FeatureSupport.cs
- ICspAsymmetricAlgorithm.cs
- _FixedSizeReader.cs
- OpacityConverter.cs
- TemplatedEditableDesignerRegion.cs
- ArgumentNullException.cs
- MSHTMLHost.cs
- NavigateUrlConverter.cs
- ScrollEventArgs.cs
- DiscardableAttribute.cs
- basevalidator.cs
- OracleParameterCollection.cs
- FontWeightConverter.cs
- X509PeerCertificateElement.cs
- KnownIds.cs
- PropertySegmentSerializer.cs
- XmlSchemaParticle.cs
- OpCodes.cs
- WarningException.cs
- TextFragmentEngine.cs
- PrivateFontCollection.cs
- PropagatorResult.cs
- OperationBehaviorAttribute.cs
- AnimatedTypeHelpers.cs
- GeneralTransform.cs
- PasswordBox.cs
- Helper.cs
- MemberInfoSerializationHolder.cs
- ObjectRef.cs
- Deflater.cs
- DefaultBinder.cs
- TryCatch.cs
- SystemMulticastIPAddressInformation.cs
- Serializer.cs
- CellTreeNodeVisitors.cs
- SoapSchemaMember.cs
- RootProfilePropertySettingsCollection.cs
- DbgCompiler.cs
- SerialReceived.cs
- SslStream.cs
- BitStream.cs
- CallId.cs
- PageClientProxyGenerator.cs
- FontWeight.cs
- ADMembershipUser.cs
- DelayedRegex.cs
- _LazyAsyncResult.cs
- PerformanceCounterLib.cs
- BufferedGraphics.cs
- PointUtil.cs
- AppDomainManager.cs
- LazyTextWriterCreator.cs
- Renderer.cs
- StandardMenuStripVerb.cs
- DiscoveryEndpointElement.cs
- AssociationSetMetadata.cs
- TypeNameHelper.cs
- PersonalizationProviderHelper.cs
- DefaultPropertyAttribute.cs
- PerfCounters.cs
- OutputScope.cs
- NoneExcludedImageIndexConverter.cs
- BrowserInteropHelper.cs
- ValueTypeFixupInfo.cs
- SecurityKeyIdentifierClause.cs
- CodeAttributeDeclarationCollection.cs
- DesignBindingValueUIHandler.cs
- HandlerMappingMemo.cs
- FormatException.cs
- DispatcherObject.cs
- Parser.cs
- PersonalizationProviderHelper.cs
- RadioButton.cs
- _HeaderInfoTable.cs
- ToolStripItemImageRenderEventArgs.cs
- StructuredTypeEmitter.cs
- CodePrimitiveExpression.cs
- ClonableStack.cs
- ItemCollection.cs
- DockPanel.cs
- EasingKeyFrames.cs
- Page.cs
- FontFamilyValueSerializer.cs
- controlskin.cs
- TextEditorCopyPaste.cs
- StrokeNode.cs
- GridViewColumnHeader.cs
- EntityCommandCompilationException.cs
- CursorConverter.cs
- UriTemplateDispatchFormatter.cs
- DBCSCodePageEncoding.cs
- TaiwanLunisolarCalendar.cs
- DiscoveryClient.cs
- XmlSchemaNotation.cs
- TextBoxBase.cs
- sqlpipe.cs
- RtfControls.cs
- Decimal.cs