diff options
10 files changed, 267 insertions, 8 deletions
diff --git a/chrome/browser/apps/web_view_browsertest.cc b/chrome/browser/apps/web_view_browsertest.cc index fbf95c9..343961e 100644 --- a/chrome/browser/apps/web_view_browsertest.cc +++ b/chrome/browser/apps/web_view_browsertest.cc @@ -1846,17 +1846,31 @@ IN_PROC_BROWSER_TEST_F(WebViewPluginTest, TestLoadPluginEvent) { // Taking a screenshot does not work with threaded compositing, so disable // threaded compositing for this test (http://crbug.com/326756). -class WebViewWithoutThreadedCompositingTest : public WebViewTest { +class WebViewCaptureTest : public WebViewTest, + public testing::WithParamInterface<std::string> { public: - WebViewWithoutThreadedCompositingTest() {} - virtual ~WebViewWithoutThreadedCompositingTest() {} + WebViewCaptureTest() {} + virtual ~WebViewCaptureTest() {} virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { - command_line->AppendSwitch(switches::kDisableThreadedCompositing); + command_line->AppendSwitch(GetParam()); + // http://crbug.com/327035 + command_line->AppendSwitch(switches::kDisableDelegatedRenderer); WebViewTest::SetUpCommandLine(command_line); } }; -IN_PROC_BROWSER_TEST_F(WebViewWithoutThreadedCompositingTest, +IN_PROC_BROWSER_TEST_P(WebViewCaptureTest, Shim_ScreenshotCapture) { TestHelper("testScreenshotCapture", "web_view/shim", NO_TEST_SERVER); } + +INSTANTIATE_TEST_CASE_P(WithoutThreadedCompositor, + WebViewCaptureTest, + ::testing::Values(std::string(switches::kDisableThreadedCompositing))); + +// http://crbug.com/171744 +#if !defined(OS_MACOSX) +INSTANTIATE_TEST_CASE_P(WithThreadedCompositor, + WebViewCaptureTest, + ::testing::Values(std::string(switches::kEnableThreadedCompositing))); +#endif diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc index d492e49..ef8d779 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.cc +++ b/content/browser/browser_plugin/browser_plugin_guest.cc @@ -351,6 +351,7 @@ BrowserPluginGuest::BrowserPluginGuest( mouse_locked_(false), pending_lock_request_(false), embedder_visible_(true), + copy_request_id_(0), next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID), has_render_view_(has_render_view), last_seen_auto_size_enabled_(false), @@ -507,6 +508,8 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder( OnSwapBuffersACK) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameACK, OnCompositorFrameACK) + IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck, + OnCopyFromCompositingSurfaceAck) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate, OnDragStatusUpdate) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand, @@ -686,6 +689,16 @@ void BrowserPluginGuest::UpdateVisibility() { OnSetVisibility(instance_id_, visible()); } +void BrowserPluginGuest::CopyFromCompositingSurface( + gfx::Rect src_subrect, + gfx::Size dst_size, + const base::Callback<void(bool, const SkBitmap&)>& callback) { + copy_request_callbacks_.insert(std::make_pair(++copy_request_id_, callback)); + SendMessageToEmbedder( + new BrowserPluginMsg_CopyFromCompositingSurface(instance_id(), + copy_request_id_, src_subrect, dst_size)); +} + // screen. gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) { gfx::Rect guest_rect(bounds); @@ -1121,6 +1134,7 @@ bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest( switch (message.type()) { case BrowserPluginHostMsg_BuffersSwappedACK::ID: case BrowserPluginHostMsg_CompositorFrameACK::ID: + case BrowserPluginHostMsg_CopyFromCompositingSurfaceAck::ID: case BrowserPluginHostMsg_DragStatusUpdate::ID: case BrowserPluginHostMsg_ExecuteEditCommand::ID: case BrowserPluginHostMsg_HandleInputEvent::ID: @@ -1564,6 +1578,18 @@ void BrowserPluginGuest::OnUpdateRectACK( OnSetSize(instance_id_, auto_size_params, resize_guest_params); } +void BrowserPluginGuest::OnCopyFromCompositingSurfaceAck( + int instance_id, + int request_id, + const SkBitmap& bitmap) { + CHECK(copy_request_callbacks_.count(request_id)); + if (!copy_request_callbacks_.count(request_id)) + return; + const CopyRequestCallback& callback = copy_request_callbacks_[request_id]; + callback.Run(!bitmap.empty() && !bitmap.isNull(), bitmap); + copy_request_callbacks_.erase(request_id); +} + void BrowserPluginGuest::OnUpdateGeometry(int instance_id, const gfx::Rect& view_rect) { // The plugin has moved within the embedder without resizing or the diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h index 6b6bf34..b3d4918 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.h +++ b/content/browser/browser_plugin/browser_plugin_guest.h @@ -144,6 +144,11 @@ class CONTENT_EXPORT BrowserPluginGuest void UpdateVisibility(); + void CopyFromCompositingSurface( + gfx::Rect src_subrect, + gfx::Size dst_size, + const base::Callback<void(bool, const SkBitmap&)>& callback); + // WebContentsObserver implementation. virtual void DidCommitProvisionalLoadForFrame( int64 frame_id, @@ -375,7 +380,9 @@ class CONTENT_EXPORT BrowserPluginGuest uint32 output_surface_id, int renderer_host_id, const cc::CompositorFrameAck& ack); - + void OnCopyFromCompositingSurfaceAck(int instance_id, + int request_id, + const SkBitmap& bitmap); // Handles drag events from the embedder. // When dragging, the drag events go to the embedder first, and if the drag // happens on the browser plugin, then the plugin sends a corresponding @@ -528,6 +535,13 @@ class CONTENT_EXPORT BrowserPluginGuest gfx::Size max_auto_size_; gfx::Size min_auto_size_; + // Each copy-request is identified by a unique number. The unique number is + // used to keep track of the right callback. + int copy_request_id_; + typedef base::Callback<void(bool, const SkBitmap&)> CopyRequestCallback; + typedef std::map<int, const CopyRequestCallback> CopyRequestMap; + CopyRequestMap copy_request_callbacks_; + typedef std::map<BrowserPluginGuest*, NewWindowInfo> PendingWindowMap; PendingWindowMap pending_new_windows_; base::WeakPtr<BrowserPluginGuest> opener_; diff --git a/content/browser/browser_plugin/browser_plugin_host_browsertest.cc b/content/browser/browser_plugin/browser_plugin_host_browsertest.cc index cb10824..209f43e 100644 --- a/content/browser/browser_plugin/browser_plugin_host_browsertest.cc +++ b/content/browser/browser_plugin/browser_plugin_host_browsertest.cc @@ -810,4 +810,119 @@ IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DoNotCrashOnInvalidNavigation) { EXPECT_TRUE(delegate->load_aborted_url().is_valid()); } + +// Tests involving the threaded compositor. +class BrowserPluginThreadedCompositorTest : public BrowserPluginHostTest { + public: + BrowserPluginThreadedCompositorTest() {} + virtual ~BrowserPluginThreadedCompositorTest() {} + + protected: + virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE { + BrowserPluginHostTest::SetUpCommandLine(cmd); + cmd->AppendSwitch(switches::kEnableThreadedCompositing); + + // http://crbug.com/327035 + cmd->AppendSwitch(switches::kDisableDelegatedRenderer); + } +}; + +static void CompareSkBitmaps(const SkBitmap& expected_bitmap, + const SkBitmap& bitmap) { + EXPECT_EQ(expected_bitmap.width(), bitmap.width()); + if (expected_bitmap.width() != bitmap.width()) + return; + EXPECT_EQ(expected_bitmap.height(), bitmap.height()); + if (expected_bitmap.height() != bitmap.height()) + return; + EXPECT_EQ(expected_bitmap.config(), bitmap.config()); + if (expected_bitmap.config() != bitmap.config()) + return; + + SkAutoLockPixels expected_bitmap_lock(expected_bitmap); + SkAutoLockPixels bitmap_lock(bitmap); + int fails = 0; + const int kAllowableError = 2; + for (int i = 0; i < bitmap.width() && fails < 10; ++i) { + for (int j = 0; j < bitmap.height() && fails < 10; ++j) { + SkColor expected_color = expected_bitmap.getColor(i, j); + SkColor color = bitmap.getColor(i, j); + int expected_alpha = SkColorGetA(expected_color); + int alpha = SkColorGetA(color); + int expected_red = SkColorGetR(expected_color); + int red = SkColorGetR(color); + int expected_green = SkColorGetG(expected_color); + int green = SkColorGetG(color); + int expected_blue = SkColorGetB(expected_color); + int blue = SkColorGetB(color); + EXPECT_NEAR(expected_alpha, alpha, kAllowableError) + << "expected_color: " << std::hex << expected_color + << " color: " << color + << " Failed at " << std::dec << i << ", " << j + << " Failure " << ++fails; + EXPECT_NEAR(expected_red, red, kAllowableError) + << "expected_color: " << std::hex << expected_color + << " color: " << color + << " Failed at " << std::dec << i << ", " << j + << " Failure " << ++fails; + EXPECT_NEAR(expected_green, green, kAllowableError) + << "expected_color: " << std::hex << expected_color + << " color: " << color + << " Failed at " << std::dec << i << ", " << j + << " Failure " << ++fails; + EXPECT_NEAR(expected_blue, blue, kAllowableError) + << "expected_color: " << std::hex << expected_color + << " color: " << color + << " Failed at " << std::dec << i << ", " << j + << " Failure " << ++fails; + } + } + EXPECT_LT(fails, 10); +} + +static void CompareSkBitmapAndRun(const base::Closure& callback, + const SkBitmap& expected_bitmap, + bool *result, + bool succeed, + const SkBitmap& bitmap) { + *result = succeed; + if (succeed) + CompareSkBitmaps(expected_bitmap, bitmap); + callback.Run(); +} + +// http://crbug.com/171744 +#if defined(OS_MACOSX) +#define MAYBE_GetBackingStore DISABLED_GetBackingStore +#else +#define MAYBE_GetBackingStore GetBackingStore +#endif +IN_PROC_BROWSER_TEST_F(BrowserPluginThreadedCompositorTest, + MAYBE_GetBackingStore) { + const char kEmbedderURL[] = "/browser_plugin_embedder.html"; + const char kHTMLForGuest[] = + "data:text/html,<html><style>body { background-color: red; }</style>" + "<body></body></html>"; + StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, + std::string("SetSize(50, 60);")); + + WebContentsImpl* guest_contents = test_guest()->web_contents(); + RenderWidgetHostImpl* guest_widget_host = + RenderWidgetHostImpl::From(guest_contents->GetRenderViewHost()); + + SkBitmap expected_bitmap; + expected_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 50, 60); + expected_bitmap.allocPixels(); + expected_bitmap.eraseARGB(255, 255, 0, 0); // #f00 + bool result = false; + while (!result) { + base::RunLoop loop; + guest_widget_host->CopyFromBackingStore(gfx::Rect(), + guest_widget_host->GetView()->GetViewBounds().size(), + base::Bind(&CompareSkBitmapAndRun, loop.QuitClosure(), expected_bitmap, + &result)); + loop.Run(); + } +} + } // namespace content diff --git a/content/browser/renderer_host/render_widget_host_view_guest.cc b/content/browser/renderer_host/render_widget_host_view_guest.cc index 49562c8..907119d 100644 --- a/content/browser/renderer_host/render_widget_host_view_guest.cc +++ b/content/browser/renderer_host/render_widget_host_view_guest.cc @@ -347,9 +347,10 @@ BackingStore* RenderWidgetHostViewGuest::AllocBackingStore( void RenderWidgetHostViewGuest::CopyFromCompositingSurface( const gfx::Rect& src_subrect, - const gfx::Size& /* dst_size */, + const gfx::Size& dst_size, const base::Callback<void(bool, const SkBitmap&)>& callback) { - callback.Run(false, SkBitmap()); + CHECK(guest_); + guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback); } void RenderWidgetHostViewGuest::CopyFromCompositingSurfaceToVideoFrame( diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h index 3fc331c..4d2c477 100644 --- a/content/common/browser_plugin/browser_plugin_messages.h +++ b/content/common/browser_plugin/browser_plugin_messages.h @@ -21,6 +21,7 @@ #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/WebKit/public/web/WebDragOperation.h" #include "third_party/WebKit/public/web/WebDragStatus.h" #include "ui/gfx/point.h" @@ -212,6 +213,11 @@ IPC_MESSAGE_ROUTED5(BrowserPluginHostMsg_BuffersSwappedACK, std::string /* mailbox_name */, uint32 /* sync_point */) +IPC_MESSAGE_ROUTED3(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck, + int /* instance_id */, + int /* request_id */, + SkBitmap); + // Acknowledge that we presented an ubercomp frame. IPC_MESSAGE_ROUTED5(BrowserPluginHostMsg_CompositorFrameACK, int /* instance_id */, @@ -338,6 +344,12 @@ IPC_MESSAGE_CONTROL2(BrowserPluginMsg_UpdateRect, int /* instance_id */, BrowserPluginMsg_UpdateRect_Params) +IPC_MESSAGE_CONTROL4(BrowserPluginMsg_CopyFromCompositingSurface, + int /* instance_id */, + int /* request_id */, + gfx::Rect /* source_rect */, + gfx::Size /* dest_size */) + // Requests the renderer to find out if a browser plugin is at position // (|x|, |y|) within the embedder. // The response message is BrowserPluginHostMsg_PluginAtPositionResponse. diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc index 0bc0f04..ee32176 100644 --- a/content/renderer/browser_plugin/browser_plugin.cc +++ b/content/renderer/browser_plugin/browser_plugin.cc @@ -120,6 +120,8 @@ bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(BrowserPluginMsg_BuffersSwapped, OnBuffersSwapped) IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped, OnCompositorFrameSwapped(message)) + IPC_MESSAGE_HANDLER(BrowserPluginMsg_CopyFromCompositingSurface, + OnCopyFromCompositingSurface) IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestContentWindowReady, OnGuestContentWindowReady) IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone) @@ -456,6 +458,23 @@ void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) { param.e /* host_id */); } +void BrowserPlugin::OnCopyFromCompositingSurface(int guest_instance_id, + int request_id, + gfx::Rect source_rect, + gfx::Size dest_size) { + if (!compositing_enabled_) { + browser_plugin_manager()->Send( + new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck( + render_view_routing_id_, + guest_instance_id_, + request_id, + SkBitmap())); + return; + } + compositing_helper_->CopyFromCompositingSurface(request_id, source_rect, + dest_size); +} + void BrowserPlugin::OnGuestContentWindowReady(int guest_instance_id, int content_window_routing_id) { DCHECK(content_window_routing_id != MSG_ROUTING_NONE); @@ -1033,6 +1052,7 @@ bool BrowserPlugin::ShouldForwardToBrowserPlugin( case BrowserPluginMsg_Attach_ACK::ID: case BrowserPluginMsg_BuffersSwapped::ID: case BrowserPluginMsg_CompositorFrameSwapped::ID: + case BrowserPluginMsg_CopyFromCompositingSurface::ID: case BrowserPluginMsg_GuestContentWindowReady::ID: case BrowserPluginMsg_GuestGone::ID: case BrowserPluginMsg_SetCursor::ID: diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h index f0d8758..cfac45dc 100644 --- a/content/renderer/browser_plugin/browser_plugin.h +++ b/content/renderer/browser_plugin/browser_plugin.h @@ -286,6 +286,10 @@ class CONTENT_EXPORT BrowserPlugin : void OnBuffersSwapped(int instance_id, const BrowserPluginMsg_BuffersSwapped_Params& params); void OnCompositorFrameSwapped(const IPC::Message& message); + void OnCopyFromCompositingSurface(int instance_id, + int request_id, + gfx::Rect source_rect, + gfx::Size dest_size); void OnGuestContentWindowReady(int instance_id, int content_window_routing_id); void OnGuestGone(int instance_id); diff --git a/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc b/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc index 2b07d35..a3ce844 100644 --- a/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc +++ b/content/renderer/browser_plugin/browser_plugin_compositing_helper.cc @@ -10,15 +10,19 @@ #include "cc/layers/solid_color_layer.h" #include "cc/layers/texture_layer.h" #include "cc/output/context_provider.h" +#include "cc/output/copy_output_request.h" +#include "cc/output/copy_output_result.h" #include "cc/resources/single_release_callback.h" #include "content/common/browser_plugin/browser_plugin_messages.h" #include "content/common/gpu/client/context_provider_command_buffer.h" #include "content/renderer/browser_plugin/browser_plugin_manager.h" #include "content/renderer/render_thread_impl.h" +#include "skia/ext/image_operations.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/WebKit/public/web/WebPluginContainer.h" #include "third_party/khronos/GLES2/gl2.h" #include "ui/gfx/size_conversions.h" +#include "ui/gfx/skia_util.h" #include "webkit/renderer/compositor_bindings/web_layer_impl.h" namespace content { @@ -52,6 +56,21 @@ BrowserPluginCompositingHelper::BrowserPluginCompositingHelper( BrowserPluginCompositingHelper::~BrowserPluginCompositingHelper() { } +void BrowserPluginCompositingHelper::CopyFromCompositingSurface( + int request_id, + gfx::Rect source_rect, + gfx::Size dest_size) { + CHECK(background_layer_); + scoped_ptr<cc::CopyOutputRequest> request = + cc::CopyOutputRequest::CreateBitmapRequest(base::Bind( + &BrowserPluginCompositingHelper::CopyFromCompositingSurfaceHasResult, + this, + request_id, + dest_size)); + request->set_area(source_rect); + background_layer_->RequestCopyOfOutput(request.Pass()); +} + void BrowserPluginCompositingHelper::DidCommitCompositorFrame() { if (software_ack_pending_) { cc::CompositorFrameAck ack; @@ -450,4 +469,25 @@ void BrowserPluginCompositingHelper::SetContentsOpaque(bool opaque) { delegated_layer_->SetContentsOpaque(opaque_); } +void BrowserPluginCompositingHelper::CopyFromCompositingSurfaceHasResult( + int request_id, + gfx::Size dest_size, + scoped_ptr<cc::CopyOutputResult> result) { + scoped_ptr<SkBitmap> bitmap; + if (result && result->HasBitmap() && !result->size().IsEmpty()) + bitmap = result->TakeBitmap(); + + SkBitmap resized_bitmap; + if (bitmap) { + resized_bitmap = skia::ImageOperations::Resize(*bitmap, + skia::ImageOperations::RESIZE_BEST, + dest_size.width(), + dest_size.height()); + } + browser_plugin_manager_->Send( + new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck( + host_routing_id_, instance_id_, request_id, + resized_bitmap)); +} + } // namespace content diff --git a/content/renderer/browser_plugin/browser_plugin_compositing_helper.h b/content/renderer/browser_plugin/browser_plugin_compositing_helper.h index dcbd6a2..7f9a473 100644 --- a/content/renderer/browser_plugin/browser_plugin_compositing_helper.h +++ b/content/renderer/browser_plugin/browser_plugin_compositing_helper.h @@ -21,6 +21,7 @@ class SharedMemory; namespace cc { class CompositorFrame; +class CopyOutputResult; class Layer; class SolidColorLayer; class TextureLayer; @@ -34,6 +35,11 @@ class WebPluginContainer; class WebLayer; } +namespace gfx { +class Rect; +class Size; +} + namespace content { class BrowserPluginManager; @@ -46,6 +52,9 @@ class CONTENT_EXPORT BrowserPluginCompositingHelper : BrowserPluginManager* manager, int instance_id, int host_routing_id); + void CopyFromCompositingSurface(int request_id, + gfx::Rect source_rect, + gfx::Size dest_size); void DidCommitCompositorFrame(); void EnableCompositing(bool); void OnContainerDestroy(); @@ -96,6 +105,10 @@ class CONTENT_EXPORT BrowserPluginCompositingHelper : unsigned sync_point, bool lost_resource); void SendReturnedDelegatedResources(); + void CopyFromCompositingSurfaceHasResult( + int request_id, + gfx::Size dest_size, + scoped_ptr<cc::CopyOutputResult> result); int instance_id_; int host_routing_id_; |