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); } }
/// <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); }