Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Print / Reach / Serialization / DrawingContextFlattener.cs / 1 / DrawingContextFlattener.cs
//------------------------------------------------------------------------------ // Microsoft Avalon // Copyright (c) Microsoft Corporation, all rights reserved // // File: DrawingContextFlattener.cs // // History: // [....]: 01/25/2005 Split from VisualSerializer.cs // //----------------------------------------------------------------------------- using System; using System.Diagnostics; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.Windows; using System.Windows.Media; using System.Windows.Media.Effects; using System.Windows.Media.Imaging; using System.Windows.Media.Media3D; using System.Windows.Media.Animation; using Microsoft.Internal.AlphaFlattener; namespace System.Windows.Xps.Serialization { #region internal class DrawingContextFlattener ////// DrawingContext flattening filter /// 1) Convert animation to static value /// 2) Rasterize video/Scene3D to bitmap /// 3) Convert shapes to Geometry /// 4) Convert VisualBrush to DrawingBrush /// 5) Convert DrawingImage to ImageBrush /// 6) Flatten DrawDrawing /// internal class DrawingContextFlattener { #region Constants ////// Percentage to inflate rasterization clip rectangle to prevent prematurely clipping /// Visuals at page edges. /// private const double RasterizationClipInflate = 0.2; #endregion #region Private Fields private IMetroDrawingContext _dc; // Stores pushed transforms. Each transform contains all prior transforms. private List_fullTransform = new List (); // Pushed combined clipping in world space. private List _fullClip = new List (); private Size _pageSize; #endregion #region Constructors internal DrawingContextFlattener(IMetroDrawingContext dc, Size pageSize) { _dc = dc; _pageSize = pageSize; } #endregion #region Public State public void Push( Transform transform, Geometry clip, double opacity, Brush opacityMask, Rect maskBounds, bool onePrimitive, String nameAttr, Visual node, Uri navigateUri, EdgeMode edgeMode) { Debug.Assert(Utility.IsValid(opacity), "Invalid opacity should clip subtree"); Matrix mat = Matrix.Identity; if (transform != null) { mat = transform.Value; } // opacity mask might be VisualBrush, hence ReduceBrush to reduce to DrawingBrush Debug.Assert(!BrushProxy.IsEmpty(opacityMask), "empty opacity mask should not result in Push"); _dc.Push( mat, clip, opacity, ReduceBrush(opacityMask, maskBounds), maskBounds, onePrimitive, nameAttr, node, navigateUri, edgeMode ); // prepend to transforms and clipping stack mat.Append(Transform); _fullTransform.Add(mat); // transform clip to world space, intersect with current clip, and push if (clip == null) { // push current clipping clip = Clip; } else { clip = Utility.TransformGeometry(clip, Transform); bool empty; clip = Utility.Intersect(clip, Clip, Matrix.Identity, out empty); if (empty) { clip = Geometry.Empty; } } _fullClip.Add(clip); } /// /// Pop the most recent Push operation /// public void Pop() { _dc.Pop(); Debug.Assert(_fullTransform.Count == _fullClip.Count); int lastIndex = _fullTransform.Count - 1; _fullTransform.RemoveAt(lastIndex); _fullClip.RemoveAt(lastIndex); } ////// Transformation representing all pushed transformations. /// public Matrix Transform { get { if (_fullTransform.Count == 0) { return Matrix.Identity; } else { return _fullTransform[_fullTransform.Count - 1]; } } } ////// Intersection of all pushed clipping in world space. /// public Geometry Clip { get { if (_fullClip.Count == 0) { return null; } else { return _fullClip[_fullClip.Count - 1]; } } } #endregion #region Public Methods #if DEBUG ////// Add comment to output, as debugging aid or add extra information like document structure /// /// public void Comment(String str) { _dc.Comment(str); } #endif ////// Simplifies brush so we don't have to handle as many cases. /// /// /// Brush fill bounds; must not be empty if VisualBrush ////// /// Cases simplified: /// - A lot of empty brush cases. See BrushProxy.IsEmpty. /// - GradientBrush where gradient colors are similar enough to be SolidColorBrush. /// - Reduce VisualBrush to DrawingBrush. /// - Reduce ImageBrush with DrawingImage to DrawingBrush. /// private Brush ReduceBrush(Brush brush, Rect bounds) { return BrushProxy.ReduceBrush(brush, bounds, Transform, _pageSize); } private Pen ReducePen(Pen pen, Rect bounds) { if (PenProxy.IsNull(pen)) { return null; } Brush b = ReduceBrush(pen.Brush, bounds); if (b == null) { return null; } if (! Object.ReferenceEquals(b, pen.Brush)) { pen = pen.CloneCurrentValue(); pen.Brush = b; } return pen; } ////// Draw a Geometry with the provided Brush and/or Pen. /// public void DrawGeometry(Brush brush, Pen pen, Geometry geometry) { if (geometry != null) { if (brush != null) { Rect bounds = geometry.Bounds; brush = ReduceBrush(brush, bounds); } if ((pen != null) && (pen.Brush != null)) { Rect bounds = Rect.Empty; if (VisualSerializer.NeedBounds(pen.Brush)) { bounds = geometry.GetRenderBounds(pen); } pen = ReducePen(pen, bounds); } else { pen = null; } // Draw even if brush/pen is null since geometry may be a hyperlink. // _dc should cull invisible geometries when necessary. _dc.DrawGeometry(brush, pen, geometry); } } ////// Draw an Image into the region specified by the Rect. /// public void DrawImage(ImageSource image, Rect rectangle) { if (image != null) { bool handled = false; BitmapSource bitmapImage = image as BitmapSource; if (bitmapImage != null) { // we can handle BitmapSource handled = true; _dc.DrawImage(image, rectangle); } DrawingImage drawingImage = image as DrawingImage; if (drawingImage != null) { // convert DrawingImage to geometry fill with DrawingBrush handled = true; DrawingBrush brush = new DrawingBrush(drawingImage.Drawing); DrawGeometry(brush, null, new RectangleGeometry(rectangle)); } Debug.Assert(handled, "Unhandled Image.ImageSource type"); } else { // no image, but may still be a hyperlink _dc.DrawImage(null, rectangle); } } ////// Clip visual bounds to rasterization clip rectangle. /// /// /// ///private Rect PerformRasterizationClip(Rect visualBounds, Matrix visualToWorldTransform) { if (! _pageSize.IsEmpty) { Rect pageBox = new Rect(0, 0, _pageSize.Width, _pageSize.Height); pageBox.Inflate( RasterizationClipInflate * pageBox.Width, RasterizationClipInflate * pageBox.Height ); visualBounds.Intersect(pageBox); } return visualBounds; } /// /// Rasterizes Visual and its descendents with optional bitmap effect. Also handles Visual opacity. /// /// /// Preserve Visual name attribute /// Preserve FixedPage.NavigateUri /// Preserve RenderOptions.EdgeMode /// Visual.Transform /// Full transform from Visual to world space, including visual transform prepended /// /// Transformation above VisualTreeFlattener instance. This is needed if we're reducing VisualBrush to /// DrawingBrush to increase rasterization fidelity if brush is small, but will eventually fill large region. /// /// Clip in world space /// Optional bitmap effect public void DrawRasterizedVisual( Visual visual, string nameAttr, Uri navigateUri, EdgeMode edgeMode, Transform visualTransform, Matrix visualToWorldTransform, Matrix inheritedTransformHint, Geometry clip, BitmapEffect effect ) { Debug.Assert(visual != null); // Compute the bounding box of the visual and its descendants Rect bounds = VisualTreeHelper.GetContentBounds(visual); bounds.Union(VisualTreeHelper.GetDescendantBounds(visual)); if (!Utility.IsRenderVisible(bounds)) return; // transform clip to visual space if (clip != null) { Matrix worldToVisualTransform = visualToWorldTransform; worldToVisualTransform.Invert(); clip = Utility.TransformGeometry(clip, worldToVisualTransform); } // // Clip visual bounds to rasterization clipping geometry. // We can't clip to Visual clipping geometry, since bitmap effects are applied // without clipping. For example, the blur effect looks different if you clip first // then apply effect, compared to applying the effect and then clipping. // bounds = PerformRasterizationClip(bounds, visualToWorldTransform); if (!Utility.IsRenderVisible(bounds)) return; // // Rasterize Visual to IMetroDrawingContext with optional banding, depending // on whether bitmap effect is present. We can Push/Pop/Draw directly on _dc // since the input we provide it is already normalized (no DrawingImage, for example). // We also don't need Transform or Clip to be updated. // _dc.Push( visualTransform == null ? Matrix.Identity : visualTransform.Value, clip, 1.0, null, Rect.Empty, /*onePrimitive=*/false, // we Push and DrawImage below, which counts as 2 primitives nameAttr, visual, navigateUri, edgeMode ); Matrix bitmapToVisualTransform; BitmapSource bitmap; // // Rasterize visual in its entirety. Banding is not useful at this point since // the resulting bands are all kept in memory anyway. Plus transformation is applied // to the band, which causes gaps between bands if they're rotated (bug 1562237). // // Banding is performed at GDIExporter layer just prior to sending images to the printer. // if (effect == null) { bitmap = Utility.RasterizeVisual( visual, bounds, visualToWorldTransform * inheritedTransformHint, out bitmapToVisualTransform ); } else { BitmapEffectInput effectInput = VisualTreeHelper.GetBitmapEffectInput(visual); bitmap = Utility.RasterizeVisualWithEffect( visual, bounds, visualToWorldTransform * inheritedTransformHint, effect, effectInput, out bitmapToVisualTransform ); } if (bitmap != null) { _dc.Push(bitmapToVisualTransform, null, 1.0, null, Rect.Empty, /*onePrimitive=*/true, null, null, null, EdgeMode.Unspecified); _dc.DrawImage(bitmap, new Rect(0, 0, bitmap.Width, bitmap.Height)); _dc.Pop(); } _dc.Pop(); } ////// Rasterizes a Drawing to IMetroDrawingContext. /// /// /// /// See RasterizeVisual. public void RasterizeDrawing( DrawingGroup drawing, Matrix drawingToWorldTransform, Matrix inheritedTransformHint ) { Rect bounds = drawing.Bounds; if (!Utility.IsRenderVisible(bounds)) return; bounds = PerformRasterizationClip(bounds, drawingToWorldTransform); if (!Utility.IsRenderVisible(bounds)) return; Matrix bitmapToDrawingTransform; BitmapSource bitmap = Utility.RasterizeDrawing( drawing, bounds, drawingToWorldTransform * inheritedTransformHint, out bitmapToDrawingTransform ); if (bitmap != null) { _dc.Push(bitmapToDrawingTransform * drawingToWorldTransform, null, 1.0, null, Rect.Empty, true, null, null, null, EdgeMode.Unspecified); _dc.DrawImage(bitmap, new Rect(0, 0, bitmap.Width, bitmap.Height)); _dc.Pop(); } } ////// Draw a GlyphRun. /// public void DrawGlyphRun(Brush foreground, GlyphRun glyphRun) { if (glyphRun != null) { foreground = ReduceBrush(foreground, glyphRun.ComputeInkBoundingBox()); // foreground may be null, but glyphrun may still be a hyperlink _dc.DrawGlyphRun(foreground, glyphRun); } } #endregion } #endregion internal static class GeometryHelper { const double FUZZ = 1e-6; // Relative 0 const double PI_OVER_180 = Math.PI / 180; // PI/180 // Function: AcceptRadius // Synopsis: Accept one radius // Return: false if the radius is too small compared to the chord length public static bool AcceptRadius( double rHalfChord2, // (1/2 chord length)squared double rFuzz2, // Squared fuzz ref double rRadius) // The radius to accept (or not) { Debug.Assert(rHalfChord2 >= rFuzz2); // Otherewise we have no guarantee that the radius is not 0, // and we need to divide by the radius bool fAccept = (rRadius * rRadius > rHalfChord2 * rFuzz2); if (fAccept) { if (rRadius < 0) { rRadius = 0; } } return fAccept; } public static Point Add(Point a, Point b) { return new Point(a.X + b.X, a.Y + b.Y); } public static Point Sub(Point a, Point b) { return new Point(a.X - b.X, a.Y - b.Y); } // Dot Product public static double DotProduct(Point a, Point b) { return a.X * b.X + a.Y * b.Y; } public static double Determinant(Point a, Point b) { return a.X * b.Y - a.Y * b.X; } //+------------------------------------------------------------------------------------------------- // // Function: GetArcAngle // // Synopsis: Get the number of Bezier arcs, and sine & cosine of each // // Notes: This is a private utility used by ArcToBezier // We break the arc into pieces so that no piece will span more than 90 degrees. // The input points are on the unit circle // //------------------------------------------------------------------------------------------------- public static void GetArcAngle( Point ptStart, // Start point Point ptEnd, // End point bool fIsLargeArc, // Choose the larger of the 2 possible arcs if TRUE SweepDirection eSweepDirection, // Direction n which to sweep the arc. out double rCosArcAngle, // Cosine of a the sweep angle of one arc piece out double rSinArcAngle, // Sine of a the sweep angle of one arc piece out int cPieces) // Out: The number of pieces { double rAngle; // The points are on the unit circle, so: rCosArcAngle = DotProduct(ptStart, ptEnd); rSinArcAngle = Determinant(ptStart, ptEnd); if (rCosArcAngle >= 0) { if (fIsLargeArc) { // The angle is between 270 and 360 degrees, so cPieces = 4; } else { // The angle is between 0 and 90 degrees, so cPieces = 1; return; // We already have the cosine and sine of the angle } } else { if (fIsLargeArc) { // The angle is between 180 and 270 degrees, so cPieces = 3; } else { // The angle is between 90 and 180 degrees, so cPieces = 2; } } // We have to chop the arc into the computed number of pieces. For cPieces=2 and 4 we could // have uses the half-angle trig formulas, but for cPieces=3 it requires solving a cubic // equation; the performance difference is not worth the extra code, so we'll get the angle, // divide it, and get its sine and cosine. Debug.Assert(cPieces > 0); rAngle = Math.Atan2(rSinArcAngle, rCosArcAngle); if (eSweepDirection == SweepDirection.Clockwise) { if (rAngle < 0) { rAngle += Math.PI * 2; } } else { if (rAngle > 0) { rAngle -= Math.PI * 2; } } rAngle /= cPieces; rCosArcAngle = Math.Cos(rAngle); rSinArcAngle = Math.Sin(rAngle); } /******************************************************************************\ * * Function Description: * * Get the distance from a circular arc's endpoints to the control points of the * Bezier arc that approximates it, as a fraction of the arc's radius. * * Since the result is relative to the arc's radius, it depends strictly on the * arc's angle. The arc is assumed to be of 90 degrees of less, so the angle is * determined by the cosine of that angle, which is derived from rDot = the dot * product of two radius vectors. We need the Bezier curve that agrees with * the arc's points and tangents at the ends and midpoint. Here we compute the * distance from the curve's endpoints to its control points. * * Since we are looking for the relative distance, we can work on the unit * circle. Place the center of the circle at the origin, and put the X axis as * the bisector between the 2 vectors. Let a be the angle between the vectors. * Then the X coordinates of the 1st & last points are cos(a/2). Let x be the X * coordinate of the 2nd & 3rd points. At t=1/2 we have a point at (1,0). * But the terms of the polynomial there are all equal: * * (1-t)^3 = t*(1-t)^2 = 2^2*(1-t) = t^3 = 1/8, * * so from the Bezier formula there we have: * * 1 = (1/8) * (cos(a/2) + 3x + 3x + cos(a/2)), * hence * x = (1 - cos(a/2)) / 3 * * The X difference between that and the 1st point is: * * DX = x - cos(a/2) = 4(1 - cos(a/2)) / 3. * * But DX = distance / sin(a/2), hence the distance is * * dist = (4/3)*(1 - cos(a/2)) / sin(a/2). * * Created: 5/29/2001 [....] * /*****************************************************************************/ public static double GetBezierDistance( // Return the distance as a fraction of the radius double rDot, // In: The dot product of the two radius vectors double rRadius) // In: The radius of the arc's circle (optional=1) { double rRadSquared = rRadius * rRadius; // Squared radius Debug.Assert(rDot >= -rRadSquared * .1); // angle < 90 degrees Debug.Assert(rDot <= rRadSquared * 1.1); // as dot product of 2 radius vectors double rDist = 0; // Acceptable fallback value /* Rather than the angle a, we are given rDot = R^2 * cos(a), so we multiply top and bottom by R: dist = (4/3)*(R - Rcos(a/2)) / Rsin(a/2) and use some trig: __________ cos(a/2) = \/1 + cos(a) / 2 ________________ __________ R*cos(a/2) = \/R^2 + R^2 cos(a) / 2 = \/R^2 + rDot / 2 */ double rCos = (rRadSquared + rDot) / 2; // =(R*cos(a))^2 if (rCos < 0) // Shouldn't happen but dist=0 will work { return rDist; } // __________________ // R*sin(a/2) = \/R^2 - R^2 cos(a/2) double rSin = rRadSquared - rCos; // =(R*sin(a))^2 if (rSin <= 0) // 0 angle, we shouldn't be rounding the corner, but dist=0 is OK return rDist; rSin = Math.Sqrt(rSin); // = R*cos(a) rCos = Math.Sqrt(rCos); // = R*sin(a) rDist = 4 * (rRadius - rCos) / 3; if (rDist <= rSin * FUZZ) { rDist = 0; } else { rDist = 4 * (rRadius - rCos) / rSin / 3; } return rDist; } //+------------------------------------------------------------------------------------------------- // // Function: ArcToBezier // // Synopsis: Compute the Bezier approximation of an arc // // Notes: This utilitycomputes the Bezier approximation for an elliptical arc as it is defined // in the SVG arc spec. The ellipse from which the arc is carved is axis-aligned in its // own coordinates, and defined there by its x and y radii. The rotation angle defines // how the ellipse's axes are rotated relative to our x axis. The start and end points // define one of 4 possible arcs; the sweep and large-arc flags determine which one of // these arcs will be chosen. See SVG spec for details. // // Returning cPieces = 0 indicates a line instead of an arc // cPieces = -1 indicates that the arc degenerates to a point // //-------------------------------------------------------------------------------------------------- [MS.Internal.ReachFramework.FriendAccessAllowed] public static PointCollection ArcToBezier( double xStart, // X coordinate of the last point double yStart, // Y coordinate of the last point double xRadius, // The ellipse's X radius double yRadius, // The ellipse's Y radius double rRotation, // Rotation angle of the ellipse's x axis bool fIsLargeArc, // Choose the larger of the 2 possible arcs if TRUE SweepDirection eSweepDirection, // Sweep the arc while increasing the angle if TRUE double xEnd, // X coordinate of the last point double yEnd, // Y coordinate of the last point out int cPieces) // The number of output Bezier curves { double rCosArcAngle, rSinArcAngle, xCenter, yCenter, r, rBezDist; Point vecToBez1, vecToBez2; Matrix matToEllipse; double rFuzz2 = FUZZ * FUZZ; bool fZeroCenter = false; cPieces = -1; // In the following, the line segment between between the arc's start and // end points is referred to as "the chord". // Transform 1: Shift the origin to the chord's midpoint double x = (xEnd - xStart) / 2; double y = (yEnd - yStart) / 2; double rHalfChord2 = x * x + y * y; // (half chord length)^2 // Degenerate case: single point if (rHalfChord2 < rFuzz2) { // The chord degeneartes to a point, the arc will be ignored return null; } // Degenerate case: straight line if (!AcceptRadius(rHalfChord2, rFuzz2, ref xRadius) || !AcceptRadius(rHalfChord2, rFuzz2, ref yRadius)) { // We have a zero radius, add a straight line segment instead of an arc cPieces = 0; return null; } // Transform 2: Rotate to the ellipse's coordinate system rRotation = -rRotation * PI_OVER_180; double rCos = Math.Cos(rRotation); double rSin = Math.Sin(rRotation); r = x * rCos - y * rSin; y = x * rSin + y * rCos; x = r; // Transform 3: Scale so that the ellipse will become a unit circle x /= xRadius; y /= yRadius; // We get to the center of that circle along a verctor perpendicular to the chord // from the origin, which is the chord's midpoint. By Pythagoras, the length of that // vector is sqrt(1 - (half chord)^2). rHalfChord2 = x * x + y * y; // now in the circle coordinates if (rHalfChord2 > 1) { // The chord is longer than the circle's diameter; we scale the radii uniformly so // that the chord will be a diameter. The center will then be the chord's midpoint, // which is now the origin. r = Math.Sqrt(rHalfChord2); xRadius *= r; yRadius *= r; xCenter = yCenter = 0; fZeroCenter = true; // Adjust the unit-circle coordinates x and y x /= r; y /= r; } else { // The length of (-y,x) or (x,-y) is sqrt(rHalfChord2), and we want a vector // of length sqrt(1 - rHalfChord2), so we'll multiply it by: r = Math.Sqrt((1 - rHalfChord2) / rHalfChord2); if (fIsLargeArc != (eSweepDirection == SweepDirection.Clockwise)) // Going to the center from the origin=chord-midpoint { // in the direction of (-y, x) xCenter = -r * y; yCenter = r * x; } else { // in the direction of (y, -x) xCenter = r * y; yCenter = -r * x; } } // Transformation 4: shift the origin to the center of the circle, which then becomes // the unit circle. Since the chord's midpoint is the origin, the start point is (-x, -y) // and the endpoint is (x, y). Point ptStart = new Point(-x - xCenter, -y - yCenter); Point ptEnd = new Point(x - xCenter, y - yCenter); // Set up the matrix that will take us back to our coordinate system. This matrix is // the inverse of the combination of transformation 1 thru 4. matToEllipse = new Matrix(rCos * xRadius, -rSin * xRadius, rSin * yRadius, rCos * yRadius, (xEnd + xStart) / 2, (yEnd + yStart) / 2); if (!fZeroCenter) { // Prepend the translation that will take the origin to the circle's center matToEllipse.OffsetX += (matToEllipse.M11 * xCenter + matToEllipse.M21 * yCenter); matToEllipse.OffsetY += (matToEllipse.M12 * xCenter + matToEllipse.M22 * yCenter); } // Get the sine & cosine of the angle that will generate the arc pieces GetArcAngle(ptStart, ptEnd, fIsLargeArc, eSweepDirection, out rCosArcAngle, out rSinArcAngle, out cPieces); // Get the vector to the first Bezier control point rBezDist = GetBezierDistance(rCosArcAngle, 1); if (eSweepDirection == SweepDirection.Counterclockwise) { rBezDist = -rBezDist; } vecToBez1 = new Point(-rBezDist * ptStart.Y, rBezDist * ptStart.X); PointCollection rslt = new PointCollection(); // Add the arc pieces, except for the last for (int i = 1; i < cPieces; i++) { // Get the arc piece's endpoint Point ptPieceEnd = new Point(ptStart.X * rCosArcAngle - ptStart.Y * rSinArcAngle, ptStart.X * rSinArcAngle + ptStart.Y * rCosArcAngle); vecToBez2 = new Point(-rBezDist * ptPieceEnd.Y, rBezDist * ptPieceEnd.X); rslt.Add(matToEllipse.Transform(Add(ptStart, vecToBez1))); rslt.Add(matToEllipse.Transform(Sub(ptPieceEnd, vecToBez2))); rslt.Add(matToEllipse.Transform(ptPieceEnd)); // Move on to the next arc ptStart = ptPieceEnd; vecToBez1 = vecToBez2; } // Last arc - we know the endpoint vecToBez2 = new Point(-rBezDist * ptEnd.Y, rBezDist * ptEnd.X); rslt.Add(matToEllipse.Transform(Add(ptStart, vecToBez1))); rslt.Add(matToEllipse.Transform(Sub(ptEnd, vecToBez2))); rslt.Add(new Point(xEnd, yEnd)); return rslt; } }; ////// IMetroDrawingContext implementation to convert VisualBrush to DrawingBrush to /// reduce the number of Brush types we need to handle. /// internal class DrawingFlattenDrawingContext : IMetroDrawingContext { #region Public Properties private DrawingContext _context = null; // Records number of DrawingContext.Push calls part of each DrawingFlattenDrawingContext.Push call // for use in stack popping. private Stack _push = new Stack(); #endregion #region Constructors public DrawingFlattenDrawingContext(DrawingContext context) { Debug.Assert(context != null); _context = context; } #endregion #region IMetroDrawingContext Members public void DrawGeometry(Brush brush, Pen pen, Geometry geometry) { _context.DrawGeometry(brush, pen, geometry); } public void DrawImage(ImageSource image, Rect rectangle) { _context.DrawImage(image, rectangle); } public void DrawGlyphRun(Brush foreground, GlyphRun glyphRun) { _context.DrawGlyphRun(foreground, glyphRun); } public void Push( Matrix transform, Geometry clip, double opacity, Brush opacityMask, Rect maskBounds, bool onePrimitive, // serialization attributes String nameAttr, Visual node, Uri navigateUri, EdgeMode edgeMode ) { opacity = Utility.NormalizeOpacity(opacity); int pushCount = 0; if (!transform.IsIdentity) { _context.PushTransform(new MatrixTransform(transform)); pushCount++; } if (clip != null) { _context.PushClip(clip); pushCount++; } if (!Utility.IsOpaque(opacity)) { _context.PushOpacity(opacity); pushCount++; } if (opacityMask != null) { _context.PushOpacityMask(opacityMask); pushCount++; } _push.Push(pushCount); } public void Pop() { int popCount = (int)_push.Pop(); for (int index = 0; index < popCount; index++) { _context.Pop(); } } public void Comment(string message) { } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FormatVersion.cs
- SynchronizedInputAdaptor.cs
- ServiceContractViewControl.Designer.cs
- xml.cs
- PropertyPushdownHelper.cs
- Baml2006ReaderSettings.cs
- StructuralCache.cs
- BridgeDataRecord.cs
- VoiceChangeEventArgs.cs
- XmlEntityReference.cs
- MemberHolder.cs
- X509SubjectKeyIdentifierClause.cs
- NumberFormatInfo.cs
- UmAlQuraCalendar.cs
- JobInputBins.cs
- BinaryConverter.cs
- BufferBuilder.cs
- TextOnlyOutput.cs
- PasswordRecoveryDesigner.cs
- ElementUtil.cs
- CharAnimationBase.cs
- MailBnfHelper.cs
- ToolStripPanel.cs
- IDictionary.cs
- RootProfilePropertySettingsCollection.cs
- TransactionManagerProxy.cs
- GenericEnumConverter.cs
- DataGridRow.cs
- ModelService.cs
- StartUpEventArgs.cs
- Rethrow.cs
- UIElementParagraph.cs
- Base64Stream.cs
- EntityTypeEmitter.cs
- _StreamFramer.cs
- SystemColors.cs
- XmlCollation.cs
- BaseAddressElement.cs
- WebCodeGenerator.cs
- XdrBuilder.cs
- Run.cs
- Utils.cs
- Socket.cs
- ClientSettings.cs
- OleDbConnectionFactory.cs
- BooleanAnimationBase.cs
- XPathNavigator.cs
- KnownColorTable.cs
- ScheduleChanges.cs
- ArrangedElementCollection.cs
- InstanceOwner.cs
- TextUtf8RawTextWriter.cs
- EnumBuilder.cs
- ResourcesGenerator.cs
- RepeatButton.cs
- SystemPens.cs
- RealizedColumnsBlock.cs
- WindowsAuthenticationModule.cs
- StringHandle.cs
- SemaphoreFullException.cs
- RuntimeHelpers.cs
- FileSystemEventArgs.cs
- DesignBindingEditor.cs
- CodeTypeReferenceExpression.cs
- FrameworkRichTextComposition.cs
- FuncCompletionCallbackWrapper.cs
- StorageAssociationSetMapping.cs
- DrawingContextWalker.cs
- SystemIPInterfaceStatistics.cs
- SerializerDescriptor.cs
- LabelTarget.cs
- EditorServiceContext.cs
- basecomparevalidator.cs
- CompareInfo.cs
- Stack.cs
- SmtpReplyReaderFactory.cs
- _NtlmClient.cs
- HttpsHostedTransportConfiguration.cs
- EntityWithChangeTrackerStrategy.cs
- CaseInsensitiveOrdinalStringComparer.cs
- HttpPostLocalhostServerProtocol.cs
- XPathSelfQuery.cs
- OdbcConnection.cs
- TranslateTransform.cs
- PeerCollaborationPermission.cs
- WorkflowMarkupSerializerMapping.cs
- AddInAdapter.cs
- EventsTab.cs
- TextDecorationCollection.cs
- DiscardableAttribute.cs
- CodeTypeReferenceExpression.cs
- UrlAuthorizationModule.cs
- SerializationIncompleteException.cs
- TrackingCondition.cs
- ExpanderAutomationPeer.cs
- EditingMode.cs
- ObservableCollection.cs
- SelectionProviderWrapper.cs
- StoreConnection.cs
- SecurityPermission.cs