Example #1
0
        /// <summary>
        /// Optimization: If a transparent primitive is covered underneath by an opaque primitive, cut its ties with all primitives before it
        /// </summary>
        /// <param name="pi"></param>
        /// <param name="commands"></param>
        /// <param name="i"></param>
        private static void ReduceTie(PrimitiveInfo pi, List <PrimitiveInfo> commands, int i)
        {
            if ((pi.underlay != null) && !pi.primitive.IsOpaque)
            {
                int len = pi.underlay.Count;

                for (int j = len - 1; j >= 0; j--)
                {
                    PrimitiveInfo qi = commands[pi.underlay[j]];

                    if (qi.primitive.IsOpaque && qi.FullyCovers(pi))
                    {
                        for (int k = j - 1; k >= 0; k--)
                        {
                            int under = pi.underlay[k];

                            commands[under].overlap.Remove(i);
                            commands[under].overlapHasTransparency--;

                            pi.underlay.Remove(under);
                        }

                        break;
                    }
                }
            }
        }
Example #2
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--;
                    }
                }
            }
        }
Example #3
0
        /// <summary>
        /// Optimization phase
        /// </summary>
        /// <param name="commands"></param>
        /// <param name="count"></param>
        /// <param name="disjoint"></param>
        private void DisplayListOptimization(List <PrimitiveInfo> commands, int count, bool disjoint)
        {
#if DEBUG
            Console.WriteLine();
            Console.WriteLine("Start 3: Display list optimization");
            Console.WriteLine();
#endif
            List <int> [] oldUnderlay = null;

            if (!disjoint) // If not in a subtree which needs full flattening
            {
                // The following optimization may change PrimitiveInfo.underlay, but this is needed
                // for cluster calcuation. So we make a copy of it for use within this routine only
                oldUnderlay = CopyUnderlay(count, commands);

                // These optimizations need to run in a seperate pass, because they may affect other primitives
                for (int i = 0; i < count; i++)
                {
repeat:
                    PrimitiveInfo pi = commands[i];

                    if (pi == null)
                    {
                        continue;
                    }

                    // Optimization: If a primitive is covered by an opaque primtive, delete it
                    if (pi.overlap != null)
                    {
                        bool deleted = false;

                        for (int j = 0; j < pi.overlap.Count; j++)
                        {
                            PrimitiveInfo qi = commands[pi.overlap[j]];

                            if (qi.primitive.IsOpaque && qi.FullyCovers(pi))
                            {
                                DeleteCommand(i);
                                deleted = true;
                                break;
                            }
                        }

                        if (deleted)
                        {
                            continue;
                        }
                    }

                    // Optimization: If a primitive is covered by overlap[0], blend brush and switch order
                    // This results in smaller area being rendered as blending of two brushes.
                    if ((pi.overlap != null) && (pi.overlap.Count != 0))
                    {
                        int j = pi.overlap[0]; // first overlapping primitive

                        PrimitiveInfo pj = commands[j];

                        // Do not attempt to blend if both primitives cover exactly same area, since blending
                        // one into the other provides no benefits.
                        if ((pj.underlay[pj.underlay.Count - 1] == i) && pj.FullyCovers(pi) && !pi.FullyCovers(pj))
                        {
                            if (BlendCommands(pi, pj))
                            {
                                SwitchCommands(commands, i, pi, j, pj, true);
                                goto repeat; // pj at position i needs to be processed
                            }
                        }
                    }

                    // Optimization: Delete white primitives with nothing underneath
                    if ((pi.underlay == null) && DisplayList.IsWhitePrimitive(pi.primitive))
                    {
                        DeleteCommand(i);

                        continue;
                    }

                    // Optimization: If a transparent primitive is covered underneath by an opaque primitive, cut its ties with all primitives before it
                    ReduceTie(pi, commands, i);

                    // Transparent primitive
                    if (!pi.primitive.IsOpaque)
                    {
                        // Optimization: If a transparent primitive is covered underneath immediately by an opaque primitive,
                        // or has nothing underneath, convert it to opaque primitive
                        if (!ConvertTransparentOnOpaque(commands, i))
                        {
                            PushTransparencyDown(commands, i);
                        }
                    }
                }

                for (int i = 0; i < count; i++)
                {
                    PrimitiveInfo pi = commands[i];

                    if (pi == null)
                    {
                        continue;
                    }

                    // Optimization: If a primitive is covered by all opaque primitives, cut its ties with primitive on top of it.

                    // This check is also implemented in PrimitiveRender.FindIntersection,
                    // in which it is on a remaing items in overlapping list.
                    // With overlapHasTransparency flag, it can be moved forward.

                    if ((pi.overlap != null) && (pi.overlapHasTransparency == 0))
                    {
                        foreach (int j in pi.overlap)
                        {
                            commands[j].underlay.Remove(i);
                        }

                        pi.overlap = null;
                    }

                    // Optimization: If an opaque primitive is covered by all opaque primitives, cut its ties with primitives under it.
                    if ((pi.underlay != null) && (pi.overlapHasTransparency == 0) && pi.primitive.IsOpaque)
                    {
                        foreach (int j in pi.underlay)
                        {
                            commands[j].overlap.Remove(i);
                        }

                        pi.underlay = null;
                    }
                }
            }

            List <Cluster> transparentCluster = Cluster.CalculateCluster(commands, count, disjoint, oldUnderlay);

            Cluster.CheckForRasterization(transparentCluster, commands);

#if DEBUG
            if (HasUnmanagedCodePermission())
            {
                LogInterestingPrimitives(commands, count, transparentCluster);
                SaveInterestingPrimitives(commands, count, transparentCluster);
            }
#endif
        }
Example #4
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);
        }