Skip to content

Commit

Permalink
perf(macOS): Avoid calling NSView.Layer getter more than once / method
Browse files Browse the repository at this point in the history
  • Loading branch information
spouliot committed Jun 17, 2022
1 parent a85c49d commit 3ced78d
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 30 deletions.
5 changes: 3 additions & 2 deletions src/Uno.UI/Controls/BindableNSView.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ public BindableNSView()
{
Initialize();
WantsLayer = true;
if (Layer != null)
var layer = Layer;
if (layer != null)
{
Layer.MasksToBounds = false;
layer.MasksToBounds = false;
}
}

Expand Down
27 changes: 15 additions & 12 deletions src/Uno.UI/Media/NativeRenderTransformAdapter.iOSmacOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ partial void Initialized()
if (Owner is FrameworkElement element && !element.IsLoaded)
{
_isDeferring = true;
element.Layer.Opacity = 0;
var layer = element.Layer;
layer.Opacity = 0;
element.Loaded += DeferredInitialize;

_deferredInitialization = Disposable.Create(CompleteInitialization);
Expand All @@ -56,7 +57,7 @@ void CompleteInitialization()
element.Loaded -= DeferredInitialize;

_isDeferring = false;
element.Layer.Opacity = 1;
layer.Opacity = 1;

if (!_isDisposed)
{
Expand All @@ -77,13 +78,14 @@ void CompleteInitialization()

private void InitializeOrigin()
{
var oldFrame = Owner.Layer.Frame;
var layer = Owner.Layer;
var oldFrame = layer.Frame;

Owner.Layer.AnchorPoint = CurrentOrigin;
layer.AnchorPoint = CurrentOrigin;

// Restore the old frame to correct the offset potentially introduced by changing AnchorPoint. This is safe to do since we know
// that the transform is currently identity.
Owner.Layer.Frame = oldFrame;
layer.Frame = oldFrame;
}

partial void Apply(bool isSizeChanged, bool isOriginChanged)
Expand All @@ -94,14 +96,15 @@ partial void Apply(bool isSizeChanged, bool isOriginChanged)
return;
}
#endif
var layer = Owner.Layer;
if (Transform.IsAnimating)
{
// While animating the transform, we let the Animator apply the transform by itself, so do not update the Transform
if (!_wasAnimating)
{
// At the beginning of the animation make sure we disable all properties of the transform
Owner.Layer.AnchorPoint = GPUFloatValueAnimator.GetAnchorForAnimation(Transform, CurrentOrigin, CurrentSize);
Owner.Layer.Transform = CoreAnimation.CATransform3D.Identity;
layer.AnchorPoint = GPUFloatValueAnimator.GetAnchorForAnimation(Transform, CurrentOrigin, CurrentSize);
layer.Transform = CoreAnimation.CATransform3D.Identity;

_wasAnimating = true;
}
Expand All @@ -112,8 +115,8 @@ partial void Apply(bool isSizeChanged, bool isOriginChanged)
{
// Make sure to fully restore the transform at the end of an animation

Owner.Layer.AnchorPoint = CurrentOrigin;
Owner.Layer.Transform = _transform = Transform.MatrixCore.ToTransform3D();
layer.AnchorPoint = CurrentOrigin;
layer.Transform = _transform = Transform.MatrixCore.ToTransform3D();

_wasAnimating = false;

Expand All @@ -124,15 +127,15 @@ partial void Apply(bool isSizeChanged, bool isOriginChanged)
{
// As we use the 'AnchorPoint', the transform matrix is independent of the size of the control
// But the layouter expects from us that we restore the transform on each measuring phase
Owner.Layer.Transform = _transform;
layer.Transform = _transform;
}
else if (isOriginChanged)
{
Owner.Layer.AnchorPoint = CurrentOrigin;
layer.AnchorPoint = CurrentOrigin;
}
else
{
Owner.Layer.Transform = _transform = Transform.MatrixCore.ToTransform3D();
layer.Transform = _transform = Transform.MatrixCore.ToTransform3D();
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ private IDisposable SettingFrame(View view)

// If NSView.Transform is not identity, then modifying the frame will give undefined behavior. (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/NSView/transform)
// We have either already applied the transform to the new frame, or we will reset the transform straight after.
// FIXME: view.Layer called twice (thrice with above check)
var transform = view.Layer.Transform;
view.Layer.Transform = CATransform3D.Identity;
return Disposable.Create(reapplyTransform);
Expand Down
22 changes: 12 additions & 10 deletions src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.macOS.tt
Original file line number Diff line number Diff line change
Expand Up @@ -366,12 +366,13 @@ namespace <#= mixin.NamespaceName #>
#endif

CoreAnimation.CATransform3D? oldTransform = null;
if (Layer != null && !Layer.Transform.IsIdentity)
var layer = Layer;
if (layer != null && !layer.Transform.IsIdentity)
{
// If NSView.Transform is not identity, then modifying the frame will give undefined behavior. (https://developer.apple.com/library/ios/documentation/UIKit/Reference/NSView_Class/#//apple_ref/occ/instp/NSView/transform)
// We reapply the transform based on the new size straight after.
oldTransform = Layer.Transform;
Layer.Transform = CoreAnimation.CATransform3D.Identity;
oldTransform = layer.Transform;
layer.Transform = CoreAnimation.CATransform3D.Identity;
}

base.Frame = value;
Expand All @@ -389,13 +390,13 @@ namespace <#= mixin.NamespaceName #>
else if (oldTransform.HasValue)
{
// We grudgingly support setting the native transform directly without going through RenderTransform.
Layer.Transform = oldTransform.Value;
layer.Transform = oldTransform.Value;
}
}
else if (oldTransform.HasValue)
{
// We grudgingly support setting the native transform directly without going through RenderTransform.
Layer.Transform = oldTransform.Value;
layer.Transform = oldTransform.Value;
}
}
}
Expand Down Expand Up @@ -882,17 +883,18 @@ namespace <#= mixin.NamespaceName #>
{
WantsLayer = true;

var layer = Layer;
if(e.NewValue is SolidColorBrush scb)
{
Layer.BackgroundColor = scb.ColorWithOpacity;
layer.BackgroundColor = scb.ColorWithOpacity;

_brushColorChanged.Disposable = scb.RegisterDisposablePropertyChangedCallback(
SolidColorBrush.ColorProperty,
(s, colorArg) => Layer.BackgroundColor = (s as SolidColorBrush).ColorWithOpacity
(s, colorArg) => layer.BackgroundColor = (s as SolidColorBrush).ColorWithOpacity
);
_brushOpacityChanged.Disposable = scb.RegisterDisposablePropertyChangedCallback(
SolidColorBrush.OpacityProperty,
(s, colorArg) => Layer.BackgroundColor = (s as SolidColorBrush).ColorWithOpacity
(s, colorArg) => layer.BackgroundColor = (s as SolidColorBrush).ColorWithOpacity
);
}
else
Expand All @@ -901,15 +903,15 @@ namespace <#= mixin.NamespaceName #>
_brushOpacityChanged.Disposable = null;
if(e.NewValue is GradientBrush gb)
{
Layer.BackgroundColor = gb.FallbackColorWithOpacity;
layer.BackgroundColor = gb.FallbackColorWithOpacity;
}
else
{
if (this.Log().IsEnabled(Uno.Foundation.Logging.LogLevel.Warning))
{
this.Log().Warn("Brush is not a SolidColorBrush, ignoring");
}
Layer.BackgroundColor = SolidColorBrushHelper.Transparent.Color;
layer.BackgroundColor = SolidColorBrushHelper.Transparent.Color;
}
}
}
Expand Down
10 changes: 4 additions & 6 deletions src/Uno.UI/UI/Xaml/UIElement.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,18 +262,16 @@ partial void ApplyNativeClip(Rect rect)
{
if (!ClippingIsSetByCornerRadius)
{
if (Layer != null)
{
this.Layer.Mask = null;
}
Layer.Mask = null;
}
return;
}

WantsLayer = true;
if (Layer != null)
var layer = Layer;
if (layer != null)
{
this.Layer.Mask = new CAShapeLayer
layer.Mask = new CAShapeLayer
{
Path = CGPath.FromRect(rect.ToCGRect())
};
Expand Down

0 comments on commit 3ced78d

Please sign in to comment.