chromium/ui/android/java/src/org/chromium/ui/resources/dynamics/CaptureUtils.java

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.ui.resources.dynamics;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.view.View;

/** Shared stateless capture utility functions. */
public class CaptureUtils {
    /** Creates a bitmap with the given size. */
    public static Bitmap createBitmap(int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.setHasAlpha(true);
        return bitmap;
    }

    /**
     * Called to draw the {@link View}'s contents into the passed in {@link Canvas}.
     *
     * @param canvas The {@link Canvas} that will be drawn to.
     * @param view The view being captuerd.
     * @param dirtyRect The area of the view that might have changed.
     * @param scale The scale to capture the view at.
     * @param drawWhileDetached drawing while detached causes crashes for both software and hardware
     *     renderer, since enabling hardware renderer caused a regression in number of crashes, this
     *     boolean will only be true for software renderer, and will be removed later on if the
     *     issue was fixed for the hardware renderer and logic for avoiding the draw would be the
     *     same for both hardware and software renderer. Software or hardware draw will both need to
     *     follow this pattern.
     * @param observer Should be notified before and after the actual bitmap draw happens.
     * @return true if the draw is successful, false if we couldn't draw because the view is
     *     detached.
     */
    public static boolean captureCommon(
            Canvas canvas,
            View view,
            Rect dirtyRect,
            float scale,
            boolean drawWhileDetached,
            CaptureObserver observer) {
        boolean willDraw = drawWhileDetached || view.isAttachedToWindow();
        if (!willDraw) {
            return false;
        }
        observer.onCaptureStart(canvas, dirtyRect.isEmpty() ? null : dirtyRect);
        if (!dirtyRect.isEmpty()) {
            canvas.clipRect(dirtyRect);
        }

        canvas.save();
        canvas.scale(scale, scale);
        view.draw(canvas);
        canvas.restore();

        observer.onCaptureEnd();
        return true;
    }
}