diff options
10 files changed, 110 insertions, 112 deletions
diff --git a/content/browser/android/content_readback_handler.cc b/content/browser/android/content_readback_handler.cc index 432b230..841ef5f 100644 --- a/content/browser/android/content_readback_handler.cc +++ b/content/browser/android/content_readback_handler.cc @@ -6,14 +6,36 @@ #include "base/android/jni_android.h" #include "base/bind.h" +#include "cc/output/copy_output_request.h" +#include "cc/output/copy_output_result.h" #include "content/browser/android/content_view_core_impl.h" #include "jni/ContentReadbackHandler_jni.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/android/window_android.h" +#include "ui/base/android/window_android_compositor.h" #include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/rect.h" namespace content { +namespace { + +typedef base::Callback<void(bool, const SkBitmap&)> ResultCallback; + +void OnFinishCopyOutputRequest( + const ResultCallback& result_callback, + scoped_ptr<cc::CopyOutputResult> copy_output_result) { + if (!copy_output_result->HasBitmap()) { + result_callback.Run(false, SkBitmap()); + return; + } + + scoped_ptr<SkBitmap> bitmap = copy_output_result->TakeBitmap(); + result_callback.Run(true, *bitmap.Pass()); +} + +} // anonymous namespace + // static bool ContentReadbackHandler::RegisterContentReadbackHandler(JNIEnv* env) { return RegisterNativesImpl(env); @@ -24,24 +46,10 @@ ContentReadbackHandler::ContentReadbackHandler(JNIEnv* env, jobject obj) java_obj_.Reset(env, obj); } -ContentReadbackHandler::~ContentReadbackHandler() {} - void ContentReadbackHandler::Destroy(JNIEnv* env, jobject obj) { delete this; } -void ContentReadbackHandler::OnFinishContentReadback(int readback_id, - bool success, - const SkBitmap& bitmap) { - JNIEnv* env = base::android::AttachCurrentThread(); - ScopedJavaLocalRef<jobject> java_bitmap; - if (success) - java_bitmap = gfx::ConvertToJavaBitmap(&bitmap); - - Java_ContentReadbackHandler_notifyGetContentBitmapFinished( - env, java_obj_.obj(), readback_id, success, java_bitmap.obj()); -} - void ContentReadbackHandler::GetContentBitmap(JNIEnv* env, jobject obj, jint readback_id, @@ -56,14 +64,55 @@ void ContentReadbackHandler::GetContentBitmap(JNIEnv* env, ContentViewCore::GetNativeContentViewCore(env, content_view_core); DCHECK(view); - base::Callback<void(bool, const SkBitmap&)> result_callback = - base::Bind(&ContentReadbackHandler::OnFinishContentReadback, + ResultCallback result_callback = + base::Bind(&ContentReadbackHandler::OnFinishReadback, weak_factory_.GetWeakPtr(), readback_id); view->GetScaledContentBitmap( scale, config, gfx::Rect(x, y, width, height), result_callback); - return; +} + +void ContentReadbackHandler::GetCompositorBitmap(JNIEnv* env, + jobject obj, + jint readback_id, + jlong native_window_android) { + ui::WindowAndroid* window_android = + reinterpret_cast<ui::WindowAndroid*>(native_window_android); + DCHECK(window_android); + + ResultCallback result_callback = + base::Bind(&ContentReadbackHandler::OnFinishReadback, + weak_factory_.GetWeakPtr(), + readback_id); + + base::Callback<void(scoped_ptr<cc::CopyOutputResult>)> copy_output_callback = + base::Bind(&OnFinishCopyOutputRequest, + result_callback); + + ui::WindowAndroidCompositor* compositor = window_android->GetCompositor(); + + if (!compositor) { + copy_output_callback.Run(cc::CopyOutputResult::CreateEmptyResult()); + return; + } + + compositor->RequestCopyOfOutputOnRootLayer( + cc::CopyOutputRequest::CreateBitmapRequest(copy_output_callback)); +} + +ContentReadbackHandler::~ContentReadbackHandler() {} + +void ContentReadbackHandler::OnFinishReadback(int readback_id, + bool success, + const SkBitmap& bitmap) { + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef<jobject> java_bitmap; + if (success) + java_bitmap = gfx::ConvertToJavaBitmap(&bitmap); + + Java_ContentReadbackHandler_notifyGetBitmapFinished( + env, java_obj_.obj(), readback_id, success, java_bitmap.obj()); } // static diff --git a/content/browser/android/content_readback_handler.h b/content/browser/android/content_readback_handler.h index 11d5aa3..403bdd0 100644 --- a/content/browser/android/content_readback_handler.h +++ b/content/browser/android/content_readback_handler.h @@ -13,6 +13,10 @@ class SkBitmap; +namespace cc { +class CopyOutputResult; +} + namespace content { // Native side of the ContentReadbackHandler.java, which issues content @@ -35,13 +39,17 @@ class ContentReadbackHandler { jfloat width, jfloat height, jobject content_view_core); + void GetCompositorBitmap(JNIEnv* env, + jobject obj, + jint readback_id, + jlong native_window_android); private: virtual ~ContentReadbackHandler(); - void OnFinishContentReadback(int readback_id, - bool success, - const SkBitmap& bitmap); + void OnFinishReadback(int readback_id, + bool success, + const SkBitmap& bitmap); base::android::ScopedJavaGlobalRef<jobject> java_obj_; base::WeakPtrFactory<ContentReadbackHandler> weak_factory_; diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 2deb358..5e01b73 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -438,10 +438,6 @@ void CompositorImpl::SetHasTransparentBackground(bool flag) { host_->set_has_transparent_background(flag); } -bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { - return false; -} - void CompositorImpl::SetNeedsComposite() { if (!host_.get() || needs_composite_) return; diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 91de0ae..0f1e88f 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h @@ -63,8 +63,6 @@ class CONTENT_EXPORT CompositorImpl virtual void setDeviceScaleFactor(float factor) OVERRIDE; virtual void SetWindowBounds(const gfx::Size& size) OVERRIDE; virtual void SetHasTransparentBackground(bool flag) OVERRIDE; - virtual bool CompositeAndReadback( - void *pixels, const gfx::Rect& rect) OVERRIDE; virtual void SetNeedsComposite() OVERRIDE; virtual cc::UIResourceId GenerateUIResource(const SkBitmap& bitmap, bool is_transient) OVERRIDE; diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentReadbackHandler.java b/content/public/android/java/src/org/chromium/content/browser/ContentReadbackHandler.java index aab9aaa..15226d5 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentReadbackHandler.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentReadbackHandler.java @@ -11,6 +11,7 @@ import android.util.SparseArray; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; import org.chromium.base.ThreadUtils; +import org.chromium.ui.base.WindowAndroid; /** * A class for reading back content. @@ -20,17 +21,17 @@ public abstract class ContentReadbackHandler { /** * A callback interface for content readback into a bitmap. */ - public static interface GetContentBitmapCallback { + public static interface GetBitmapCallback { /** * Called when the content readback finishes. * @param success Indicates whether the readback succeeded or not. * @param bitmap The {@link Bitmap} of the content. */ - public void onFinishGetContentBitmap(boolean success, Bitmap bitmap); + public void onFinishGetBitmap(boolean success, Bitmap bitmap); } private int mNextReadbackId = 1; - private SparseArray<GetContentBitmapCallback> mGetContentBitmapRequests; + private SparseArray<GetBitmapCallback> mGetBitmapRequests; private long mNativeContentReadbackHandler; @@ -38,7 +39,7 @@ public abstract class ContentReadbackHandler { * Creates a {@link ContentReadbackHandler}. */ public ContentReadbackHandler() { - mGetContentBitmapRequests = new SparseArray<GetContentBitmapCallback>(); + mGetBitmapRequests = new SparseArray<GetBitmapCallback>(); } /** @@ -58,11 +59,11 @@ public abstract class ContentReadbackHandler { @CalledByNative - private void notifyGetContentBitmapFinished(int readbackId, boolean success, Bitmap bitmap) { - GetContentBitmapCallback callback = mGetContentBitmapRequests.get(readbackId); + private void notifyGetBitmapFinished(int readbackId, boolean success, Bitmap bitmap) { + GetBitmapCallback callback = mGetBitmapRequests.get(readbackId); if (callback != null) { - mGetContentBitmapRequests.delete(readbackId); - callback.onFinishGetContentBitmap(success, bitmap); + mGetBitmapRequests.delete(readbackId); + callback.onFinishGetBitmap(success, bitmap); } else { // readback Id is unregistered. assert false : "Readback finished for unregistered Id: " + readbackId; @@ -80,21 +81,40 @@ public abstract class ContentReadbackHandler { * @param callback The callback to be executed after readback completes. */ public void getContentBitmapAsync(float scale, Rect srcRect, ContentViewCore view, - GetContentBitmapCallback callback) { + GetBitmapCallback callback) { if (!readyForReadback()) { - callback.onFinishGetContentBitmap(false, null); + callback.onFinishGetBitmap(false, null); return; } ThreadUtils.assertOnUiThread(); int readbackId = mNextReadbackId++; - mGetContentBitmapRequests.put(readbackId, callback); + mGetBitmapRequests.put(readbackId, callback); nativeGetContentBitmap(mNativeContentReadbackHandler, readbackId, scale, Bitmap.Config.ARGB_8888, srcRect.top, srcRect.left, srcRect.width(), srcRect.height(), view); } /** + * Asynchronously, grab a bitmap of the current browser compositor root layer. + * + * @param windowAndroid The window that hosts the compositor. + * @param callback The callback to be executed after readback completes. + */ + public void getCompositorBitmapAsync(WindowAndroid windowAndroid, GetBitmapCallback callback) { + if (!readyForReadback()) { + callback.onFinishGetBitmap(false, null); + return; + } + ThreadUtils.assertOnUiThread(); + + int readbackId = mNextReadbackId++; + mGetBitmapRequests.put(readbackId, callback); + nativeGetCompositorBitmap(mNativeContentReadbackHandler, readbackId, + windowAndroid.getNativePointer()); + } + + /** * Implemented by the owner of this class to signal whether readback is possible or not. * @return Whether readback is possible or not. */ @@ -105,4 +125,6 @@ public abstract class ContentReadbackHandler { private native void nativeGetContentBitmap(long nativeContentReadbackHandler, int readback_id, float scale, Bitmap.Config config, float x, float y, float width, float height, Object contentViewCore); + private native void nativeGetCompositorBitmap(long nativeContentReadbackHandler, + int readback_id, long nativeWindowAndroid); } diff --git a/content/public/browser/android/compositor.h b/content/public/browser/android/compositor.h index 236a90d..2d8126b 100644 --- a/content/public/browser/android/compositor.h +++ b/content/public/browser/android/compositor.h @@ -64,11 +64,6 @@ class CONTENT_EXPORT Compositor { // Tells the view tree to assume a transparent background when rendering. virtual void SetHasTransparentBackground(bool flag) = 0; - // Attempts to composite and read back the result into the provided buffer. - // The buffer must be at least window width * height * 4 (RGBA) bytes large. - // The buffer is not modified if false is returned. - virtual bool CompositeAndReadback(void *pixels, const gfx::Rect& rect) = 0; - // Request layout and draw. You only need to call this if you need to trigger // Composite *without* having modified the layer tree. virtual void SetNeedsComposite() = 0; diff --git a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java index 99c8c41..07f48dc 100644 --- a/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java +++ b/ui/android/java/src/org/chromium/ui/base/ActivityWindowAndroid.java @@ -9,14 +9,7 @@ import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.IntentSender.SendIntentException; -import android.graphics.Bitmap; -import android.graphics.Rect; -import android.util.Log; -import android.view.View; -import org.chromium.ui.UiUtils; - -import java.io.ByteArrayOutputStream; import java.lang.ref.WeakReference; /** @@ -105,41 +98,6 @@ public class ActivityWindowAndroid extends WindowAndroid { return new WeakReference<Activity>(mActivityRef.get()); } - /** - * Returns a PNG-encoded screenshot of the the window region at (|windowX|, - * |windowY|) with the size |width| by |height| pixels. - */ - @Override - public byte[] grabSnapshot(int windowX, int windowY, int width, int height) { - Activity activity = mActivityRef.get(); - if (activity == null) return null; - try { - // Take a screenshot of the root activity view. This generally includes UI - // controls such as the URL bar and OS windows such as the status bar. - View rootView = activity.findViewById(android.R.id.content).getRootView(); - Bitmap bitmap = UiUtils.generateScaledScreenshot(rootView, 0, Bitmap.Config.ARGB_8888); - if (bitmap == null) return null; - - // Clip the result into the requested region. - if (windowX > 0 || windowY > 0 || width != bitmap.getWidth() || - height != bitmap.getHeight()) { - Rect clip = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); - clip.intersect(windowX, windowY, windowX + width, windowY + height); - bitmap = Bitmap.createBitmap( - bitmap, clip.left, clip.top, clip.width(), clip.height()); - } - - // Compress the result into a PNG. - ByteArrayOutputStream result = new ByteArrayOutputStream(); - if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, result)) return null; - bitmap.recycle(); - return result.toByteArray(); - } catch (OutOfMemoryError e) { - Log.e(TAG, "Out of memory while grabbing window snapshot.", e); - return null; - } - } - private int generateNextRequestCode() { int requestCode = REQUEST_CODE_PREFIX + mNextRequestCode; mNextRequestCode = (mNextRequestCode + 1) % REQUEST_CODE_RANGE_SIZE; diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java index 4a68dea..424b566 100644 --- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java +++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java @@ -279,15 +279,6 @@ public class WindowAndroid { return mNativeWindowAndroid; } - /** - * Returns a PNG-encoded screenshot of the the window region at (|windowX|, - * |windowY|) with the size |width| by |height| pixels. - */ - @CalledByNative - public byte[] grabSnapshot(int windowX, int windowY, int width, int height) { - return null; - } - private native long nativeInit(long vsyncPeriod); private native void nativeOnVSync(long nativeWindowAndroid, long vsyncTimeMicros); private native void nativeDestroy(long nativeWindowAndroid); diff --git a/ui/base/android/window_android.cc b/ui/base/android/window_android.cc index 3dd3e6e..e462550 100644 --- a/ui/base/android/window_android.cc +++ b/ui/base/android/window_android.cc @@ -41,22 +41,6 @@ WindowAndroid::~WindowAndroid() { WindowAndroidObserver, observer_list_, OnWillDestroyWindow()); } -bool WindowAndroid::GrabSnapshot( - int content_x, int content_y, int width, int height, - std::vector<unsigned char>* png_representation) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jbyteArray> result = - Java_WindowAndroid_grabSnapshot(env, GetJavaObject().obj(), - content_x + content_offset_.x(), - content_y + content_offset_.y(), - width, height); - if (result.is_null()) - return false; - base::android::JavaByteArrayToByteVector( - env, result.obj(), png_representation); - return true; -} - void WindowAndroid::OnCompositingDidCommit() { FOR_EACH_OBSERVER(WindowAndroidObserver, observer_list_, diff --git a/ui/base/android/window_android.h b/ui/base/android/window_android.h index 7e39184..df8685d 100644 --- a/ui/base/android/window_android.h +++ b/ui/base/android/window_android.h @@ -36,9 +36,6 @@ class UI_BASE_EXPORT WindowAndroid { content_offset_ = content_offset; } - bool GrabSnapshot(int content_x, int content_y, int width, int height, - std::vector<unsigned char>* png_representation); - // Compositor callback relay. void OnCompositingDidCommit(); |