diff --git a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml
index 7501c80940..e9a245a8e1 100644
--- a/samples/ControlCatalog/Pages/AdornerLayerPage.xaml
+++ b/samples/ControlCatalog/Pages/AdornerLayerPage.xaml
@@ -44,21 +44,31 @@
VerticalContentAlignment="Center" VerticalAlignment="Stretch"
Width="200" Height="42">
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Base/Input/TextInput/InputMethodManager.cs b/src/Avalonia.Base/Input/TextInput/InputMethodManager.cs
index ae3a8bc6a1..005a015644 100644
--- a/src/Avalonia.Base/Input/TextInput/InputMethodManager.cs
+++ b/src/Avalonia.Base/Input/TextInput/InputMethodManager.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Input.TextInput
private IInputElement? _focusedElement;
private Interactive? _visualRoot;
private TextInputMethodClient? _client;
- private readonly TransformTrackingHelper _transformTracker = new TransformTrackingHelper();
+ private readonly TransformTrackingHelper _transformTracker = new TransformTrackingHelper(true);
public TextInputMethodManager()
{
diff --git a/src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs b/src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs
index 1ea754f0f4..418acbf42f 100644
--- a/src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs
+++ b/src/Avalonia.Base/Input/TextInput/TransformTrackingHelper.cs
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
+using Avalonia.Media;
+using Avalonia.Reactive;
using Avalonia.Threading;
using Avalonia.VisualTree;
@@ -7,13 +9,15 @@ namespace Avalonia.Input.TextInput
{
class TransformTrackingHelper : IDisposable
{
+ private readonly bool _deferAfterRenderPass;
private Visual? _visual;
private bool _queuedForUpdate;
private readonly EventHandler _propertyChangedHandler;
private readonly List _propertyChangedSubscriptions = new List();
- public TransformTrackingHelper()
+ public TransformTrackingHelper(bool deferAfterRenderPass)
{
+ _deferAfterRenderPass = deferAfterRenderPass;
_propertyChangedHandler = PropertyChangedHandler;
}
@@ -91,7 +95,10 @@ namespace Avalonia.Input.TextInput
if(_queuedForUpdate)
return;
_queuedForUpdate = true;
- Dispatcher.UIThread.Post(UpdateMatrix, DispatcherPriority.AfterRender);
+ if (_deferAfterRenderPass)
+ Dispatcher.UIThread.Post(UpdateMatrix, DispatcherPriority.AfterRender);
+ else
+ MediaContext.Instance.BeginInvokeOnRender(UpdateMatrix);
}
private void PropertyChangedHandler(object? sender, AvaloniaPropertyChangedEventArgs e)
@@ -106,12 +113,23 @@ namespace Avalonia.Input.TextInput
UpdateMatrix();
}
- public static IDisposable Track(Visual visual, Action cb)
+ public static IDisposable Track(Visual visual, bool deferAfterRenderPass, Action cb)
{
- var rv = new TransformTrackingHelper();
+ var rv = new TransformTrackingHelper(deferAfterRenderPass);
rv.MatrixChanged += () => cb(visual, rv.Matrix);
rv.SetVisual(visual);
return rv;
}
+
+ public static IObservable Observe(Visual visual, bool deferAfterRenderPass)
+ {
+ return Observable.Create(observer =>
+ {
+ var rv = new TransformTrackingHelper(deferAfterRenderPass);
+ rv.MatrixChanged += () => observer.OnNext(rv.Matrix);
+ rv.SetVisual(visual);
+ return rv;
+ });
+ }
}
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs
index 396009841b..e9bfa8f6a0 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs
@@ -34,15 +34,10 @@ namespace Avalonia.Rendering.Composition.Server
var (combinedBounds, oldInvalidated, newInvalidated) = base.Update(root, parentCombinedTransform);
foreach (var child in Children)
{
- if (child.AdornedVisual != null)
- root.EnqueueAdornerUpdate(child);
- else
- {
- var res = child.Update(root, GlobalTransformMatrix);
- oldInvalidated |= res.InvalidatedOld;
- newInvalidated |= res.InvalidatedNew;
- combinedBounds = LtrbRect.FullUnion(combinedBounds, res.Bounds);
- }
+ var res = child.Update(root, GlobalTransformMatrix);
+ oldInvalidated |= res.InvalidatedOld;
+ newInvalidated |= res.InvalidatedNew;
+ combinedBounds = LtrbRect.FullUnion(combinedBounds, res.Bounds);
}
// If effect is changed, we need to clean both old and new bounds
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
index 90b973c3a8..48ce97c908 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
@@ -31,7 +31,6 @@ namespace Avalonia.Rendering.Composition.Server
private bool _fullRedrawRequested;
private bool _disposed;
private readonly HashSet _attachedVisuals = new();
- private readonly Queue _adornerUpdateQueue = new();
public long Id { get; }
public ulong Revision { get; private set; }
@@ -129,12 +128,6 @@ namespace Avalonia.Rendering.Composition.Server
// Update happens in a separate phase to extend dirty rect if needed
Root.Update(this, transform);
- while (_adornerUpdateQueue.Count > 0)
- {
- var adorner = _adornerUpdateQueue.Dequeue();
- adorner.Update(this, transform);
- }
-
_updateRequested = false;
Readback.CompleteWrite(Revision);
@@ -263,7 +256,5 @@ namespace Avalonia.Rendering.Composition.Server
if (visual.IsVisibleInFrame)
AddDirtyRect(visual.TransformedOwnContentBounds);
}
-
- public void EnqueueAdornerUpdate(ServerCompositionVisual visual) => _adornerUpdateQueue.Enqueue(visual);
}
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs
index 9d17756f2b..bc4b1eb769 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.DirtyProperties.cs
@@ -24,7 +24,6 @@ partial class ServerCompositionVisual
| CompositionVisualChangedFields.AnchorPointAnimated
| CompositionVisualChangedFields.CenterPoint
| CompositionVisualChangedFields.CenterPointAnimated
- | CompositionVisualChangedFields.AdornedVisual
| CompositionVisualChangedFields.TransformMatrix
| CompositionVisualChangedFields.Scale
| CompositionVisualChangedFields.ScaleAnimated
@@ -63,7 +62,6 @@ partial class ServerCompositionVisual
if (offset == s_IdOfSizeProperty
|| offset == s_IdOfAnchorPointProperty
|| offset == s_IdOfCenterPointProperty
- || offset == s_IdOfAdornedVisualProperty
|| offset == s_IdOfTransformMatrixProperty
|| offset == s_IdOfScaleProperty
|| offset == s_IdOfRotationAngleProperty
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
index 9225dd6ac6..370e851547 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
@@ -44,18 +44,7 @@ namespace Avalonia.Rendering.Composition.Server
Root!.DebugEvents?.IncrementRenderedVisuals();
var boundsRect = new Rect(new Size(Size.X, Size.Y));
-
- if (AdornedVisual != null)
- {
- // Adorners are currently not supported in detached rendering mode
- if(context.DetachedRendering)
- return;
-
- canvas.Transform = Matrix.Identity;
- if (AdornerIsClipped)
- canvas.PushClip(AdornedVisual._combinedTransformedClipBounds.ToRect());
- }
-
+
using var _ = context.SetOrPushTransform(this);
var applyRenderOptions = RenderOptions != default;
@@ -87,8 +76,7 @@ namespace Avalonia.Rendering.Composition.Server
canvas.PopGeometryClip();
if (ClipToBounds && !HandlesClipToBounds)
canvas.PopClip();
- if (AdornedVisual != null && AdornerIsClipped)
- canvas.PopClip();
+
if (Opacity != 1)
canvas.PopOpacity();
@@ -144,7 +132,7 @@ namespace Avalonia.Rendering.Composition.Server
}
}
- public virtual UpdateResult Update(ServerCompositionTarget root, Matrix parentVisualTransform)
+ public virtual UpdateResult Update(ServerCompositionTarget root, Matrix parentTransform)
{
if (Parent == null && Root == null)
return default;
@@ -155,14 +143,11 @@ namespace Avalonia.Rendering.Composition.Server
if (_combinedTransformDirty)
{
CombinedTransformMatrix = MatrixUtils.ComputeTransform(Size, AnchorPoint, CenterPoint,
- // HACK: Ignore RenderTransform set by the adorner layer
- AdornedVisual != null ? Matrix.Identity : TransformMatrix,
+ TransformMatrix,
Scale, RotationAngle, Orientation, Offset);
_combinedTransformDirty = false;
}
- var parentTransform = AdornedVisual?.GlobalTransformMatrix ?? parentVisualTransform;
-
var newTransform = CombinedTransformMatrix * parentTransform;
// Check if visual was moved and recalculate face orientation
@@ -229,8 +214,7 @@ namespace Avalonia.Rendering.Composition.Server
}
_combinedTransformedClipBounds =
- (AdornerIsClipped ? AdornedVisual?._combinedTransformedClipBounds : null)
- ?? (Parent?.Effect == null ? Parent?._combinedTransformedClipBounds : null)
+ (Parent?.Effect == null ? Parent?._combinedTransformedClipBounds : null)
?? new LtrbRect(0, 0, Root!.PixelSize.Width, Root!.PixelSize.Height);
if (_transformedClipBounds != null)
diff --git a/src/Avalonia.Base/composition-schema.xml b/src/Avalonia.Base/composition-schema.xml
index dd1d284cd5..102ef904c5 100644
--- a/src/Avalonia.Base/composition-schema.xml
+++ b/src/Avalonia.Base/composition-schema.xml
@@ -29,8 +29,6 @@
-
-
diff --git a/src/Avalonia.Controls/Primitives/AdornerHelper.cs b/src/Avalonia.Controls/Primitives/AdornerHelper.cs
new file mode 100644
index 0000000000..312bfb80c3
--- /dev/null
+++ b/src/Avalonia.Controls/Primitives/AdornerHelper.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Media;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Controls.Primitives;
+
+class AdornerHelper
+{
+
+ public static IDisposable SubscribeToAncestorPropertyChanges(Visual visual,
+ bool includeClip, Action changed)
+ {
+ return new AncestorPropertyChangesSubscription(visual, includeClip, changed);
+ }
+
+ private class AncestorPropertyChangesSubscription : IDisposable
+ {
+ private readonly Visual _visual;
+ private readonly bool _includeClip;
+ private readonly Action _changed;
+ private readonly EventHandler _propertyChangedHandler;
+ private readonly List _subscriptions = new List();
+ private bool _isDisposed;
+
+ public AncestorPropertyChangesSubscription(Visual visual, bool includeClip, Action changed)
+ {
+ _visual = visual;
+ _includeClip = includeClip;
+ _changed = changed;
+ _propertyChangedHandler = OnPropertyChanged;
+
+ _visual.AttachedToVisualTree += OnAttachedToVisualTree;
+ _visual.DetachedFromVisualTree += OnDetachedFromVisualTree;
+
+ if (_visual.IsAttachedToVisualTree)
+ {
+ SubscribeToAncestors();
+ }
+ }
+
+ private void SubscribeToAncestors()
+ {
+ UnsubscribeFromAncestors();
+
+ // Subscribe to the visual's own Bounds property
+ _visual.PropertyChanged += _propertyChangedHandler;
+ _subscriptions.Add(_visual);
+
+ // Walk up the ancestor chain
+ var ancestor = _visual.VisualParent;
+ while (ancestor != null)
+ {
+ if (ancestor is Visual visualAncestor)
+ {
+ visualAncestor.PropertyChanged += _propertyChangedHandler;
+ _subscriptions.Add(visualAncestor);
+ }
+ ancestor = ancestor.VisualParent;
+ }
+ }
+
+ private void UnsubscribeFromAncestors()
+ {
+ foreach (var subscription in _subscriptions)
+ {
+ subscription.PropertyChanged -= _propertyChangedHandler;
+ }
+ _subscriptions.Clear();
+ }
+
+ private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
+ {
+ if (!e.IsEffectiveValueChange)
+ return;
+
+ bool shouldNotify = false;
+
+ if (e.Property == Visual.RenderTransformProperty || e.Property == Visual.BoundsProperty)
+ {
+ shouldNotify = true;
+ }
+ else if (_includeClip)
+ {
+ if (e.Property == Visual.ClipToBoundsProperty ||
+ e.Property == Visual.ClipProperty) shouldNotify = true;
+ }
+
+ if (shouldNotify)
+ {
+ _changed();
+ }
+ }
+
+ private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
+ {
+ SubscribeToAncestors();
+ _changed();
+ }
+
+ private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
+ {
+ UnsubscribeFromAncestors();
+ _changed();
+ }
+
+ public void Dispose()
+ {
+ if (_isDisposed)
+ return;
+
+ _isDisposed = true;
+ UnsubscribeFromAncestors();
+ _visual.AttachedToVisualTree -= OnAttachedToVisualTree;
+ _visual.DetachedFromVisualTree -= OnDetachedFromVisualTree;
+ }
+ }
+
+ public static Geometry? CalculateAdornerClip(Visual adornedElement)
+ {
+ // Walk ancestor stack and calculate clip geometry relative to the current visual.
+ // If ClipToBounds = true, add extra RectangleGeometry for Bounds.Size
+
+ Geometry? result = null;
+ var ancestor = adornedElement.VisualParent;
+
+ while (ancestor != null)
+ {
+ if (ancestor is Visual visualAncestor)
+ {
+ Geometry? ancestorClip = null;
+
+ // Check if ancestor has ClipToBounds enabled
+ if (visualAncestor.ClipToBounds)
+ {
+ ancestorClip = new RectangleGeometry(new Rect(visualAncestor.Bounds.Size));
+ }
+
+ // Check if ancestor has explicit Clip geometry
+ if (visualAncestor.Clip != null)
+ {
+ if (ancestorClip != null)
+ {
+ ancestorClip = new CombinedGeometry(GeometryCombineMode.Intersect, ancestorClip, visualAncestor.Clip);
+ }
+ else
+ {
+ ancestorClip = visualAncestor.Clip;
+ }
+ }
+
+ // Transform the clip geometry to adorned element's coordinate space
+ if (ancestorClip != null)
+ {
+ var transform = visualAncestor.TransformToVisual(adornedElement);
+ if (transform.HasValue && !transform.Value.IsIdentity)
+ {
+ ancestorClip = ancestorClip.Clone();
+ ancestorClip.Transform = new MatrixTransform(transform.Value);
+ }
+
+ // Combine with existing result
+ if (result != null)
+ {
+ result = new CombinedGeometry(GeometryCombineMode.Intersect, result, ancestorClip);
+ }
+ else
+ {
+ result = ancestorClip;
+ }
+ }
+ }
+
+ ancestor = ancestor.VisualParent;
+ }
+
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
index 412dd236ff..5fe3f16a78 100644
--- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs
+++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Specialized;
+using Avalonia.Input.TextInput;
using Avalonia.Media;
using Avalonia.Reactive;
using Avalonia.VisualTree;
@@ -45,15 +46,20 @@ namespace Avalonia.Controls.Primitives
private static readonly AttachedProperty s_savedAdornerLayerProperty =
AvaloniaProperty.RegisterAttached("SavedAdornerLayer");
+ private TransformTrackingHelper _trackingHelper = new TransformTrackingHelper(false);
+
static AdornerLayer()
{
AdornedElementProperty.Changed.Subscribe(AdornedElementChanged);
AdornerProperty.Changed.Subscribe(AdornerChanged);
+ IsClipEnabledProperty.Changed.Subscribe(AdornerIsClipEnabledChanged);
}
public AdornerLayer()
{
Children.CollectionChanged += ChildrenCollectionChanged;
+ _trackingHelper.SetVisual(this);
+ _trackingHelper.MatrixChanged += delegate { InvalidateMeasure(); };
}
public static Visual? GetAdornedElement(Visual adorner)
@@ -199,9 +205,9 @@ namespace Avalonia.Controls.Primitives
{
var info = ao.GetValue(s_adornedElementInfoProperty);
- if (info != null && info.Bounds.HasValue)
+ if (info is { AdornedElement: not null })
{
- child.Measure(info.Bounds.Value.Bounds.Size);
+ child.Measure(info.AdornedElement.Bounds.Size);
}
else
{
@@ -223,12 +229,22 @@ namespace Avalonia.Controls.Primitives
var info = ao.GetValue(s_adornedElementInfoProperty);
var isClipEnabled = ao.GetValue(IsClipEnabledProperty);
- if (info != null && info.Bounds.HasValue)
+ var adorned = info?.AdornedElement;
+
+ if (adorned != null)
{
- child.RenderTransform = new MatrixTransform(info.Bounds.Value.Transform);
+ child.Arrange(new(adorned.Bounds.Size));
+ var transform = adorned.TransformToVisual(this);
+ // If somebody decides that having Margin on an adorner is a good idea,
+ // we need to compensate for element being positioned at non-(0,0) coords.
+ if (transform != null && child.Bounds.Position != default)
+ {
+ transform = Matrix.CreateTranslation(child.Bounds.Position) * transform.Value *
+ Matrix.CreateTranslation(-child.Bounds.Position);
+ }
+ child.RenderTransform = new MatrixTransform(transform ?? default);
child.RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Absolute);
- UpdateClip(child, info.Bounds.Value, isClipEnabled);
- child.Arrange(info.Bounds.Value.Bounds);
+ UpdateClip(child, adorned, isClipEnabled);
}
else
{
@@ -248,29 +264,22 @@ namespace Avalonia.Controls.Primitives
layer?.UpdateAdornedElement(adorner, adorned);
}
- private void UpdateClip(Control control, TransformedBounds bounds, bool isEnabled)
+ private static void AdornerIsClipEnabledChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ var info = ((Visual)e.Sender).GetValue(s_adornedElementInfoProperty);
+ info?.UpdateSubscription();
+ info?.Layer?.InvalidateMeasure();
+ }
+
+ private void UpdateClip(Control control, Visual adorned, bool isEnabled)
{
if (!isEnabled)
{
control.Clip = null;
-
return;
}
- if (!(control.Clip is RectangleGeometry clip))
- {
- clip = new RectangleGeometry();
- control.Clip = clip;
- }
-
- var clipBounds = bounds.Bounds;
-
- if (bounds.Transform.HasInverse)
- {
- clipBounds = bounds.Clip.TransformToAABB(bounds.Transform.Invert());
- }
-
- clip.Rect = clipBounds;
+ control.Clip = AdornerHelper.CalculateAdornerClip(adorned);
}
private void ChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@@ -291,17 +300,12 @@ namespace Avalonia.Controls.Primitives
private void UpdateAdornedElement(Visual adorner, Visual? adorned)
{
- if (adorner.CompositionVisual != null)
- {
- adorner.CompositionVisual.AdornedVisual = adorned?.CompositionVisual;
- adorner.CompositionVisual.AdornerIsClipped = GetIsClipEnabled(adorner);
- }
-
var info = adorner.GetValue(s_adornedElementInfoProperty);
if (info != null)
{
info.Subscription!.Dispose();
+ info.Subscription = null;
if (adorned == null)
{
@@ -313,24 +317,35 @@ namespace Avalonia.Controls.Primitives
{
if (info == null)
{
- info = new AdornedElementInfo();
+ info = new AdornedElementInfo(adorner);
adorner.SetValue(s_adornedElementInfoProperty, info);
}
- if (adorner.CompositionVisual != null)
- info.Subscription = adorned.GetObservable(BoundsProperty).Subscribe(x =>
- {
- info.Bounds = new TransformedBounds(new Rect(adorned.Bounds.Size), new Rect(adorned.Bounds.Size), Matrix.Identity);
- InvalidateMeasure();
- });
+ info.Layer = this;
+ info.AdornedElement = adorned;
+ info.UpdateSubscription();
}
}
- private class AdornedElementInfo
+ private class AdornedElementInfo(Visual adorner)
{
+ public AdornerLayer? Layer { get; set; }
public IDisposable? Subscription { get; set; }
+ public Visual? AdornedElement { get; set; }
- public TransformedBounds? Bounds { get; set; }
+ public void UpdateSubscription()
+ {
+ Subscription?.Dispose();
+ Subscription = null;
+ if (AdornedElement != null)
+ {
+ Subscription = AdornerHelper.SubscribeToAncestorPropertyChanges(AdornedElement,
+ GetIsClipEnabled(adorner), () =>
+ {
+ Layer?.InvalidateMeasure();
+ });
+ }
+ }
}
}
}
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index 6de5b1ea78..889f4fe397 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -470,7 +470,7 @@ namespace Avalonia.Controls.Primitives
if (InheritsTransform)
{
- TransformTrackingHelper.Track(placementTarget, PlacementTargetTransformChanged)
+ TransformTrackingHelper.Track(placementTarget, true, PlacementTargetTransformChanged)
.DisposeWith(handlerCleanup);
}
else
diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
index 82dead1ed5..2f735ef691 100644
--- a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
+++ b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
@@ -570,16 +570,8 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
var target = positionRequest.Target;
if (target == null)
throw new InvalidOperationException("Placement mode is not Pointer and PlacementTarget is null");
- Matrix? matrix;
- if (TryGetAdorner(target, out var adorned, out var adornerLayer))
- {
- matrix = adorned!.TransformToVisual(topLevel) * target.TransformToVisual(adornerLayer!);
- }
- else
- {
- matrix = target.TransformToVisual(topLevel);
- }
-
+ Matrix? matrix = target.TransformToVisual(topLevel);
+
if (matrix == null)
{
if (target.GetVisualRoot() == null)
@@ -591,25 +583,6 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
var anchorRect = positionRequest.AnchorRect ?? bounds;
return anchorRect.Intersect(bounds).TransformToAABB(matrix.Value);
}
-
- private static bool TryGetAdorner(Visual target, out Visual? adorned, out Visual? adornerLayer)
- {
- var element = target;
- while (element != null)
- {
- if (AdornerLayer.GetAdornedElement(element) is { } adornedElement)
- {
- adorned = adornedElement;
- adornerLayer = AdornerLayer.GetAdornerLayer(adorned);
- return true;
- }
- element = element.VisualParent;
- }
-
- adorned = null;
- adornerLayer = null;
- return false;
- }
}
}