Skip to content

Commit

Permalink
Small speedup
Browse files Browse the repository at this point in the history
  • Loading branch information
albyrock87 committed Jan 14, 2025
1 parent a9b540b commit 14eecfe
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public PlatformWrapperView(Context context) {

private Paint shadowPaint;
private Bitmap shadowBitmap;
private float shadowBitmapX;
private float shadowBitmapY;
private Canvas shadowCanvas;
private boolean shadowInvalidated = true;
private boolean hasClip = false;
Expand Down Expand Up @@ -170,7 +172,7 @@ protected void drawShadow(@NonNull Canvas canvas, int viewWidth, int viewHeight)
View child = getChildAt(0);
Drawable background = child.getBackground();
// See if we can quickly draw shadow through Canvas API thanks to the fact we have a solid content
if (background != null && background instanceof PlatformShadowDrawable && ((PlatformShadowDrawable)background).canDrawShadow()) {
if (false && background != null && background instanceof PlatformShadowDrawable && ((PlatformShadowDrawable)background).canDrawShadow()) {
background.setBounds(0, 0, viewWidth, viewHeight);
drawShadowViaPlatformShadowDrawable(canvas, (PlatformShadowDrawable)background, viewWidth, viewHeight);
return;
Expand Down Expand Up @@ -201,15 +203,15 @@ private void drawShadowViaPlatformShadowDrawable(@NonNull Canvas canvas, @NonNul
}

private void drawShadowViaDispatchDraw(@NonNull Canvas canvas, int viewWidth, int viewHeight) {
int radiusSafeSpace = getRadiusSafeSpace();
int bitmapWidth = viewWidth + radiusSafeSpace;
int bitmapHeight = viewHeight + radiusSafeSpace;
int drawOriginX = (bitmapWidth - viewWidth) / 2;
int drawOriginY = (bitmapHeight - viewHeight) / 2;

if (shadowInvalidated) {
shadowInvalidated = false;

int radiusSafeSpace = getRadiusSafeSpace();
int bitmapWidth = normalizeForPool(viewWidth + radiusSafeSpace);
int bitmapHeight = normalizeForPool(viewHeight + radiusSafeSpace);
int drawOriginX = (bitmapWidth - viewWidth) / 2;
int drawOriginY = (bitmapHeight - viewHeight) / 2;

if (shadowBitmap != null) {
if (shadowBitmap.getWidth() == bitmapWidth && shadowBitmap.getHeight() == bitmapHeight) {
shadowBitmap.eraseColor(Color.TRANSPARENT);
Expand All @@ -224,30 +226,30 @@ private void drawShadowViaDispatchDraw(@NonNull Canvas canvas, int viewWidth, in
shadowCanvas.setBitmap(shadowBitmap);

// Create the local copy of all content to draw bitmap as a bottom layer of natural canvas.
shadowCanvas.save();
shadowCanvas.translate(drawOriginX, drawOriginY);
super.dispatchDraw(shadowCanvas);
shadowCanvas.restore();

// Get the alpha bounds of bitmap
Bitmap extractAlpha = shadowBitmap.extractAlpha();

// Clear the shadow canvas
shadowCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
Bitmap extractAlpha = bitmapPool.get(normalizeForPool(viewWidth), normalizeForPool(viewHeight), Bitmap.Config.ALPHA_8);
Canvas alphaCanvas = new Canvas(extractAlpha);
super.dispatchDraw(alphaCanvas);

// Apply shader if needed
Shader shader = createShader(bitmapWidth, bitmapHeight);
if (shader != null) {
shadowPaint.setShader(shader);
}

shadowCanvas.drawBitmap(extractAlpha, 0, 0, shadowPaint);
// Why don't we simply draw the alpha bitmap directly on the view canvas?
// Reason: setMaskFilter (used by shadowPaint) is *not* supported in hardware accelerated mode
// https://developer.android.com/develop/ui/views/graphics/hardware-accel
// If we use `SOFTWARE` layer, than we fall into a view-clipped `Canvas` where we can't draw the outer shadow.
shadowCanvas.drawBitmap(extractAlpha, drawOriginX, drawOriginY, shadowPaint);

bitmapPool.put(extractAlpha);

extractAlpha.recycle();
shadowBitmapX = offsetX - drawOriginX;
shadowBitmapY = offsetY - drawOriginY;
}

// Draw shadow rectangle
canvas.drawBitmap(shadowBitmap, offsetX - drawOriginX, offsetY - drawOriginY, null);
canvas.drawBitmap(shadowBitmap, shadowBitmapX, shadowBitmapY, null);
}

private int getRadiusSafeSpace() {
Expand All @@ -258,6 +260,11 @@ private int getRadiusSafeSpace() {
return (int)(radius * 3);
}

private static int normalizeForPool(int pixels) {
// We want to reuse memory as much as possible so let's normalize bitmaps to the nearest 48px grid.
return (int)(Math.ceil(((double)pixels) / 48.0) * 48.0);
}

private Shader createShader(int bitmapWidth, int bitmapHeight) {
Shader shader = null;

Expand Down
7 changes: 4 additions & 3 deletions src/Core/src/Platform/Android/WrapperView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ partial void ShadowChanged()
{
if (Shadow?.Paint is { } shadowPaint)
{
var context = Context;
var shadowOpacity = Shadow.Opacity;
float radius = Context.ToPixels(Shadow.Radius);
float offsetX = Context.ToPixels(Shadow.Offset.X);
float offsetY = Context.ToPixels(Shadow.Offset.Y);
float radius = context.ToPixels(Shadow.Radius);
float offsetX = context.ToPixels(Shadow.Offset.X);
float offsetY = context.ToPixels(Shadow.Offset.Y);
int paintType;
int[] colors;
float[] positions;
Expand Down
Binary file modified src/Core/src/maui.aar
Binary file not shown.

0 comments on commit 14eecfe

Please sign in to comment.