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); } } }
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; }
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); }
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); }
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); }
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); }
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); }
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(); } } } }
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];