Skip to content

Commit eb1f784

Browse files
committed
Merge branch 'master' into feature/embedded-automation-roots
2 parents 4fc2a0d + 47988db commit eb1f784

File tree

7 files changed

+182
-152
lines changed

7 files changed

+182
-152
lines changed

build/ExternalConsumers.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
22
<ItemGroup>
33
<InternalsVisibleTo Include="AvaloniaUI.Xpf.WinApiShim, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a7f4b8b7db0bfb8d74992dc94ecafae031019197ff4263d87ac0a5835fab101c973ccab6fa6e7d90e8f987374f7c6de18dd0b5cd7d6c41e574a8bc66b64836b7c7e707e1aa393d27e33a08f372c1c9965be81658937c85698f4a1c0f73be68a61ffce06d49d1366bf18464c20a29859ccf105fc2d5e35c7ae68919eab668bf8e" />
4+
<InternalsVisibleTo Include="AvaloniaUI.Xpf.WpfAbstractions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a7f4b8b7db0bfb8d74992dc94ecafae031019197ff4263d87ac0a5835fab101c973ccab6fa6e7d90e8f987374f7c6de18dd0b5cd7d6c41e574a8bc66b64836b7c7e707e1aa393d27e33a08f372c1c9965be81658937c85698f4a1c0f73be68a61ffce06d49d1366bf18464c20a29859ccf105fc2d5e35c7ae68919eab668bf8e" />
45
<InternalsVisibleTo Include="System.Windows.Forms, PublicKey=00000000000000000400000000000000" />
56
<InternalsVisibleTo Include="System.Windows.Forms.Primitives, PublicKey=00000000000000000400000000000000" />
67
<InternalsVisibleTo Include="PresentationFramework-SystemData, PublicKey=00000000000000000400000000000000" />

src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

Lines changed: 3 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -142,93 +142,6 @@ public void RecalculateChildren(Visual visual)
142142
QueueUpdate();
143143
}
144144

145-
private static void SyncChildren(Visual v)
146-
{
147-
//TODO: Optimize by moving that logic to Visual itself
148-
if(v.CompositionVisual == null)
149-
return;
150-
var compositionChildren = v.CompositionVisual.Children;
151-
var visualChildren = (AvaloniaList<Visual>)v.GetVisualChildren();
152-
153-
PooledList<(Visual visual, int index)>? sortedChildren = null;
154-
if (v.HasNonUniformZIndexChildren && visualChildren.Count > 1)
155-
{
156-
sortedChildren = new (visualChildren.Count);
157-
for (var c = 0; c < visualChildren.Count; c++)
158-
sortedChildren.Add((visualChildren[c], c));
159-
160-
// Regular Array.Sort is unstable, we need to provide indices as well to avoid reshuffling elements.
161-
sortedChildren.Sort(static (lhs, rhs) =>
162-
{
163-
var result = lhs.visual.ZIndex.CompareTo(rhs.visual.ZIndex);
164-
return result == 0 ? lhs.index.CompareTo(rhs.index) : result;
165-
});
166-
}
167-
168-
var childVisual = v.ChildCompositionVisual;
169-
170-
// Check if the current visual somehow got migrated to another compositor
171-
if (childVisual != null && childVisual.Compositor != v.CompositionVisual.Compositor)
172-
childVisual = null;
173-
174-
var expectedCount = visualChildren.Count;
175-
if (childVisual != null)
176-
expectedCount++;
177-
178-
if (compositionChildren.Count == expectedCount)
179-
{
180-
bool mismatch = false;
181-
if (sortedChildren != null)
182-
for (var c = 0; c < visualChildren.Count; c++)
183-
{
184-
if (!ReferenceEquals(compositionChildren[c], sortedChildren[c].visual.CompositionVisual))
185-
{
186-
mismatch = true;
187-
break;
188-
}
189-
}
190-
else
191-
for (var c = 0; c < visualChildren.Count; c++)
192-
if (!ReferenceEquals(compositionChildren[c], visualChildren[c].CompositionVisual))
193-
{
194-
mismatch = true;
195-
break;
196-
}
197-
198-
if (childVisual != null &&
199-
!ReferenceEquals(compositionChildren[compositionChildren.Count - 1], childVisual))
200-
mismatch = true;
201-
202-
if (!mismatch)
203-
{
204-
sortedChildren?.Dispose();
205-
return;
206-
}
207-
}
208-
209-
compositionChildren.Clear();
210-
if (sortedChildren != null)
211-
{
212-
foreach (var ch in sortedChildren)
213-
{
214-
var compositionChild = ch.visual.CompositionVisual;
215-
if (compositionChild != null)
216-
compositionChildren.Add(compositionChild);
217-
}
218-
sortedChildren.Dispose();
219-
}
220-
else
221-
foreach (var ch in visualChildren)
222-
{
223-
var compositionChild = ch.CompositionVisual;
224-
if (compositionChild != null)
225-
compositionChildren.Add(compositionChild);
226-
}
227-
228-
if (childVisual != null)
229-
compositionChildren.Add(childVisual);
230-
}
231-
232145
private void UpdateCore()
233146
{
234147
_queuedUpdate = false;
@@ -238,36 +151,7 @@ private void UpdateCore()
238151
if(comp == null)
239152
continue;
240153

241-
// TODO: Optimize all of that by moving to the Visual itself, so we won't have to recalculate every time
242-
comp.Offset = new (visual.Bounds.Left, visual.Bounds.Top, 0);
243-
comp.Size = new (visual.Bounds.Width, visual.Bounds.Height);
244-
comp.Visible = visual.IsVisible;
245-
comp.Opacity = (float)visual.Opacity;
246-
comp.ClipToBounds = visual.ClipToBounds;
247-
comp.Clip = visual.Clip?.PlatformImpl;
248-
249-
250-
if (!Equals(comp.OpacityMask, visual.OpacityMask))
251-
comp.OpacityMask = visual.OpacityMask?.ToImmutable();
252-
253-
if (!comp.Effect.EffectEquals(visual.Effect))
254-
comp.Effect = visual.Effect?.ToImmutable();
255-
256-
comp.RenderOptions = visual.RenderOptions;
257-
258-
var renderTransform = Matrix.Identity;
259-
260-
if (visual.HasMirrorTransform)
261-
renderTransform = new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0);
262-
263-
if (visual.RenderTransform != null)
264-
{
265-
var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height));
266-
var offset = Matrix.CreateTranslation(origin);
267-
renderTransform *= (-offset) * visual.RenderTransform.Value * (offset);
268-
}
269-
270-
comp.TransformMatrix = renderTransform;
154+
visual.SynchronizeCompositionProperties();
271155

272156
try
273157
{
@@ -279,11 +163,11 @@ private void UpdateCore()
279163
_recorder.Reset();
280164
}
281165

282-
SyncChildren(visual);
166+
visual.SynchronizeCompositionChildVisuals();
283167
}
284168
foreach(var v in _recalculateChildren)
285169
if (!_dirty.Contains(v))
286-
SyncChildren(v);
170+
v.SynchronizeCompositionChildVisuals();
287171
_dirty.Clear();
288172
_recalculateChildren.Clear();
289173
CompositionTarget.Size = _root.ClientSize;
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using Avalonia.Collections;
2+
using Avalonia.Collections.Pooled;
3+
using Avalonia.Media;
4+
using Avalonia.Rendering.Composition;
5+
using Avalonia.Rendering.Composition.Server;
6+
using Avalonia.VisualTree;
7+
8+
namespace Avalonia;
9+
10+
public partial class Visual
11+
{
12+
internal CompositionDrawListVisual? CompositionVisual { get; private set; }
13+
internal CompositionVisual? ChildCompositionVisual { get; set; }
14+
15+
16+
private protected virtual CompositionDrawListVisual CreateCompositionVisual(Compositor compositor)
17+
=> new CompositionDrawListVisual(compositor,
18+
new ServerCompositionDrawListVisual(compositor.Server, this), this);
19+
20+
internal CompositionVisual AttachToCompositor(Compositor compositor)
21+
{
22+
if (CompositionVisual == null || CompositionVisual.Compositor != compositor)
23+
{
24+
CompositionVisual = CreateCompositionVisual(compositor);
25+
}
26+
27+
return CompositionVisual;
28+
}
29+
30+
internal virtual void DetachFromCompositor()
31+
{
32+
if (CompositionVisual != null)
33+
{
34+
if (ChildCompositionVisual != null)
35+
CompositionVisual.Children.Remove(ChildCompositionVisual);
36+
37+
CompositionVisual.DrawList = null;
38+
CompositionVisual = null;
39+
}
40+
}
41+
42+
internal virtual void SynchronizeCompositionChildVisuals()
43+
{
44+
if(CompositionVisual == null)
45+
return;
46+
var compositionChildren = CompositionVisual.Children;
47+
var visualChildren = (AvaloniaList<Visual>)VisualChildren;
48+
49+
PooledList<(Visual visual, int index)>? sortedChildren = null;
50+
if (HasNonUniformZIndexChildren && visualChildren.Count > 1)
51+
{
52+
sortedChildren = new (visualChildren.Count);
53+
for (var c = 0; c < visualChildren.Count; c++)
54+
sortedChildren.Add((visualChildren[c], c));
55+
56+
// Regular Array.Sort is unstable, we need to provide indices as well to avoid reshuffling elements.
57+
sortedChildren.Sort(static (lhs, rhs) =>
58+
{
59+
var result = lhs.visual.ZIndex.CompareTo(rhs.visual.ZIndex);
60+
return result == 0 ? lhs.index.CompareTo(rhs.index) : result;
61+
});
62+
}
63+
64+
var childVisual = ChildCompositionVisual;
65+
66+
// Check if the current visual somehow got migrated to another compositor
67+
if (childVisual != null && childVisual.Compositor != CompositionVisual.Compositor)
68+
childVisual = null;
69+
70+
var expectedCount = visualChildren.Count;
71+
if (childVisual != null)
72+
expectedCount++;
73+
74+
if (compositionChildren.Count == expectedCount)
75+
{
76+
bool mismatch = false;
77+
if (sortedChildren != null)
78+
for (var c = 0; c < visualChildren.Count; c++)
79+
{
80+
if (!ReferenceEquals(compositionChildren[c], sortedChildren[c].visual.CompositionVisual))
81+
{
82+
mismatch = true;
83+
break;
84+
}
85+
}
86+
else
87+
for (var c = 0; c < visualChildren.Count; c++)
88+
if (!ReferenceEquals(compositionChildren[c], visualChildren[c].CompositionVisual))
89+
{
90+
mismatch = true;
91+
break;
92+
}
93+
94+
if (childVisual != null &&
95+
!ReferenceEquals(compositionChildren[compositionChildren.Count - 1], childVisual))
96+
mismatch = true;
97+
98+
if (!mismatch)
99+
{
100+
sortedChildren?.Dispose();
101+
return;
102+
}
103+
}
104+
105+
compositionChildren.Clear();
106+
if (sortedChildren != null)
107+
{
108+
foreach (var ch in sortedChildren)
109+
{
110+
var compositionChild = ch.visual.CompositionVisual;
111+
if (compositionChild != null)
112+
compositionChildren.Add(compositionChild);
113+
}
114+
sortedChildren.Dispose();
115+
}
116+
else
117+
foreach (var ch in visualChildren)
118+
{
119+
var compositionChild = ch.CompositionVisual;
120+
if (compositionChild != null)
121+
compositionChildren.Add(compositionChild);
122+
}
123+
124+
if (childVisual != null)
125+
compositionChildren.Add(childVisual);
126+
}
127+
128+
internal virtual void SynchronizeCompositionProperties()
129+
{
130+
if(CompositionVisual == null)
131+
return;
132+
var comp = CompositionVisual;
133+
134+
// TODO: Introduce a dirty mask like WPF has, so we don't overwrite properties every time
135+
136+
comp.Offset = new (Bounds.Left, Bounds.Top, 0);
137+
comp.Size = new (Bounds.Width, Bounds.Height);
138+
comp.Visible = IsVisible;
139+
comp.Opacity = (float)Opacity;
140+
comp.ClipToBounds = ClipToBounds;
141+
comp.Clip = Clip?.PlatformImpl;
142+
143+
if (!Equals(comp.OpacityMask, OpacityMask))
144+
comp.OpacityMask = OpacityMask?.ToImmutable();
145+
146+
if (!comp.Effect.EffectEquals(Effect))
147+
comp.Effect = Effect?.ToImmutable();
148+
149+
comp.RenderOptions = RenderOptions;
150+
151+
var renderTransform = Matrix.Identity;
152+
153+
if (HasMirrorTransform)
154+
renderTransform = new Matrix(-1.0, 0.0, 0.0, 1.0, Bounds.Width, 0);
155+
156+
if (RenderTransform != null)
157+
{
158+
var origin = RenderTransformOrigin.ToPixels(new Size(Bounds.Width, Bounds.Height));
159+
var offset = Matrix.CreateTranslation(origin);
160+
renderTransform *= (-offset) * RenderTransform.Value * (offset);
161+
}
162+
163+
comp.TransformMatrix = renderTransform;
164+
}
165+
}

src/Avalonia.Base/Visual.cs

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace Avalonia
2929
/// extension methods defined in <see cref="VisualExtensions"/>.
3030
/// </remarks>
3131
[UsableDuringInitialization]
32-
public class Visual : StyledElement
32+
public partial class Visual : StyledElement
3333
{
3434
/// <summary>
3535
/// Defines the <see cref="Bounds"/> property.
@@ -316,9 +316,6 @@ protected internal IAvaloniaList<Visual> VisualChildren
316316
/// </summary>
317317
protected internal IRenderRoot? VisualRoot => _visualRoot ?? (this as IRenderRoot);
318318

319-
internal CompositionDrawListVisual? CompositionVisual { get; private set; }
320-
internal CompositionVisual? ChildCompositionVisual { get; set; }
321-
322319
internal RenderOptions RenderOptions { get; set; }
323320

324321
internal bool HasNonUniformZIndexChildren { get; private set; }
@@ -515,20 +512,6 @@ protected virtual void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs
515512
}
516513
}
517514

518-
private protected virtual CompositionDrawListVisual CreateCompositionVisual(Compositor compositor)
519-
=> new CompositionDrawListVisual(compositor,
520-
new ServerCompositionDrawListVisual(compositor.Server, this), this);
521-
522-
internal CompositionVisual AttachToCompositor(Compositor compositor)
523-
{
524-
if (CompositionVisual == null || CompositionVisual.Compositor != compositor)
525-
{
526-
CompositionVisual = CreateCompositionVisual(compositor);
527-
}
528-
529-
return CompositionVisual;
530-
}
531-
532515
/// <summary>
533516
/// Calls the <see cref="OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs)"/> method
534517
/// for this control and all of its visual descendants.
@@ -547,14 +530,7 @@ protected virtual void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArg
547530

548531
DisableTransitions();
549532
OnDetachedFromVisualTree(e);
550-
if (CompositionVisual != null)
551-
{
552-
if (ChildCompositionVisual != null)
553-
CompositionVisual.Children.Remove(ChildCompositionVisual);
554-
555-
CompositionVisual.DrawList = null;
556-
CompositionVisual = null;
557-
}
533+
DetachFromCompositor();
558534

559535
DetachedFromVisualTree?.Invoke(this, e);
560536
e.Root.Renderer.AddDirty(this);

src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFrameworks>netstandard2.0</TargetFrameworks>
4-
<OutputType>exe</OutputType>
5-
<GenerateDocumentationFile>false</GenerateDocumentationFile>
6-
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
7-
<DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants>
8-
<CopyLocalLockFileAssemblies Condition="$(TargetFramework) == 'netstandard2.0'">true</CopyLocalLockFileAssemblies>
9-
<NoWarn>$(NoWarn);NU1605;CS8632</NoWarn>
3+
<TargetFrameworks>netstandard2.0</TargetFrameworks>
4+
<OutputType>exe</OutputType>
5+
<GenerateDocumentationFile>false</GenerateDocumentationFile>
6+
<BuildOutputTargetFolder>tools</BuildOutputTargetFolder>
7+
<DefineConstants>$(DefineConstants);BUILDTASK;XAMLX_CECIL_INTERNAL;XAMLX_INTERNAL</DefineConstants>
8+
<CopyLocalLockFileAssemblies Condition="$(TargetFramework) == 'netstandard2.0'">true</CopyLocalLockFileAssemblies>
9+
<NoWarn>$(NoWarn);NU1605;CS8632</NoWarn>
10+
<DebugType>embedded</DebugType>
11+
<IncludeSymbols>false</IncludeSymbols>
1012
</PropertyGroup>
1113

1214
<!--Disable Net Perf. analyzer for submodule to avoid commit issue -->

0 commit comments

Comments
 (0)