Ejemplo n.º 1
0
 public DisplayListDrawingContext(
     Flattener flattener,
     double opacity,
     BrushProxy opacityMask,
     Matrix trans,
     Geometry clip)
 {
     _flattener   = flattener;
     _opacity     = opacity;
     _opacityMask = opacityMask;
     _transform   = trans;
     _clip        = clip;
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Start Tree/alpha flattening and send result to ILegacyDevice interface
        /// </summary>
        public void FlushPage(ILegacyDevice sink, double width, double height, Nullable <OutputQuality> outputQuality)
        {
            AssertState(DeviceState.PageStarted, DeviceState.DocStarted);

            if (_stack.Count != 0)
            {
                throw new InvalidOperationException();
            }

            if (sink != null)
            {
                Flattener.Convert(_root, sink, width, height, 96, 96, outputQuality);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Flatten the structure of a primitive tree by push clip/transform/opacity onto each leaf node.
        /// Build an index in a DisplayList.
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="clip"></param>
        /// <param name="transform"></param>
        /// <param name="opacity"></param>
        /// <param name="opacityMask"></param>
        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);
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Flatten Primitive to ILegacyDevice
        /// </summary>
        public static void Convert(Primitive tree, ILegacyDevice dc, double width, double height, double dpix, double dpiy,
                                   Nullable <OutputQuality> 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:
                    Configuration.RasterizationDPI             = 300;
                    Configuration.MaximumTransparencyLayer     = 16;
                    Configuration.GradientDecompositionDensity = 1.25;
                    Configuration.DecompositionDepth           = 4;
                    break;

                case OutputQuality.Photographic:
                    uint dcDpi = Math.Max(PrintQueue.GetDpiX(dc), PrintQueue.GetDpiY(dc));
                    Configuration.RasterizationDPI             = (int)(Math.Max(dcDpi, 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.EmitEvent(EventTrace.Event.WClientDRXTreeFlattenBegin);

            fl.TreeFlatten(tree, clip, transform, 1.0, null);

            Toolbox.EmitEvent(EventTrace.Event.WClientDRXTreeFlattenEnd);

            Toolbox.EmitEvent(EventTrace.Event.WClientDRXAlphaFlattenBegin);

            fl.AlphaFlatten(new BrushProxyDecomposer(dc), false);

            Toolbox.EmitEvent(EventTrace.Event.WClientDRXAlphaFlattenEnd);

#if DEBUG
            if (Configuration.Verbose >= 2)
            {
                Console.WriteLine();
                Console.WriteLine("End AlphaFlattening");
                Console.WriteLine();
            }
#endif
        }