Example #1
0
        private static void PropagateLayer(VisualNode node, SceneLayer layer, SceneLayer oldLayer)
        {
            node.LayerRoot = layer.LayerRoot;

            layer.Dirty.Add(node.Bounds);
            oldLayer.Dirty.Add(node.Bounds);

            foreach (VisualNode child in node.Children)
            {
                // If the child is not the start of a new layer, recurse.
                if (child.LayerRoot != child.Visual)
                {
                    PropagateLayer(child, layer, oldLayer);
                }
            }
        }
Example #2
0
        private static void UpdateLayer(VisualNode node, SceneLayer layer)
        {
            layer.Opacity = node.Visual.Opacity;

            if (node.Visual.OpacityMask != null)
            {
                layer.OpacityMask     = node.Visual.OpacityMask?.ToImmutable();
                layer.OpacityMaskRect = node.ClipBounds;
            }
            else
            {
                layer.OpacityMask     = null;
                layer.OpacityMaskRect = Rect.Empty;
            }

            layer.GeometryClip = node.HasAncestorGeometryClip ?
                                 CreateLayerGeometryClip(node) :
                                 null;
        }
Example #3
0
        private static void ClearLayer(Scene scene, VisualNode node)
        {
            var parent             = (VisualNode)node.Parent;
            var oldLayerRoot       = node.LayerRoot;
            var newLayerRoot       = parent.LayerRoot;
            var existingDirtyRects = scene.Layers[node.LayerRoot].Dirty;
            var newDirtyRects      = scene.Layers[newLayerRoot].Dirty;

            existingDirtyRects.Coalesce();

            foreach (var r in existingDirtyRects)
            {
                newDirtyRects.Add(r);
            }

            var oldLayer = scene.Layers[oldLayerRoot];

            PropagateLayer(node, scene.Layers[newLayerRoot], oldLayer);
            scene.Layers.Remove(oldLayer);
        }
Example #4
0
        private VisualNode Clone(VisualNode source, IVisualNode parent, Dictionary <IVisual, IVisualNode> index)
        {
            var result = source.Clone(parent);

            index.Add(result.Visual, result);

            int childCount = source.Children.Count;

            if (childCount > 0)
            {
                Span <IVisualNode> children = result.AddChildrenSpan(childCount);

                for (var i = 0; i < childCount; i++)
                {
                    var child = source.Children[i];

                    children[i] = Clone((VisualNode)child, result, index);
                }
            }

            return(result);
        }
Example #5
0
        private static IGeometryImpl CreateLayerGeometryClip(VisualNode node)
        {
            IGeometryImpl result = null;

            for (;;)
            {
                node = (VisualNode)node.Parent;

                if (node == null || (node.GeometryClip == null && !node.HasAncestorGeometryClip))
                {
                    break;
                }

                if (node?.GeometryClip != null)
                {
                    var transformed = node.GeometryClip.WithTransform(node.Transform);

                    result = result == null ? transformed : result.Intersect(transformed);
                }
            }

            return(result);
        }
Example #6
0
        private VisualNode Clone(VisualNode source, IVisualNode?parent, Dictionary <IVisual, IVisualNode> index)
        {
            var result = source.Clone(parent);

            index.Add(result.Visual, result);

            var children      = source.Children;
            var childrenCount = children.Count;

            if (childrenCount > 0)
            {
                result.TryPreallocateChildren(childrenCount);

                for (var i = 0; i < childrenCount; i++)
                {
                    var child = children[i];

                    result.AddChild(Clone((VisualNode)child, result, index));
                }
            }

            return(result);
        }
Example #7
0
        private static void Deindex(Scene scene, VisualNode node)
        {
            foreach (VisualNode child in node.Children)
            {
                if (child is VisualNode visual)
                {
                    Deindex(scene, visual);
                }
            }
            scene.Remove(node);

            node.SubTreeUpdated = true;

            scene.Layers[node.LayerRoot].Dirty.Add(node.Bounds);

            node.Visual.TransformedBounds = null;


            if (node.LayerRoot == node.Visual && node.Visual != scene.Root.Visual)
            {
                scene.Layers.Remove(node.LayerRoot);
            }
        }
        /// <summary>
        /// Informs the drawing context of the visual node that is about to be rendered.
        /// </summary>
        /// <param name="node">The visual node.</param>
        /// <returns>
        /// An object which when disposed will commit the changes to visual node.
        /// </returns>
        public UpdateState BeginUpdate(VisualNode node)
        {
            Contract.Requires<ArgumentNullException>(node != null);

            if (_node != null)
            {
                if (_childIndex < _node.Children.Count)
                {
                    _node.ReplaceChild(_childIndex, node);
                }
                else
                {
                    _node.AddChild(node);
                }

                ++_childIndex;
            }

            var state = new UpdateState(this, _node, _childIndex, _drawOperationindex);
            _node = node;
            _childIndex = _drawOperationindex = 0;
            return state;
        }
        /// <summary>
        /// Informs the drawing context of the visual node that is about to be rendered.
        /// </summary>
        /// <param name="node">The visual node.</param>
        /// <returns>
        /// An object which when disposed will commit the changes to visual node.
        /// </returns>
        public UpdateState BeginUpdate(VisualNode node)
        {
            _ = node ?? throw new ArgumentNullException(nameof(node));

            if (_node != null)
            {
                if (_childIndex < _node.Children.Count)
                {
                    _node.ReplaceChild(_childIndex, node);
                }
                else
                {
                    _node.AddChild(node);
                }

                ++_childIndex;
            }

            var state = new UpdateState(this, _node, _childIndex, _drawOperationindex);

            _node       = node;
            _childIndex = _drawOperationindex = 0;
            return(state);
        }
Example #10
0
        private static void Update(DrawingContext context, Scene scene, VisualNode node, Rect clip, bool forceRecurse)
        {
            var visual       = node.Visual;
            var opacity      = visual.Opacity;
            var clipToBounds = visual.ClipToBounds;
            var bounds       = new Rect(visual.Bounds.Size);
            var contextImpl  = (DeferredDrawingContextImpl)context.PlatformImpl;

            contextImpl.Layers.Find(node.LayerRoot)?.Dirty.Add(node.Bounds);

            if (visual.IsVisible)
            {
                var m = Matrix.CreateTranslation(visual.Bounds.Position);

                var renderTransform = Matrix.Identity;

                if (visual.RenderTransform != null)
                {
                    var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
                    var offset = Matrix.CreateTranslation(origin);
                    renderTransform = (-offset) * visual.RenderTransform.Value * (offset);
                }

                m = renderTransform * m;

                using (contextImpl.BeginUpdate(node))
                    using (context.PushPostTransform(m))
                        using (context.PushTransformContainer())
                        {
                            var clipBounds = bounds.TransformToAABB(contextImpl.Transform).Intersect(clip);

                            forceRecurse = forceRecurse ||
                                           node.Transform != contextImpl.Transform ||
                                           node.ClipBounds != clipBounds;

                            node.Transform    = contextImpl.Transform;
                            node.ClipBounds   = clipBounds;
                            node.ClipToBounds = clipToBounds;
                            node.GeometryClip = visual.Clip?.PlatformImpl;
                            node.Opacity      = opacity;

                            // TODO: Check equality between node.OpacityMask and visual.OpacityMask before assigning.
                            node.OpacityMask = visual.OpacityMask?.ToImmutable();

                            if (ShouldStartLayer(visual))
                            {
                                if (node.LayerRoot != visual)
                                {
                                    MakeLayer(scene, node);
                                }
                                else
                                {
                                    UpdateLayer(node, scene.Layers[node.LayerRoot]);
                                }
                            }
                            else if (node.LayerRoot == node.Visual && node.Parent != null)
                            {
                                ClearLayer(scene, node);
                            }

                            if (node.ClipToBounds)
                            {
                                clip = clip.Intersect(node.ClipBounds);
                            }

                            try
                            {
                                visual.Render(context);
                            }
                            catch { }

                            var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
                            visual.TransformedBounds = transformed;

                            if (forceRecurse)
                            {
                                foreach (var child in visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance))
                                {
                                    var childNode = scene.FindNode(child) ?? CreateNode(scene, child, node);
                                    Update(context, scene, (VisualNode)childNode, clip, forceRecurse);
                                }

                                node.SubTreeUpdated = true;
                                contextImpl.TrimChildren();
                            }
                        }
            }
        }
Example #11
0
        private static void Update(DrawingContext context, Scene scene, VisualNode node, Rect clip, bool forceRecurse)
        {
            var visual       = node.Visual;
            var opacity      = visual.Opacity;
            var clipToBounds = visual.ClipToBounds;

#pragma warning disable CS0618 // Type or member is obsolete
            var clipToBoundsRadius = visual is IVisualWithRoundRectClip roundRectClip ?
                                     roundRectClip.ClipToBoundsRadius :
                                     default;
#pragma warning restore CS0618 // Type or member is obsolete

            var bounds      = new Rect(visual.Bounds.Size);
            var contextImpl = (DeferredDrawingContextImpl)context.PlatformImpl;

            contextImpl.Layers.Find(node.LayerRoot)?.Dirty.Add(node.Bounds);

            if (visual.IsVisible)
            {
                var m = node != scene.Root ?
                        Matrix.CreateTranslation(visual.Bounds.Position) :
                        Matrix.Identity;

                var renderTransform = Matrix.Identity;

                if (visual.RenderTransform != null)
                {
                    var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
                    var offset = Matrix.CreateTranslation(origin);
                    renderTransform = (-offset) * visual.RenderTransform.Value * (offset);
                }

                m = renderTransform * m;

                using (contextImpl.BeginUpdate(node))
                    using (context.PushPostTransform(m))
                        using (context.PushTransformContainer())
                        {
                            var globalBounds = bounds.TransformToAABB(contextImpl.Transform);
                            var clipBounds   = clipToBounds ?
                                               globalBounds.Intersect(clip) :
                                               clip;

                            forceRecurse = forceRecurse ||
                                           node.ClipBounds != clipBounds ||
                                           node.Opacity != opacity ||
                                           node.Transform != contextImpl.Transform;

                            node.Transform          = contextImpl.Transform;
                            node.ClipBounds         = clipBounds;
                            node.ClipToBounds       = clipToBounds;
                            node.LayoutBounds       = globalBounds;
                            node.ClipToBoundsRadius = clipToBoundsRadius;
                            node.GeometryClip       = visual.Clip?.PlatformImpl;
                            node.Opacity            = opacity;

                            // TODO: Check equality between node.OpacityMask and visual.OpacityMask before assigning.
                            node.OpacityMask = visual.OpacityMask?.ToImmutable();

                            if (ShouldStartLayer(visual))
                            {
                                if (node.LayerRoot != visual)
                                {
                                    MakeLayer(scene, node);
                                }
                                else
                                {
                                    UpdateLayer(node, scene.Layers[node.LayerRoot]);
                                }
                            }
                            else if (node.LayerRoot == node.Visual && node.Parent != null)
                            {
                                ClearLayer(scene, node);
                            }

                            if (node.ClipToBounds)
                            {
                                clip = clip.Intersect(node.ClipBounds);
                            }

                            try
                            {
                                visual.Render(context);
                            }
                            catch { }

                            var transformed = new TransformedBounds(new Rect(visual.Bounds.Size), clip, node.Transform);
                            visual.TransformedBounds = transformed;

                            if (forceRecurse)
                            {
                                var visualChildren = (IList <IVisual>)visual.VisualChildren;

                                node.TryPreallocateChildren(visualChildren.Count);

                                if (visualChildren.Count == 1)
                                {
                                    var childNode = GetOrCreateChildNode(scene, visualChildren[0], node);
                                    Update(context, scene, (VisualNode)childNode, clip, forceRecurse);
                                }
                                else if (visualChildren.Count > 1)
                                {
                                    var count          = visualChildren.Count;
                                    var sortedChildren = new (IVisual visual, int index)[count];