From 2e6f39e1739c4e408a6f635e31678376187c232e Mon Sep 17 00:00:00 2001 From: "danakj@chromium.org" Date: Thu, 15 May 2014 19:36:36 +0000 Subject: [PATCH] Make ui::Snapshot asynchronous on Android, remove CompositeAndReadback. The android pixel tests use the ui::Snapshot code to get a pixel copy of the content_shell's output. Make this behaviour match the aura implementation of ui::Snapshot by returning false in the synchronous verion, causing callsites to fall back to the async one. This implements the async snapshots by moving the aura implementation out into snapshot_async.cc and reusing that code (with one #if for RGBA vs BGRA ordering). After this, the pixel tests get a bitmap from cc instead of creating their own bitmap. The result is that the bitmap has a slightly different size (384x528) which is the size of the root layer. The pixel tests were previously trying to crop to 400x300, which is outside the bounds of this bitmap, so change them to crop to 300x300 instead, and increment their versions to pick up the new pngs. BUG=252046, 371592 Review URL: https://codereview.chromium.org/281003002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270778 0039d316-1c4b-4281-b951-d872f2087c98 --- cc/output/copy_output_request.cc | 1 - cc/output/copy_output_request.h | 2 +- cc/output/copy_output_result.cc | 1 - cc/output/copy_output_result.h | 2 +- .../android/content_view_render_view.cc | 9 -- .../android/content_view_render_view.h | 1 - .../renderer_host/compositor_impl_android.cc | 10 +- .../renderer_host/compositor_impl_android.h | 2 + .../browser/ContentViewRenderView.java | 16 +-- .../test/gpu/gpu_tests/pixel_expectations.py | 4 + content/test/gpu/page_sets/pixel_tests.py | 12 +- ui/base/DEPS | 1 + ui/base/android/window_android_compositor.h | 3 + ui/snapshot/snapshot.gyp | 17 ++- ui/snapshot/snapshot_android.cc | 58 ++++++---- ui/snapshot/snapshot_async.cc | 103 ++++++++++++++++++ ui/snapshot/snapshot_async.h | 42 +++++++ ui/snapshot/snapshot_aura.cc | 100 +---------------- 18 files changed, 225 insertions(+), 159 deletions(-) create mode 100644 ui/snapshot/snapshot_async.cc create mode 100644 ui/snapshot/snapshot_async.h diff --git a/cc/output/copy_output_request.cc b/cc/output/copy_output_request.cc index 0e8401140e5eaf..2d42fa97b762c6 100644 --- a/cc/output/copy_output_request.cc +++ b/cc/output/copy_output_request.cc @@ -9,7 +9,6 @@ #include "base/debug/trace_event.h" #include "base/logging.h" #include "cc/output/copy_output_result.h" -#include "cc/resources/single_release_callback.h" #include "cc/resources/texture_mailbox.h" #include "third_party/skia/include/core/SkBitmap.h" diff --git a/cc/output/copy_output_request.h b/cc/output/copy_output_request.h index dcb2fe25672126..60a5f11204d9ce 100644 --- a/cc/output/copy_output_request.h +++ b/cc/output/copy_output_request.h @@ -8,6 +8,7 @@ #include "base/callback.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "cc/resources/single_release_callback.h" #include "cc/resources/texture_mailbox.h" #include "ui/gfx/rect.h" @@ -15,7 +16,6 @@ class SkBitmap; namespace cc { class CopyOutputResult; -class SingleReleaseCallback; class CC_EXPORT CopyOutputRequest { public: diff --git a/cc/output/copy_output_result.cc b/cc/output/copy_output_result.cc index adbb8de60d0b9c..8dee046ce84dac 100644 --- a/cc/output/copy_output_result.cc +++ b/cc/output/copy_output_result.cc @@ -5,7 +5,6 @@ #include "cc/output/copy_output_result.h" #include "base/logging.h" -#include "cc/resources/single_release_callback.h" #include "cc/resources/texture_mailbox.h" #include "third_party/skia/include/core/SkBitmap.h" diff --git a/cc/output/copy_output_result.h b/cc/output/copy_output_result.h index b4806581c3fa1b..8529e3f152289c 100644 --- a/cc/output/copy_output_result.h +++ b/cc/output/copy_output_result.h @@ -7,13 +7,13 @@ #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "cc/resources/single_release_callback.h" #include "cc/resources/texture_mailbox.h" #include "ui/gfx/size.h" class SkBitmap; namespace cc { -class SingleReleaseCallback; class TextureMailbox; class CC_EXPORT CopyOutputResult { diff --git a/content/browser/android/content_view_render_view.cc b/content/browser/android/content_view_render_view.cc index 4a398859b1e66a..06590fa7513c75 100644 --- a/content/browser/android/content_view_render_view.cc +++ b/content/browser/android/content_view_render_view.cc @@ -117,15 +117,6 @@ void ContentViewRenderView::SurfaceChanged(JNIEnv* env, jobject obj, compositor_->SetWindowBounds(gfx::Size(width, height)); } -jboolean ContentViewRenderView::CompositeToBitmap(JNIEnv* env, jobject obj, - jobject java_bitmap) { - gfx::JavaBitmap bitmap(java_bitmap); - if (!compositor_ || bitmap.format() != ANDROID_BITMAP_FORMAT_RGBA_8888) - return false; - return compositor_->CompositeAndReadback(bitmap.pixels(), - gfx::Rect(bitmap.size())); -} - void ContentViewRenderView::SetOverlayVideoMode( JNIEnv* env, jobject obj, bool enabled) { compositor_->SetHasTransparentBackground(enabled); diff --git a/content/browser/android/content_view_render_view.h b/content/browser/android/content_view_render_view.h index cbdb1f19b40f11..2f1bcc1e7c7836 100644 --- a/content/browser/android/content_view_render_view.h +++ b/content/browser/android/content_view_render_view.h @@ -40,7 +40,6 @@ class ContentViewRenderView : public CompositorClient { void SurfaceChanged(JNIEnv* env, jobject obj, jint format, jint width, jint height, jobject surface); jboolean Composite(JNIEnv* env, jobject obj); - jboolean CompositeToBitmap(JNIEnv* env, jobject obj, jobject java_bitmap); void SetOverlayVideoMode(JNIEnv* env, jobject obj, bool enabled); // CompositorClient implementation diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index c8a803cd5c78a1..2deb35849e7b4e 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc @@ -439,10 +439,7 @@ void CompositorImpl::SetHasTransparentBackground(bool flag) { } bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { - if (host_) - return host_->CompositeAndReadback(pixels, rect); - else - return false; + return false; } void CompositorImpl::SetNeedsComposite() { @@ -623,6 +620,11 @@ void CompositorImpl::AttachLayerForReadback(scoped_refptr layer) { root_layer_->AddChild(layer); } +void CompositorImpl::RequestCopyOfOutputOnRootLayer( + scoped_ptr request) { + root_layer_->RequestCopyOfOutput(request.Pass()); +} + void CompositorImpl::OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period) { vsync_period_ = vsync_period; diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h index 8fd65add01b367..91de0aee2a9b25 100644 --- a/content/browser/renderer_host/compositor_impl_android.h +++ b/content/browser/renderer_host/compositor_impl_android.h @@ -100,6 +100,8 @@ class CONTENT_EXPORT CompositorImpl // WindowAndroidCompositor implementation. virtual void AttachLayerForReadback(scoped_refptr layer) OVERRIDE; + virtual void RequestCopyOfOutputOnRootLayer( + scoped_ptr request) OVERRIDE; virtual void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period) OVERRIDE; diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java index 709d57499b7715..d869ab015196c9 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java @@ -5,8 +5,6 @@ package org.chromium.content.browser; import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PixelFormat; import android.view.Surface; @@ -150,18 +148,7 @@ protected void onReadyToRender() { * @return The created SurfaceView object. */ protected SurfaceView createSurfaceView(Context context) { - return new SurfaceView(context) { - @Override - public void onDraw(Canvas canvas) { - // We only need to draw to software canvases, which are used for taking screenshots. - if (canvas.isHardwareAccelerated()) return; - Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), - Bitmap.Config.ARGB_8888); - if (nativeCompositeToBitmap(mNativeContentViewRenderView, bitmap)) { - canvas.drawBitmap(bitmap, 0, 0, null); - } - } - }; + return new SurfaceView(context); } /** @@ -214,7 +201,6 @@ private native void nativeSetLayerTreeBuildHelper(long nativeContentViewRenderVi private native void nativeSurfaceDestroyed(long nativeContentViewRenderView); private native void nativeSurfaceChanged(long nativeContentViewRenderView, int format, int width, int height, Surface surface); - private native boolean nativeCompositeToBitmap(long nativeContentViewRenderView, Bitmap bitmap); private native void nativeSetOverlayVideoMode(long nativeContentViewRenderView, boolean enabled); } diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py index 1d9594a9df4a42..8f89792359137d 100644 --- a/content/test/gpu/gpu_tests/pixel_expectations.py +++ b/content/test/gpu/gpu_tests/pixel_expectations.py @@ -24,4 +24,8 @@ def SetExpectations(self): # self.Fail('Pixel.Canvas2DRedBox', # ['mac', 'amd', ('nvidia', 0x1234)], bug=123) + self.Fail('Pixel.Canvas2DRedBox', bug=371592) + self.Fail('Pixel.CSS3DBlueBox', bug=371592) + self.Fail('Pixel.WebGLGreenTriangle', bug=371592) + pass diff --git a/content/test/gpu/page_sets/pixel_tests.py b/content/test/gpu/page_sets/pixel_tests.py index 897893aece7724..254e047e484ca3 100644 --- a/content/test/gpu/page_sets/pixel_tests.py +++ b/content/test/gpu/page_sets/pixel_tests.py @@ -34,20 +34,20 @@ def __init__(self): self.AddPage(PixelTestsPage( url='file://../../data/gpu/pixel_canvas2d.html', name='Pixel.Canvas2DRedBox', - test_rect=[0, 0, 400, 300], - revision=2, + test_rect=[0, 0, 300, 300], + revision=3, page_set=self)) self.AddPage(PixelTestsPage( url='file://../../data/gpu/pixel_css3d.html', name='Pixel.CSS3DBlueBox', - test_rect=[0, 0, 400, 300], - revision=5, + test_rect=[0, 0, 300, 300], + revision=6, page_set=self)) self.AddPage(PixelTestsPage( url='file://../../data/gpu/pixel_webgl.html', name='Pixel.WebGLGreenTriangle', - test_rect=[0, 0, 400, 300], - revision=6, + test_rect=[0, 0, 300, 300], + revision=7, page_set=self)) diff --git a/ui/base/DEPS b/ui/base/DEPS index 99ec151740525d..dd9bbe8d08db8c 100644 --- a/ui/base/DEPS +++ b/ui/base/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+cc", "+grit/app_locale_settings.h", "+grit/ui_resources.h", "+grit/ui_strings.h", diff --git a/ui/base/android/window_android_compositor.h b/ui/base/android/window_android_compositor.h index 1c2fefcdd64544..3f4a2effe8410a 100644 --- a/ui/base/android/window_android_compositor.h +++ b/ui/base/android/window_android_compositor.h @@ -5,6 +5,7 @@ #ifndef UI_BASE_ANDROID_WINDOW_ANDROID_COMPOSITOR_H_ #define UI_BASE_ANDROID_WINDOW_ANDROID_COMPOSITOR_H_ +#include "cc/output/copy_output_request.h" #include "ui/base/ui_base_export.h" namespace cc { @@ -19,6 +20,8 @@ class UI_BASE_EXPORT WindowAndroidCompositor { virtual ~WindowAndroidCompositor() {} virtual void AttachLayerForReadback(scoped_refptr layer) = 0; + virtual void RequestCopyOfOutputOnRootLayer( + scoped_ptr request) = 0; virtual void OnVSync(base::TimeTicks frame_time, base::TimeDelta vsync_period) = 0; }; diff --git a/ui/snapshot/snapshot.gyp b/ui/snapshot/snapshot.gyp index a6a997e0b5d9f8..3aa1fcaba692ac 100644 --- a/ui/snapshot/snapshot.gyp +++ b/ui/snapshot/snapshot.gyp @@ -11,8 +11,8 @@ 'target_name': 'snapshot', 'type': '<(component)', 'dependencies': [ - '../../skia/skia.gyp:skia', '../../base/base.gyp:base', + '../../skia/skia.gyp:skia', '../base/ui_base.gyp:ui_base', '../gfx/gfx.gyp:gfx', '../gfx/gfx.gyp:gfx_geometry', @@ -23,6 +23,8 @@ 'sources': [ 'snapshot.h', 'snapshot_android.cc', + 'snapshot_async.cc', + 'snapshot_async.h', 'snapshot_aura.cc', 'snapshot_export.h', 'snapshot_ios.mm', @@ -34,9 +36,20 @@ '..', ], 'conditions': [ - ['use_aura==1', { + ['use_aura==1 or OS=="android"', { 'dependencies': [ '../../cc/cc.gyp:cc', + '../../gpu/gpu.gyp:command_buffer_common', + ], + }], + ['use_aura!=1 and OS!="android"', { + 'sources!': [ + 'snapshot_async.cc', + 'snapshot_async.h', + ], + }], + ['use_aura==1', { + 'dependencies': [ '../aura/aura.gyp:aura', '../compositor/compositor.gyp:compositor', ], diff --git a/ui/snapshot/snapshot_android.cc b/ui/snapshot/snapshot_android.cc index 837c13c8d4f157..49e276c579b087 100644 --- a/ui/snapshot/snapshot_android.cc +++ b/ui/snapshot/snapshot_android.cc @@ -4,13 +4,13 @@ #include "ui/snapshot/snapshot.h" -#include "base/callback.h" +#include "base/bind.h" +#include "cc/output/copy_output_request.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/android/view_android.h" #include "ui/base/android/window_android.h" -#include "ui/gfx/display.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/screen.h" +#include "ui/base/android/window_android_compositor.h" +#include "ui/snapshot/snapshot_async.h" namespace ui { @@ -24,39 +24,53 @@ bool GrabViewSnapshot(gfx::NativeView view, bool GrabWindowSnapshot(gfx::NativeWindow window, std::vector* png_representation, const gfx::Rect& snapshot_bounds) { - gfx::Display display = - gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); - gfx::Rect scaled_bounds = - gfx::ScaleToEnclosingRect(snapshot_bounds, - display.device_scale_factor()); - return window->GrabSnapshot( - scaled_bounds.x(), scaled_bounds.y(), scaled_bounds.width(), - scaled_bounds.height(), png_representation); + // Not supported in Android. Callers should fall back to the async version. + return false; +} + +static void MakeAsyncCopyRequest( + gfx::NativeWindow window, + const gfx::Rect& source_rect, + const cc::CopyOutputRequest::CopyOutputRequestCallback& callback) { + scoped_ptr request = + cc::CopyOutputRequest::CreateBitmapRequest(callback); + request->set_area(source_rect); + window->GetCompositor()->RequestCopyOfOutputOnRootLayer(request.Pass()); } void GrabWindowSnapshotAndScaleAsync( gfx::NativeWindow window, - const gfx::Rect& snapshot_bounds, + const gfx::Rect& source_rect, const gfx::Size& target_size, scoped_refptr background_task_runner, - GrabWindowSnapshotAsyncCallback callback) { - callback.Run(gfx::Image()); + const GrabWindowSnapshotAsyncCallback& callback) { + MakeAsyncCopyRequest(window, + source_rect, + base::Bind(&SnapshotAsync::ScaleCopyOutputResult, + callback, + target_size, + background_task_runner)); } -void GrabViewSnapshotAsync( - gfx::NativeView view, +void GrabWindowSnapshotAsync( + gfx::NativeWindow window, const gfx::Rect& source_rect, scoped_refptr background_task_runner, const GrabWindowSnapshotAsyncPNGCallback& callback) { - callback.Run(scoped_refptr()); + MakeAsyncCopyRequest(window, + source_rect, + base::Bind(&SnapshotAsync::EncodeCopyOutputResult, + callback, + background_task_runner)); } -void GrabWindowSnapshotAsync( - gfx::NativeWindow window, +void GrabViewSnapshotAsync( + gfx::NativeView view, const gfx::Rect& source_rect, scoped_refptr background_task_runner, const GrabWindowSnapshotAsyncPNGCallback& callback) { - callback.Run(scoped_refptr()); + GrabWindowSnapshotAsync( + view->GetWindowAndroid(), source_rect, background_task_runner, callback); } } // namespace ui diff --git a/ui/snapshot/snapshot_async.cc b/ui/snapshot/snapshot_async.cc new file mode 100644 index 00000000000000..5f18225fcf431d --- /dev/null +++ b/ui/snapshot/snapshot_async.cc @@ -0,0 +1,103 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/snapshot/snapshot_async.h" + +#include "base/location.h" +#include "base/memory/ref_counted.h" +#include "base/numerics/safe_conversions.h" +#include "base/task_runner_util.h" +#include "skia/ext/image_operations.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkPixelRef.h" +#include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/skbitmap_operations.h" + +namespace ui { + +namespace { + +void OnFrameScalingFinished(const GrabWindowSnapshotAsyncCallback& callback, + const SkBitmap& scaled_bitmap) { + callback.Run(gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(scaled_bitmap))); +} + +SkBitmap ScaleBitmap(const SkBitmap& input_bitmap, + const gfx::Size& target_size) { + return skia::ImageOperations::Resize(input_bitmap, + skia::ImageOperations::RESIZE_GOOD, + target_size.width(), + target_size.height(), + static_cast(NULL)); +} + +scoped_refptr EncodeBitmap(const SkBitmap& bitmap) { + scoped_refptr png_data(new base::RefCountedBytes); + SkAutoLockPixels lock(bitmap); + unsigned char* pixels = reinterpret_cast(bitmap.getPixels()); +#if SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 + gfx::PNGCodec::ColorFormat kColorFormat = gfx::PNGCodec::FORMAT_BGRA; +#elif SK_A32_SHIFT == 24 && SK_B32_SHIFT == 16 && SK_G32_SHIFT == 8 + gfx::PNGCodec::ColorFormat kColorFormat = gfx::PNGCodec::FORMAT_RGBA; +#else +#error Unknown color format +#endif + if (!gfx::PNGCodec::Encode(pixels, + kColorFormat, + gfx::Size(bitmap.width(), bitmap.height()), + base::checked_cast(bitmap.rowBytes()), + true, + std::vector(), + &png_data->data())) { + return scoped_refptr(); + } + return png_data; +} + +} // namespace + +void SnapshotAsync::ScaleCopyOutputResult( + const GrabWindowSnapshotAsyncCallback& callback, + const gfx::Size& target_size, + scoped_refptr background_task_runner, + scoped_ptr result) { + if (result->IsEmpty()) { + callback.Run(gfx::Image()); + return; + } + + // TODO(sergeyu): Potentially images can be scaled on GPU before reading it + // from GPU. Image scaling is implemented in content::GlHelper, but it's can't + // be used here because it's not in content/public. Move the scaling code + // somewhere so that it can be reused here. + base::PostTaskAndReplyWithResult( + background_task_runner, + FROM_HERE, + base::Bind(ScaleBitmap, *result->TakeBitmap(), target_size), + base::Bind(&OnFrameScalingFinished, callback)); +} + +void SnapshotAsync::EncodeCopyOutputResult( + const GrabWindowSnapshotAsyncPNGCallback& callback, + scoped_refptr background_task_runner, + scoped_ptr result) { + if (result->IsEmpty()) { + callback.Run(scoped_refptr()); + return; + } + + // TODO(sergeyu): Potentially images can be scaled on GPU before reading it + // from GPU. Image scaling is implemented in content::GlHelper, but it's can't + // be used here because it's not in content/public. Move the scaling code + // somewhere so that it can be reused here. + base::PostTaskAndReplyWithResult( + background_task_runner, + FROM_HERE, + base::Bind(EncodeBitmap, *result->TakeBitmap()), + callback); +} + +} // namespace ui diff --git a/ui/snapshot/snapshot_async.h b/ui/snapshot/snapshot_async.h new file mode 100644 index 00000000000000..41da62ba2ac0e0 --- /dev/null +++ b/ui/snapshot/snapshot_async.h @@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_SNAPSHOT_SNAPSHOT_ASYNC_H_ +#define UI_SNAPSHOT_SNAPSHOT_ASYNC_H_ + +#include "cc/output/copy_output_result.h" +#include "ui/snapshot/snapshot.h" + +namespace base { +class TaskRunner; +} + +namespace gfx { +class Size; +} + +namespace ui { + +// Helper methods for async snapshots to convert a cc::CopyOutputResult into a +// ui::GrabWindowSnapshot callback. +class SnapshotAsync { + public: + static void ScaleCopyOutputResult( + const GrabWindowSnapshotAsyncCallback& callback, + const gfx::Size& target_size, + scoped_refptr background_task_runner, + scoped_ptr result); + + static void EncodeCopyOutputResult( + const GrabWindowSnapshotAsyncPNGCallback& callback, + scoped_refptr background_task_runner, + scoped_ptr result); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SnapshotAsync); +}; + +} // namespace ui + +#endif // UI_SNAPSHOT_SNAPSHOT_ASYNC_H_ diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc index a360b87e116ff5..fc7e6e7271d55c 100644 --- a/ui/snapshot/snapshot_aura.cc +++ b/ui/snapshot/snapshot_aura.cc @@ -6,109 +6,17 @@ #include "base/bind.h" #include "base/callback.h" -#include "base/logging.h" -#include "base/numerics/safe_conversions.h" #include "base/task_runner_util.h" #include "cc/output/copy_output_request.h" -#include "cc/output/copy_output_result.h" -#include "skia/ext/image_operations.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkPixelRef.h" #include "ui/aura/window.h" -#include "ui/aura/window_event_dispatcher.h" #include "ui/compositor/compositor.h" #include "ui/compositor/dip_util.h" #include "ui/compositor/layer.h" -#include "ui/gfx/codec/png_codec.h" -#include "ui/gfx/display.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/rect_conversions.h" -#include "ui/gfx/rect_f.h" -#include "ui/gfx/screen.h" -#include "ui/gfx/skbitmap_operations.h" -#include "ui/gfx/transform.h" +#include "ui/snapshot/snapshot_async.h" namespace ui { -namespace { - -void OnFrameScalingFinished( - const GrabWindowSnapshotAsyncCallback& callback, - const SkBitmap& scaled_bitmap) { - callback.Run(gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(scaled_bitmap))); -} - -SkBitmap ScaleBitmap(const SkBitmap& input_bitmap, - const gfx::Size& target_size) { - return skia::ImageOperations::Resize( - input_bitmap, - skia::ImageOperations::RESIZE_GOOD, - target_size.width(), - target_size.height(), - static_cast(NULL)); -} - -scoped_refptr EncodeBitmap(const SkBitmap& bitmap) { - scoped_refptr png_data(new base::RefCountedBytes); - unsigned char* pixels = - reinterpret_cast(bitmap.pixelRef()->pixels()); - if (!gfx::PNGCodec::Encode(pixels, - gfx::PNGCodec::FORMAT_BGRA, - gfx::Size(bitmap.width(), bitmap.height()), - base::checked_cast(bitmap.rowBytes()), - true, - std::vector(), - &png_data->data())) { - return scoped_refptr(); - } - return png_data; -} - -void ScaleCopyOutputResult( - const GrabWindowSnapshotAsyncCallback& callback, - const gfx::Size& target_size, - scoped_refptr background_task_runner, - scoped_ptr result) { - if (result->IsEmpty()) { - callback.Run(gfx::Image()); - return; - } - - // TODO(sergeyu): Potentially images can be scaled on GPU before reading it - // from GPU. Image scaling is implemented in content::GlHelper, but it's can't - // be used here because it's not in content/public. Move the scaling code - // somewhere so that it can be reused here. - base::PostTaskAndReplyWithResult( - background_task_runner, - FROM_HERE, - base::Bind(ScaleBitmap, *result->TakeBitmap(), target_size), - base::Bind(&OnFrameScalingFinished, callback)); -} - -void EncodeCopyOutputResult( - const GrabWindowSnapshotAsyncPNGCallback& callback, - scoped_refptr background_task_runner, - scoped_ptr result) { - if (result->IsEmpty()) { - callback.Run(scoped_refptr()); - return; - } - - // TODO(sergeyu): Potentially images can be scaled on GPU before reading it - // from GPU. Image scaling is implemented in content::GlHelper, but it's can't - // be used here because it's not in content/public. Move the scaling code - // somewhere so that it can be reused here. - base::PostTaskAndReplyWithResult(background_task_runner, - FROM_HERE, - base::Bind(EncodeBitmap, - *result->TakeBitmap()), - callback); -} - -} // namespace - bool GrabViewSnapshot(gfx::NativeView view, std::vector* png_representation, const gfx::Rect& snapshot_bounds) { @@ -122,7 +30,7 @@ bool GrabWindowSnapshot(gfx::NativeWindow window, return false; } -void MakeAsyncCopyRequest( +static void MakeAsyncCopyRequest( gfx::NativeWindow window, const gfx::Rect& source_rect, const cc::CopyOutputRequest::CopyOutputRequestCallback& callback) { @@ -140,7 +48,7 @@ void GrabWindowSnapshotAndScaleAsync( const GrabWindowSnapshotAsyncCallback& callback) { MakeAsyncCopyRequest(window, source_rect, - base::Bind(&ScaleCopyOutputResult, + base::Bind(&SnapshotAsync::ScaleCopyOutputResult, callback, target_size, background_task_runner)); @@ -153,7 +61,7 @@ void GrabWindowSnapshotAsync( const GrabWindowSnapshotAsyncPNGCallback& callback) { MakeAsyncCopyRequest(window, source_rect, - base::Bind(&EncodeCopyOutputResult, + base::Bind(&SnapshotAsync::EncodeCopyOutputResult, callback, background_task_runner)); }