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)
{
List commands = _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(List commands, 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(List commands, 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(List commands, 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, List commands, 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(List commands, 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, List overlapping, 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,
Nullable quality)
{
// 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
- PointCollection.cs
- FontStyleConverter.cs
- SystemIPGlobalStatistics.cs
- ItemCollection.cs
- ToolStripOverflowButton.cs
- SecurityDocument.cs
- ToolTip.cs
- DetailsViewAutoFormat.cs
- BaseAppDomainProtocolHandler.cs
- TraceInternal.cs
- ListItemCollection.cs
- NamespaceDisplayAutomationPeer.cs
- Validator.cs
- StringUtil.cs
- Compiler.cs
- ACE.cs
- FacetChecker.cs
- OleServicesContext.cs
- ConsoleCancelEventArgs.cs
- XmlSchemaGroup.cs
- WebDescriptionAttribute.cs
- Graph.cs
- FileChangesMonitor.cs
- XmlSchemaIdentityConstraint.cs
- CallbackCorrelationInitializer.cs
- RegexWriter.cs
- Point.cs
- FakeModelPropertyImpl.cs
- InfoCardTrace.cs
- SequentialWorkflowRootDesigner.cs
- UserPreferenceChangedEventArgs.cs
- MappedMetaModel.cs
- XmlDataSourceNodeDescriptor.cs
- CompModSwitches.cs
- EndpointConfigContainer.cs
- RegexEditorDialog.cs
- HttpStaticObjectsCollectionBase.cs
- DotExpr.cs
- BinHexEncoder.cs
- RecordBuilder.cs
- DataSvcMapFileSerializer.cs
- TraceInternal.cs
- DbDeleteCommandTree.cs
- SafeNativeMethods.cs
- WebDisplayNameAttribute.cs
- MD5CryptoServiceProvider.cs
- TabletCollection.cs
- TraceHandlerErrorFormatter.cs
- ExceptionUtility.cs
- DataRecordObjectView.cs
- UserPrincipalNameElement.cs
- NativeMethods.cs
- OutputCacheSettingsSection.cs
- SettingsProperty.cs
- Item.cs
- XmlFormatExtensionPointAttribute.cs
- TransactionProtocolConverter.cs
- Odbc32.cs
- WaitHandle.cs
- ObjectStateEntryBaseUpdatableDataRecord.cs
- Frame.cs
- ScriptingProfileServiceSection.cs
- SQLRoleProvider.cs
- RecordBuilder.cs
- DriveInfo.cs
- XmlIlVisitor.cs
- DBSchemaRow.cs
- _NtlmClient.cs
- WindowCollection.cs
- TextRunCacheImp.cs
- Application.cs
- BufferBuilder.cs
- XamlToRtfWriter.cs
- WebPartsPersonalizationAuthorization.cs
- SystemIPv6InterfaceProperties.cs
- SoapFault.cs
- Table.cs
- HandlerBase.cs
- Axis.cs
- ScriptingRoleServiceSection.cs
- WebConfigurationHost.cs
- PictureBox.cs
- StringAnimationUsingKeyFrames.cs
- BufferedGraphics.cs
- UnknownMessageReceivedEventArgs.cs
- SendActivityEventArgs.cs
- HostingEnvironment.cs
- MenuBase.cs
- UseLicense.cs
- Native.cs
- EncodingInfo.cs
- PerfCounters.cs
- NumberFunctions.cs
- MouseButtonEventArgs.cs
- VersionPair.cs
- DuplicateWaitObjectException.cs
- DataGridItem.cs
- UpdatePanelTriggerCollection.cs
- AssemblyBuilder.cs
- SmiEventSink_Default.cs