summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorskerner@chromium.org <skerner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-08 19:06:15 +0000
committerskerner@chromium.org <skerner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-08 19:06:15 +0000
commit35213ce9dc9de27866e6b81b39078ace964ecdc6 (patch)
treecd0399fcd59493002546f9dee9c0e37b83104ebe /chrome
parentfde3a3cadf7ad4a206eb9382b919f73114d4877c (diff)
downloadchromium_src-35213ce9dc9de27866e6b81b39078ace964ecdc6.zip
chromium_src-35213ce9dc9de27866e6b81b39078ace964ecdc6.tar.gz
chromium_src-35213ce9dc9de27866e6b81b39078ace964ecdc6.tar.bz2
Support PNG and quality control in chrome.tabs.captureVisibleTab().
BUG=21072 TEST=ExtensionAPIClientTest.CaptureVisibleTab Review URL: http://codereview.chromium.org/1527015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43985 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/extension_function.cc9
-rw-r--r--chrome/browser/extensions/extension_function.h4
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc84
-rw-r--r--chrome/browser/extensions/extension_tabs_module.h16
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.cc10
-rw-r--r--chrome/browser/extensions/extension_tabs_module_constants.h8
-rwxr-xr-xchrome/common/extensions/api/extension_api.json24
-rw-r--r--chrome/common/extensions/docs/tabs.html125
-rw-r--r--chrome/renderer/extensions/extension_api_client_unittest.cc96
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js59
10 files changed, 387 insertions, 48 deletions
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 006fe99..f319315 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -31,6 +31,13 @@ void AsyncExtensionFunction::SendResponse(bool success) {
}
}
+bool AsyncExtensionFunction::HasOptionalArgument(size_t index) {
+ DCHECK(args_->IsType(Value::TYPE_LIST));
+ ListValue* args_list = static_cast<ListValue*>(args_.get());
+ Value* value;
+ return args_list->Get(index, &value) && !value->IsType(Value::TYPE_NULL);
+}
+
std::string AsyncExtensionFunction::extension_id() {
DCHECK(dispatcher());
return dispatcher()->extension_id();
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index 272d6c1..1727ae0 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -176,6 +176,8 @@ class AsyncExtensionFunction : public ExtensionFunction {
return static_cast<DictionaryValue*>(args_.get());
}
+ bool HasOptionalArgument(size_t index);
+
// Note: After Run() returns, dispatcher() can be NULL. Since these getters
// rely on dispatcher(), make sure it is valid before using them.
std::string extension_id();
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 28b50e9..ae275e9 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -25,12 +25,15 @@
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/url_constants.h"
#include "gfx/codec/jpeg_codec.h"
+#include "gfx/codec/png_codec.h"
#include "skia/ext/image_operations.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace keys = extension_tabs_module_constants;
+const int CaptureVisibleTabFunction::kDefaultQuality = 90;
+
// Forward declare static helper functions defined below.
// |error_message| can optionally be passed in a will be set with an appropriate
@@ -805,8 +808,11 @@ bool CaptureVisibleTabFunction::RunImpl() {
// windowId defaults to "current" window.
int window_id = -1;
- if (!args_->IsType(Value::TYPE_NULL)) {
- EXTENSION_FUNCTION_VALIDATE(args_->GetAsInteger(&window_id));
+ EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST));
+ const ListValue* args = args_as_list();
+
+ if (HasOptionalArgument(0)) {
+ EXTENSION_FUNCTION_VALIDATE(args->GetInteger(0, &window_id));
browser = GetBrowserInProfileWithId(profile(), window_id,
include_incognito(), &error_);
} else {
@@ -818,6 +824,34 @@ bool CaptureVisibleTabFunction::RunImpl() {
return false;
}
+ image_format_ = FORMAT_JPEG; // Default format is JPEG.
+ image_quality_ = kDefaultQuality; // Default quality setting.
+
+ if (HasOptionalArgument(1)) {
+ DictionaryValue* options;
+ EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(1, &options));
+
+ if (options->HasKey(keys::kFormatKey)) {
+ std::string format;
+ EXTENSION_FUNCTION_VALIDATE(
+ options->GetString(keys::kFormatKey, &format));
+
+ if (format == keys::kFormatValueJpeg) {
+ image_format_ = FORMAT_JPEG;
+ } else if (format == keys::kFormatValuePng) {
+ image_format_ = FORMAT_PNG;
+ } else {
+ // Schema validation should make this unreachable.
+ EXTENSION_FUNCTION_VALIDATE(0);
+ }
+ }
+
+ if (options->HasKey(keys::kQualityKey)) {
+ EXTENSION_FUNCTION_VALIDATE(
+ options->GetInteger(keys::kQualityKey, &image_quality_));
+ }
+ }
+
TabContents* tab_contents = browser->GetSelectedTabContents();
if (!tab_contents) {
error_ = keys::kInternalVisibleTabCaptureError;
@@ -884,14 +918,35 @@ void CaptureVisibleTabFunction::Observe(NotificationType type,
// and call SendResponse().
void CaptureVisibleTabFunction::SendResultFromBitmap(
const SkBitmap& screen_capture) {
- scoped_refptr<RefCountedBytes> jpeg_data(new RefCountedBytes);
+ scoped_refptr<RefCountedBytes> image_data(new RefCountedBytes);
SkAutoLockPixels screen_capture_lock(screen_capture);
- bool encoded = gfx::JPEGCodec::Encode(
- reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
- gfx::JPEGCodec::FORMAT_BGRA, screen_capture.width(),
- screen_capture.height(),
- static_cast<int>(screen_capture.rowBytes()), 90,
- &jpeg_data->data);
+ bool encoded;
+ std::string mime_type;
+ switch (image_format_) {
+ case FORMAT_JPEG:
+ encoded = gfx::JPEGCodec::Encode(
+ reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
+ gfx::JPEGCodec::FORMAT_BGRA,
+ screen_capture.width(),
+ screen_capture.height(),
+ static_cast<int>(screen_capture.rowBytes()), image_quality_,
+ &image_data->data);
+ mime_type = keys::kMimeTypeJpeg;
+ break;
+ case FORMAT_PNG:
+ encoded = gfx::PNGCodec::Encode(
+ reinterpret_cast<unsigned char*>(screen_capture.getAddr32(0, 0)),
+ gfx::PNGCodec::FORMAT_BGRA,
+ screen_capture.width(),
+ screen_capture.height(),
+ static_cast<int>(screen_capture.rowBytes()), false,
+ &image_data->data);
+ mime_type = keys::kMimeTypePng;
+ break;
+ default:
+ NOTREACHED() << "Invalid image format.";
+ }
+
if (!encoded) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
keys::kInternalVisibleTabCaptureError, "");
@@ -901,13 +956,13 @@ void CaptureVisibleTabFunction::SendResultFromBitmap(
std::string base64_result;
std::string stream_as_string;
- stream_as_string.resize(jpeg_data->data.size());
+ stream_as_string.resize(image_data->data.size());
memcpy(&stream_as_string[0],
- reinterpret_cast<const char*>(&jpeg_data->data[0]),
- jpeg_data->data.size());
+ reinterpret_cast<const char*>(&image_data->data[0]),
+ image_data->data.size());
base::Base64Encode(stream_as_string, &base64_result);
- base64_result.insert(0, "data:image/jpg;base64,");
+ base64_result.insert(0, StringPrintf("data:%s;base64,", mime_type.c_str()));
result_.reset(new StringValue(base64_result));
SendResponse(true);
}
@@ -1071,4 +1126,3 @@ static GURL ResolvePossiblyRelativeURL(std::string url_string,
return url;
}
-
diff --git a/chrome/browser/extensions/extension_tabs_module.h b/chrome/browser/extensions/extension_tabs_module.h
index a2aaf0d..839e3cb 100644
--- a/chrome/browser/extensions/extension_tabs_module.h
+++ b/chrome/browser/extensions/extension_tabs_module.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -141,6 +141,14 @@ class DetectTabLanguageFunction : public AsyncExtensionFunction,
class CaptureVisibleTabFunction : public AsyncExtensionFunction,
public NotificationObserver {
private:
+ enum ImageFormat {
+ FORMAT_JPEG,
+ FORMAT_PNG
+ };
+
+ // The default quality setting used when encoding jpegs.
+ static const int kDefaultQuality;
+
~CaptureVisibleTabFunction() {}
virtual bool RunImpl();
virtual bool CaptureSnapshotFromBackingStore(BackingStore* backing_store);
@@ -151,6 +159,12 @@ class CaptureVisibleTabFunction : public AsyncExtensionFunction,
NotificationRegistrar registrar_;
+ // The format (JPEG vs PNG) of the resulting image. Set in RunImpl().
+ ImageFormat image_format_;
+
+ // Quality setting to use when encoding jpegs. Set in RunImpl().
+ int image_quality_;
+
DECLARE_EXTENSION_FUNCTION_NAME("tabs.captureVisibleTab")
};
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.cc b/chrome/browser/extensions/extension_tabs_module_constants.cc
index ebcc662..dc397f0 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.cc
+++ b/chrome/browser/extensions/extension_tabs_module_constants.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -11,9 +11,11 @@ const wchar_t kCodeKey[] = L"code";
const wchar_t kFavIconUrlKey[] = L"favIconUrl";
const wchar_t kFileKey[] = L"file";
const wchar_t kFocusedKey[] = L"focused";
+const wchar_t kFormatKey[] = L"format";
const wchar_t kFromIndexKey[] = L"fromIndex";
const wchar_t kHeightKey[] = L"height";
const wchar_t kIdKey[] = L"id";
+const wchar_t kIncognitoKey[] = L"incognito";
const wchar_t kIndexKey[] = L"index";
const wchar_t kLeftKey[] = L"left";
const wchar_t kNewPositionKey[] = L"newPosition";
@@ -21,6 +23,7 @@ const wchar_t kNewWindowIdKey[] = L"newWindowId";
const wchar_t kOldPositionKey[] = L"oldPosition";
const wchar_t kOldWindowIdKey[] = L"oldWindowId";
const wchar_t kPopulateKey[] = L"populate";
+const wchar_t kQualityKey[] = L"quality";
const wchar_t kSelectedKey[] = L"selected";
const wchar_t kStatusKey[] = L"status";
const wchar_t kTabIdKey[] = L"tabId";
@@ -32,9 +35,12 @@ const wchar_t kTopKey[] = L"top";
const wchar_t kUrlKey[] = L"url";
const wchar_t kWidthKey[] = L"width";
const wchar_t kWindowIdKey[] = L"windowId";
-const wchar_t kIncognitoKey[] = L"incognito";
const wchar_t kWindowTypeKey[] = L"type";
+const char kFormatValueJpeg[] = "jpeg";
+const char kFormatValuePng[] = "png";
+const char kMimeTypeJpeg[] = "image/jpg";
+const char kMimeTypePng[] = "image/png";
const char kStatusValueComplete[] = "complete";
const char kStatusValueLoading[] = "loading";
diff --git a/chrome/browser/extensions/extension_tabs_module_constants.h b/chrome/browser/extensions/extension_tabs_module_constants.h
index fd82d20..8e0d949 100644
--- a/chrome/browser/extensions/extension_tabs_module_constants.h
+++ b/chrome/browser/extensions/extension_tabs_module_constants.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -15,6 +15,7 @@ extern const wchar_t kCodeKey[];
extern const wchar_t kFavIconUrlKey[];
extern const wchar_t kFileKey[];
extern const wchar_t kFocusedKey[];
+extern const wchar_t kFormatKey[];
extern const wchar_t kFromIndexKey[];
extern const wchar_t kHeightKey[];
extern const wchar_t kIdKey[];
@@ -25,6 +26,7 @@ extern const wchar_t kNewWindowIdKey[];
extern const wchar_t kOldPositionKey[];
extern const wchar_t kOldWindowIdKey[];
extern const wchar_t kPopulateKey[];
+extern const wchar_t kQualityKey[];
extern const wchar_t kSelectedKey[];
extern const wchar_t kStatusKey[];
extern const wchar_t kTabIdKey[];
@@ -40,6 +42,10 @@ extern const wchar_t kIncognitoKey[];
extern const wchar_t kWindowTypeKey[];
// Value consts.
+extern const char kFormatValueJpeg[];
+extern const char kFormatValuePng[];
+extern const char kMimeTypeJpeg[];
+extern const char kMimeTypePng[];
extern const char kStatusValueComplete[];
extern const char kStatusValueLoading[];
extern const char kWindowTypeValueNormal[];
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index 6512c6d..30b3f12 100755
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -979,8 +979,30 @@
"description": "The target window. Defaults to the <a href='windows.html#current-window'>current window</a>."
},
{
+ "type": "object",
+ "name": "options",
+ "optional": true,
+ "description": "Set parameters of image capture, such as the format of the resulting image. This parameter was added in version 5.0 . Earlier versions of chrome will throw an exception unless you omit it.",
+ "properties": {
+ "format": {
+ "type": "string",
+ "optional": true,
+ "enum": ["jpeg", "png"],
+ "description": "The format of the resulting image. Default is jpeg."
+ },
+ "quality": {
+ "type": "integer",
+ "name": "quality",
+ "optional": true,
+ "minimum": 0,
+ "maximum": 100,
+ "description": "When format is 'jpeg', controls the quality of the resulting image. This value is ignored for PNG images. As quality is decreased, the resulting image will have more visual artifacts, and the number of bytes needed to store it will decrease."
+ }
+ }
+ },
+ {
"type": "function", "name": "callback", "parameters": [
- {"type": "string", "name": "dataUrl", "description": "A data URL of a JPEG encoding of the visible area of the captured tab. May be assigned to the 'src' property of an HTML Image element for display."}
+ {"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."}
]
}
]
diff --git a/chrome/common/extensions/docs/tabs.html b/chrome/common/extensions/docs/tabs.html
index fa722bc..faa84a5d 100644
--- a/chrome/common/extensions/docs/tabs.html
+++ b/chrome/common/extensions/docs/tabs.html
@@ -369,7 +369,8 @@ For other examples and for help in viewing the source code, see
<div class="summary"><span style="display: none; ">void</span>
<!-- Note: intentionally longer 80 columns -->
<span>chrome.tabs.captureVisibleTab</span>(<span class="optional"><span style="display: none; ">, </span><span>integer</span>
- <var><span>windowId</span></var></span><span class="null"><span>, </span><span>function</span>
+ <var><span>windowId</span></var></span><span class="optional"><span>, </span><span>object</span>
+ <var><span>options</span></var></span><span class="null"><span>, </span><span>function</span>
<var><span>callback</span></var></span>)</div>
<div class="description">
@@ -423,6 +424,126 @@ For other examples and for help in viewing the source code, see
</div><div>
<div>
<dt>
+ <var>options</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Set parameters of image capture, such as the format of the resulting image. This parameter was added in version 5.0 . Earlier versions of chrome will throw an exception unless you omit it.</dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>format</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The format of the resulting image. Default is jpeg.</dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>quality</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>When format is 'jpeg', controls the quality of the resulting image. This value is ignored for PNG images. As quality is decreased, the resulting image will have more visual artifacts, and the number of bytes needed to store it will decrease.</dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div>
+ </dl>
+ </dd>
+ </div>
+ </div><div>
+ <div>
+ <dt>
<var>callback</var>
<em>
@@ -520,7 +641,7 @@ For other examples and for help in viewing the source code, see
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>A data URL of a JPEG encoding of the visible area of the captured tab. May be assigned to the 'src' property of an HTML Image element for display.</dd>
+ <dd>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.</dd>
<!-- OBJECT PROPERTIES -->
<dd style="display: none; ">
diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc
index 111c991..87c2505 100644
--- a/chrome/renderer/extensions/extension_api_client_unittest.cc
+++ b/chrome/renderer/extensions/extension_api_client_unittest.cc
@@ -1,9 +1,10 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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 "base/file_util.h"
#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/chrome_paths.h"
@@ -13,6 +14,19 @@
#include "chrome/test/render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"
+// Make failures easier to locate by using SCOPED_TRACE() to print out the line
+// number of a failing call to ExtensionAPIClientTest::ExpectJs(Pass|Fail) .
+// Sadly, a #define is the only reasonable way to get the line number.
+#define ExpectJsFail(js, expected_failure_message) { \
+ SCOPED_TRACE(js); \
+ ExpectJsFailInternal(js, expected_failure_message); \
+}
+
+#define ExpectJsPass(js, function, arg1) { \
+ SCOPED_TRACE(js); \
+ ExpectJsPassInternal(js, function, arg1); \
+}
+
class ExtensionAPIClientTest : public RenderViewTest {
protected:
virtual void SetUp() {
@@ -36,15 +50,17 @@ class ExtensionAPIClientTest : public RenderViewTest {
}
}
- void ExpectJsFail(const std::string& js, const std::string& message) {
+ // Don't call this directly. Use the macro ExpectJsFail.
+ void ExpectJsFailInternal(const std::string& js, const std::string& message) {
ExecuteJavaScript(js.c_str());
EXPECT_EQ(message, GetConsoleMessage());
render_thread_.sink().ClearMessages();
}
- void ExpectJsPass(const std::string& js,
- const std::string& function,
- const std::string& arg1) {
+ // Don't call this directly. Use the macro ExpectJsPass.
+ void ExpectJsPassInternal(const std::string& js,
+ const std::string& function,
+ const std::string& arg1) {
ExecuteJavaScript(js.c_str());
const IPC::Message* request_msg =
render_thread_.sink().GetUniqueMessageMatching(
@@ -61,7 +77,16 @@ class ExtensionAPIClientTest : public RenderViewTest {
base::JSONReader reader;
scoped_ptr<Value> arg1_value(reader.JsonToValue(arg1, false, false));
- ASSERT_TRUE(args->Equals(arg1_value.get())) << js;
+ ASSERT_TRUE(arg1_value.get())
+ << "Failed to parse expected result as JSON: " << arg1;
+
+ std::string args_as_string;
+ base::JSONWriter::Write(args, false, &args_as_string);
+
+ ASSERT_TRUE(args->Equals(arg1_value.get()))
+ << js
+ << "\n Expected "<< arg1
+ << "\n Actual: "<< args_as_string;
render_thread_.sink().ClearMessages();
}
};
@@ -437,14 +462,67 @@ TEST_F(ExtensionAPIClientTest, RemoveTab) {
TEST_F(ExtensionAPIClientTest, CaptureVisibleTab) {
ExpectJsFail("chrome.tabs.captureVisibleTab(0);",
- "Uncaught Error: Parameter 1 is required.");
+ "Uncaught Error: Parameter 2 is required.");
+
+ ExpectJsFail("chrome.tabs.captureVisibleTab(0, null);",
+ "Uncaught Error: Parameter 2 is required.");
+
+ ExpectJsFail("chrome.tabs.captureVisibleTab(null, {});",
+ "Uncaught Error: Parameter 2 is required.");
ExpectJsFail("chrome.tabs.captureVisibleTab(function(){}, 0)",
"Uncaught Error: Invalid value for argument 0. "
"Expected 'integer' but got 'function'.");
- ExpectJsPass("chrome.tabs.captureVisibleTab(null, function(img){});",
- "tabs.captureVisibleTab", "null");
+ // Use old signiture. Check that a null value of the options paramenter
+ // is added.
+ ExpectJsPass("chrome.tabs.captureVisibleTab(null, function(img){});",
+ "tabs.captureVisibleTab", "[null, null]");
+
+ ExpectJsPass("chrome.tabs.captureVisibleTab(1, function(img){});",
+ "tabs.captureVisibleTab", "[1, null]");
+
+ ExpectJsPass("chrome.tabs.captureVisibleTab(null, null, function(img){});",
+ "tabs.captureVisibleTab", "[null, null]");
+
+ ExpectJsPass("chrome.tabs.captureVisibleTab("
+ "null, undefined, function(img){});",
+ "tabs.captureVisibleTab", "[null, null]");
+
+ ExpectJsPass("chrome.tabs.captureVisibleTab(null, {}, function(img){});",
+ "tabs.captureVisibleTab", "[null, {}]");
+
+ ExpectJsFail("chrome.tabs.captureVisibleTab(null, 42, function(img){});",
+ "Uncaught Error: Invalid value for argument 1. "
+ "Expected 'object' but got 'integer'.");
+
+ ExpectJsPass("chrome.tabs.captureVisibleTab("
+ "null, {\"format\": \"jpeg\"}, function(img){});",
+ "tabs.captureVisibleTab", "[null, {\"format\": \"jpeg\"}]");
+
+ ExpectJsPass("chrome.tabs.captureVisibleTab("
+ "null, {\"quality\": 100}, function(img){});",
+ "tabs.captureVisibleTab", "[null, {\"quality\": 100}]");
+
+ ExpectJsFail("chrome.tabs.captureVisibleTab("
+ "null, {\"quality\": 101}, function(img){});",
+ "Uncaught Error: Invalid value for argument 1. "
+ "Property 'quality': Value must not be greater than 100.");
+
+ ExpectJsFail("chrome.tabs.captureVisibleTab("
+ "null, {'not_a_param': 'jpeg'}, function(img){});",
+ "Uncaught Error: Invalid value for argument 1. "
+ "Property 'not_a_param': Unexpected property.");
+
+ ExpectJsFail("chrome.tabs.captureVisibleTab("
+ "null, {'format': 'invalid'}, function(img){});",
+ "Uncaught Error: Invalid value for argument 1. "
+ "Property 'format': Value must be one of: [jpeg, png].");
+
+ ExpectJsFail("chrome.tabs.captureVisibleTab("
+ "null, {'format': 42}, function(img){});",
+ "Uncaught Error: Invalid value for argument 1. "
+ "Property 'format': Value must be one of: [jpeg, png].");
}
// Bookmark API tests
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index 0879e91..d7b0aac 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -351,17 +351,27 @@ var chrome = chrome || {};
var apiFunction = {};
apiFunction.definition = functionDef;
- apiFunction.name = apiDef.namespace + "." + functionDef.name;;
+ apiFunction.name = apiDef.namespace + "." + functionDef.name;
apiFunctions[apiFunction.name] = apiFunction;
module[functionDef.name] = bind(apiFunction, function() {
- chromeHidden.validate(arguments, this.definition.parameters);
+ var args = arguments;
+ if (this.updateArguments) {
+ // Functions whose signature has changed can define an
+ // |updateArguments| function to transform old argument lists
+ // into the new form, preserving compatibility.
+ // TODO(skerner): Once optional args can be omitted (crbug/29215),
+ // this mechanism will become unnecessary. Consider removing it
+ // when crbug/29215 is fixed.
+ args = this.updateArguments.apply(this, args);
+ }
+ chromeHidden.validate(args, this.definition.parameters);
var retval;
if (this.handleRequest) {
- retval = this.handleRequest.apply(this, arguments);
+ retval = this.handleRequest.apply(this, args);
} else {
- retval = sendRequest(this.name, arguments,
+ retval = sendRequest(this.name, args,
this.definition.parameters,
this.customCallback);
}
@@ -405,7 +415,7 @@ var chrome = chrome || {};
var portId = OpenChannelToTab(
tabId, chromeHidden.extensionId, name);
return chromeHidden.Port.createPort(portId, name);
- }
+ };
apiFunctions["tabs.sendRequest"].handleRequest =
function(tabId, request, responseCallback) {
@@ -417,7 +427,7 @@ var chrome = chrome || {};
responseCallback(response);
port.disconnect();
});
- }
+ };
apiFunctions["extension.getViews"].handleRequest = function(properties) {
var windowId = -1;
@@ -431,25 +441,25 @@ var chrome = chrome || {};
}
}
return GetExtensionViews(windowId, type) || null;
- }
+ };
apiFunctions["extension.getBackgroundPage"].handleRequest = function() {
return GetExtensionViews(-1, "BACKGROUND")[0] || null;
- }
+ };
apiFunctions["extension.getToolstrips"].handleRequest =
function(windowId) {
if (typeof(windowId) == "undefined")
windowId = -1;
return GetExtensionViews(windowId, "TOOLSTRIP");
- }
+ };
apiFunctions["extension.getExtensionTabs"].handleRequest =
function(windowId) {
if (typeof(windowId) == "undefined")
windowId = -1;
return GetExtensionViews(windowId, "TAB");
- }
+ };
apiFunctions["devtools.getTabEvents"].handleRequest = function(tabId) {
var tabIdProxy = {};
@@ -461,7 +471,7 @@ var chrome = chrome || {};
tabIdProxy[name] = new chrome.Event("devtools." + tabId + "." + name);
});
return tabIdProxy;
- }
+ };
apiFunctions["experimental.popup.show"].handleRequest =
function(url, showDetails, callback) {
@@ -503,17 +513,17 @@ var chrome = chrome || {};
},
callback],
internalSchema);
- }
+ };
apiFunctions["experimental.extension.getPopupView"].handleRequest =
function() {
return GetPopupView();
- }
+ };
apiFunctions["experimental.popup.getParentWindow"].handleRequest =
function() {
return GetPopupParentWindow();
- }
+ };
var canvas;
function setIconCommon(details, name, parameters, actionType) {
@@ -601,7 +611,26 @@ var chrome = chrome || {};
var menuItemId = request.args[0];
delete chromeHidden.contextMenuHandlers[menuItemId];
}
- }
+ };
+
+ apiFunctions["tabs.captureVisibleTab"].updateArguments = function() {
+ // Old signature:
+ // captureVisibleTab(int windowId, function callback);
+ // New signature:
+ // captureVisibleTab(int windowId, object details, function callback);
+ //
+ // TODO(skerner): The next step to omitting optional arguments is the
+ // replacement of this code with code that matches arguments by type.
+ // Once this is working for captureVisibleTab() it can be enabled for
+ // the rest of the API. See crbug/29215 .
+ if (arguments.length == 2 && typeof(arguments[1]) == "function") {
+ // If the old signature is used, add a null details object.
+ newArgs = [arguments[0], null, arguments[1]];
+ } else {
+ newArgs = arguments;
+ }
+ return newArgs;
+ };
if (chrome.test) {
chrome.test.getApiDefinitions = GetExtensionAPIDefinition;