Ejemplo n.º 1
0
        void IProxyDrawingContext.Push(double opacity, BrushProxy opacityMask)
        {
            _pushedStack.Push(_opacity);
            _pushedStack.Push(_opacityMask);

            _opacity    *= opacity;
            _opacityMask = BrushProxy.BlendBrush(_opacityMask, opacityMask);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        // 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);
        }
Ejemplo n.º 4
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.º 5
0
        /// <summary>
        /// Optimization: If a transparent primitive is covered underneath immediately by an opaque primitive,
        /// or has nothing underneath, convert it to opaque primitive
        /// </summary>
        /// <param name="commands"></param>
        /// <param name="i"></param>
        private static bool ConvertTransparentOnOpaque(List <PrimitiveInfo> 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);
        }