[Android] Changes to improve Border control drawing performance (#3620)

* Changes to improve Border control drawing performance

* Avoid to draw unnecesary Path
This commit is contained in:
Javier Suárez 2022-01-13 17:46:43 +01:00 коммит произвёл GitHub
Родитель 8316f7ab23
Коммит 516fe302fe
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 78 добавлений и 74 удалений

Просмотреть файл

@ -23,12 +23,11 @@ namespace Microsoft.Maui.Graphics
bool _disposed; bool _disposed;
ARect? _bounds;
int _width; int _width;
int _height; int _height;
Path? _clipPath; Path? _clipPath;
Path? _maskPath;
APaint? _maskPaint;
APaint? _borderPaint; APaint? _borderPaint;
IShape? _shape; IShape? _shape;
@ -60,6 +59,9 @@ namespace Microsoft.Maui.Graphics
public void SetBackgroundColor(AColor? backgroundColor) public void SetBackgroundColor(AColor? backgroundColor)
{ {
if (_backgroundColor == backgroundColor)
return;
_backgroundColor = backgroundColor; _backgroundColor = backgroundColor;
InvalidateSelf(); InvalidateSelf();
@ -98,6 +100,9 @@ namespace Microsoft.Maui.Graphics
public void SetBackground(LinearGradientPaint linearGradientPaint) public void SetBackground(LinearGradientPaint linearGradientPaint)
{ {
if (_background == linearGradientPaint)
return;
_invalidatePath = true; _invalidatePath = true;
_backgroundColor = null; _backgroundColor = null;
@ -109,6 +114,9 @@ namespace Microsoft.Maui.Graphics
public void SetBackground(RadialGradientPaint radialGradientPaint) public void SetBackground(RadialGradientPaint radialGradientPaint)
{ {
if (_background == radialGradientPaint)
return;
_invalidatePath = true; _invalidatePath = true;
_backgroundColor = null; _backgroundColor = null;
@ -130,6 +138,9 @@ namespace Microsoft.Maui.Graphics
public void SetBorderShape(IShape? shape) public void SetBorderShape(IShape? shape)
{ {
if (_shape == shape)
return;
_invalidatePath = true; _invalidatePath = true;
_shape = shape; _shape = shape;
@ -140,6 +151,9 @@ namespace Microsoft.Maui.Graphics
public void SetBorderColor(AColor? borderColor) public void SetBorderColor(AColor? borderColor)
{ {
if (_borderColor == borderColor)
return;
_borderColor = borderColor; _borderColor = borderColor;
InvalidateSelf(); InvalidateSelf();
@ -178,6 +192,9 @@ namespace Microsoft.Maui.Graphics
public void SetBorderBrush(LinearGradientPaint linearGradientPaint) public void SetBorderBrush(LinearGradientPaint linearGradientPaint)
{ {
if (_stroke == linearGradientPaint)
return;
_invalidatePath = true; _invalidatePath = true;
_borderColor = null; _borderColor = null;
@ -189,6 +206,9 @@ namespace Microsoft.Maui.Graphics
public void SetBorderBrush(RadialGradientPaint radialGradientPaint) public void SetBorderBrush(RadialGradientPaint radialGradientPaint)
{ {
if (_stroke == radialGradientPaint)
return;
_invalidatePath = true; _invalidatePath = true;
_borderColor = null; _borderColor = null;
@ -210,9 +230,14 @@ namespace Microsoft.Maui.Graphics
public void SetBorderWidth(double strokeWidth) public void SetBorderWidth(double strokeWidth)
{ {
float strokeThickness = (float)(strokeWidth * _density);
if (_strokeThickness == strokeThickness)
return;
_invalidatePath = true; _invalidatePath = true;
_strokeThickness = (float)(strokeWidth * _density); _strokeThickness = strokeThickness;
InitializeBorderIfNeeded(); InitializeBorderIfNeeded();
InvalidateSelf(); InvalidateSelf();
@ -238,6 +263,9 @@ namespace Microsoft.Maui.Graphics
public void SetBorderMiterLimit(float strokeMiterLimit) public void SetBorderMiterLimit(float strokeMiterLimit)
{ {
if (_strokeMiterLimit == strokeMiterLimit)
return;
_strokeMiterLimit = strokeMiterLimit; _strokeMiterLimit = strokeMiterLimit;
InvalidateSelf(); InvalidateSelf();
@ -260,6 +288,9 @@ namespace Microsoft.Maui.Graphics
break; break;
} }
if (_strokeLineJoin == aLineJoin)
return;
_strokeLineJoin = aLineJoin; _strokeLineJoin = aLineJoin;
InvalidateSelf(); InvalidateSelf();
@ -282,6 +313,9 @@ namespace Microsoft.Maui.Graphics
break; break;
} }
if (_strokeLineCap == aLineCap)
return;
_strokeLineCap = aLineCap; _strokeLineCap = aLineCap;
InvalidateSelf(); InvalidateSelf();
@ -289,10 +323,14 @@ namespace Microsoft.Maui.Graphics
protected override void OnBoundsChange(ARect? bounds) protected override void OnBoundsChange(ARect? bounds)
{ {
if (bounds != null) if (_bounds != bounds)
{ {
var width = bounds.Width(); _bounds = bounds;
var height = bounds.Height();
if (_bounds != null)
{
var width = _bounds.Width();
var height = _bounds.Height();
if (_width == width && _height == height) if (_width == width && _height == height)
return; return;
@ -302,6 +340,7 @@ namespace Microsoft.Maui.Graphics
_width = width; _width = width;
_height = height; _height = height;
} }
}
base.OnBoundsChange(bounds); base.OnBoundsChange(bounds);
} }
@ -352,13 +391,6 @@ namespace Microsoft.Maui.Graphics
{ {
_clipPath.Reset(); _clipPath.Reset();
_clipPath.Set(clipPath); _clipPath.Set(clipPath);
if (_maskPath != null && HasBorder())
{
_maskPath.Reset();
_maskPath.AddRect(0, 0, _width, _height, Path.Direction.Cw!);
_maskPath.InvokeOp(_clipPath, Path.Op.Difference!);
}
} }
} }
} }
@ -374,9 +406,6 @@ namespace Microsoft.Maui.Graphics
if (_clipPath != null && _borderPaint != null) if (_clipPath != null && _borderPaint != null)
canvas.DrawPath(_clipPath, _borderPaint); canvas.DrawPath(_clipPath, _borderPaint);
if (_maskPath != null && _maskPaint != null)
canvas.DrawPath(_maskPath, _maskPaint);
canvas.RestoreToCount(saveCount); canvas.RestoreToCount(saveCount);
} }
else else
@ -419,19 +448,6 @@ namespace Microsoft.Maui.Graphics
{ {
if (disposing) if (disposing)
{ {
if (_maskPath != null)
{
_maskPath.Dispose();
_maskPath = null;
}
if (_maskPaint != null)
{
_maskPaint.SetXfermode(null);
_maskPaint.Dispose();
_maskPaint = null;
}
if (_borderPaint != null) if (_borderPaint != null)
{ {
_borderPaint.Dispose(); _borderPaint.Dispose();
@ -455,18 +471,6 @@ namespace Microsoft.Maui.Graphics
return; return;
} }
if (_maskPath == null)
_maskPath = new Path();
if (_maskPaint == null)
{
_maskPaint = new APaint(PaintFlags.AntiAlias);
_maskPaint.SetStyle(APaint.Style.FillAndStroke);
PorterDuffXfermode porterDuffClearMode = new PorterDuffXfermode(PorterDuff.Mode.Clear);
_maskPaint.SetXfermode(porterDuffClearMode);
}
if (_borderPaint == null) if (_borderPaint == null)
{ {
_borderPaint = new APaint(PaintFlags.AntiAlias); _borderPaint = new APaint(PaintFlags.AntiAlias);

Просмотреть файл

@ -17,6 +17,10 @@ namespace Microsoft.Maui.Handlers
CrossPlatformArrange = VirtualView.CrossPlatformArrange CrossPlatformArrange = VirtualView.CrossPlatformArrange
}; };
// We only want to use a hardware layer for the entering view because its quite likely
// the view will invalidate several times the Drawable (Draw).
viewGroup.SetLayerType(Android.Views.LayerType.Hardware, null);
return viewGroup; return viewGroup;
} }
@ -51,6 +55,7 @@ namespace Microsoft.Maui.Handlers
{ {
// If we're being disconnected from the xplat element, then we should no longer be managing its chidren // If we're being disconnected from the xplat element, then we should no longer be managing its chidren
nativeView.RemoveAllViews(); nativeView.RemoveAllViews();
base.DisconnectHandler(nativeView); base.DisconnectHandler(nativeView);
} }
} }

Просмотреть файл

@ -8,9 +8,9 @@ namespace Microsoft.Maui.Platform
public static void UpdateStrokeShape(this AView nativeView, IBorder border) public static void UpdateStrokeShape(this AView nativeView, IBorder border)
{ {
var borderShape = border.Shape; var borderShape = border.Shape;
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
if (background == null && borderShape == null) if (mauiDrawable == null && borderShape == null)
return; return;
nativeView.UpdateMauiDrawable(border); nativeView.UpdateMauiDrawable(border);
@ -19,82 +19,83 @@ namespace Microsoft.Maui.Platform
public static void UpdateStroke(this AView nativeView, IBorder border) public static void UpdateStroke(this AView nativeView, IBorder border)
{ {
var stroke = border.Stroke; var stroke = border.Stroke;
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
if (background == null && stroke.IsNullOrEmpty()) if (mauiDrawable == null && stroke.IsNullOrEmpty())
return; return;
nativeView.UpdateMauiDrawable(border); nativeView.UpdateMauiDrawable(border);
mauiDrawable?.SetBorderBrush(border.Stroke);
} }
public static void UpdateStrokeThickness(this AView nativeView, IBorder border) public static void UpdateStrokeThickness(this AView nativeView, IBorder border)
{ {
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
bool hasBorder = border.Shape != null && border.Stroke != null; bool hasBorder = border.Shape != null && border.Stroke != null;
if (background == null && !hasBorder) if (mauiDrawable == null && !hasBorder)
return; return;
nativeView.UpdateMauiDrawable(border); mauiDrawable?.SetBorderWidth(border.StrokeThickness);
} }
public static void UpdateStrokeDashPattern(this AView nativeView, IBorder border) public static void UpdateStrokeDashPattern(this AView nativeView, IBorder border)
{ {
var strokeDashPattern = border.StrokeDashPattern; var strokeDashPattern = border.StrokeDashPattern;
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
bool hasBorder = border.Shape != null && border.Stroke != null; bool hasBorder = border.Shape != null && border.Stroke != null;
if (background == null && !hasBorder && (strokeDashPattern == null || strokeDashPattern.Length == 0)) if (mauiDrawable == null && !hasBorder && (strokeDashPattern == null || strokeDashPattern.Length == 0))
return; return;
nativeView.UpdateMauiDrawable(border); mauiDrawable?.SetBorderDash(border.StrokeDashPattern, border.StrokeDashOffset);
} }
public static void UpdateStrokeDashOffset(this AView nativeView, IBorder border) public static void UpdateStrokeDashOffset(this AView nativeView, IBorder border)
{ {
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
bool hasBorder = border.Shape != null && border.Stroke != null; bool hasBorder = border.Shape != null && border.Stroke != null;
if (background == null && !hasBorder) if (mauiDrawable == null && !hasBorder)
return; return;
nativeView.UpdateMauiDrawable(border); mauiDrawable?.SetBorderDash(border.StrokeDashPattern, border.StrokeDashOffset);
} }
public static void UpdateStrokeMiterLimit(this AView nativeView, IBorder border) public static void UpdateStrokeMiterLimit(this AView nativeView, IBorder border)
{ {
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
bool hasBorder = border.Shape != null && border.Stroke != null; bool hasBorder = border.Shape != null && border.Stroke != null;
if (background == null && !hasBorder) if (mauiDrawable == null && !hasBorder)
return; return;
nativeView.UpdateMauiDrawable(border); mauiDrawable?.SetBorderMiterLimit(border.StrokeMiterLimit);
} }
public static void UpdateStrokeLineCap(this AView nativeView, IBorder border) public static void UpdateStrokeLineCap(this AView nativeView, IBorder border)
{ {
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
bool hasBorder = border.Shape != null && border.Stroke != null; bool hasBorder = border.Shape != null && border.Stroke != null;
if (background == null && !hasBorder) if (mauiDrawable == null && !hasBorder)
return; return;
nativeView.UpdateMauiDrawable(border); mauiDrawable?.SetBorderLineCap(border.StrokeLineCap);
} }
public static void UpdateStrokeLineJoin(this AView nativeView, IBorder border) public static void UpdateStrokeLineJoin(this AView nativeView, IBorder border)
{ {
MauiDrawable? background = nativeView.Background as MauiDrawable; MauiDrawable? mauiDrawable = nativeView.Background as MauiDrawable;
bool hasBorder = border.Shape != null && border.Stroke != null; bool hasBorder = border.Shape != null && border.Stroke != null;
if (background == null && !hasBorder) if (mauiDrawable == null && !hasBorder)
return; return;
nativeView.UpdateMauiDrawable(border); mauiDrawable?.SetBorderLineJoin(border.StrokeLineJoin);
} }
internal static void UpdateMauiDrawable(this AView nativeView, IBorder border) internal static void UpdateMauiDrawable(this AView nativeView, IBorder border)
@ -114,12 +115,6 @@ namespace Microsoft.Maui.Platform
} }
mauiDrawable.SetBackground(border.Background); mauiDrawable.SetBackground(border.Background);
mauiDrawable.SetBorderBrush(border.Stroke);
mauiDrawable.SetBorderWidth(border.StrokeThickness);
mauiDrawable.SetBorderDash(border.StrokeDashPattern, border.StrokeDashOffset);
mauiDrawable.SetBorderMiterLimit(border.StrokeMiterLimit);
mauiDrawable.SetBorderLineJoin(border.StrokeLineJoin);
mauiDrawable.SetBorderLineCap(border.StrokeLineCap);
mauiDrawable.SetBorderShape(border.Shape); mauiDrawable.SetBorderShape(border.Shape);
} }
} }