Esempio n. 1
0
        /// <summary>
        /// General routine for adding a Primitive to DisplayList
        /// 1) Apply transformation to Geometry, Brush, Pen
        /// 2) Optimize Primitive
        /// 3) Add to DisplayList
        /// </summary>
        /// <param name="p"></param>
        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);
        }
        // External API
        public void DrawGeometry(Geometry cur, string desp, GeometryPrimitive gp)
        {
            if (cur == null)
            {
                return;
            }

            int start = 0;

            PrimitiveInfo topPI;
            Geometry      topBounds;
            Geometry      inter;

            if (_pen != null)
            {
                Debug.Assert(_brush == null, "no brush");

                if ((_overlapping != null) && FindIntersection(gp.WidenGeometry, ref start, out topPI, out topBounds, out inter))
                {
                    cur    = gp.WidenGeometry;
                    _brush = _pen.StrokeBrush;
                    _pen   = null;

                    // Draw the stroking as filling widened path
#if DEBUG
                    FillGeometry(topPI, cur, desp + "_widen", null, null, start, inter, topBounds);
#else
                    FillGeometry(topPI, cur, null, null, null, start, inter, topBounds);
#endif
                }
                else
                {
                    // Render to dc if nothing on top
                    _dc.Comment(desp);
                    _dc.DrawGeometry(_brush, _pen, cur, _clip, Matrix.Identity, ProxyDrawingFlags.None);
                }
            }
            else
            {
                if (FindIntersection(cur, ref start, out topPI, out topBounds, out inter))
                {
                    FillGeometry(topPI, cur, desp, null, null, start, inter, topBounds);
                }
                else
                {
                    // Render to dc if nothing on top
                    _dc.Comment(desp);
                    _dc.DrawGeometry(_brush, _pen, cur, _clip, Matrix.Identity, ProxyDrawingFlags.None);
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// 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'
        /// </summary>
        /// <param name="commands"></param>
        /// <param name="j"></param>
        private static void PushTransparencyDown(List <PrimitiveInfo> 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--;
                    }
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Check if a primitive only contains white color
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        internal static bool IsWhitePrimitive(Primitive p)
        {
            GeometryPrimitive gp = p as GeometryPrimitive;

            if (gp != null)
            {
                if ((gp.Brush != null) && (gp.Pen == null))
                {
                    return(gp.Brush.IsWhite());
                }

                if ((gp.Pen != null) && (gp.Brush == null))
                {
                    return(gp.Pen.StrokeBrush.IsWhite());
                }
            }

            return(false);
        }
Esempio n. 5
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);
        }
Esempio n. 6
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);
        }
Esempio n. 7
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);
            }
        }
        /// <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);
        }
Esempio n. 9
0
        static internal void PrintPrimitive(PrimitiveInfo info, int index, bool verbose)
        {
            if (index < 0)
            {
                Console.WriteLine();

                Console.WriteLine(" No      Type           Und Ovr TrO           Bounding Box                   Clipping");

                if (verbose)
                {
                    Console.Write("                     Transform");
                }

                Console.WriteLine();
                return;
            }

            Primitive p = info.primitive;

            string typ = p.GetType().ToString();

            typ = typ.Substring(typ.LastIndexOf('.') + 1);

            Console.Write(LeftPad(index, 4) + LeftPad(typ, 18) + ":");

            List <int> extra = null;

            if (p.IsOpaque)
            {
                Console.Write(' ');
            }
            else
            {
                Console.Write('@');
            }

            if (info.underlay == null)
            {
                Console.Write("   ");
            }
            else
            {
                extra = info.underlay;

                Console.Write(LeftPad(info.underlay.Count, 3));
            }

            if (info.overlap != null)
            {
                Console.Write(' ' + LeftPad(info.overlap.Count, 3));

                if (info.overlapHasTransparency != 0)
                {
                    Console.Write('$');
                    Console.Write(LeftPad(info.overlapHasTransparency, 3));
                }
                else
                {
                    Console.Write("    ");
                }

                Console.Write(' ');
            }
            else
            {
                Console.Write("         ");
            }

            Console.Write(LeftPad(info.bounds, 0));

            Geometry clip = p.Clip;

            if (clip != null)
            {
                Console.Write(LeftPad(clip.Bounds, 0));
            }

            if (verbose)
            {
                Matrix m = p.Transform;

                Console.Write(" {");
                Console.Write(LeftPad(m.M11, 3) + ' ');
                Console.Write(LeftPad(m.M12, 3) + ' ');
                Console.Write(LeftPad(m.M21, 3) + ' ');
                Console.Write(LeftPad(m.M22, 3) + ' ');
                Console.Write(LeftPad(m.OffsetX, 6) + ' ');
                Console.Write(LeftPad(m.OffsetY, 6));
                Console.Write("} ");
            }

            if (verbose)
            {
                GlyphPrimitive gp = p as GlyphPrimitive;

                if (gp != null)
                {
                    IList <char> chars = gp.GlyphRun.Characters;

                    Console.Write(" \"");

                    for (int i = 0; i < chars.Count; i++)
                    {
                        Console.Write(chars[i]);
                    }

                    Console.Write('"');
                }
            }

            if (verbose)
            {
                GeometryPrimitive gp = p as GeometryPrimitive;

                if ((gp != null) && (gp.Brush != null) && (gp.Pen == null))
                {
                    Brush b = gp.Brush.Brush;

                    if (b != null)
                    {
                        SolidColorBrush sb = b as SolidColorBrush;

                        if (sb != null)
                        {
                            Console.Write(" SolidColorBrush({0})", sb.Color);
                        }
                    }
                }
            }

            if (extra != null)
            {
                Console.Write(' ');
                Console.Write(LeftPad(extra, 0));
            }

            Console.WriteLine();
        }
Esempio n. 10
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);
                }
            }
        }
Esempio n. 11
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);
        }
Esempio n. 12
0
        /// <summary>
        /// Resolve overlapping for a single primitive
        /// </summary>
        /// <param name="primitive"></param>
        /// <param name="overlapping"></param>
        /// <param name="overlapHasTransparency"></param>
        /// <param name="disjoint"></param>
        /// <param name="desp"></param>
        private void AlphaRender(Primitive primitive, List <int> 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");
            }
        }