Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Print / Reach / AlphaFlattener / DrawingContext.cs / 1 / DrawingContext.cs
//------------------------------------------------------------------------------ // Microsoft Printing // Copyright (c) Microsoft Corporation, 2004 // // File: DrawingContext.cs // // History: // [....]: 04/20/2004 Created //----------------------------------------------------------------------------- using System; using System.Collections; // for ArrayList using System.Diagnostics; using System.Windows; // for Rect WindowsBase.dll using System.Windows.Media; // for Geometry, Brush, ImageData. PresentationCore.dll using System.Windows.Media.Imaging; using System.Windows.Shapes; // for Glyphs using System.Printing; using System.Security; using System.Security.Permissions; namespace Microsoft.Internal.AlphaFlattener { ////// Implementation of IProxyDrawingContext interface which stores primitives to a DisplayList /// internal class DisplayListDrawingContext : IProxyDrawingContext { #region Private Fields private Flattener _flattener; private double _opacity; private BrushProxy _opacityMask; private Matrix _transform; private Geometry _clip; // stores settings prior to pushing new settings private Stack _pushedStack = new Stack(); #endregion #region Constructors public DisplayListDrawingContext( Flattener flattener, double opacity, BrushProxy opacityMask, Matrix trans, Geometry clip) { _flattener = flattener; _opacity = opacity; _opacityMask = opacityMask; _transform = trans; _clip = clip; } #endregion #region IProxyDrawingContext Members void IProxyDrawingContext.Comment(string message) { } void IProxyDrawingContext.Push(double opacity, BrushProxy opacityMask) { _pushedStack.Push(_opacity); _pushedStack.Push(_opacityMask); _opacity *= opacity; _opacityMask = BrushProxy.BlendBrush(_opacityMask, opacityMask); } void IProxyDrawingContext.Pop() { _opacityMask = (BrushProxy)_pushedStack.Pop(); _opacity = (double)_pushedStack.Pop(); } void IProxyDrawingContext.DrawGeometry(BrushProxy brush, PenProxy pen, Geometry geometry, Geometry clip, Matrix brushTrans, ProxyDrawingFlags flags) { if ((brush != null) && (pen != null)) // Split fill & stroke into two { ((IProxyDrawingContext)(this)).DrawGeometry(brush, null, geometry, clip, brushTrans, flags); brush = null; } bool empty; clip = Utility.Intersect(_clip, Utility.TransformGeometry(clip, _transform), Matrix.Identity, out empty); if (empty) { return; } GeometryPrimitive geo = new GeometryPrimitive(); // apply drawing flags to primitive if ((flags & ProxyDrawingFlags.PixelSnapBounds) != 0) { geo.PixelSnapBounds = true; } if (pen != null) { if (! brushTrans.IsIdentity) { double scale; bool uniform = Utility.HasUniformScale(brushTrans, out scale); if (uniform) { geo.Pen = pen.Clone(); geo.Pen.Scale(scale); geo.Pen.StrokeBrush.ApplyTransform(brushTrans); } else { // geometry = Utility.InverseTransformGeometry(geometry, brushTrans); geometry = geometry.GetWidenedPathGeometry(pen.GetPen(true), 0.0001, ToleranceType.Relative); geometry = Utility.TransformGeometry(geometry, brushTrans); brush = pen.StrokeBrush; pen = null; } } else { geo.Pen = pen.Clone(); } } if (brush != null) { geo.Brush = brush.ApplyTransformCopy(brushTrans); } geo.Geometry = geometry; geo.Clip = clip; geo.Transform = _transform; geo.PushOpacity(_opacity, _opacityMask); _flattener.AddPrimitive(geo); } void IProxyDrawingContext.DrawImage(ImageProxy image, Rect dest, Geometry clip, Matrix trans) { bool empty; clip = Utility.Intersect(_clip, Utility.TransformGeometry(clip, _transform), Matrix.Identity, out empty); if (empty) { return; } ImagePrimitive ip = new ImagePrimitive(); // Fix bug 1460208: Give each ImagePrimitive its own ImageProxy, since rendering may alter // the images. ip.Image = image.Clone(); ip.DstRect = dest; ip.Clip = clip; ip.Transform = trans * _transform; ip.PushOpacity(_opacity, _opacityMask); _flattener.AddPrimitive(ip); } bool IProxyDrawingContext.DrawGlyphs(GlyphRun glyphrun, Geometry clip, Matrix trans, BrushProxy foreground) { bool empty; clip = Utility.Intersect(_clip, Utility.TransformGeometry(clip, _transform), Matrix.Identity, out empty); if (empty) { return true; } GlyphPrimitive gp = new GlyphPrimitive(); gp.GlyphRun = glyphrun; gp.Clip = clip; gp.Transform = trans * _transform; gp.Brush = foreground; gp.PushOpacity(_opacity, _opacityMask); _flattener.AddPrimitive(gp); return true; } #endregion } ////// Implement of IProxyDrawingContext on white background. /// 1) BrushProxy/PenProxy is broken down to Avalon Brush/Pen. /// 2) All transparency as blended with white. /// 3) Output is sent to ILegacyDevice interfiace. /// internal class BrushProxyDecomposer : IProxyDrawingContext { #if DEBUG static int _seq; // = 0; private string _comment; #endif #region Private Fields private ILegacyDevice _dc; private bool _costing; private double _cost; #endregion #region Constructors public BrushProxyDecomposer(ILegacyDevice dc) { _dc = dc; // _costing = false; // _cost = 0; } #endregion #region Private Methods // Breaking RadialGradientBrush apart to simplify drawing private bool LinearFillGeometry(BrushProxy linear, BrushProxy other, bool pre, ArrayList brushes, int from, Geometry shape) { bool opacityOnly = false; LinearGradientBrush b = null; double opacity = 0; bool result = true; b = linear.Brush as LinearGradientBrush; BrushProxy saveMask = linear.OpacityMask; double saveOpacity = linear.Opacity; if (b != null) { opacity = linear.Opacity; } else { b = saveMask.Brush as LinearGradientBrush; opacity = saveMask.Opacity; opacityOnly = true; Debug.Assert(b != null, "LinearGradientBrush expected"); } linear.OpacityMask = null; // Need to give flattener BrushProxy's opacity, which includes Brush's opacity and // opacity pushed from parent primitives. LinearGradientFlattener rf = new LinearGradientFlattener(b, shape, opacity); int steps = rf.Steps; if (_costing) { if (steps > Configuration.MaxGradientSteps) // Avoid decomposition if there are too many steps { _cost = 1; return true; } } else { _dc.PushClip(shape); } for (int i = 0; i < steps; i ++) { Color color; Geometry slice = rf.GetSlice(i, out color); BrushProxy blend; if (opacityOnly) { linear.Opacity = saveOpacity * Utility.NormalizeOpacity(color.ScA); if (pre) { blend = linear.BlendBrush(other); } else { blend = other.BlendBrush(linear); } } else { if (saveMask == null) { blend = BrushProxy.BlendColorWithBrush(false, color, other, !pre); } else { blend = BrushProxy.BlendColorWithBrush(false, color, saveMask, false); if (blend != null) { if (pre) { blend = blend.BlendBrush(other); } else { blend = other.BlendBrush(blend); } } } } if (blend == null) { result = false; } else { result = FillGeometry(blend, brushes, from, slice); } if (!result) { break; } // Break when we already know decomposition of gradient is more costly if (_costing && (_cost > 0)) { break; } } linear.OpacityMask = saveMask; linear.Opacity = saveOpacity; if (!_costing) { _dc.PopClip(); } return result; } // Breaking RadialGradientBrush apart to simplify drawing private bool RadialFillGeometry(BrushProxy radial, BrushProxy other, bool pre, ArrayList brushes, int from, Geometry shape) { bool opacityOnly = false; RadialGradientBrush b = null; double opacity = 0; b = radial.Brush as RadialGradientBrush; BrushProxy saveMask = radial.OpacityMask; double saveOpacity = radial.Opacity; if (b != null) { opacity = radial.Opacity; } else { b = saveMask.Brush as RadialGradientBrush; opacity = saveMask.Opacity; opacityOnly = true; Debug.Assert(b != null, "RadialGradientBrush expected"); } radial.OpacityMask = null; // Need to give flattener BrushProxy's opacity, which includes Brush's opacity and // opacity pushed from parent primitives. RadialGradientFlattener rf = new RadialGradientFlattener(b, shape, opacity); int steps = rf.Steps; if (_costing) { if (steps > Configuration.MaxGradientSteps) // Avoid decomposition if there are too many steps { _cost = 1; return true; } } else { _dc.PushClip(shape); } bool result = true; for (int i = steps; i > 0; i--) { Color color; Geometry slice = rf.GetSlice(i, out color); BrushProxy blend = null; if (opacityOnly) { radial.Opacity = saveOpacity * Utility.NormalizeOpacity(color.ScA); if (pre) { blend = radial.BlendBrush(other); } else { blend = other.BlendBrush(radial); } } else { if (saveMask == null) { blend = BrushProxy.BlendColorWithBrush(false, color, other, !pre); } else { blend = BrushProxy.BlendColorWithBrush(false, color, saveMask, false); if (pre) { blend = blend.BlendBrush(other); } else { blend = other.BlendBrush(blend); } } } result = FillGeometry(blend, brushes, from, slice); if (!result) { break; } // Break when we already know decomposition of gradient is more costly if (_costing && (_cost > 0)) { break; } } radial.OpacityMask = saveMask; radial.Opacity = saveOpacity; if (!_costing) { _dc.PopClip(); } return result; } ////// Fill a geometry using a list of brushes /// /// First brush to use /// Brush list /// Index to get the second brush /// Geometry to fill private bool FillGeometry(BrushProxy one, ArrayList brushes, int from, Geometry geometry) { Debug.Assert(one != null); BrushProxy two = null; if (one.BrushList == null) { if (from >= brushes.Count) // Only single brush left { ((IProxyDrawingContext)this).DrawGeometry(one, null, geometry, null, Matrix.Identity, ProxyDrawingFlags.None); return true; } two = brushes[from] as BrushProxy; from ++; // Move to next brush } else { Debug.Assert(one.BrushList.Count == 2, "Only two brushes allowed here"); two = one.BrushList[1] as BrushProxy; one = one.BrushList[0] as BrushProxy; } BrushProxy.BrushTypes typeOne = one.BrushType; BrushProxy.BrushTypes typeTwo = two.BrushType; bool pre = true; // Try to break the brush with higher BrushTypes first, and then the other one for (int i = 0; i < 2; i ++) { // swap to higher one first iteration, then swap for the second loop if ((typeOne < typeTwo) || (i == 1)) { BrushProxy t = one; one = two; two = t; BrushProxy.BrushTypes bt = typeOne; typeOne = typeTwo; typeTwo = bt; pre = ! pre; } if ((typeOne & BrushProxy.BrushTypes.RadialGradientBrush) != 0) { return RadialFillGeometry(one, two, pre, brushes, from, geometry); } if ((typeOne & BrushProxy.BrushTypes.LinearGradientBrush) != 0) { return LinearFillGeometry(one, two, pre, brushes, from, geometry); } if ((typeOne & BrushProxy.BrushTypes.HasOpacityMask) != 0) { BrushProxy.BrushTypes opacityType = one.OpacityMask.BrushType; if ((opacityType & BrushProxy.BrushTypes.RadialGradientBrush) != 0) { return RadialFillGeometry(one, two, pre, brushes, from, geometry); } if ((opacityType & BrushProxy.BrushTypes.LinearGradientBrush) != 0) { return LinearFillGeometry(one, two, pre, brushes, from, geometry); } } } #if DEBUG if (Configuration.Verbose >= 2) { Debug.WriteLine("FillGeometry not implemented " + one + " " + two); } #endif return false; } ////// Check if rasterizing an area is more effective /// /// /// ///True if rasterizing is more cost effective private bool BetterRasterize(BrushProxy brush, Geometry shape) { if ((brush == null) || (brush.BrushList == null)) { return false; } if (brush.GetBrushDepth() > Configuration.DecompositionDepth) { return true; } Rect bounds = shape.Bounds; _costing = true; _cost = - Configuration.RasterizationCost(bounds.Width, bounds.Height); bool rslt = FillGeometry(brush.BrushList[0] as BrushProxy, brush.BrushList, 1, shape); _costing = false; if (rslt) { return _cost > 0; } else { return true; } } ////// Rasterize filling a geometry shape using a BrushProxy and render to _dc /// private void RasterizeGeometry(BrushProxy brush, Geometry shape) { Debug.Assert(brush != null, "brush expected"); Debug.Assert(shape != null, "shape expected"); Debug.Assert(!_costing, "in costing mode DrawImage"); Rect bounds = shape.Bounds; int width = (int) Math.Round(bounds.Width * Configuration.RasterizationDPI / 96); int height = (int) Math.Round(bounds.Height * Configuration.RasterizationDPI / 96); if ((width >= 1) && (height >= 1)) // skip shape which is too small { Matrix mat = Utility.CreateMappingTransform(bounds, width, height); BitmapSource id = brush.CreateBrushImage_ID(mat, width, height); _dc.PushClip(shape); #if DEBUG _seq++; _dc.Comment("-> DrawImage(raster) " + _seq); #endif _dc.DrawImage(id, null, bounds); #if DEBUG _dc.Comment("<- DrawImage(raster) " + _seq); #endif _dc.PopClip(); } } private static double DrawGeometryCost(Brush b, Pen p, Geometry g) { if (g == null) { return 0; } if ((b == null) && (p == null)) { return 0; } if (b == null) { b = p.Brush; } if (b is SolidColorBrush) { return 512; } Rect bounds = g.Bounds; if (b is ImageBrush) { return 512 + Configuration.RasterizationCost(bounds.Width, bounds.Height); } if (b is LinearGradientBrush) { // return 512 + Configuration.RasterizationCost(Math.Max(bounds.Width, bounds.Height)); } return 512 + Configuration.RasterizationCost(bounds.Width, bounds.Height); } #endregion #region IProxyDrawingContext Members void IProxyDrawingContext.Comment(string message) { #if DEBUG _comment = message; #endif } void IProxyDrawingContext.Push(double opacity, BrushProxy opacityMask) { // BrushProxyDecomposer sends output directly to GDI, so opacity // is invalid by this point. Debug.Assert(false, "Opacity invalid at BrushProxyDecomposer"); } void IProxyDrawingContext.Pop() { Debug.Assert(false, "Opacity invalid at BrushProxyDecomposer"); } void IProxyDrawingContext.DrawGeometry(BrushProxy brush, PenProxy pen, Geometry geometry, Geometry clip, Matrix brushTrans, ProxyDrawingFlags flags) { Debug.Assert(brushTrans.IsIdentity, "brushTrans not supported"); if ((brush == null) && (pen == null)) { return; } if (!_costing && (clip != null)) { _dc.PushClip(clip); } if (brush != null) { brush = BrushProxy.BlendColorWithBrush(false, Colors.White, brush, false); } // Simplification, pushing transformation if (geometry is LineGeometry) { LineGeometry line = geometry.CloneCurrentValue() as LineGeometry; line.StartPoint = geometry.Transform.Value.Transform(line.StartPoint); line.EndPoint = geometry.Transform.Value.Transform(line.EndPoint); line.Transform = Transform.Identity; } if ((brush != null) && (brush.BrushList != null)) // List of brushes { Debug.Assert(pen == null, "no pen"); if (_costing) { FillGeometry(brush.BrushList[0] as BrushProxy, brush.BrushList, 1, geometry); } else { bool rasterize = BetterRasterize(brush, geometry); if (!rasterize) { rasterize = ! FillGeometry(brush.BrushList[0] as BrushProxy, brush.BrushList, 1, geometry); } if (rasterize) { bool empty = false; if (clip != null) { // Fix bug 1506957: Clip geometry prior to rasterizing to prevent excessive // rasterization bitmap size. geometry = Utility.Intersect(geometry, clip, Matrix.Identity, out empty); } if (!empty) { RasterizeGeometry(brush, geometry); } } } } else // Single Avalon brush or pen { Pen p = null; BrushProxy strokeBrush = null; if (pen != null) // Blend pen with White { p = pen.GetPen(true); strokeBrush = pen.StrokeBrush; if (! strokeBrush.IsOpaque()) { strokeBrush = BrushProxy.BlendColorWithBrush(false, Colors.White, strokeBrush, false); } } Brush b = null; if (_costing) { if (brush != null) { // DrawingBrush is always rasterized onward from this stage. // Avoid the cost of creating new DrawingBrush in GetRealBrush during costing if ((brush.Brush != null) && (brush.Brush is DrawingBrush)) { b = brush.Brush; } else { b = brush.GetRealBrush(); } } _cost += DrawGeometryCost(b, p, geometry); } else { if (brush != null) { b = brush.GetRealBrush(); } #if DEBUG _seq++; _dc.Comment("-> DrawGeometry " + _seq + ' ' + _comment); #endif if (p == null) { _dc.DrawGeometry(b, null, null, geometry); } else { _dc.DrawGeometry(b, p, strokeBrush.GetRealBrush(), geometry); } #if DEBUG _dc.Comment("<- DrawGeometry" + _seq + ' ' + _comment); if (Configuration.Verbose >= 2) { Console.WriteLine(" DrawGeometry(" + _comment + ")"); } #endif } } if (!_costing && (clip != null)) { _dc.PopClip(); } } ////// Critical: image.Buffer is SecurityCritical /// TreatAsSafe: Output is sent to GDIExporter, GDI, and then to printer driver, all considered trusted /// [SecurityCritical, SecurityTreatAsSafe] void IProxyDrawingContext.DrawImage(ImageProxy image, Rect dest, Geometry clip, Matrix trans) { if (_costing) { _cost += image.PixelWidth * image.PixelHeight * 3; return; } // Sometimes clip selects only a small portion of the image. Clip image to reduce amount // of data sent to GDI. if (clip != null) { if (!Utility.IsRenderVisible(clip.Bounds)) { // completely clipped away return; } // transform clip to image space, taking into account image DPI Matrix imageTransform = new Matrix(); imageTransform.Scale(dest.Width / image.Image.Width, dest.Height / image.Image.Height); imageTransform.Translate(dest.X, dest.Y); imageTransform.Append(trans); imageTransform.Invert(); Geometry imageClip = Utility.TransformGeometry(clip, imageTransform); // Clip the image to clip bounds. ImageProxy.GetClippedImage has no effect if clipping // bounds are almost image size. Rect clippedImageBounds; BitmapSource clippedImageSource = image.GetClippedImage(imageClip.Bounds, out clippedImageBounds); if (clippedImageSource == null) { // image has been clipped away return; } ImageProxy clippedImage = new ImageProxy(clippedImageSource); // adjust destination rectangle to new clipped image bounds double scaleX = dest.Width / image.Image.Width; double scaleY = dest.Height / image.Image.Height; dest = new Rect( clippedImageBounds.X * scaleX + dest.X, clippedImageBounds.Y * scaleY + dest.Y, clippedImageBounds.Width * scaleX, clippedImageBounds.Height * scaleY ); image = clippedImage; } image.BlendOverColor(Colors.White, 1.0, false); // BitmapSource img = image.GetImage(); if (clip != null) { _dc.PushClip(clip); } if (! trans.IsIdentity) { _dc.PushTransform(trans); } #if DEBUG _seq ++; _dc.Comment("-> DrawImage " + _seq); #endif _dc.DrawImage(image.Image, image.Buffer, dest); #if DEBUG _dc.Comment("<- DrawImage " + _seq); if (Configuration.Verbose >= 2) { Console.WriteLine(" DrawImage(" + _comment + ")"); } #endif if (!trans.IsIdentity) { _dc.PopTransform(); } if (clip != null) { _dc.PopClip(); } } bool IProxyDrawingContext.DrawGlyphs(GlyphRun glyphrun, Geometry clip, Matrix trans, BrushProxy foreground) { Debug.Assert(!_costing, "in costing mode DrawyGlyphs"); BrushProxy bp = BrushProxy.BlendColorWithBrush(false, Colors.White, foreground, false); Brush b = bp.Brush; if ((b == null) || (b is DrawingBrush)) { return false; } if (clip != null) { _dc.PushClip(clip); } if (!trans.IsIdentity) { _dc.PushTransform(trans); } #if DEBUG _seq ++; _dc.Comment("-> DrawGlyphRun " + _seq); #endif _dc.DrawGlyphRun(b, glyphrun); #if DEBUG _dc.Comment("<- DrawGlyphRun " + _seq); if (Configuration.Verbose >= 2) { Console.WriteLine(" DrawGlyphRun(" + _comment + ")"); } #endif if (!trans.IsIdentity) { _dc.PopTransform(); } if (clip != null) { _dc.PopClip(); } return true; } #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
- TextRangeAdaptor.cs
- Positioning.cs
- DbConnectionPoolIdentity.cs
- UserPreferenceChangingEventArgs.cs
- AppDomain.cs
- ExpressionBuilderContext.cs
- CompositeControl.cs
- ScriptManager.cs
- ValueExpressions.cs
- DynamicQueryStringParameter.cs
- FixedSOMLineRanges.cs
- BindingSourceDesigner.cs
- BamlRecords.cs
- StatusBarPanelClickEvent.cs
- RecommendedAsConfigurableAttribute.cs
- SHA512Managed.cs
- InstanceDataCollection.cs
- CaseDesigner.xaml.cs
- BooleanToVisibilityConverter.cs
- WebInvokeAttribute.cs
- IndexingContentUnit.cs
- UpdatePanelControlTrigger.cs
- TdsParserHelperClasses.cs
- XmlSchemaComplexContent.cs
- NullableLongAverageAggregationOperator.cs
- UIElement3D.cs
- StrokeRenderer.cs
- SiteMapNodeCollection.cs
- IgnorePropertiesAttribute.cs
- SQLCharsStorage.cs
- DigestTraceRecordHelper.cs
- WaitForChangedResult.cs
- ColorTranslator.cs
- ItemContainerPattern.cs
- ButtonBase.cs
- RubberbandSelector.cs
- Exceptions.cs
- ContextStack.cs
- Operator.cs
- UDPClient.cs
- ErrorTableItemStyle.cs
- CoTaskMemHandle.cs
- COM2ComponentEditor.cs
- TextElementEnumerator.cs
- EventListenerClientSide.cs
- DefaultShape.cs
- XmlFormatReaderGenerator.cs
- xmlglyphRunInfo.cs
- TreeViewAutomationPeer.cs
- XmlConvert.cs
- AuthorizationSection.cs
- BooleanProjectedSlot.cs
- NumericExpr.cs
- CryptoHelper.cs
- ObjectViewEntityCollectionData.cs
- JsonObjectDataContract.cs
- SystemResourceHost.cs
- WmlControlAdapter.cs
- SafeProcessHandle.cs
- ConnectionPointConverter.cs
- MachineKeyConverter.cs
- LineBreakRecord.cs
- CodeCommentStatement.cs
- PropertyMap.cs
- ReflectionUtil.cs
- CodeAttributeDeclarationCollection.cs
- Int32.cs
- LayoutEvent.cs
- MonitoringDescriptionAttribute.cs
- PeerCredential.cs
- AstTree.cs
- Vector3DKeyFrameCollection.cs
- SmiSettersStream.cs
- externdll.cs
- InstanceCreationEditor.cs
- AppModelKnownContentFactory.cs
- ReadContentAsBinaryHelper.cs
- sqlser.cs
- ReflectTypeDescriptionProvider.cs
- ProcessModuleCollection.cs
- XpsDigitalSignature.cs
- CatalogZone.cs
- GeneralTransform3DTo2D.cs
- OuterGlowBitmapEffect.cs
- FixedDocumentSequencePaginator.cs
- TableLayoutColumnStyleCollection.cs
- PermissionRequestEvidence.cs
- MediaContext.cs
- FixedSOMGroup.cs
- EditableLabelControl.cs
- ByteAnimationUsingKeyFrames.cs
- ReturnEventArgs.cs
- CompressedStack.cs
- ColorDialog.cs
- CommandHelper.cs
- DynamicObject.cs
- SequentialActivityDesigner.cs
- Base64Encoding.cs
- RuntimeEnvironment.cs
- ArrayConverter.cs