示例#1
0
        void IProxyDrawingContext.Push(double opacity, BrushProxy opacityMask)
        {
            _pushedStack.Push(_opacity);
            _pushedStack.Push(_opacityMask);

            _opacity    *= opacity;
            _opacityMask = BrushProxy.BlendBrush(_opacityMask, opacityMask);
        }
示例#2
0
        public void Pop()
        {
            AssertState(DeviceState.PageStarted, DeviceState.NoChange);

            _opacityMask = _stack.Pop() as BrushProxy;
            _opacity     = (double)_stack.Pop();
            _clip        = _stack.Pop() as Geometry;
            _root        = _stack.Pop() as CanvasPrimitive;
        }
示例#3
0
 public DisplayListDrawingContext(
     Flattener flattener,
     double opacity,
     BrushProxy opacityMask,
     Matrix trans,
     Geometry clip)
 {
     _flattener   = flattener;
     _opacity     = opacity;
     _opacityMask = opacityMask;
     _transform   = trans;
     _clip        = clip;
 }
示例#4
0
        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);
        }
示例#5
0
        /// <summary>
        ///
        /// </summary>
        public bool StartPage()
        {
            AssertState(DeviceState.DocStarted, DeviceState.PageStarted);

            _page  = new CanvasPrimitive();
            _root  = _page;
            _stack = new Stack();

            _opacity     = 1;
            _opacityMask = null;
            _clip        = null;

            return(true);
        }
示例#6
0
        public void BlendUnderBrush(bool opacityOnly, BrushProxy brush, Matrix trans)
        {
            if (brush.Brush is SolidColorBrush)
            {
                SolidColorBrush sb = brush.Brush as SolidColorBrush;

                BlendUnderColor(Utility.Scale(sb.Color, brush.Opacity), 1, opacityOnly);
            }
            else
            {
                Byte[] brushPixels = RasterizeBrush(brush, trans);

                Decode();

                Utility.BlendPixels(_pixels, opacityOnly, brushPixels, brush.OpacityOnly, _pixelWidth * _pixelHeight, _pixels);
            }
        }
示例#7
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);
        }
示例#8
0
        public void BlendOverBrush(bool opacityOnly, BrushProxy brush, Matrix trans)
        {
            if (IsOpaque())
            {
                Debug.Assert(!opacityOnly, "Opaque image OpacityMask should not be blended with brush");
                return;
            }

            if (brush.Brush is SolidColorBrush)
            {
                SolidColorBrush sb = brush.Brush as SolidColorBrush;

                BlendOverColor(Utility.Scale(sb.Color, brush.Opacity), 1.0, opacityOnly);
            }
            else
            {
                Byte[] brushPixels = RasterizeBrush(brush, trans);

                Decode();

                Utility.BlendPixels(brushPixels, brush.OpacityOnly, _pixels, opacityOnly, _pixelWidth * _pixelHeight, _pixels);
            }
        }
示例#9
0
 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");
 }
示例#10
0
        /// <summary>
        /// Fill a geometry using a list of brushes
        /// </summary>
        /// <param name="one">First brush to use</param>
        /// <param name="brushes">Brush list</param>
        /// <param name="from">Index to get the second brush</param>
        /// <param name="geometry">Geometry to fill</param>
        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);
        }
示例#11
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);
                }
            }
        }
示例#12
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);
        }
示例#13
0
        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);
        }
示例#14
0
        public void Push(
            Transform transform,
            Geometry clip,
            double opacity,
            Brush opacityMask,
            Rect maskBounds,
            bool onePrimitive,
            String nameAttr,
            Visual node,
            Uri navigateUri,
            EdgeMode edgeMode)
        {
            Debug.Assert(Utility.IsValid(opacity), "Invalid opacity should clip subtree");

            Matrix mat = Matrix.Identity;

            if (transform != null)
            {
                mat = transform.Value;
            }

            // opacity mask might be VisualBrush, hence ReduceBrush to reduce to DrawingBrush
            Debug.Assert(!BrushProxy.IsEmpty(opacityMask), "empty opacity mask should not result in Push");
            _dc.Push(
                mat,
                clip,
                opacity,
                ReduceBrush(opacityMask, maskBounds),
                maskBounds,
                onePrimitive,
                nameAttr,
                node,
                navigateUri,
                edgeMode
                );

            // prepend to transforms and clipping stack
            mat.Append(Transform);
            _fullTransform.Add(mat);

            // transform clip to world space, intersect with current clip, and push
            if (clip == null)
            {
                // push current clipping
                clip = Clip;
            }
            else
            {
                clip = Utility.TransformGeometry(clip, Transform);

                bool empty;
                clip = Utility.Intersect(clip, Clip, Matrix.Identity, out empty);

                if (empty)
                {
                    clip = Geometry.Empty;
                }
            }

            _fullClip.Add(clip);
        }
示例#15
0
        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
                    {
                        // relative may not be good enough
                        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);
        }
示例#16
0
        public void DrawGeometry(Brush brush, Pen pen, Geometry geometry)
        {
            // Ignore total transparent primitive
            if (Utility.IsTransparent(_opacity) || ((brush == null) && (pen == null || pen.Brush == null)) || (geometry == null))
            {
                return;
            }

            // Split if having both pen and brush
            if ((brush != null) && (pen != null))
            // if (!Utility.IsOpaque(_opacity) || (_opacityMask != null))
            {
                // Push a canvas to handle geometry with brush + pen properly
                Push(Matrix.Identity, null, 1.0, null, Rect.Empty, false);

                DrawGeometry(brush, null, geometry);
                DrawGeometry(null, pen, geometry);

                Pop();

                return;
            }

            AssertState(DeviceState.PageStarted, DeviceState.NoChange);

            GeometryPrimitive g = new GeometryPrimitive();

            g.Geometry    = geometry;
            g.Clip        = _clip;
            g.Opacity     = _opacity;
            g.OpacityMask = _opacityMask;

            int needBounds = 0; // 1 for fill, 2 for stroke

            if (brush != null)
            {
                // Fix bug 1427695: Need bounds for non-SolidColorBrushes to enable rebuilding Brush from BrushProxy.
                if (!(brush is SolidColorBrush))
                {
                    needBounds |= 1;
                }
            }

            if ((pen != null) && (pen.Brush != null))
            {
                if (!(pen.Brush is SolidColorBrush))
                {
                    needBounds |= 2;
                }
            }

            if (g.OpacityMask != null)
            {
                if (g.OpacityMask.BrushList == null && !(g.OpacityMask.Brush is SolidColorBrush))
                {
                    if (pen != null)
                    {
                        needBounds |= 2;
                    }
                    else
                    {
                        needBounds |= 1;
                    }
                }
            }

            Rect bounds = g.GetRectBounds((needBounds & 1) != 0);

            if (brush != null)
            {
                g.Brush = BrushProxy.CreateBrush(brush, bounds);
            }

            if ((needBounds & 2) != 0)
            {
                bounds = geometry.GetRenderBounds(pen);
            }

            if ((pen != null) && (pen.Brush != null))
            {
                g.Pen = PenProxy.CreatePen(pen, bounds);
            }

            if (g.OpacityMask != null)
            {
                if (!g.OpacityMask.MakeBrushAbsolute(bounds))
                {
                    // Fix bug 1463955: Brush has become empty; replace with transparent brush.
                    g.OpacityMask = BrushProxy.CreateColorBrush(Colors.Transparent);
                }
            }

            // Optimization: Unfold primitive DrawingBrush when possible to avoid rasterizing it.
            Primitive primitive = g.UnfoldDrawingBrush();

            if (primitive != null)
            {
                _root.Children.Add(primitive);
            }
        }
示例#17
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);
        }
示例#18
0
 private Byte[] RasterizeBrush(BrushProxy brush, Matrix trans)
 {
     return(brush.CreateBrushImage(trans, _pixelWidth, _pixelHeight));
 }
示例#19
0
        public void PushOpacity(double opacity, BrushProxy opacityMask, Rect rect, Matrix trans)
        {
            if (opacityMask != null)
            {
                rect.Transform(trans);

                //
                // Blend this image on top of opacity mask.
                //

                // Calculate scaling factor from opacity mask to this image.
                TileBrush opacityBrush = opacityMask.Brush as TileBrush;
                Rect      viewport;

                if (opacityBrush != null)
                {
                    Debug.Assert(opacityBrush.ViewportUnits == BrushMappingMode.Absolute, "TileBrush must have absolute viewport by this point");

                    viewport = opacityBrush.Viewport;
                }
                else
                {
                    // viewport covers entire image
                    viewport = rect;
                }

                // Fix for 1689025:

                double scaleX = _pixelWidth / rect.Width;
                double scaleY = _pixelHeight / rect.Height;

                // If current image is too small, magnify it to match opacity mask's size,
                // otherwise we lose the detail in opacity mask.
                if ((scaleX < MinimumBlendRatio || scaleY < MinimumBlendRatio) &&
                    (rect.Width <= MaximumOpacityMaskViewport) &&
                    (rect.Height <= MaximumOpacityMaskViewport)) // Avoiding generate huge bitmap
                {
                    Scale(rect.Width / _pixelWidth,
                          rect.Height / _pixelHeight);
                    scaleX = 1.0;
                    scaleY = 1.0;
                }

                // Transform brush to image space.
                Matrix transform = new Matrix();
                transform.Translate(-rect.Left, -rect.Top);
                transform.Scale(scaleX, scaleY);

                // Blend opacity mask into image.
                BlendUnderBrush(false, opacityMask, transform);
            }

            int op = Utility.OpacityToByte(opacity);

            if (op <= 0)
            {
                _image  = null;
                _pixels = null;
                return;
            }
            else if (op >= 255)
            {
                return;
            }

            Decode();

            Byte[] map = new Byte[256];

            for (int i = 0; i < 256; i++)
            {
                map[i] = (Byte)(i * op / 255);
            }

            int count = _pixelWidth * _pixelHeight * 4;

            for (int i = 0; i < count; i++)
            {
                _pixels[i] = map[_pixels[i]];
            }
        }
        /// <summary>
        /// Check if the whole cluster is complex enough such that rasterizing the whole thing is better than flattening it
        /// </summary>
        /// <param name="commands"></param>
        /// <returns></returns>
        private bool BetterRasterize(List <PrimitiveInfo> commands)
        {
            double clustersize = m_bounds.Width * m_bounds.Height;

            double diff = -Configuration.RasterizationCost(m_bounds.Width, m_bounds.Height);

            // Estimate cost of geometry operations (intersecting)
            double pathComplexity = 1;

            foreach (int i in m_primitives)
            {
                PrimitiveInfo pi = commands[i];

                Primitive p = pi.primitive;

                GeometryPrimitive gp = p as GeometryPrimitive;

                Rect bounds = pi.GetClippedBounds();

                bool rasterize = true;

                if (gp != null)
                {
                    double complexity = 1;

                    Geometry geo = gp.Geometry;

                    if (geo != null)
                    {
                        complexity = Utility.GetGeometryPointCount(geo);

                        // weight down the complexity of small region
                        complexity *= bounds.Width * bounds.Height / clustersize;
                    }

                    BrushProxy bp = gp.Brush;

                    if (bp == null)
                    {
                        bp = gp.Pen.StrokeBrush;

                        // Widen path would at least double the points
                        complexity *= 3;
                    }

                    if (complexity > 1)
                    {
                        pathComplexity *= complexity;

                        if (pathComplexity > 100000) // 333 x 333
                        {
                            return(true);
                        }
                    }

                    if (bp != null)
                    {
                        Brush b = bp.Brush;

                        if ((b != null) && ((b is SolidColorBrush) || (b is LinearGradientBrush)))
                        {
                            // SolidColorBrush does not need full rasterization
                            // Vertical/Horizontal linear gradient brush does not need full rasterization
                            rasterize = false;
                        }
                    }
                }

                if (rasterize)
                {
                    diff += Configuration.RasterizationCost(bounds.Width, bounds.Height);

                    if (diff > 0)
                    {
                        break;
                    }
                }
            }

            return(diff > 0);
        }
示例#21
0
 void IProxyDrawingContext.Pop()
 {
     _opacityMask = (BrushProxy)_pushedStack.Pop();
     _opacity     = (double)_pushedStack.Pop();
 }
示例#22
0
        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();
            }
        }
示例#23
0
        public void Push(Matrix transform, Geometry clip, double opacity, Brush opacityMask, Rect maskBounds, bool onePrimitive)
        {
            AssertState(DeviceState.PageStarted, DeviceState.NoChange);

            opacity = Utility.NormalizeOpacity(opacity);

            if (!Utility.IsValid(transform))
            {
                // treat as invisible subtree
                opacity   = 0.0;
                transform = Matrix.Identity;
            }

            _stack.Push(_root);
            _stack.Push(_clip);
            _stack.Push(_opacity);
            _stack.Push(_opacityMask);

            bool noTrans = transform.IsIdentity;

            if (onePrimitive && noTrans && (opacityMask == null))
            {
                bool empty;

                _clip        = Utility.Intersect(_clip, clip, Matrix.Identity, out empty);
                _opacity    *= opacity;
                _opacityMask = null;

                if (empty)
                {
                    _opacity = 0;
                }
            }
            else
            {
                CanvasPrimitive c = new CanvasPrimitive();

                if (noTrans)
                {
                    c.Transform = Matrix.Identity;
                }
                else
                {
                    c.Transform = transform;

                    Matrix invertTransform = transform;
                    invertTransform.Invert();

                    _clip = Utility.TransformGeometry(_clip, invertTransform); // transform inherited clip to this level
                }

                bool empty;

                c.Clip    = Utility.Intersect(clip, _clip, Matrix.Identity, out empty); // Combined with inherited attributes
                c.Opacity = opacity * _opacity;

                if (empty)
                {
                    c.Opacity = 0; // Invisible
                }

                if (opacityMask != null)
                {
                    double op;

                    if (Utility.ExtractOpacityMaskOpacity(opacityMask, out op, maskBounds))
                    {
                        c.Opacity = opacity * _opacity * op;
                    }
                    else
                    {
                        c.OpacityMask = BrushProxy.CreateOpacityMaskBrush(opacityMask, maskBounds);
                    }
                }

                _root.Children.Add(c);

                _root = c;

                _clip        = null;
                _opacity     = 1.0;
                _opacityMask = null;
            }
        }
        // Recursive
        // _brush must be in world space
        private void FillGeometry(
            PrimitiveInfo topPI,
            Geometry cur,
            string desp,
            Geometry curAlt,
            string despAlt,
            int start,
            Geometry inter,
            Geometry topBounds
            )
        {
            Primitive p    = topPI.primitive;
            Geometry  diff = Utility.Exclude(cur, topBounds, Matrix.Identity);

            if (diff != null)
            {
                // Render cur [- topBounds] using original brush

                if (_disjoint)
                {
#if DEBUG
                    FillGeometry(diff, Oper(desp, '-', topPI.id), null, null, start + 1);
#else
                    FillGeometry(diff, null, null, null, start + 1);
#endif
                }
                else
                {
                    // Only diff = cur - topBounds need to be rendered. But it may generate more
                    // complicated path and gaps between objects

                    if (curAlt != null)
                    {
#if DEBUG
                        FillGeometry(diff, Oper(desp, '-', topPI.id), curAlt, despAlt, start + 1);
#else
                        FillGeometry(diff, null, curAlt, despAlt, start + 1);
#endif
                    }
                    else
                    {
#if DEBUG
                        FillGeometry(diff, Oper(desp, '-', topPI.id), cur, desp, start + 1);
#else
                        FillGeometry(diff, null, cur, desp, start + 1);
#endif
                    }
                }
            }

            //if (_disjoint || ! p.IsOpaque)
            {
                if (topPI.primitive is ImagePrimitive)
                {
                    // If primitve on the top is ImagePrimitive, change it to DrawImage with blended image.
                    // An alternative will be generating an image brush

                    ImagePrimitive ip = topPI.primitive as ImagePrimitive;

                    bool empty;

                    double imageWidth  = ip.Image.Image.Width;
                    double imageHeight = ip.Image.Image.Height;

                    // Get clip in world space.
                    Geometry clip = Utility.Intersect(inter, Utility.TransformGeometry(new RectangleGeometry(ip.DstRect), ip.Transform), ip.Transform, out empty);

                    if (!empty)
                    {
                        // Get clip bounds in image space.
                        Geometry clipImageSpace = Utility.TransformGeometry(clip, ReverseMap(ip.Transform, ip.DstRect, imageWidth, imageHeight));
                        Rect     drawBounds     = clipImageSpace.Bounds;

                        // Clip image data to the intersection. Resulting draw bounds are in image space.
                        BitmapSource clippedImage = ip.Image.GetClippedImage(drawBounds, out drawBounds);
                        if (clippedImage != null)
                        {
                            // Transform draw bounds back to world space.
                            drawBounds.Scale(ip.DstRect.Width / imageWidth, ip.DstRect.Height / imageHeight);
                            drawBounds.Offset(ip.DstRect.Left, ip.DstRect.Top);

                            ImageProxy image = new ImageProxy(clippedImage);

                            // Blend image with other brush, then render composited image.
                            image.BlendOverBrush(false, _brush, ReverseMap(ip.Transform, drawBounds, image.PixelWidth, image.PixelHeight));

#if DEBUG
                            RenderImage(image, drawBounds, clip, true, start + 1, ip.Transform, Oper(desp, '*', topPI.id));
#else
                            RenderImage(image, drawBounds, clip, true, start + 1, ip.Transform, null);
#endif
                        }
                    }
                }
                else
                {
                    // -- If top primitive opaque, skip the intersection
                    // -- If current primitive is completely covered by an opaque object, skip the intersection
                    if (p.IsOpaque) // && Utility.Covers(topBounds, cur))
                    {
                        cur = null;
                    }
                    else
                    {
                        // Render the intersection using blended brush
                        BrushProxy oldbrush = _brush;

                        _brush = p.BlendBrush(_brush);

#if DEBUG
                        FillGeometry(inter, Oper(desp, '*', topPI.id), null, null, start + 1);
#else
                        FillGeometry(inter, null, null, null, start + 1);
#endif

                        _brush = oldbrush;
                    }
                }

                if (cur != null)
                {
                    bool empty;

                    Geometry geo = Utility.Intersect(cur, _clip, Matrix.Identity, out empty);

                    if (geo != null)
                    {
                        topPI.primitive.Exclude(geo); // exclude cur & _clip

#if DEBUG
                        topPI.id = Oper(topPI.id, '-', Oper(desp, '*', Oper(desp, '.', "c")));
#endif
                    }
                }
            }
        }
示例#25
0
 /// <summary>
 /// Simplifies brush so we don't have to handle as many cases.
 /// </summary>
 /// <param name="brush"></param>
 /// <param name="bounds">Brush fill bounds; must not be empty if VisualBrush</param>
 /// <returns></returns>
 /// <remarks>
 /// Cases simplified:
 /// - A lot of empty brush cases. See BrushProxy.IsEmpty.
 /// - GradientBrush where gradient colors are similar enough to be SolidColorBrush.
 /// - Reduce VisualBrush to DrawingBrush.
 /// - Reduce ImageBrush with DrawingImage to DrawingBrush.
 /// </remarks>
 private Brush ReduceBrush(Brush brush, Rect bounds)
 {
     return(BrushProxy.ReduceBrush(brush, bounds, Transform, _pageSize, _treeWalkProgress));
 }