| Index: chrome/renderer/extensions/webstore_bindings.cc
|
| diff --git a/chrome/renderer/extensions/webstore_bindings.cc b/chrome/renderer/extensions/webstore_bindings.cc
|
| index 85ecbf21a4ad205b3c787f008ffa8f669348d232..225919c362aa3edf7aa030bd96f300d46cf376e2 100644
|
| --- a/chrome/renderer/extensions/webstore_bindings.cc
|
| +++ b/chrome/renderer/extensions/webstore_bindings.cc
|
| @@ -5,6 +5,7 @@
|
| #include "chrome/renderer/extensions/webstore_bindings.h"
|
|
|
| #include "base/strings/string_util.h"
|
| +#include "chrome/common/extensions/api/webstore_api_constants.h"
|
| #include "chrome/common/extensions/extension_constants.h"
|
| #include "chrome/common/extensions/extension_messages.h"
|
| #include "chrome/renderer/extensions/chrome_v8_context.h"
|
| @@ -46,12 +47,36 @@ const char kNoWebstoreItemLinkFoundError[] =
|
| "No Chrome Web Store item link found.";
|
| const char kInvalidWebstoreItemUrlError[] =
|
| "Invalid Chrome Web Store item URL.";
|
| +const char kInstallStageListenerCallbackNotAFunctionError[] =
|
| + "The listener callback for install stage change must be a function.";
|
| +const char kDownloadProgressListenerCallbackNotAFunctionError[] =
|
| + "The listener callback for download progress must be a function.";
|
|
|
| // chrome.webstore.install() calls generate an install ID so that the install's
|
| // callbacks may be fired when the browser notifies us of install completion
|
| // (successful or not) via OnInlineWebstoreInstallResponse.
|
| int g_next_install_id = 0;
|
|
|
| +// Parses the given |args| to determine if a valid listener function argument
|
| +// was passed. NULL is considered valid, since it is used to unset the current
|
| +// listener.
|
| +// Returns true on success, false on failure. If successful,
|
| +// populates |is_listener_set| with whether or not the listener should be set.
|
| +bool GetIsListenerSet(const v8::FunctionCallbackInfo<v8::Value>& args,
|
| + bool* is_listener_set) {
|
| + if (args[0]->IsNull()) {
|
| + *is_listener_set = false;
|
| + return true;
|
| + }
|
| +
|
| + if (args[0]->IsFunction()) {
|
| + *is_listener_set = true;
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| } // anonymous namespace
|
|
|
| WebstoreBindings::WebstoreBindings(Dispatcher* dispatcher,
|
| @@ -60,23 +85,52 @@ WebstoreBindings::WebstoreBindings(Dispatcher* dispatcher,
|
| ChromeV8ExtensionHandler(context) {
|
| RouteFunction("Install",
|
| base::Bind(&WebstoreBindings::Install, base::Unretained(this)));
|
| + RouteFunction("ValidateInstallStageListener",
|
| + base::Bind(&WebstoreBindings::ValidateInstallStageListener,
|
| + base::Unretained(this)));
|
| + RouteFunction("ValidateDownloadProgressListener",
|
| + base::Bind(&WebstoreBindings::ValidateDownloadProgressListener,
|
| + base::Unretained(this)));
|
| }
|
|
|
| -void WebstoreBindings::Install(
|
| - const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| +content::RenderView* WebstoreBindings::GetRenderView() {
|
| WebFrame* frame = WebFrame::frameForContext(context()->v8_context());
|
| if (!frame || !frame->view())
|
| - return;
|
| -
|
| + return NULL;
|
| content::RenderView* render_view =
|
| content::RenderView::FromWebView(frame->view());
|
| + return render_view;
|
| +}
|
| +
|
| +void WebstoreBindings::Install(
|
| + const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| + content::RenderView* render_view = GetRenderView();
|
| if (!render_view)
|
| return;
|
|
|
| + // The first two arguments, which indicate whether or not there are install
|
| + // stage and download progress listeners, are provided directly by the
|
| + // custom bindings, so should always be valid.
|
| + int listener_mask = 0;
|
| + if (args[0]->IsBoolean()) {
|
| + if (args[0]->BooleanValue())
|
| + listener_mask |= api::webstore::INSTALL_STAGE_LISTENER;
|
| + } else {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| + if (args[1]->IsBoolean()) {
|
| + if (args[1]->BooleanValue())
|
| + listener_mask |= api::webstore::DOWNLOAD_PROGRESS_LISTENER;
|
| + } else {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| std::string preferred_store_link_url;
|
| - if (!args[0]->IsUndefined()) {
|
| - if (args[0]->IsString()) {
|
| - preferred_store_link_url = std::string(*v8::String::Utf8Value(args[0]));
|
| + if (!args[2]->IsUndefined()) {
|
| + if (args[2]->IsString()) {
|
| + preferred_store_link_url = std::string(*v8::String::Utf8Value(args[2]));
|
| } else {
|
| args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
|
| args.GetIsolate(), kPreferredStoreLinkUrlNotAString));
|
| @@ -86,6 +140,8 @@ void WebstoreBindings::Install(
|
|
|
| std::string webstore_item_id;
|
| std::string error;
|
| + WebFrame* frame = WebFrame::frameForContext(context()->v8_context());
|
| +
|
| if (!GetWebstoreItemIdFromFrame(
|
| frame, preferred_store_link_url, &webstore_item_id, &error)) {
|
| args.GetIsolate()->ThrowException(
|
| @@ -94,28 +150,58 @@ void WebstoreBindings::Install(
|
| }
|
|
|
| int install_id = g_next_install_id++;
|
| - if (!args[1]->IsUndefined() && !args[1]->IsFunction()) {
|
| + if (!args[3]->IsUndefined() && !args[3]->IsFunction()) {
|
| args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
|
| args.GetIsolate(), kSuccessCallbackNotAFunctionError));
|
| return;
|
| }
|
|
|
| - if (!args[2]->IsUndefined() && !args[2]->IsFunction()) {
|
| + if (!args[4]->IsUndefined() && !args[4]->IsFunction()) {
|
| args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
|
| args.GetIsolate(), kFailureCallbackNotAFunctionError));
|
| return;
|
| }
|
|
|
| - Send(new ExtensionHostMsg_InlineWebstoreInstall(
|
| - render_view->GetRoutingID(),
|
| - install_id,
|
| - GetRoutingID(),
|
| - webstore_item_id,
|
| - frame->document().url()));
|
| + Send(new ExtensionHostMsg_InlineWebstoreInstall(render_view->GetRoutingID(),
|
| + install_id,
|
| + GetRoutingID(),
|
| + webstore_item_id,
|
| + frame->document().url(),
|
| + listener_mask));
|
|
|
| args.GetReturnValue().Set(static_cast<int32_t>(install_id));
|
| }
|
|
|
| +void WebstoreBindings::ValidateInstallStageListener(
|
| + const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| + content::RenderView* render_view = GetRenderView();
|
| + if (!render_view)
|
| + return;
|
| +
|
| + bool is_listener_set = false;
|
| + if (!GetIsListenerSet(args, &is_listener_set)) {
|
| + args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
|
| + args.GetIsolate(), kInstallStageListenerCallbackNotAFunctionError));
|
| + args.GetReturnValue().Set(false);
|
| + }
|
| + args.GetReturnValue().Set(true);
|
| +}
|
| +
|
| +void WebstoreBindings::ValidateDownloadProgressListener(
|
| + const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| + content::RenderView* render_view = GetRenderView();
|
| + if (!render_view)
|
| + return;
|
| +
|
| + bool is_listener_set = false;
|
| + if (!GetIsListenerSet(args, &is_listener_set)) {
|
| + args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
|
| + args.GetIsolate(), kDownloadProgressListenerCallbackNotAFunctionError));
|
| + args.GetReturnValue().Set(false);
|
| + }
|
| + args.GetReturnValue().Set(true);
|
| +}
|
| +
|
| // static
|
| bool WebstoreBindings::GetWebstoreItemIdFromFrame(
|
| WebFrame* frame, const std::string& preferred_store_link_url,
|
| @@ -207,6 +293,10 @@ bool WebstoreBindings::OnMessageReceived(const IPC::Message& message) {
|
| IPC_BEGIN_MESSAGE_MAP(WebstoreBindings, message)
|
| IPC_MESSAGE_HANDLER(ExtensionMsg_InlineWebstoreInstallResponse,
|
| OnInlineWebstoreInstallResponse)
|
| + IPC_MESSAGE_HANDLER(ExtensionMsg_InlineInstallStageChanged,
|
| + OnInlineInstallStageChanged)
|
| + IPC_MESSAGE_HANDLER(ExtensionMsg_InlineInstallDownloadProgress,
|
| + OnInlineInstallDownloadProgress)
|
| IPC_MESSAGE_UNHANDLED(CHECK(false) << "Unhandled IPC message")
|
| IPC_END_MESSAGE_MAP()
|
| return true;
|
| @@ -228,4 +318,24 @@ void WebstoreBindings::OnInlineWebstoreInstallResponse(
|
| "webstore", "onInstallResponse", arraysize(argv), argv);
|
| }
|
|
|
| +void WebstoreBindings::OnInlineInstallStageChanged(const std::string& stage) {
|
| + v8::Isolate* isolate = context()->isolate();
|
| + v8::HandleScope handle_scope(isolate);
|
| + v8::Context::Scope context_scope(context()->v8_context());
|
| + v8::Handle<v8::Value> argv[] = {
|
| + v8::String::NewFromUtf8(isolate, stage.c_str())};
|
| + context()->module_system()->CallModuleMethod(
|
| + "webstore", "onInstallStageChanged", arraysize(argv), argv);
|
| +}
|
| +
|
| +void WebstoreBindings::OnInlineInstallDownloadProgress(int percent_downloaded) {
|
| + v8::Isolate* isolate = context()->isolate();
|
| + v8::HandleScope handle_scope(isolate);
|
| + v8::Context::Scope context_scope(context()->v8_context());
|
| + v8::Handle<v8::Value> argv[] = {
|
| + v8::Integer::New(isolate, percent_downloaded)};
|
| + context()->module_system()->CallModuleMethod(
|
| + "webstore", "onDownloadProgress", arraysize(argv), argv);
|
| +}
|
| +
|
| } // namespace extensions
|
|
|