diff options
author | wjmaclean <wjmaclean@chromium.org> | 2016-02-01 14:54:30 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-01 22:55:58 +0000 |
commit | f89035216b627283b79731c3e6a7957707ed9034 (patch) | |
tree | bae27a93918c32402c6af6ad5dd7bf66d320766c /extensions | |
parent | 1624f7e07304daf5b9872643b713de12c6296b2e (diff) | |
download | chromium_src-f89035216b627283b79731c3e6a7957707ed9034.zip chromium_src-f89035216b627283b79731c3e6a7957707ed9034.tar.gz chromium_src-f89035216b627283b79731c3e6a7957707ed9034.tar.bz2 |
Implement webview.captureVisibleRegion()
This CL implements webview.captureVisibleRegion(), an extension/apps
API to allow WebView users to capture screenshots of the contents
displayed in a WebView. The surfaces contents capture has been plumbed
via RenderWidgetHostViewChildFrame so this implementation should not
require changes when WebView switches to using OOPIF.
As part of the implementation, there are two notable refactors:
1) CaptureWebContentsFunction has been refactored into
WebContentsCaptureClient to remove the extensions::AsyncExtensionFunction
dependence so that this code can be used by both tabs.captureVisibleTab
and webview.captureVisibleRegion, and
2) common code from DelegatedFrameHost has ben moved to
content/browser/compositor/surface_utils.* in order to avoid duplication
as both DelegatedFrameHost and RenderWidgetHostViewChildFrame now
use the code.
Finally, this CL adds a surface-drawn callback to
RenderWidgetHostViewChildFrame, to allow deferring a
screen capture request until a frame has actually been
drawn. This callback can be used to simplify some
existing tests.
BUG=326755
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_site_isolation
Review URL: https://codereview.chromium.org/1635513003
Cr-Commit-Position: refs/heads/master@{#372799}
Diffstat (limited to 'extensions')
14 files changed, 243 insertions, 73 deletions
diff --git a/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.h b/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.h index 9e77cbd..1899d42 100644 --- a/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.h +++ b/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.h @@ -6,7 +6,6 @@ #define EXTENSIONS_BROWSER_API_EXTENSION_VIEW_EXTENSION_VIEW_INTERNAL_API_H_ #include "base/macros.h" -#include "extensions/browser/api/capture_web_contents_function.h" #include "extensions/browser/api/execute_code_function.h" #include "extensions/browser/extension_function.h" #include "extensions/browser/guest_view/extension_view/extension_view_guest.h" diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc index bba531d..3e3a8ed 100644 --- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc +++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc @@ -259,6 +259,62 @@ bool WebViewInternalExtensionFunction::RunAsync() { return RunAsyncSafe(guest); } +bool WebViewInternalCaptureVisibleRegionFunction::RunAsyncSafe( + WebViewGuest* guest) { + using api::extension_types::ImageDetails; + + scoped_ptr<web_view_internal::CaptureVisibleRegion::Params> params( + web_view_internal::CaptureVisibleRegion::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(params.get()); + + scoped_ptr<ImageDetails> image_details; + if (args_->GetSize() > 1) { + base::Value* spec = NULL; + EXTENSION_FUNCTION_VALIDATE(args_->Get(1, &spec) && spec); + image_details = ImageDetails::FromValue(*spec); + } + + return CaptureAsync(guest->web_contents(), image_details.get(), + base::Bind(&WebViewInternalCaptureVisibleRegionFunction:: + CopyFromBackingStoreComplete, + this)); +} +bool WebViewInternalCaptureVisibleRegionFunction::IsScreenshotEnabled() { + // TODO(wjmaclean): Is it ok to always return true here? + return true; +} + +void WebViewInternalCaptureVisibleRegionFunction::OnCaptureSuccess( + const SkBitmap& bitmap) { + std::string base64_result; + if (!EncodeBitmap(bitmap, &base64_result)) { + OnCaptureFailure(FAILURE_REASON_ENCODING_FAILED); + return; + } + + SetResult(new base::StringValue(base64_result)); + SendResponse(true); +} + +void WebViewInternalCaptureVisibleRegionFunction::OnCaptureFailure( + FailureReason reason) { + const char* reason_description = "internal error"; + switch (reason) { + case FAILURE_REASON_UNKNOWN: + reason_description = "unknown error"; + break; + case FAILURE_REASON_ENCODING_FAILED: + reason_description = "encoding failed"; + break; + case FAILURE_REASON_VIEW_INVISIBLE: + reason_description = "view is invisible"; + break; + } + error_ = ErrorUtils::FormatErrorMessage("Failed to capture webview: *", + reason_description); + SendResponse(false); +} + bool WebViewInternalNavigateFunction::RunAsyncSafe(WebViewGuest* guest) { scoped_ptr<web_view_internal::Navigate::Params> params( web_view_internal::Navigate::Params::Create(*args_)); diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.h b/extensions/browser/api/guest_view/web_view/web_view_internal_api.h index dcdb828..388491e 100644 --- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.h +++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.h @@ -8,8 +8,8 @@ #include <stdint.h> #include "base/macros.h" -#include "extensions/browser/api/capture_web_contents_function.h" #include "extensions/browser/api/execute_code_function.h" +#include "extensions/browser/api/web_contents_capture_client.h" #include "extensions/browser/extension_function.h" #include "extensions/browser/guest_view/web_view/web_ui/web_ui_url_fetcher.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h" @@ -37,6 +37,29 @@ class WebViewInternalExtensionFunction : public AsyncExtensionFunction { virtual bool RunAsyncSafe(WebViewGuest* guest) = 0; }; +class WebViewInternalCaptureVisibleRegionFunction + : public WebViewInternalExtensionFunction, + public WebContentsCaptureClient { + public: + DECLARE_EXTENSION_FUNCTION("webViewInternal.captureVisibleRegion", + WEBVIEWINTERNAL_CAPTUREVISIBLEREGION); + WebViewInternalCaptureVisibleRegionFunction() {} + + protected: + ~WebViewInternalCaptureVisibleRegionFunction() override {} + + private: + // WebViewInternalExtensionFunction implementation. + bool RunAsyncSafe(WebViewGuest* guest) override; + + // extensions::WebContentsCaptureClient: + bool IsScreenshotEnabled() override; + void OnCaptureSuccess(const SkBitmap& bitmap) override; + void OnCaptureFailure(FailureReason reason) override; + + DISALLOW_COPY_AND_ASSIGN(WebViewInternalCaptureVisibleRegionFunction); +}; + class WebViewInternalNavigateFunction : public WebViewInternalExtensionFunction { public: diff --git a/extensions/browser/api/capture_web_contents_function.cc b/extensions/browser/api/web_contents_capture_client.cc index 77c8a3e..78c3760 100644 --- a/extensions/browser/api/capture_web_contents_function.cc +++ b/extensions/browser/api/web_contents_capture_client.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "extensions/browser/api/capture_web_contents_function.h" +#include "extensions/browser/api/web_contents_capture_client.h" #include "base/base64.h" #include "base/strings/stringprintf.h" @@ -25,28 +25,14 @@ namespace extensions { using api::extension_types::ImageDetails; -bool CaptureWebContentsFunction::HasPermission() { - return true; -} - -bool CaptureWebContentsFunction::RunAsync() { - EXTENSION_FUNCTION_VALIDATE(args_); - - context_id_ = extension_misc::kCurrentWindowId; - args_->GetInteger(0, &context_id_); - - scoped_ptr<ImageDetails> image_details; - if (args_->GetSize() > 1) { - base::Value* spec = NULL; - EXTENSION_FUNCTION_VALIDATE(args_->Get(1, &spec) && spec); - image_details = ImageDetails::FromValue(*spec); - } - - if (!IsScreenshotEnabled()) +bool WebContentsCaptureClient::CaptureAsync( + WebContents* web_contents, + const ImageDetails* image_details, + const content::ReadbackRequestCallback callback) { + if (!web_contents) return false; - WebContents* contents = GetWebContentsForID(context_id_); - if (!contents) + if (!IsScreenshotEnabled()) return false; // The default format and quality setting used when encoding jpegs. @@ -65,7 +51,7 @@ bool CaptureWebContentsFunction::RunAsync() { } // TODO(miu): Account for fullscreen render widget? http://crbug.com/419878 - RenderWidgetHostView* const view = contents->GetRenderWidgetHostView(); + RenderWidgetHostView* const view = web_contents->GetRenderWidgetHostView(); RenderWidgetHost* const host = view ? view->GetRenderWidgetHost() : nullptr; if (!view || !host) { OnCaptureFailure(FAILURE_REASON_VIEW_INVISIBLE); @@ -84,26 +70,41 @@ bool CaptureWebContentsFunction::RunAsync() { if (scale > 1.0f) bitmap_size = gfx::ScaleToCeiledSize(view_size, scale); - host->CopyFromBackingStore( - gfx::Rect(view_size), - bitmap_size, - base::Bind(&CaptureWebContentsFunction::CopyFromBackingStoreComplete, - this), - kN32_SkColorType); + host->CopyFromBackingStore(gfx::Rect(view_size), bitmap_size, callback, + kN32_SkColorType); return true; } -void CaptureWebContentsFunction::CopyFromBackingStoreComplete( +void WebContentsCaptureClient::CopyFromBackingStoreComplete( const SkBitmap& bitmap, content::ReadbackResponse response) { if (response == content::READBACK_SUCCESS) { OnCaptureSuccess(bitmap); return; } + // TODO(wjmaclean): Improve error reporting. Why aren't we passing more + // information here? + std::string reason; + switch (response) { + case content::READBACK_FAILED: + reason = "READBACK_FAILED"; + break; + case content::READBACK_SURFACE_UNAVAILABLE: + reason = "READBACK_SURFACE_UNAVAILABLE"; + break; + case content::READBACK_BITMAP_ALLOCATION_FAILURE: + reason = "READBACK_BITMAP_ALLOCATION_FAILURE"; + break; + default: + reason = "<unknown>"; + } OnCaptureFailure(FAILURE_REASON_UNKNOWN); } -void CaptureWebContentsFunction::OnCaptureSuccess(const SkBitmap& bitmap) { +// TODO(wjmaclean) can this be static? +bool WebContentsCaptureClient::EncodeBitmap(const SkBitmap& bitmap, + std::string* base64_result) { + DCHECK(base64_result); std::vector<unsigned char> data; SkAutoLockPixels screen_capture_lock(bitmap); bool encoded = false; @@ -112,12 +113,8 @@ void CaptureWebContentsFunction::OnCaptureSuccess(const SkBitmap& bitmap) { case api::extension_types::IMAGE_FORMAT_JPEG: encoded = gfx::JPEGCodec::Encode( reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), - gfx::JPEGCodec::FORMAT_SkBitmap, - bitmap.width(), - bitmap.height(), - static_cast<int>(bitmap.rowBytes()), - image_quality_, - &data); + gfx::JPEGCodec::FORMAT_SkBitmap, bitmap.width(), bitmap.height(), + static_cast<int>(bitmap.rowBytes()), image_quality_, &data); mime_type = kMimeTypeJpeg; break; case api::extension_types::IMAGE_FORMAT_PNG: @@ -131,20 +128,17 @@ void CaptureWebContentsFunction::OnCaptureSuccess(const SkBitmap& bitmap) { NOTREACHED() << "Invalid image format."; } - if (!encoded) { - OnCaptureFailure(FAILURE_REASON_ENCODING_FAILED); - return; - } + if (!encoded) + return false; - std::string base64_result; base::StringPiece stream_as_string(reinterpret_cast<const char*>(data.data()), data.size()); - base::Base64Encode(stream_as_string, &base64_result); - base64_result.insert( + base::Base64Encode(stream_as_string, base64_result); + base64_result->insert( 0, base::StringPrintf("data:%s;base64,", mime_type.c_str())); - SetResult(new base::StringValue(base64_result)); - SendResponse(true); + + return true; } } // namespace extensions diff --git a/extensions/browser/api/capture_web_contents_function.h b/extensions/browser/api/web_contents_capture_client.h index 53f78f7..4107ee4 100644 --- a/extensions/browser/api/capture_web_contents_function.h +++ b/extensions/browser/api/web_contents_capture_client.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef EXTENSIONS_BROWSER_API_CAPTURE_WEB_CONTENTS_FUNCTION_H_ -#define EXTENSIONS_BROWSER_API_CAPTURE_WEB_CONTENTS_FUNCTION_H_ +#ifndef EXTENSIONS_BROWSER_API_WEB_CONTENTS_CAPTURE_CLIENT_H_ +#define EXTENSIONS_BROWSER_API_WEB_CONTENTS_CAPTURE_CLIENT_H_ #include "base/macros.h" #include "content/public/browser/readback_types.h" @@ -18,50 +18,41 @@ class WebContents; namespace extensions { -// Base class for capturing visibile area of a WebContents. +// Base class for capturing visible area of a WebContents. // This is used by both webview.captureVisibleRegion and tabs.captureVisibleTab. -class CaptureWebContentsFunction : public AsyncExtensionFunction { +class WebContentsCaptureClient { public: - CaptureWebContentsFunction() {} + WebContentsCaptureClient() {} protected: - ~CaptureWebContentsFunction() override {} - - // ExtensionFunction implementation. - bool HasPermission() override; - bool RunAsync() override; + virtual ~WebContentsCaptureClient() {} virtual bool IsScreenshotEnabled() = 0; - virtual content::WebContents* GetWebContentsForID(int context_id) = 0; enum FailureReason { FAILURE_REASON_UNKNOWN, FAILURE_REASON_ENCODING_FAILED, FAILURE_REASON_VIEW_INVISIBLE }; + bool CaptureAsync(content::WebContents* web_contents, + const api::extension_types::ImageDetails* image_detail, + const content::ReadbackRequestCallback callback); + bool EncodeBitmap(const SkBitmap& bitmap, std::string* base64_result); virtual void OnCaptureFailure(FailureReason reason) = 0; - - private: - + virtual void OnCaptureSuccess(const SkBitmap& bitmap) = 0; void CopyFromBackingStoreComplete(const SkBitmap& bitmap, content::ReadbackResponse response); - void OnCaptureSuccess(const SkBitmap& bitmap); - - // |context_id_| is the ID used to find the relevant WebContents. In the - // |tabs.captureVisibleTab()| api, this represents the window-id, and in the - // |webview.captureVisibleRegion()| api, this represents the instance-id of - // the guest. - int context_id_; + private: // The format (JPEG vs PNG) of the resulting image. Set in RunAsync(). api::extension_types::ImageFormat image_format_; // Quality setting to use when encoding jpegs. Set in RunAsync(). int image_quality_; - DISALLOW_COPY_AND_ASSIGN(CaptureWebContentsFunction); + DISALLOW_COPY_AND_ASSIGN(WebContentsCaptureClient); }; } // namespace extensions -#endif // EXTENSIONS_BROWSER_API_CAPTURE_WEB_CONTENTS_FUNCTION_H_ +#endif // EXTENSIONS_BROWSER_API_WEB_CONTENTS_CAPTURE_CLIENT_H_ diff --git a/extensions/browser/guest_view/web_view/web_view_apitest.cc b/extensions/browser/guest_view/web_view/web_view_apitest.cc index 9896e13..89bbf05 100644 --- a/extensions/browser/guest_view/web_view/web_view_apitest.cc +++ b/extensions/browser/guest_view/web_view/web_view_apitest.cc @@ -736,5 +736,8 @@ IN_PROC_BROWSER_TEST_F(WebViewAPITest, TestWebViewInsideFrame) { LaunchApp("web_view/inside_iframe"); } +IN_PROC_BROWSER_TEST_F(WebViewAPITest, TestCaptureVisibleRegion) { + RunTest("testCaptureVisibleRegion", "web_view/apitest"); +} } // namespace extensions diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index b30775f..5e07269 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json @@ -460,6 +460,12 @@ "chrome://oobe/*" ] }], + "webViewExperimentalInternal": [{ + "internal": true, + "channel": "dev", + "dependencies": ["permission:webview"], + "contexts": ["blessed_extension"] + }], "webViewRequest": [{ "dependencies": ["permission:webview"], "contexts": ["blessed_extension"] diff --git a/extensions/common/api/web_view_internal.json b/extensions/common/api/web_view_internal.json index a33f500..94a6eb9 100644 --- a/extensions/common/api/web_view_internal.json +++ b/extensions/common/api/web_view_internal.json @@ -670,6 +670,33 @@ ] }, { + "name": "captureVisibleRegion", + "type": "function", + "description": "foo", + "parameters": [ + { + "type": "integer", + "name": "instanceId", + "description": "The instance ID of the guest <webview> process." + }, + { + "$ref": "extensionTypes.ImageDetails", + "name": "options", + "optional": true + }, + { + "type": "function", + "name": "callback", + "parameters": [ + {"type": "string", + "name": "dataUrl", + "description": "A data URL which encodes an image of the visible area of the captured tab. May be assigned to the 'src' property of an HTML Image element for display." + } + ] + } + ] + }, + { "name": "clearData", "type": "function", "description": "Clears various types of browsing data stored in a storage partition of a <webview>.", diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi index 9128d49..4d285b8 100644 --- a/extensions/extensions.gypi +++ b/extensions/extensions.gypi @@ -272,8 +272,6 @@ 'browser/api/bluetooth_socket/bluetooth_socket_api.h', 'browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.cc', 'browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h', - 'browser/api/capture_web_contents_function.cc', - 'browser/api/capture_web_contents_function.h', 'browser/api/cast_channel/cast_auth_ica.cc', 'browser/api/cast_channel/cast_auth_ica.h', 'browser/api/cast_channel/cast_auth_util.cc', @@ -490,6 +488,8 @@ 'browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h', 'browser/api/virtual_keyboard_private/virtual_keyboard_private_api.cc', 'browser/api/virtual_keyboard_private/virtual_keyboard_private_api.h', + 'browser/api/web_contents_capture_client.cc', + 'browser/api/web_contents_capture_client.h', 'browser/api/web_request/form_data_parser.cc', 'browser/api/web_request/form_data_parser.h', 'browser/api/web_request/upload_data_presenter.cc', diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index 7ec76ad..a8a2b3e 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc @@ -644,6 +644,8 @@ std::vector<std::pair<std::string, int> > Dispatcher::GetJsResources() { resources.push_back(std::make_pair("webViewEvents", IDR_WEB_VIEW_EVENTS_JS)); resources.push_back(std::make_pair("webViewInternal", IDR_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS)); + resources.push_back( + std::make_pair("webViewExperimental", IDR_WEB_VIEW_EXPERIMENTAL_JS)); if (content::BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) { resources.push_back(std::make_pair("webViewIframe", IDR_WEB_VIEW_IFRAME_JS)); @@ -1597,6 +1599,10 @@ void Dispatcher::RequireGuestViewModules(ScriptContext* context) { module_system->Require("webView"); module_system->Require("webViewApiMethods"); module_system->Require("webViewAttributes"); + if (context->GetAvailability("webViewExperimentalInternal") + .is_available()) { + module_system->Require("webViewExperimental"); + } if (content::BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) { module_system->Require("webViewIframe"); diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd index bad8e29..b4f5dad 100644 --- a/extensions/renderer/resources/extensions_renderer_resources.grd +++ b/extensions/renderer/resources/extensions_renderer_resources.grd @@ -61,6 +61,7 @@ <include name="IDR_WEB_VIEW_ATTRIBUTES_JS" file="guest_view/web_view/web_view_attributes.js" type="BINDATA" /> <include name="IDR_WEB_VIEW_CONSTANTS_JS" file="guest_view/web_view/web_view_constants.js" type="BINDATA" /> <include name="IDR_WEB_VIEW_EVENTS_JS" file="guest_view/web_view/web_view_events.js" type="BINDATA" /> + <include name="IDR_WEB_VIEW_EXPERIMENTAL_JS" file="guest_view/web_view/web_view_experimental.js" type="BINDATA" /> <include name="IDR_WEB_VIEW_IFRAME_JS" file="guest_view/web_view/web_view_iframe.js" type="BINDATA" /> <include name="IDR_WEB_VIEW_INTERNAL_CUSTOM_BINDINGS_JS" file="guest_view/web_view/web_view_internal.js" type="BINDATA" /> <include name="IDR_WEB_VIEW_JS" file="guest_view/web_view/web_view.js" type="BINDATA" /> diff --git a/extensions/renderer/resources/guest_view/web_view/web_view.js b/extensions/renderer/resources/guest_view/web_view/web_view.js index 6dd4fae..b5d08c1 100644 --- a/extensions/renderer/resources/guest_view/web_view/web_view.js +++ b/extensions/renderer/resources/guest_view/web_view/web_view.js @@ -31,6 +31,10 @@ WebViewImpl.setupElement = function(proto) { // Public-facing API methods. var apiMethods = WebViewImpl.getApiMethods(); + // Add the experimental API methods, if available. + var experimentalApiMethods = WebViewImpl.maybeGetExperimentalApiMethods(); + apiMethods = $Array.concat(apiMethods, experimentalApiMethods); + // Create default implementations for undefined API methods. var createDefaultApiMethod = function(m) { return function(var_args) { @@ -220,6 +224,11 @@ WebViewImpl.prototype.makeElementFullscreen = function() { // Implemented when the ChromeWebView API is available. WebViewImpl.prototype.maybeSetupContextMenus = function() {}; +// Implemented when the experimental WebView API is available. +WebViewImpl.maybeGetExperimentalApiMethods = function() { + return []; +}; + GuestViewContainer.registerElement(WebViewImpl); // Exports. diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_experimental.js b/extensions/renderer/resources/guest_view/web_view/web_view_experimental.js new file mode 100644 index 0000000..96331df --- /dev/null +++ b/extensions/renderer/resources/guest_view/web_view/web_view_experimental.js @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// This module implements experimental API for <webview>. +// See web_view.js and web_view_api_methods.js for details. +// +// <webview> Experimental API is only available on canary and channels of +// Chrome. + +var WebViewImpl = require('webView').WebViewImpl; +var WebViewInternal = require('webViewInternal').WebViewInternal; + +// An array of <webview>'s experimental API methods. See |WEB_VIEW_API_METHODS| +// in web_view_api_methods.js for more details. +var WEB_VIEW_EXPERIMENTAL_API_METHODS = [ + // Captures the visible region of the WebView contents into a bitmap. + 'captureVisibleRegion' +]; + +// Registers the experimantal WebVIew API when available. +WebViewImpl.maybeGetExperimentalApiMethods = function() { + return WEB_VIEW_EXPERIMENTAL_API_METHODS; +}; diff --git a/extensions/test/data/web_view/apitest/main.js b/extensions/test/data/web_view/apitest/main.js index 983212c..3d6e50f 100644 --- a/extensions/test/data/web_view/apitest/main.js +++ b/extensions/test/data/web_view/apitest/main.js @@ -1685,6 +1685,36 @@ function testWebRequestAPIGoogleProperty() { document.body.appendChild(webview); } +// This is a basic test to verify that image data is returned by +// captureVisibleRegion(). +function testCaptureVisibleRegion() { + var webview = document.createElement('webview'); + webview.setAttribute('src', 'data:text/html,webview test'); + + webview.addEventListener('loadstop', function(e) { + webview.captureVisibleRegion( + {}, + function(imgdata) { + if (chrome.runtime.lastError) { + console.log( + 'webview.apitest.testCaptureVisibleRegion: ' + + chrome.runtime.lastError.message); + embedder.test.fail(); + } else { + if (imgdata.indexOf('data:image/jpeg;base64') != 0) { + console_log('imgdata = ' + imgdata); + } + embedder.test.assertTrue( + imgdata.indexOf('data:image/jpeg;base64') == 0); + embedder.test.succeed(); + } + }); + }); + document.body.appendChild(webview); +} + +function captureVisibleRegionDoCapture() {} + // Tests end. embedder.test.testList = { @@ -1752,7 +1782,8 @@ embedder.test.testList = { 'testWebRequestAPI': testWebRequestAPI, 'testWebRequestAPIWithHeaders': testWebRequestAPIWithHeaders, 'testWebRequestAPIExistence': testWebRequestAPIExistence, - 'testWebRequestAPIGoogleProperty': testWebRequestAPIGoogleProperty + 'testWebRequestAPIGoogleProperty': testWebRequestAPIGoogleProperty, + 'testCaptureVisibleRegion': testCaptureVisibleRegion }; onload = function() { |