Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / BoundsDrawingContextWalker.cs / 1305600 / BoundsDrawingContextWalker.cs
//----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: BoundsDrawingContextWalker.cs
//
// Description: This file contains the implementation of BoundsDrawingContextWalker.
// This DrawingContextWalker is used to perform bounds calculations
// on renderdata.
//
// History:
// 04/15/2004 : [....] - Created it.
//
//---------------------------------------------------------------------------
using MS.Internal;
using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Runtime.InteropServices;
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.Security;
using System.Security.Permissions;
namespace System.Windows.Media
{
///
/// BoundsDrawingContextWalker - a DrawingContextWalker which will calculate the bounds
/// of the contents of a render data.
///
internal class BoundsDrawingContextWalker : DrawingContextWalker
{
///
/// PushType enum - this defines the type of Pushes in a context, so that our
/// untyped Pops know what to Pop.
///
private enum PushType
{
Transform,
Clip,
Opacity,
OpacityMask,
Guidelines,
BitmapEffect
}
///
/// Constructor for BoundsDrawingContextWalker
///
public BoundsDrawingContextWalker()
{
_bounds = Rect.Empty;
_transform = Matrix.Identity;
}
public Rect Bounds
{
get
{
return _bounds;
}
}
#region Static Drawing Context Methods
///
/// DrawLine -
/// Draws a line with the specified pen.
/// Note that this API does not accept a Brush, as there is no area to fill.
///
/// The Pen with which to stroke the line.
/// The start Point for the line.
/// The end Point for the line.
public override void DrawLine(
Pen pen,
Point point0,
Point point1)
{
if (Pen.ContributesToBounds(pen))
{
// _bounds is always in "world" space
// So, we need to transform the geometry to world to bound it
Rect geometryBounds = LineGeometry.GetBoundsHelper(
pen,
_transform, // world transform
point0,
point1,
Matrix.Identity, // geometry transform
Geometry.StandardFlatteningTolerance,
ToleranceType.Absolute
);
AddTransformedBounds(ref geometryBounds);
}
}
///
/// DrawRectangle -
/// Draw a rectangle with the provided Brush and/or Pen.
/// If both the Brush and Pen are null this call is a no-op.
///
///
/// The Brush with which to fill the rectangle.
/// This is optional, and can be null, in which case no fill is performed.
///
///
/// The Pen with which to stroke the rectangle.
/// This is optional, and can be null, in which case no stroke is performed.
///
/// The Rect to fill and/or stroke.
public override void DrawRectangle(
Brush brush,
Pen pen,
Rect rectangle)
{
if ((brush != null) || Pen.ContributesToBounds(pen))
{
// _bounds is always in "world" space
// So, we need to transform the geometry to world to bound it
Rect geometryBounds = RectangleGeometry.GetBoundsHelper(
pen,
_transform, // world transform
rectangle,
0.0,
0.0,
Matrix.Identity, // geometry transform
Geometry.StandardFlatteningTolerance,
ToleranceType.Absolute
);
AddTransformedBounds(ref geometryBounds);
}
}
///
/// DrawRoundedRectangle -
/// Draw a rounded rectangle with the provided Brush and/or Pen.
/// If both the Brush and Pen are null this call is a no-op.
///
///
/// The Brush with which to fill the rectangle.
/// This is optional, and can be null, in which case no fill is performed.
///
///
/// The Pen with which to stroke the rectangle.
/// This is optional, and can be null, in which case no stroke is performed.
///
/// The Rect to fill and/or stroke.
///
/// The radius in the X dimension of the rounded corners of this
/// rounded Rect. This value will be clamped to the range [0..rectangle.Width/2]
///
///
/// The radius in the Y dimension of the rounded corners of this
/// rounded Rect. This value will be clamped to the range [0..rectangle.Height/2].
///
public override void DrawRoundedRectangle(
Brush brush,
Pen pen,
Rect rectangle,
Double radiusX,
Double radiusY)
{
if ((brush != null) || Pen.ContributesToBounds(pen))
{
// _bounds is always in "world" space
// So, we need to transform the geometry to world to bound it
Rect geometryBounds = RectangleGeometry.GetBoundsHelper(
pen,
_transform, // world transform
rectangle,
radiusX,
radiusY,
Matrix.Identity, // geometry transform
Geometry.StandardFlatteningTolerance,
ToleranceType.Absolute
);
AddTransformedBounds(ref geometryBounds);
}
}
///
/// DrawEllipse -
/// Draw an ellipse with the provided Brush and/or Pen.
/// If both the Brush and Pen are null this call is a no-op.
///
///
/// The Brush with which to fill the ellipse.
/// This is optional, and can be null, in which case no fill is performed.
///
///
/// The Pen with which to stroke the ellipse.
/// This is optional, and can be null, in which case no stroke is performed.
///
///
/// The center of the ellipse to fill and/or stroke.
///
///
/// The radius in the X dimension of the ellipse.
/// The absolute value of the radius provided will be used.
///
///
/// The radius in the Y dimension of the ellipse.
/// The absolute value of the radius provided will be used.
///
public override void DrawEllipse(
Brush brush,
Pen pen,
Point center,
Double radiusX,
Double radiusY)
{
if ((brush != null) || Pen.ContributesToBounds(pen))
{
// _bounds is always in "world" space
// So, we need to transform the geometry to world to bound it
Rect geometryBounds = EllipseGeometry.GetBoundsHelper(
pen,
_transform, // world transform
center,
radiusX,
radiusY,
Matrix.Identity, // geometry transform
Geometry.StandardFlatteningTolerance,
ToleranceType.Absolute
);
AddTransformedBounds(ref geometryBounds);
}
}
///
/// DrawGeometry -
/// Draw a Geometry with the provided Brush and/or Pen.
/// If both the Brush and Pen are null this call is a no-op.
///
///
/// The Brush with which to fill the Geometry.
/// This is optional, and can be null, in which case no fill is performed.
///
///
/// The Pen with which to stroke the Geometry.
/// This is optional, and can be null, in which case no stroke is performed.
///
/// The Geometry to fill and/or stroke.
public override void DrawGeometry(
Brush brush,
Pen pen,
Geometry geometry)
{
if ((geometry != null) && ((brush != null) || Pen.ContributesToBounds(pen)))
{
// _bounds is always in "world" space
// So, we need to transform the geometry to world to bound it
Rect geometryBounds = geometry.GetBoundsInternal(pen, _transform);
AddTransformedBounds(ref geometryBounds);
}
}
///
/// DrawImage -
/// Draw an Image into the region specified by the Rect.
/// The Image will potentially be stretched and distorted to fit the Rect.
/// For more fine grained control, consider filling a Rect with an ImageBrush via
/// DrawRectangle.
///
/// The BitmapSource to draw.
///
/// The Rect into which the BitmapSource will be fit.
///
public override void DrawImage(
ImageSource imageSource,
Rect rectangle)
{
if (imageSource != null)
{
AddBounds(ref rectangle);
}
}
///
/// DrawVideo -
/// Draw a Video into the region specified by the Rect.
/// The Video will potentially be stretched and distorted to fit the Rect.
/// For more fine grained control, consider filling a Rect with an VideoBrush via
/// DrawRectangle.
///
/// The MediaPlayer to draw.
///
/// The Rect into which the MediaPlayer will be fit.
///
public override void DrawVideo(
MediaPlayer video,
Rect rectangle)
{
if (video != null)
{
AddBounds(ref rectangle);
}
}
///
/// Draw a GlyphRun.
///
/// Foreground brush to draw GlyphRun with.
/// The GlyphRun to draw.
public override void DrawGlyphRun(Brush foregroundBrush, GlyphRun glyphRun)
{
if ((foregroundBrush != null) && (glyphRun != null))
{
// The InkBoundingBox + the Origin produce the true InkBoundingBox.
Rect rectangle = glyphRun.ComputeInkBoundingBox();
if (!rectangle.IsEmpty)
{
rectangle.Offset((Vector)glyphRun.BaselineOrigin);
AddBounds(ref rectangle);
}
}
}
///
/// PushOpacityMask -
/// Push an opacity mask, which will apply to all drawing primitives until the
/// corresponding Pop call.
///
/// Brush for opacity mask.
public override void PushOpacityMask(
Brush brush)
{
// Push the opacity type
PushTypeStack(PushType.OpacityMask);
}
///
/// PushClip -
/// Push a clip region, which will apply to all drawing primitives until the
/// corresponding Pop call.
///
/// The Geometry to which we will clip.
public override void PushClip(
Geometry clipGeometry)
{
// If we have an old clip, push the old clip onto the stack.
if (_haveClip)
{
// Ensure the clip stack
if (_clipStack == null)
{
_clipStack = new Stack(2);
}
_clipStack.Push(_clip);
}
// Push the clip type
PushTypeStack(PushType.Clip);
if (clipGeometry != null)
{
// Since _clip is a value type, we need to know whether we have a clip or not.
// If not, we can assert that the initial value is present (Rect.Empty).
// We should also now set the _haveClip flag.
if (!_haveClip)
{
_haveClip = true;
_clip = clipGeometry.GetBoundsInternal(null /* pen */, _transform);
}
else
{
// update current clip
_clip.Intersect(clipGeometry.GetBoundsInternal(null /* pen */, _transform));
}
}
}
///
/// PushOpacity -
/// Push an opacity which will blend the composite of all drawing primitives added
/// until the corresponding Pop call.
///
///
/// The opacity with which to blend - 0 is transparent, 1 is opaque.
///
public override void PushOpacity(
Double opacity)
{
// Push the opacity type
PushTypeStack(PushType.Opacity);
}
///
/// PushTransform -
/// Push a Transform which will apply to all drawing operations until the corresponding
/// Pop.
///
/// The Transform to push.
public override void PushTransform(
Transform transform)
{
// Ensure the transform stack
if (_transformStack == null)
{
_transformStack = new Stack(2);
}
// Push the old transform.
_transformStack.Push(_transform);
// Push the transform type
PushTypeStack(PushType.Transform);
Matrix newValue = Matrix.Identity;
// Retrieve the new transform as a matrix if it exists
if ((transform != null) && !transform.IsIdentity)
{
// If the transform is degeneraate, we can skip all instructions until the
// corresponding Pop.
newValue = transform.Value;
}
// Update the current transform
_transform = newValue * _transform;
}
///
/// PushGuidelineSet -
/// Push a set of guidelines which should be applied
/// to all drawing operations until the
/// corresponding Pop.
///
/// The GuidelineSet to push.
public override void PushGuidelineSet(
GuidelineSet guidelines)
{
// Push the guidelines type
PushTypeStack(PushType.Guidelines);
// Nothing else to do. Guidelines are not used,
// so we only need to register Push() type in order to treat
// Pop() properly.
}
///
/// PushGuidelineY1 -
/// Explicitly push one horizontal guideline.
///
/// The coordinate of leading guideline.
internal override void PushGuidelineY1(
Double coordinate)
{
// Push the guidelines type
PushTypeStack(PushType.Guidelines);
// Nothing else to do. Guidelines are not used,
// so we only need to register Push() type in order to treat
// Pop() properly.
}
///
/// PushGuidelineY2 -
/// Explicitly push a pair of horizontal guidelines.
///
///
/// The coordinate of leading guideline.
///
///
/// The offset from leading guideline to driven guideline.
///
internal override void PushGuidelineY2(
Double leadingCoordinate,
Double offsetToDrivenCoordinate)
{
// Push the guidelines type
PushTypeStack(PushType.Guidelines);
// Nothing else to do. Guidelines are not used,
// so we only need to register Push() type in order to treat
// Pop() properly.
}
///
/// PushEffect -
/// Push a BitmapEffect which will apply to all drawing operations until the
/// corresponding Pop.
///
/// The BitmapEffect to push.
/// The BitmapEffectInput.
[Obsolete(MS.Internal.Media.VisualTreeUtils.BitmapEffectObsoleteMessage)]
public override void PushEffect(
BitmapEffect effect,
BitmapEffectInput effectInput)
{
// Ensure the type stack
PushTypeStack(PushType.BitmapEffect);
// This API has been deprecated, so any BitmapEffect is ignored.
}
///
/// Pop
///
public override void Pop()
{
// We must have a type stack and it must not be empty.
Debug.Assert(_pushTypeStack != null);
Debug.Assert(_pushTypeStack.Count > 0);
// Retrieve the PushType to figure out what what this Pop is.
PushType pushType = _pushTypeStack.Pop();
switch (pushType)
{
case PushType.Transform:
// We must have a Transform stack and it must not be empty.
Debug.Assert(_transformStack != null);
Debug.Assert(_transformStack.Count > 0);
// Restore the transform
_transform = _transformStack.Pop();
break;
case PushType.Clip:
// Restore the clip, if there's one to restore
if ((_clipStack != null) &&
(_clipStack.Count > 0))
{
_clip = _clipStack.Pop();
}
else
{
// If the _clipStack was empty or null, then we no longer have a clip.
_haveClip = false;
}
break;
case PushType.BitmapEffect:
//
break;
default:
// Ignore the rest
break;
}
}
#endregion Static Drawing Context Methods
#region Private Methods
///
/// AddBounds - Unions the non-transformed bounds which are
/// local to the current Drawing operation with the
/// aggregate bounds of other Drawing operations encountered
/// during this walk.
///
///
/// In: The bounds of the geometry to union in the coordinate
/// space of the current Drawing operations
/// Out: The transformed and clipped bounds of the geometry
/// in the coordinate space of the top-level Drawing
/// operation.
///
private void AddBounds(ref Rect bounds)
{
// _bounds is always in "world" space
// So, we need to transform the Rect to world to bound it
if (!_transform.IsIdentity)
{
MatrixUtil.TransformRect(ref bounds, ref _transform);
}
AddTransformedBounds(ref bounds);
}
///
/// AddTransformedBounds - Unions bounds which have been transformed
/// into the top-level Drawing operation with the aggregate bounds of
/// other Drawing operations encountered during this walk.
///
///
/// In: The bounds of the geometry to union in the coordinate
/// space of the current Drawing operations
/// Out: The transformed and clipped bounds of the geometry
/// in the coordinate space of the top-level Drawing
/// operation.
///
private void AddTransformedBounds(ref Rect bounds)
{
if (DoubleUtil.RectHasNaN(bounds))
{
// We set the bounds to infinity if it has NaN
bounds.X = Double.NegativeInfinity;
bounds.Y = Double.NegativeInfinity;
bounds.Width = Double.PositiveInfinity;
bounds.Height = Double.PositiveInfinity;
}
if (_haveClip)
{
bounds.Intersect(_clip);
}
_bounds.Union(bounds);
}
///
/// Ensure the type stack exists, and store given push type there.
///
/// the push type to store
private void PushTypeStack(PushType pushType)
{
if (_pushTypeStack == null)
{
_pushTypeStack = new Stack(2);
}
_pushTypeStack.Push(pushType);
}
///
/// Ensure that the state is clear and is good for next use.
///
internal void ClearState()
{
_clip = Rect.Empty;
_bounds = Rect.Empty;
_haveClip = false;
_transform = new Matrix();
_pushTypeStack = null;
_transformStack = null;
_clipStack = null;
}
#endregion Private Methods
// The accumulated bounds, in world space
private Rect _bounds;
// The current clip in world space, if _haveClip is true. Otherwise, this
// variable may hold random rects (stuff left over from previously pop'ed clipped)
private Rect _clip;
// States whether or not we have a clip (because Rect isn't nullable).
private bool _haveClip;
// The current local->world Transform as a matrix.
private Matrix _transform;
// The Type stack for our Push/Pop calls. This tells whether a given Pop corresponds
// to a Transform, Clip, etc.
private Stack _pushTypeStack;
// This stack contains the Matricies encountered during our walk.
// The current transform is stored in _transform and not in the Stack.
private Stack _transformStack;
// This stack contains the clip rects encountered during our walk.
// The current clip is stored in _clip and not in the Stack.
private Stack _clipStack;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ExtentKey.cs
- AutomationPatternInfo.cs
- MdiWindowListItemConverter.cs
- DialogResultConverter.cs
- ObjectDataSourceDesigner.cs
- HandlerBase.cs
- TextSelectionHelper.cs
- XPathNavigator.cs
- PrimitiveSchema.cs
- MatrixCamera.cs
- ObjectIDGenerator.cs
- DataServiceProcessingPipeline.cs
- WindowsListViewGroup.cs
- TypeForwardedToAttribute.cs
- TraceEventCache.cs
- RegistryPermission.cs
- TypeLoadException.cs
- XpsS0ValidatingLoader.cs
- XsdCachingReader.cs
- ExtendedPropertiesHandler.cs
- DataTablePropertyDescriptor.cs
- CodeIdentifier.cs
- OperationCanceledException.cs
- QilList.cs
- FixedSOMTextRun.cs
- CodeMethodInvokeExpression.cs
- DateTimeUtil.cs
- WindowsFormsHost.cs
- JpegBitmapEncoder.cs
- SqlClientWrapperSmiStreamChars.cs
- CrossAppDomainChannel.cs
- SqlNodeAnnotation.cs
- HTTPNotFoundHandler.cs
- ValidationErrorCollection.cs
- ServiceOperationViewControl.cs
- RequestQueryProcessor.cs
- MergeLocalizationDirectives.cs
- PostBackTrigger.cs
- ProxyWebPartConnectionCollection.cs
- VerificationException.cs
- ServiceHttpHandlerFactory.cs
- AutoSizeToolBoxItem.cs
- QueryCacheEntry.cs
- EntityDataSourceDesignerHelper.cs
- CustomExpressionEventArgs.cs
- SoapAttributes.cs
- TopClause.cs
- CorrelationInitializer.cs
- TextServicesManager.cs
- KeyValuePair.cs
- XamlWriter.cs
- Exceptions.cs
- BindingBase.cs
- Pkcs7Recipient.cs
- AesManaged.cs
- RubberbandSelector.cs
- ISSmlParser.cs
- DetailsViewUpdatedEventArgs.cs
- SqlInternalConnectionSmi.cs
- _RequestCacheProtocol.cs
- ProfileSection.cs
- AdornerDecorator.cs
- UITypeEditor.cs
- ListBox.cs
- XmlNodeComparer.cs
- DataRelation.cs
- _NegoState.cs
- ObjectFullSpanRewriter.cs
- HyperlinkAutomationPeer.cs
- CoTaskMemHandle.cs
- StateMachineWorkflowInstance.cs
- CheckBoxFlatAdapter.cs
- XPathNode.cs
- EmptyCollection.cs
- ListBoxItemWrapperAutomationPeer.cs
- RemotingConfigParser.cs
- UnmanagedMarshal.cs
- ProfileEventArgs.cs
- DataControlFieldCell.cs
- SplitterDesigner.cs
- ComboBox.cs
- ListBoxDesigner.cs
- Quack.cs
- TreeViewCancelEvent.cs
- ValueSerializer.cs
- SignedXml.cs
- AssemblyFilter.cs
- ProcessHost.cs
- SettingsPropertyValueCollection.cs
- BindingElementCollection.cs
- UIServiceHelper.cs
- BasicExpressionVisitor.cs
- TextElementEditingBehaviorAttribute.cs
- HttpCachePolicyElement.cs
- ADConnectionHelper.cs
- DataGridViewCellMouseEventArgs.cs
- StringKeyFrameCollection.cs
- WebBaseEventKeyComparer.cs
- ListBox.cs
- AvtEvent.cs