77using Microsoft . UI . Xaml . Controls ;
88using Microsoft . UI . Xaml . Media ;
99using System . Numerics ;
10-
11-
12- using WindowSizeChangedEventArgs = Microsoft . UI . Xaml . WindowSizeChangedEventArgs ;
10+ using Uno . Extensions ;
1311
1412namespace Uno . UI . Xaml . Controls ;
1513
1614internal partial class SystemFocusVisual : Control
1715{
16+ #if __SKIA__
17+ private static readonly SkiaSharp . SKPath _spareRenderPath = new SkiaSharp . SKPath ( ) ;
18+ #endif
1819 private SerialDisposable _focusedElementSubscriptions = new SerialDisposable ( ) ;
19- private Rect _lastRect = Rect . Empty ;
2020
2121 public SystemFocusVisual ( )
2222 {
2323 DefaultStyleKey = typeof ( SystemFocusVisual ) ;
24+ #if ! __SKIA__
2425 Loaded += OnLoaded ;
2526 Unloaded += OnUnloaded ;
26- }
27-
28- private void OnLoaded ( object sender , RoutedEventArgs e )
29- {
30- if ( XamlRoot is not null )
31- {
32- XamlRoot . Changed += XamlRootChanged ;
33- }
34- }
35-
36- private void OnUnloaded ( object sender , RoutedEventArgs e )
37- {
38- if ( XamlRoot is not null )
39- {
40- XamlRoot . Changed -= XamlRootChanged ;
41- }
27+ #endif
4228 }
4329
4430 public UIElement ? FocusedElement
@@ -54,16 +40,28 @@ public UIElement? FocusedElement
5440 typeof ( SystemFocusVisual ) ,
5541 new FrameworkPropertyMetadata ( default , OnFocusedElementChanged ) ) ;
5642
57- internal void Redraw ( ) => SetLayoutProperties ( ) ;
58-
5943 private static void OnFocusedElementChanged ( DependencyObject dependencyObject , DependencyPropertyChangedEventArgs args )
6044 {
6145 var focusVisual = ( SystemFocusVisual ) dependencyObject ;
6246
6347 focusVisual . _focusedElementSubscriptions . Disposable = null ;
6448
49+ #if __SKIA__
50+ focusVisual . Visibility = Visibility . Collapsed ;
51+ #endif
52+
6553 if ( args . NewValue is FrameworkElement element )
6654 {
55+ #if __SKIA__
56+ if ( element . XamlRoot ? . VisualTree . ContentRoot . CompositionTarget is { } compositionTarget )
57+ {
58+ compositionTarget . FrameRendered += focusVisual . OnFrameRendered ;
59+ focusVisual . _focusedElementSubscriptions . Disposable = Disposable . Create ( ( ) =>
60+ {
61+ compositionTarget . FrameRendered -= focusVisual . OnFrameRendered ;
62+ } ) ;
63+ }
64+ #else
6765 element . SizeChanged += focusVisual . FocusedElementSizeChanged ;
6866#if ! UNO_HAS_ENHANCED_LIFECYCLE
6967 element . LayoutUpdated += focusVisual . FocusedElementLayoutUpdated ;
@@ -75,7 +73,6 @@ private static void OnFocusedElementChanged(DependencyObject dependencyObject, D
7573
7674 focusVisual . AttachVisualPartial ( ) ;
7775
78- focusVisual . _lastRect = Rect . Empty ;
7976 focusVisual . SetLayoutProperties ( ) ;
8077 var parentViewport = element . GetParentViewport ( ) ; // the parent Viewport is used, similar to PropagateEffectiveViewportChange
8178 focusVisual . ApplyClipping ( parentViewport . Effective ) ;
@@ -91,6 +88,76 @@ private static void OnFocusedElementChanged(DependencyObject dependencyObject, D
9188
9289 focusVisual . DetachVisualPartial ( ) ;
9390 } ) ;
91+ #endif
92+ }
93+ }
94+
95+ #if __SKIA__
96+ private void OnFrameRendered ( )
97+ {
98+ if ( XamlRoot is null ||
99+ FocusedElement is null ||
100+ FocusedElement . Visibility == Visibility . Collapsed ||
101+ FocusedElement is Control { IsEnabled : false , AllowFocusWhenDisabled : false } )
102+ {
103+ Visibility = Visibility . Collapsed ;
104+ return ;
105+ }
106+
107+ if ( VisualTreeHelper . GetParent ( FocusedElement ) is not UIElement )
108+ {
109+ Visibility = Visibility . Collapsed ;
110+ return ;
111+ }
112+
113+ var transform = GetTransform ( FocusedElement , XamlRoot . VisualTree . RootElement ) ;
114+
115+ FocusedElement . Visual . GetTotalClipPath ( _spareRenderPath , true ) ;
116+ var totalClipRect = _spareRenderPath . Bounds ;
117+ var inverseMatrix = transform . Inverse ( ) ;
118+ var topLeft = inverseMatrix . Transform ( new Point ( totalClipRect . Left , totalClipRect . Top ) ) ;
119+ var topRight = inverseMatrix . Transform ( new Point ( totalClipRect . Right , totalClipRect . Top ) ) ;
120+ var bottomLeft = inverseMatrix . Transform ( new Point ( totalClipRect . Left , totalClipRect . Bottom ) ) ;
121+ var bottomRight = inverseMatrix . Transform ( new Point ( totalClipRect . Right , totalClipRect . Bottom ) ) ;
122+
123+ var minX = Math . Min ( Math . Min ( topLeft . X , topRight . X ) , Math . Min ( bottomLeft . X , bottomRight . X ) ) ;
124+ var maxX = Math . Max ( Math . Max ( topLeft . X , topRight . X ) , Math . Max ( bottomLeft . X , bottomRight . X ) ) ;
125+ var minY = Math . Min ( Math . Min ( topLeft . Y , topRight . Y ) , Math . Min ( bottomLeft . Y , bottomRight . Y ) ) ;
126+ var maxY = Math . Max ( Math . Max ( topLeft . Y , topRight . Y ) , Math . Max ( bottomLeft . Y , bottomRight . Y ) ) ;
127+
128+ var clipRect = new Rect ( minX , minY , maxX - minX , maxY - minY ) ;
129+ var layoutRect = new Rect ( 0 , 0 , FocusedElement . ActualSize . X , FocusedElement . ActualSize . Y ) ;
130+ var left = Math . Max ( clipRect . Left , layoutRect . Left ) ;
131+ var top = Math . Max ( clipRect . Top , layoutRect . Top ) ;
132+ var right = Math . Min ( clipRect . Right , layoutRect . Right ) ;
133+ var bottom = Math . Min ( clipRect . Bottom , layoutRect . Bottom ) ;
134+
135+ var translatedMatrix = new Matrix ( Matrix3x2 . CreateTranslation ( ( float ) left , ( float ) top ) * transform ) ;
136+ if ( ( RenderTransform as MatrixTransform ) ? . Matrix != translatedMatrix )
137+ {
138+ RenderTransform = new MatrixTransform { Matrix = translatedMatrix } ;
139+ }
140+
141+ var newWidth = Math . Max ( 0 , right - left ) ;
142+ var newHeight = Math . Max ( 0 , bottom - top ) ;
143+ Width = newWidth ;
144+ Height = newHeight ;
145+ Visibility = newWidth <= 0 || newHeight <= 0 ? Visibility . Collapsed : Visibility . Visible ;
146+ }
147+ #else
148+ private void OnLoaded ( object sender , RoutedEventArgs e )
149+ {
150+ if ( XamlRoot is not null )
151+ {
152+ XamlRoot . Changed += XamlRootChanged ;
153+ }
154+ }
155+
156+ private void OnUnloaded ( object sender , RoutedEventArgs e )
157+ {
158+ if ( XamlRoot is not null )
159+ {
160+ XamlRoot . Changed -= XamlRootChanged ;
94161 }
95162 }
96163
@@ -192,4 +259,5 @@ private void ApplyClipping(Rect effectiveViewport)
192259
193260 Clip = clip ;
194261 }
262+ #endif
195263}
0 commit comments