1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.content.browser; 6 7 import android.graphics.Bitmap; 8 import android.graphics.Rect; 9 import android.util.SparseArray; 10 11 import org.chromium.base.CalledByNative; 12 import org.chromium.base.JNINamespace; 13 import org.chromium.base.ThreadUtils; 14 import org.chromium.ui.base.WindowAndroid; 15 16 /** 17 * A class for reading back content. 18 */ 19 @JNINamespace("content") 20 public abstract class ContentReadbackHandler { 21 /** 22 * A callback interface for content readback into a bitmap. 23 */ 24 public static interface GetBitmapCallback { 25 /** 26 * Called when the content readback finishes. 27 * @param bitmap The {@link Bitmap} of the content. Null will be passed for readback 28 * failure. 29 */ onFinishGetBitmap(Bitmap bitmap)30 public void onFinishGetBitmap(Bitmap bitmap); 31 } 32 33 private int mNextReadbackId = 1; 34 private SparseArray<GetBitmapCallback> mGetBitmapRequests; 35 36 private long mNativeContentReadbackHandler; 37 38 /** 39 * Creates a {@link ContentReadbackHandler}. 40 */ ContentReadbackHandler()41 public ContentReadbackHandler() { 42 mGetBitmapRequests = new SparseArray<GetBitmapCallback>(); 43 } 44 45 /** 46 * Initialize the native object. 47 */ initNativeContentReadbackHandler()48 public void initNativeContentReadbackHandler() { 49 mNativeContentReadbackHandler = nativeInit(); 50 } 51 52 /** 53 * Should be called when the ContentReadackHandler is not needed anymore. 54 */ destroy()55 public void destroy() { 56 if (mNativeContentReadbackHandler != 0) nativeDestroy(mNativeContentReadbackHandler); 57 mNativeContentReadbackHandler = 0; 58 } 59 60 61 @CalledByNative notifyGetBitmapFinished(int readbackId, Bitmap bitmap)62 private void notifyGetBitmapFinished(int readbackId, Bitmap bitmap) { 63 GetBitmapCallback callback = mGetBitmapRequests.get(readbackId); 64 if (callback != null) { 65 mGetBitmapRequests.delete(readbackId); 66 callback.onFinishGetBitmap(bitmap); 67 } else { 68 // readback Id is unregistered. 69 assert false : "Readback finished for unregistered Id: " + readbackId; 70 } 71 } 72 73 /** 74 * Asynchronously, generate and grab a bitmap representing what is currently on the screen 75 * for {@code view}. 76 * 77 * @param scale The scale that should be applied to the content. 78 * @param srcRect A subrect of the original content to capture. If this is empty, it will grab 79 * the whole surface. 80 * @param view The {@link ContentViewCore} to grab the bitmap from. 81 * @param callback The callback to be executed after readback completes. 82 */ getContentBitmapAsync(float scale, Rect srcRect, ContentViewCore view, GetBitmapCallback callback)83 public void getContentBitmapAsync(float scale, Rect srcRect, ContentViewCore view, 84 GetBitmapCallback callback) { 85 if (!readyForReadback()) { 86 callback.onFinishGetBitmap(null); 87 return; 88 } 89 ThreadUtils.assertOnUiThread(); 90 91 int readbackId = mNextReadbackId++; 92 mGetBitmapRequests.put(readbackId, callback); 93 nativeGetContentBitmap(mNativeContentReadbackHandler, readbackId, scale, 94 Bitmap.Config.ARGB_8888, srcRect.top, srcRect.left, srcRect.width(), 95 srcRect.height(), view); 96 } 97 98 /** 99 * Asynchronously, grab a bitmap of the current browser compositor root layer. 100 * 101 * @param windowAndroid The window that hosts the compositor. 102 * @param callback The callback to be executed after readback completes. 103 */ getCompositorBitmapAsync(WindowAndroid windowAndroid, GetBitmapCallback callback)104 public void getCompositorBitmapAsync(WindowAndroid windowAndroid, GetBitmapCallback callback) { 105 if (!readyForReadback()) { 106 callback.onFinishGetBitmap(null); 107 return; 108 } 109 ThreadUtils.assertOnUiThread(); 110 111 int readbackId = mNextReadbackId++; 112 mGetBitmapRequests.put(readbackId, callback); 113 nativeGetCompositorBitmap(mNativeContentReadbackHandler, readbackId, 114 windowAndroid.getNativePointer()); 115 } 116 117 /** 118 * Implemented by the owner of this class to signal whether readback is possible or not. 119 * @return Whether readback is possible or not. 120 */ readyForReadback()121 protected abstract boolean readyForReadback(); 122 nativeInit()123 private native long nativeInit(); nativeDestroy(long nativeContentReadbackHandler)124 private native void nativeDestroy(long nativeContentReadbackHandler); nativeGetContentBitmap(long nativeContentReadbackHandler, int readbackId, float scale, Bitmap.Config config, float x, float y, float width, float height, Object contentViewCore)125 private native void nativeGetContentBitmap(long nativeContentReadbackHandler, int readbackId, 126 float scale, Bitmap.Config config, float x, float y, float width, float height, 127 Object contentViewCore); nativeGetCompositorBitmap(long nativeContentReadbackHandler, int readbackId, long nativeWindowAndroid)128 private native void nativeGetCompositorBitmap(long nativeContentReadbackHandler, 129 int readbackId, long nativeWindowAndroid); 130 } 131