Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Print / Reach / AlphaFlattener / Flattener.cs / 2 / Flattener.cs
//------------------------------------------------------------------------------ // Microsoft Printing // Copyright (c) Microsoft Corporation, 2004 // // File: Flattener.cs // // History: // [....]: 04/20/2004 Created //----------------------------------------------------------------------------- using System; using System.Diagnostics; using System.Collections; // for ArrayList using System.Windows; // for Rect WindowsBase.dll using System.Windows.Media; // for Geometry, Brush, ImageData. PresentationCore.dll using System.Windows.Media.Imaging; using System.Collections.Generic; using System.IO; using System.Xml; using System.Globalization; using System.Windows.Xps.Serialization; using System.Printing; using System.Security; using System.Security.Permissions; namespace Microsoft.Internal.AlphaFlattener { ////// Tree flattener and Alpha flattener. /// internal class Flattener { #region Constructors public Flattener(bool disJoint, double width, double height) { _dl = new DisplayList(disJoint, width, height); } #endregion #region Public Methods ////// General routine for adding a Primitive to DisplayList /// 1) Apply transformation to Geometry, Brush, Pen /// 2) Optimize Primitive /// 3) Add to DisplayList /// /// public void AddPrimitive(Primitive p) { if (p.IsTransparent) { return; } p.ApplyTransform(); if (!p.Optimize()) { return; } GeometryPrimitive gp = p as GeometryPrimitive; if (gp != null) { if ((gp.Pen != null) && (gp.Pen.StrokeBrush.Brush is DrawingBrush)) { gp.Widen(); } } _dl.RecordPrimitive(p); } ////// Flatten the structure of a primitive tree by push clip/transform/opacity onto each leaf node. /// Build an index in a DisplayList. /// /// /// /// /// /// public void TreeFlatten(Primitive tree, Geometry clip, Matrix transform, double opacity, BrushProxy opacityMask) { More: if (tree == null) { return; } Debug.Assert(Utility.IsValid(opacity) && Utility.IsValid(tree.Opacity), "Invalid opacity encountered, should've been normalized in conversion to Primitive"); // Non-invertible transforms may arise from brush unfolding, where brush content is huge but // we need to scale down significantly to fill target region. Allow such transforms. CanvasPrimitive canvas = tree as CanvasPrimitive; if (canvas != null) { ArrayList children = canvas.Children; // No children, nothing to do if ((children == null) || (children.Count == 0)) { return; } opacity *= tree.Opacity; // transform opacity mask into current primitive space if (opacityMask != null) { Matrix worldToPrimitiveTransform = tree.Transform; worldToPrimitiveTransform.Invert(); opacityMask.ApplyTransform(worldToPrimitiveTransform); } opacityMask = BrushProxy.BlendBrush(opacityMask, tree.OpacityMask); // Skip the subtree if it's transparent enough if (Utility.IsTransparent(opacity)) { return; } transform = tree.Transform * transform; Geometry transclip = Utility.TransformGeometry(tree.Clip, transform); bool empty; clip = Utility.Intersect(clip, transclip, Matrix.Identity, out empty); if (empty) { return; } // For single child, just push transform/clip/opacity onto it. if (children.Count == 1) { tree = children[0] as Primitive; // Save a recursive call goto More; } if (Configuration.BlendAlphaWithWhite || Configuration.ForceAlphaOpaque || (Utility.IsOpaque(opacity) && (opacityMask == null))) // For opaque subtree, just push trasform/clip into it. { foreach (Primitive p in children) { TreeFlatten(p, clip, transform, opacity, opacityMask); } } else { // A semi-transparent sub-tree with more than one child Flattener fl = new Flattener(true, _dl.m_width, _dl.m_height); Primitive ntree = tree; ntree.Clip = null; ntree.Transform = Matrix.Identity; ntree.Opacity = 1.0; ntree.OpacityMask = null; #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine("TreeFlatten for subtree"); } #endif if (opacityMask != null) { opacityMask.ApplyTransform(transform); } // Flatten sub-tree structure into a new DisplayList fl.TreeFlatten(ntree, clip, transform, 1.0, null); // Remove alpha in the sub-tree and add to the current display list #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine("end TreeFlatten for subtree"); Console.WriteLine("AlphaFlatten for subtree"); } #endif fl.AlphaFlatten(new DisplayListDrawingContext(this, opacity, opacityMask, Matrix.Identity, null), true); #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine("end AlphaFlatten for subtree"); } #endif } } else { GeometryPrimitive gp = tree as GeometryPrimitive; if (gp != null && gp.Brush != null && gp.Pen != null && (!gp.IsOpaque || !Utility.IsOpaque(opacity))) { // // As an optimization we split fill from stroke, however doing so requires // an intermediate canvas to handle translucent fill/stroke, otherwise // the translucent stroke and fill will overlap. // CanvasPrimitive splitCanvas = new CanvasPrimitive(); GeometryPrimitive fill = (GeometryPrimitive)gp; GeometryPrimitive stroke = (GeometryPrimitive)gp.Clone(); fill.Pen = null; stroke.Brush = null; splitCanvas.Children.Add(fill); splitCanvas.Children.Add(stroke); tree = splitCanvas; goto More; } // Push transform/clip/opacity to leaf node tree.Transform = tree.Transform * transform; if (tree.Clip == null) { tree.Clip = clip; } else { Geometry transclip = Utility.TransformGeometry(tree.Clip, transform); bool empty; tree.Clip = Utility.Intersect(transclip, clip, Matrix.Identity, out empty); if (!empty) { empty = Utility.IsEmpty(tree.Clip, Matrix.Identity); } if (empty) { return; } } tree.PushOpacity(opacity, opacityMask); if (gp != null) { // Split fill and stroke into separate primitives if no opacity involved. // Intermediate Canvas not needed due to opaqueness. if ((gp.Brush != null) && (gp.Pen != null)) { GeometryPrimitive fill = gp.Clone() as GeometryPrimitive; fill.Pen = null; AddPrimitive(fill); // Fill only first // Stroke is flattend to fill only when needed gp.Brush = null; AddPrimitive(gp); // Followed by stroke only } else if ((gp.Pen != null) || (gp.Brush != null)) { AddPrimitive(gp); } } else { // Record it AddPrimitive(tree); } } } ////// Resolve object overlapping in a primitive tree. /// Send broken down drawing primitives to _dc. /// /// /// True if all output primitives need to be disjoint public void AlphaFlatten(IProxyDrawingContext dc, bool disjoint) { Listcommands = _dl.Commands; if (commands == null) { return; } int count = commands.Count; _dc = dc; bool needFlattening = true; if (Configuration.BlendAlphaWithWhite || Configuration.ForceAlphaOpaque) { needFlattening = false; } else if (!disjoint) { needFlattening = false; for (int i = 0; i < count; i++) { PrimitiveInfo info = commands[i]; if (!info.primitive.IsOpaque) { needFlattening = true; break; } } } if (needFlattening) { #if DEBUG Console.WriteLine(); Console.WriteLine("Stage 2: Calculating intersections using bounding boxes"); Console.WriteLine(); #endif // Still need all the primitive, for removal by opaque covering and white primitive removal _dl.CalculateIntersections(count); } #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine(); Console.WriteLine("Original display list"); Console.WriteLine(); DisplayList.PrintPrimitive(null, -1, true); for (int i = 0; i < count; i ++) { DisplayList.PrintPrimitive(commands[i], i, true); } Console.WriteLine(); Console.WriteLine("Primitives in display list: {0}", count); Console.WriteLine(); } #endif if (needFlattening) { DisplayListOptimization(commands, count, disjoint); } #if DEBUG for (int i = 0; i < count; i ++) { if (commands[i] != null) { commands[i].SetID(i); } } Console.WriteLine(); Console.WriteLine("Stage 4: Alpha flattening"); Console.WriteLine(); #endif for (int i = 0; i < count; i++) { PrimitiveInfo info = commands[i]; if (info == null) { continue; } String desp = null; #if DEBUG if (Configuration.Verbose >= 2) { Console.Write(i); Console.Write(": "); } desp = info.id; #endif if (info.m_cluster != null) { info.m_cluster.Render(commands, dc); } else { AlphaRender(info.primitive, info.overlap, info.overlapHasTransparency, disjoint, desp); } #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine(""); } #endif } _dc = null; } #endregion #region Private Methods /// /// Remove a primitive from display list /// /// private void DeleteCommand(int i) { #if DEBUG Console.WriteLine("Delete command {0}", i); #endif PrimitiveInfo pi = _dl.Commands[i]; if (pi.overlap != null) { foreach (int j in pi.overlap) { _dl.Commands[j].underlay.Remove(i); } } if (pi.underlay != null) { bool trans = ! pi.primitive.IsOpaque; foreach (int j in pi.underlay) { if (trans) { _dl.Commands[j].overlapHasTransparency--; } _dl.Commands[j].overlap.Remove(i); } } _dl.Commands[i] = null; } #if DEBUG static int vipID; // = 0; static void SerializeVisual(Visual visual, double width, double height, String filename) { FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite); XmlTextWriter writer = new System.Xml.XmlTextWriter(stream, System.Text.Encoding.UTF8); writer.Formatting = System.Xml.Formatting.Indented; writer.Indentation = 4; writer.WriteStartElement("FixedDocument"); writer.WriteAttributeString("xmlns", "http://schemas.microsoft.com/winfx/2006/xaml/presentation"); writer.WriteAttributeString("xmlns:x", "http://schemas.microsoft.com/winfx/2006/xaml"); writer.WriteStartElement("PageContent"); writer.WriteStartElement("FixedPage"); writer.WriteAttributeString("Width", width.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Height", height.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Background", "White"); writer.WriteStartElement("Canvas"); System.IO.StringWriter resString = new StringWriter(CultureInfo.InvariantCulture); System.Xml.XmlTextWriter resWriter = new System.Xml.XmlTextWriter(resString); resWriter.Formatting = System.Xml.Formatting.Indented; resWriter.Indentation = 4; System.IO.StringWriter bodyString = new StringWriter(CultureInfo.InvariantCulture); System.Xml.XmlTextWriter bodyWriter = new System.Xml.XmlTextWriter(bodyString); bodyWriter.Formatting = System.Xml.Formatting.Indented; bodyWriter.Indentation = 4; VisualTreeFlattener.SaveAsXml(visual, resWriter, bodyWriter, filename); resWriter.Close(); bodyWriter.Close(); writer.Flush(); writer.WriteRaw(resString.ToString()); writer.WriteRaw(bodyString.ToString()); writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndElement(); // FixedDocument writer.Close(); stream.Close(); } #endif private static bool BlendCommands(PrimitiveInfo pi, PrimitiveInfo pj) { GeometryPrimitive gi = pi.primitive as GeometryPrimitive; GeometryPrimitive gj = pj.primitive as GeometryPrimitive; if ((gi != null) && (gi.Brush != null) && (gj != null) && (gj.Brush != null)) { // get brushes in world space BrushProxy bi = gi.Brush.ApplyTransformCopy(gi.Transform); BrushProxy bj = gj.Brush.ApplyTransformCopy(gj.Transform); gi.Brush = bi.BlendBrush(bj); return true; } return false; } ////// Switch commands [i] [j], when i is covered by j /// /// Display list /// first command /// commands[i] /// second command /// command[j] /// Disconnect (i,j) overlap/underlay relationship static private void SwitchCommands(Listcommands, int i, PrimitiveInfo pi, int j, PrimitiveInfo pj, bool disconnect) { if ((pi != null) && (pj != null) && disconnect) { pi.overlap.Remove(j); if (!pj.primitive.IsOpaque) { pi.overlapHasTransparency--; } pj.underlay.Remove(i); } if (pi != null) { if (pi.overlap != null) { foreach (int k in pi.overlap) { commands[k].underlay.Remove(i); commands[k].underlay.Add(j); } } if (pi.underlay != null) { foreach (int k in pi.underlay) { commands[k].overlap.Remove(i); commands[k].overlap.Add(j); } } } if (pj != null) { if (pj.overlap != null) { foreach (int k in pj.overlap) { commands[k].underlay.Remove(j); commands[k].underlay.Add(i); } } if (pj.underlay != null) { foreach (int k in pj.underlay) { commands[k].overlap.Remove(j); commands[k].overlap.Add(i); } } } commands[i] = pj; commands[j] = pi; } /// /// Bug 1687865 /// Special optimization for annotation type of visual: lots of glyph runs covered by a single transparency geometry /// t1 ... tn g => t1 ... tn-1 g tn' /// => g t1' ... tn' /// /// /// private static void PushTransparencyDown(Listcommands, int j) { PrimitiveInfo pj = commands[j]; GeometryPrimitive gj = pj.primitive as GeometryPrimitive; if ((gj == null) || (pj.underlay == null) || (pj.underlay.Count == 0)) { return; } for (int n = pj.underlay.Count - 1; n >= 0; n --) { int i = pj.underlay[n]; PrimitiveInfo pi = commands[i]; if (pi == null) { continue; } GeometryPrimitive gi = pi.primitive as GeometryPrimitive; if ((gi != null) && (gi.Pen == null) && (pi.overlap.Count == 1) && pj.FullyCovers(pi)) { // c[i] ... c[j] => ... c[j] c[i]' if (BlendCommands(pi, pj)) // pi.Brush = Blend(pi.Brush, pj.Brush) { pj.underlay.Remove(i); pi.overlap = null; pi.overlapHasTransparency = 0; while (i < j) { SwitchCommands(commands, i, commands[i], i + 1, commands[i + 1], false); i ++; } j --; } } } } /// /// Optimization: If a transparent primitive is covered underneath immediately by an opaque primitive, /// or has nothing underneath, convert it to opaque primitive /// /// /// private static bool ConvertTransparentOnOpaque(Listcommands, int i) { PrimitiveInfo pi = commands[i]; GeometryPrimitive gp = pi.primitive as GeometryPrimitive; if (gp != null) { PrimitiveInfo qi = null; if ((pi.underlay != null) && (pi.underlay.Count != 0)) { qi = commands[pi.underlay[pi.underlay.Count - 1]]; } if ((qi == null) || (qi.primitive.IsOpaque && qi.FullyCovers(pi))) { BrushProxy under = BrushProxy.CreateColorBrush(Colors.White); if (qi != null) { GeometryPrimitive qp = qi.primitive as GeometryPrimitive; if (qp != null) { under = qp.Brush; } } if (under != null) { // Blend it with brush underneath BrushProxy blendedBrush = gp.Brush; BrushProxy blendedPenBrush = gp.Pen == null ? null : gp.Pen.StrokeBrush; if (blendedBrush != null) { blendedBrush = under.BlendBrush(blendedBrush); } else if (blendedPenBrush != null) { blendedPenBrush = under.BlendBrush(blendedPenBrush); } // // Fix bug 1293500: // Allow blending to proceed only if we did not generate pen stroke // brush that is a brush list. Reason: Such a case would have to be // handled during rendering by stroking the object with each brush // in the list. But we're already rendering brushes of underlying // objects, so the optimization is pointless. // bool proceedBlending = true; if (blendedPenBrush != null && blendedPenBrush.BrushList != null) { proceedBlending = false; } if (proceedBlending) { gp.Brush = blendedBrush; if (gp.Pen != null) { gp.Pen.StrokeBrush = blendedPenBrush; } } if (proceedBlending && pi.primitive.IsOpaque) { #if DEBUG Console.WriteLine("Make {0} opaque", i); #endif if (pi.underlay != null) { for (int k = 0; k < pi.underlay.Count; k++) { commands[pi.underlay[k]].overlapHasTransparency--; } } return true; } } } } return false; } /// /// Optimization: If a transparent primitive is covered underneath by an opaque primitive, cut its ties with all primitives before it /// /// /// /// private static void ReduceTie(PrimitiveInfo pi, Listcommands, int i) { if ((pi.underlay != null) && !pi.primitive.IsOpaque) { int len = pi.underlay.Count; for (int j = len - 1; j >= 0; j--) { PrimitiveInfo qi = commands[pi.underlay[j]]; if (qi.primitive.IsOpaque && qi.FullyCovers(pi)) { for (int k = j - 1; k >= 0; k--) { int under = pi.underlay[k]; commands[under].overlap.Remove(i); commands[under].overlapHasTransparency--; pi.underlay.Remove(under); } break; } } } } private static List [] CopyUnderlay(int count, List commands) { List [] oldUnderlay = new List [count]; for (int i = 0; i < count; i++) { List l = commands[i].underlay; if (l != null) { oldUnderlay[i] = new List (l.Count); for (int j = 0; j < l.Count; j++) { oldUnderlay[i].Add(l[j]); } } } return oldUnderlay; } /// /// Optimization phase /// /// /// /// private void DisplayListOptimization(Listcommands, int count, bool disjoint) { #if DEBUG Console.WriteLine(); Console.WriteLine("Start 3: Display list optimization"); Console.WriteLine(); #endif List [] oldUnderlay = null; if (!disjoint) // If not in a subtree which needs full flattening { // The following optimization may change PrimitiveInfo.underlay, but this is needed // for cluster calcuation. So we make a copy of it for use within this routine only oldUnderlay = CopyUnderlay(count, commands); // These optimizations need to run in a seperate pass, because they may affect other primitives for (int i = 0; i < count; i++) { repeat: PrimitiveInfo pi = commands[i]; if (pi == null) continue; // Optimization: If a primitive is covered by an opaque primtive, delete it if (pi.overlap != null) { bool deleted = false; for (int j = 0; j < pi.overlap.Count; j++) { PrimitiveInfo qi = commands[pi.overlap[j]]; if (qi.primitive.IsOpaque && qi.FullyCovers(pi)) { DeleteCommand(i); deleted = true; break; } } if (deleted) { continue; } } // Optimization: If a primitive is covered by overlap[0], blend brush and switch order // This results in smaller area being rendered as blending of two brushes. if ((pi.overlap != null) && (pi.overlap.Count != 0)) { int j = pi.overlap[0]; // first overlapping primitive PrimitiveInfo pj = commands[j]; // Do not attempt to blend if both primitives cover exactly same area, since blending // one into the other provides no benefits. if ((pj.underlay[pj.underlay.Count - 1] == i) && pj.FullyCovers(pi) && !pi.FullyCovers(pj)) { if (BlendCommands(pi, pj)) { SwitchCommands(commands, i, pi, j, pj, true); goto repeat; // pj at position i needs to be processed } } } // Optimization: Delete white primitives with nothing underneath if ((pi.underlay == null) && DisplayList.IsWhitePrimitive(pi.primitive)) { DeleteCommand(i); continue; } // Optimization: If a transparent primitive is covered underneath by an opaque primitive, cut its ties with all primitives before it ReduceTie(pi, commands, i); // Transparent primitive if (!pi.primitive.IsOpaque) { // Optimization: If a transparent primitive is covered underneath immediately by an opaque primitive, // or has nothing underneath, convert it to opaque primitive if (! ConvertTransparentOnOpaque(commands, i)) { PushTransparencyDown(commands, i); } } } for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; if (pi == null) { continue; } // Optimization: If a primitive is covered by all opaque primitives, cut its ties with primitive on top of it. // This check is also implemented in PrimitiveRender.FindIntersection, // in which it is on a remaing items in overlapping list. // With overlapHasTransparency flag, it can be moved forward. if ((pi.overlap != null) && (pi.overlapHasTransparency == 0)) { foreach (int j in pi.overlap) { commands[j].underlay.Remove(i); } pi.overlap = null; } // Optimization: If an opaque primitive is covered by all opaque primitives, cut its ties with primitives under it. if ((pi.underlay != null) && (pi.overlapHasTransparency == 0) && pi.primitive.IsOpaque) { foreach (int j in pi.underlay) { commands[j].overlap.Remove(i); } pi.underlay = null; } } } List transparentCluster = Cluster.CalculateCluster(commands, count, disjoint, oldUnderlay); Cluster.CheckForRasterization(transparentCluster, commands); #if DEBUG if (HasUnmanagedCodePermission()) { LogInterestingPrimitives(commands, count, transparentCluster); SaveInterestingPrimitives(commands, count, transparentCluster); } #endif } #if DEBUG static bool HasUnmanagedCodePermission() { try { new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); } catch(SecurityException ) { return false ; } return true; } internal void LogInterestingPrimitives(List commands, int count, List transparentCluster) { if (Configuration.Verbose >= 1) { // Display only interesting primitives DisplayList.PrintPrimitive(null, -1, false); Rect target = Rect.Empty; int vip = 0; for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; if ((pi != null) && ((pi.overlapHasTransparency != 0) || !pi.primitive.IsOpaque)) { if (!pi.primitive.IsOpaque) { target.Union(pi.bounds); } DisplayList.PrintPrimitive(commands[i], i, false); vip++; } } Console.WriteLine(); Console.WriteLine("Interesting primitives: {0}", vip); Console.WriteLine("Area with transparency: {0}", DisplayList.LeftPad(target, 0)); Console.WriteLine(); for (int i = 0; i < transparentCluster.Count; i++) { Console.WriteLine( "Cluster {0}: {1} {2} {3}", i + 1, DisplayList.LeftPad(transparentCluster[i].DebugBounds, 0), DisplayList.LeftPad(transparentCluster[i].DebugPrimitives, 0), transparentCluster[i].DebugRasterize); } Console.WriteLine(); } } internal void SaveInterestingPrimitives(List commands, int count, List transparentCluster) { if (Configuration.SerializePrimitives) { // render primitives to DrawingVisual DrawingVisual dv = new DrawingVisual(); using (DrawingContext ctx = dv.RenderOpen()) { Pen black = new Pen(Brushes.Black, 0.8); black.DashStyle = DashStyles.Dash; for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; if ((pi != null) && ((pi.overlapHasTransparency != 0) || !pi.primitive.IsOpaque)) { pi.primitive.OnRender(ctx); if (!pi.primitive.IsOpaque) { ctx.DrawRectangle(null, black, pi.bounds); } // Rect bounds = pi.bounds; // Console.WriteLine(" ", // bounds.Left, bounds.Top, bounds.Width, bounds.Height); } } Pen pen = new Pen(Brushes.Blue, 0.8); pen.DashStyle = DashStyles.Dot; for (int i = 0; i < transparentCluster.Count; i++) { ctx.DrawRectangle(null, pen, transparentCluster[i].DebugBounds); } } // save visual to xaml string name = "vip.xaml"; for (int i = 0; (name != null) && (i < 10); i++) { try { if (vipID != 0) { name = "vip" + vipID + ".xaml"; } SerializeVisual(dv, _dl.m_width, _dl.m_height, name); Console.WriteLine("Serialized primitives to " + name); name = null; } catch (System.IO.IOException e) { Console.WriteLine(e.ToString()); name = "vip" + vipID + ".xaml"; } vipID++; } } } #endif /// /// Resolve overlapping for a single primitive /// /// /// /// /// /// private void AlphaRender(Primitive primitive, Listoverlapping, int overlapHasTransparency, bool disjoint, string desp) { if (primitive == null) { return; } // Skip alpha flattening when there are too many layer of transparency if (overlapHasTransparency > Configuration.MaximumTransparencyLayer) { overlapping = null; } PrimitiveRenderer ri = new PrimitiveRenderer(); ri.Clip = primitive.Clip; ri.Brush = null; ri.Pen = null; ri.Overlapping = overlapping; ri.Commands = _dl.Commands; ri.DC = _dc; ri.Disjoint = disjoint; GeometryPrimitive p = primitive as GeometryPrimitive; if (p != null) { ri.Brush = p.Brush; ri.Pen = p.Pen; bool done = false; Geometry g = p.Geometry; GlyphPrimitive gp = p as GlyphPrimitive; if (gp != null) { done = ri.DrawGlyphs(gp.GlyphRun, gp.GetRectBounds(true), p.Transform, desp); if (!done) { g = p.WidenGeometry; } } if (!done) { if (!p.Transform.IsIdentity) { // Should not occur; GeometryPrimitive.ApplyTransform will push transform // to geometry and brush. g = Utility.TransformGeometry(g, p.Transform); if (ri.Brush != null) { ri.Brush = ri.Brush.ApplyTransformCopy(p.Transform); } if (ri.Pen != null && ri.Pen.StrokeBrush != null) { ri.Pen = ri.Pen.Clone(); ri.Pen.StrokeBrush = ri.Pen.StrokeBrush.ApplyTransformCopy(p.Transform); } } ri.DrawGeometry(g, desp, p); } return; } ImagePrimitive ip = primitive as ImagePrimitive; if (ip != null) { ri.RenderImage(ip.Image, ip.DstRect, ip.Clip, ip.Transform, desp); } else { Debug.Assert(false, "Wrong Primitive type"); } } #endregion #region Private Fields private IProxyDrawingContext _dc; private DisplayList _dl; #endregion #region Public Static Methods /// /// Flatten Primitive to ILegacyDevice /// public static void Convert(Primitive tree, ILegacyDevice dc, double width, double height, double dpix, double dpiy, Nullablequality) { // Change Flattener quality setting based on OutputQualityValue if (quality != null) { switch (quality) { case OutputQuality.Unknown: case OutputQuality.Automatic: break; case OutputQuality.Draft: case OutputQuality.Fax: case OutputQuality.Text: Configuration.RasterizationDPI = 96; Configuration.MaximumTransparencyLayer = 8; Configuration.GradientDecompositionDensity = 0.75; Configuration.DecompositionDepth = 2; break; case OutputQuality.Normal: Configuration.RasterizationDPI = 150; Configuration.MaximumTransparencyLayer = 12; Configuration.GradientDecompositionDensity = 1; Configuration.DecompositionDepth = 3; break; case OutputQuality.High: case OutputQuality.Photographic: Configuration.RasterizationDPI = 300; Configuration.MaximumTransparencyLayer = 16; Configuration.GradientDecompositionDensity = 1.25; Configuration.DecompositionDepth = 4; break; } } #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine(); Console.WriteLine("\r\nStage 1: Tree Flattening"); Console.WriteLine(); } #endif // Paper dimension as clipping Geometry clip = null; if ((width != 0) && (height != 0)) { clip = new RectangleGeometry(new Rect(0, 0, width, height)); } // Transform to device resolution Matrix transform = Matrix.Identity; transform.Scale(dpix / 96, dpiy / 96); Flattener fl = new Flattener(false, width, height); Toolbox.StartEvent(MS.Utility.EventTraceGuidId.DRXTREEFLATTENGUID); fl.TreeFlatten(tree, clip, transform, 1.0, null); Toolbox.EndEvent(MS.Utility.EventTraceGuidId.DRXTREEFLATTENGUID); Toolbox.StartEvent(MS.Utility.EventTraceGuidId.DRXALPHAFLATTENGUID); fl.AlphaFlatten(new BrushProxyDecomposer(dc), false); Toolbox.EndEvent(MS.Utility.EventTraceGuidId.DRXALPHAFLATTENGUID); #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine(); Console.WriteLine("End AlphaFlattening"); Console.WriteLine(); } #endif } #endregion } // end of class Flattener /// /// Implement ILegacyDevice using DrawingContext /// internal class OutputContext : ILegacyDevice { #region Private Fields private DrawingContext _ctx; #endregion #region Constructors ////// /// public OutputContext(DrawingContext context) { _ctx = context; } #endregion #region ILegacyDevice Members void ILegacyDevice.PopClip() { _ctx.Pop(); } void ILegacyDevice.PopTransform() { _ctx.Pop(); } void ILegacyDevice.PushClip(Geometry clipGeometry) { _ctx.PushClip(clipGeometry); } void ILegacyDevice.PushTransform(Matrix transform) { _ctx.PushTransform(new MatrixTransform(transform)); } int ILegacyDevice.StartDocument(string printerName, string jobName, string filename, byte[] devmode) { throw new InvalidOperationException(); } void ILegacyDevice.StartDocumentWithoutCreatingDC(string printerName, string jobName, string filename) { throw new InvalidOperationException(); } void ILegacyDevice.EndDocument() { throw new InvalidOperationException(); } void ILegacyDevice.CreateDeviceContext(string printerName, string jobName, byte[] devmode) { throw new InvalidOperationException(); } void ILegacyDevice.DeleteDeviceContext() { throw new InvalidOperationException(); } String ILegacyDevice.ExtEscGetName() { throw new InvalidOperationException(); } bool ILegacyDevice.ExtEscMXDWPassThru() { throw new InvalidOperationException(); } void ILegacyDevice.StartPage(byte[] devmode, int rasterizationDPI) { throw new InvalidOperationException(); } /* void ILegacyDevice.PushOpacity(double opacity, Brush opacityMask) { Debug.Assert(opacityMask == null); _ctx.PushOpacity(opacity); } */ void ILegacyDevice.DrawGeometry(Brush brush, Pen pen, Brush strokeBrush, Geometry geometry) { if (pen != null) { if (strokeBrush == null) { pen = null; } else { pen = pen.CloneCurrentValue(); pen.Brush = strokeBrush; } } _ctx.DrawGeometry(brush, pen, geometry); } void ILegacyDevice.DrawImage(BitmapSource source, Byte[] buffer, Rect rc) { if (buffer != null) { source = BitmapSource.Create(source.PixelWidth, source.PixelHeight, 96, 96, PixelFormats.Pbgra32, null, buffer, source.PixelWidth * 4); } _ctx.DrawImage(source, rc); } void ILegacyDevice.DrawGlyphRun(Brush foreground, GlyphRun glyphRun) { _ctx.DrawGlyphRun(foreground, glyphRun); } void ILegacyDevice.Comment(string message) { } void ILegacyDevice.EndPage() { throw new InvalidOperationException(); } #endregion } } // end of namespace // 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
- UnauthorizedWebPart.cs
- AbsoluteQuery.cs
- EntityCodeGenerator.cs
- Config.cs
- Util.cs
- RTLAwareMessageBox.cs
- SchemaObjectWriter.cs
- EtwTrace.cs
- AuthorizationRule.cs
- CommandConverter.cs
- ReceiveMessageContent.cs
- BitArray.cs
- XmlSiteMapProvider.cs
- RSAOAEPKeyExchangeFormatter.cs
- RSAPKCS1SignatureFormatter.cs
- SafeHandle.cs
- MembershipSection.cs
- WebZoneDesigner.cs
- AsyncCompletedEventArgs.cs
- ContentTextAutomationPeer.cs
- ErrorRuntimeConfig.cs
- GetRecipientRequest.cs
- DialogWindow.cs
- ProcessHostMapPath.cs
- DeclarationUpdate.cs
- EtwTrace.cs
- Win32Native.cs
- LambdaCompiler.cs
- DelegatingTypeDescriptionProvider.cs
- Button.cs
- DiffuseMaterial.cs
- WebPartMenuStyle.cs
- AuthenticodeSignatureInformation.cs
- NestPullup.cs
- ConnectionStringsSection.cs
- ChannelManagerHelpers.cs
- ScrollData.cs
- MenuItemStyle.cs
- Types.cs
- MimeMapping.cs
- DataFormats.cs
- PkcsUtils.cs
- WorkflowLayouts.cs
- AccessorTable.cs
- FileDialog_Vista_Interop.cs
- ControlPropertyNameConverter.cs
- DataSet.cs
- SchemaCollectionPreprocessor.cs
- SqlDataSourceConfigureSelectPanel.cs
- RemoteWebConfigurationHost.cs
- OperationResponse.cs
- DataTrigger.cs
- ValidationError.cs
- GAC.cs
- InvalidFilterCriteriaException.cs
- PropertyMapper.cs
- TypedTableBase.cs
- SqlNodeAnnotations.cs
- StylusCaptureWithinProperty.cs
- XmlArrayItemAttribute.cs
- ButtonBaseAutomationPeer.cs
- DataGridViewRow.cs
- SchemaType.cs
- XhtmlBasicControlAdapter.cs
- MatrixAnimationBase.cs
- TableRowCollection.cs
- IDispatchConstantAttribute.cs
- StopRoutingHandler.cs
- MultiPageTextView.cs
- FileDialogCustomPlace.cs
- StreamWriter.cs
- CodeStatementCollection.cs
- DataDocumentXPathNavigator.cs
- PathSegment.cs
- PublisherMembershipCondition.cs
- XmlWrappingReader.cs
- DbException.cs
- ThreadStaticAttribute.cs
- SystemDropShadowChrome.cs
- XmlDataLoader.cs
- AmbientProperties.cs
- VisualStateManager.cs
- GradientStop.cs
- AccessDataSourceDesigner.cs
- EmptyWithCancelationCheckWorkItem.cs
- MembershipValidatePasswordEventArgs.cs
- WeakReferenceList.cs
- CompensationHandlingFilter.cs
- GZipUtils.cs
- StringPropertyBuilder.cs
- MobileErrorInfo.cs
- SharedDp.cs
- HttpResponseHeader.cs
- HandlerBase.cs
- MimeTypeMapper.cs
- DbTransaction.cs
- SchemaImporter.cs
- TextRenderer.cs
- NetStream.cs
- ExtentKey.cs