summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPS2
-rw-r--r--chrome/browser/browser.scons2
-rw-r--r--chrome/browser/browser.vcproj8
-rw-r--r--chrome/browser/extensions/extension_api_handler.cc45
-rw-r--r--chrome/browser/extensions/extension_api_handler.h29
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc17
-rw-r--r--chrome/browser/renderer_host/render_view_host.h10
-rw-r--r--chrome/chrome.gyp4
-rw-r--r--chrome/common/render_messages_internal.h16
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc105
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.h27
-rw-r--r--chrome/renderer/render_thread.cc4
-rw-r--r--chrome/renderer/render_view.cc46
-rw-r--r--chrome/renderer/render_view.h8
-rw-r--r--chrome/renderer/renderer.scons2
-rw-r--r--chrome/renderer/renderer.vcproj8
-rwxr-xr-xchrome/renderer/renderer_resources.grd1
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js71
-rw-r--r--webkit/glue/webframe.h2
-rw-r--r--webkit/glue/webframe_impl.cc9
-rw-r--r--webkit/port/bindings/v8/v8_proxy.cpp19
-rw-r--r--webkit/port/bindings/v8/v8_proxy.h21
22 files changed, 440 insertions, 16 deletions
diff --git a/DEPS b/DEPS
index 1b2ce8a..4fafe545 100644
--- a/DEPS
+++ b/DEPS
@@ -19,7 +19,7 @@ deps = {
"http://googletest.googlecode.com/svn/trunk@214",
"src/third_party/WebKit":
- "/trunk/deps/third_party/WebKit@12324",
+ "/trunk/deps/third_party/WebKit@12346",
"src/third_party/icu38":
"/trunk/deps/third_party/icu38@11496",
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons
index 69a8ba7..fec32ef 100644
--- a/chrome/browser/browser.scons
+++ b/chrome/browser/browser.scons
@@ -506,6 +506,8 @@ input_files = ChromeFileList([
MSVSFilter('Extensions', [
'extensions/extension.cc',
'extensions/extension.h',
+ 'extensions/extension_api_handler.cc',
+ 'extensions/extension_api_handler.h',
'extensions/extension_view.cc',
'extensions/extension_view.h',
'extensions/extension_error_reporter.cc',
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 842f44c..ff76afb 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -1906,6 +1906,14 @@
>
</File>
<File
+ RelativePath=".\extensions\extension_api_handler.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\extensions\extension_api_handler.h"
+ >
+ </File>
+ <File
RelativePath=".\extensions\extension_error_reporter.cc"
>
</File>
diff --git a/chrome/browser/extensions/extension_api_handler.cc b/chrome/browser/extensions/extension_api_handler.cc
new file mode 100644
index 0000000..702917b
--- /dev/null
+++ b/chrome/browser/extensions/extension_api_handler.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2009 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 "chrome/browser/extensions/extension_api_handler.h"
+
+#include "base/json_reader.h"
+#include "base/json_writer.h"
+#include "base/values.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+
+ExtensionAPIHandler::ExtensionAPIHandler(RenderViewHost* render_view_host)
+ : render_view_host_(render_view_host) {}
+
+void ExtensionAPIHandler::HandleRequest(const std::string& name,
+ const std::string& args,
+ int callback_id) {
+ scoped_ptr<Value> value;
+ if (!args.empty()) {
+ value.reset(JSONReader::Read(args, false));
+ DCHECK(value.get());
+ }
+
+ // TODO(aa): This will probably dispatch to per-module specialized classes.
+ // Consider refactoring similar work in dom_ui to reuse.
+ if (name == "CreateTab") {
+ Browser* browser = BrowserList::GetLastActive();
+ if (browser) {
+ DCHECK(value->IsType(Value::TYPE_DICTIONARY));
+ std::string url;
+ static_cast<DictionaryValue*>(value.get())->GetString(L"url", &url);
+ browser->AddTabWithURL(GURL(url), GURL(), PageTransition::TYPED, true,
+ NULL);
+
+ static int response_count = 0;
+ scoped_ptr<Value> response(Value::CreateIntegerValue(response_count++));
+ std::string json;
+ JSONWriter::Write(response.get(), false, &json);
+
+ render_view_host_->SendExtensionResponse(callback_id, json);
+ }
+ }
+}
diff --git a/chrome/browser/extensions/extension_api_handler.h b/chrome/browser/extensions/extension_api_handler.h
new file mode 100644
index 0000000..3cd6efd
--- /dev/null
+++ b/chrome/browser/extensions/extension_api_handler.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 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 CHROME_BROWSER_EXTENSIONS_EXTENSION_APIS_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_APIS_H_
+
+#include <string>
+
+class RenderViewHost;
+
+// ExtensionAPIHandler is the top-level entry point for extension callbacks
+// in the browser process. It lives on the UI thread.
+class ExtensionAPIHandler {
+ public:
+ ExtensionAPIHandler(RenderViewHost* render_view_host);
+
+ // Handle a request to perform some synchronous API.
+ // TODO(aa): args should be a Value object.
+ void HandleRequest(const std::string& name, const std::string& args,
+ int callback_id);
+
+ private:
+ // TODO(aa): Once there can be APIs that are asynchronous wrt the browser's UI
+ // thread, we may have to have to do something about this raw pointer.
+ RenderViewHost* render_view_host_;
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_APIS_H_
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index cb6110b..a02f15c 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -98,7 +98,8 @@ RenderViewHost::RenderViewHost(SiteInstance* instance,
run_modal_reply_msg_(NULL),
has_unload_listener_(false),
is_waiting_for_unload_ack_(false),
- are_javascript_messages_suppressed_(false) {
+ are_javascript_messages_suppressed_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(extension_api_handler_(this)) {
DCHECK(instance_);
DCHECK(delegate_);
if (modal_dialog_event == NULL)
@@ -761,6 +762,7 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_RemoveAutofillEntry,
OnRemoveAutofillEntry)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFeedList, OnMsgUpdateFeedList)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionRequest, OnExtensionRequest)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(RenderWidgetHost::OnMessageReceived(msg))
IPC_END_MESSAGE_MAP_EX()
@@ -1344,3 +1346,16 @@ void RenderViewHost::ForwardMessageFromExternalHost(const std::string& message,
Send(new ViewMsg_HandleMessageFromExternalHost(routing_id(), message, origin,
target));
}
+
+void RenderViewHost::OnExtensionRequest(const std::string& name,
+ const std::string& args,
+ int callback_id) {
+ // TODO(aa): Here is where we can check that this renderer was supposed to be
+ // able to call extension APIs.
+ extension_api_handler_.HandleRequest(name, args, callback_id);
+}
+
+void RenderViewHost::SendExtensionResponse(int callback_id,
+ const std::string& response) {
+ Send(new ViewMsg_ExtensionResponse(routing_id(), callback_id, response));
+}
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index fdaf769..1e61e7e 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/scoped_ptr.h"
+#include "chrome/browser/extensions/extension_api_handler.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/common/modal_dialog_event.h"
@@ -429,6 +430,8 @@ class RenderViewHost : public RenderWidgetHost {
// Creates a new RenderWidget with the given route id.
void CreateNewWidget(int route_id, bool activatable);
+ void SendExtensionResponse(int callback_id, const std::string& response);
+
protected:
// RenderWidgetHost protected overrides.
virtual void UnhandledKeyboardEvent(const NativeWebKeyboardEvent& event);
@@ -553,6 +556,9 @@ class RenderViewHost : public RenderWidgetHost {
void OnRemoveAutofillEntry(const std::wstring& field_name,
const std::wstring& value);
+ void OnExtensionRequest(const std::string& name, const std::string& args,
+ int callback_id);
+
// Helper function to send a navigation message. If a cross-site request is
// in progress, we may be suspended while waiting for the onbeforeunload
// handler, so this function might buffer the message rather than sending it.
@@ -631,6 +637,10 @@ class RenderViewHost : public RenderWidgetHost {
bool are_javascript_messages_suppressed_;
+ // Handler for extension API requests.
+ // Handles processing IPC messages related to the extension system.
+ ExtensionAPIHandler extension_api_handler_;
+
DISALLOW_EVIL_CONSTRUCTORS(RenderViewHost);
};
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 0475f20..d62f58e 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -612,6 +612,8 @@
'browser/encoding_menu_controller_delegate.h',
'browser/extensions/extension.cc',
'browser/extensions/extension.h',
+ 'browser/extensions/extension_api_handler.cc',
+ 'browser/extensions/extension_api_handler.h',
'browser/extensions/extension_error_reporter.cc',
'browser/extensions/extension_error_reporter.h',
'browser/extensions/extension_message_service.cc',
@@ -1357,6 +1359,8 @@
# All .cc, .h, and .mm files under renderer except tests and mocks.
'renderer/automation/dom_automation_controller.cc',
'renderer/automation/dom_automation_controller.h',
+ 'renderer/extensions/extension_process_bindings.cc',
+ 'renderer/extensions/extension_process_bindings.h',
'renderer/extensions/renderer_extension_bindings.cc',
'renderer/extensions/renderer_extension_bindings.h',
'renderer/media/audio_renderer_impl.cc',
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 577bde2..150bdbe 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -512,8 +512,13 @@ IPC_BEGIN_MESSAGES(View)
// started.
IPC_MESSAGE_ROUTED0(ViewMsg_MoveOrResizeStarted)
- // Send a message to an extension process. channel_id is a handle that can
- // be used for sending a response.
+ // The browser sends this message when an extension API has a response.
+ IPC_MESSAGE_ROUTED2(ViewMsg_ExtensionResponse,
+ int /* callback id */,
+ std::string /* response */)
+
+ // Relay a message sent from a renderer to an extension process. channel_id
+ // is a handle that can be used for sending a response.
IPC_MESSAGE_ROUTED2(ViewMsg_HandleExtensionMessage,
std::string /* message */,
int /* channel_id */)
@@ -1197,6 +1202,13 @@ IPC_BEGIN_MESSAGES(ViewHost)
double /* left_channel */,
double /* right_channel */)
+ // A renderer sends this message when an extension process starts an API
+ // request. If callback id is -1, no response will be sent.
+ IPC_MESSAGE_ROUTED3(ViewHostMsg_ExtensionRequest,
+ std::string /* name */,
+ std::string /* argument */,
+ int /* callback id */)
+
#if defined(OS_MACOSX)
// On OSX, we cannot allocated shared memory from within the sandbox, so
// this call exists for the renderer to ask the browser to allocate memory
diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
new file mode 100644
index 0000000..63c0562
--- /dev/null
+++ b/chrome/renderer/extensions/extension_process_bindings.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2009 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 "chrome/renderer/extensions/extension_process_bindings.h"
+
+#include "chrome/common/render_messages.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/renderer/render_view.h"
+#include "grit/renderer_resources.h"
+#include "webkit/glue/webframe.h"
+
+namespace extensions_v8 {
+
+const char kExtensionProcessExtensionName[] = "v8/ExtensionProcess";
+
+class ExtensionProcessBindingsWrapper : public v8::Extension {
+ public:
+ ExtensionProcessBindingsWrapper()
+ : v8::Extension(kExtensionProcessExtensionName, GetSource()) {}
+
+ virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
+ v8::Handle<v8::String> name) {
+ if (name->Equals(v8::String::New("GetNextCallbackId")))
+ return v8::FunctionTemplate::New(GetNextCallbackId);
+ else if (name->Equals(v8::String::New("CreateTab")))
+ return v8::FunctionTemplate::New(StartRequest, name);
+
+ return v8::Handle<v8::FunctionTemplate>();
+ }
+
+ private:
+ static const char* GetSource() {
+ // This is weird. The v8::Extension constructor expects a null-terminated
+ // string which it doesn't own (all current uses are constant). The value
+ // returned by GetDataResource is *not* null-terminated, and simply
+ // converting it to a string, then using that string's c_str() in this
+ // class's constructor doesn't work because the resulting string is stack-
+ // allocated.
+ if (!source_)
+ source_ = new std::string(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_EXTENSION_PROCESS_BINDINGS_JS).as_string());
+
+ return source_->c_str();
+ }
+
+ static v8::Handle<v8::Value> GetNextCallbackId(const v8::Arguments& args) {
+ static int next_callback_id = 0;
+ return v8::Integer::New(next_callback_id++);
+ }
+
+ static v8::Handle<v8::Value> StartRequest(const v8::Arguments& args) {
+ WebFrame* webframe = WebFrame::RetrieveActiveFrame();
+ DCHECK(webframe) << "There should be an active frame since we just got "
+ "an API called.";
+ if (!webframe) return v8::Undefined();
+
+ WebView* webview = webframe->GetView();
+ if (!webview) return v8::Undefined(); // can happen during closing
+
+ RenderView* renderview = static_cast<RenderView*>(webview->GetDelegate());
+ DCHECK(renderview) << "Encountered a WebView without a WebViewDelegate";
+ if (!renderview) return v8::Undefined();
+
+ if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsInt32())
+ return v8::Undefined();
+
+ int callback_id = args[1]->Int32Value();
+ renderview->SendExtensionRequest(
+ std::string(*v8::String::AsciiValue(args.Data())),
+ std::string(*v8::String::Utf8Value(args[0])),
+ callback_id, webframe);
+
+ return v8::Undefined();
+ }
+
+ static std::string* source_;
+};
+
+std::string* ExtensionProcessBindingsWrapper::source_;
+
+
+// static
+v8::Extension* ExtensionProcessBindings::Get() {
+ return new ExtensionProcessBindingsWrapper();
+}
+
+// static
+void ExtensionProcessBindings::ExecuteCallbackInFrame(
+ WebFrame* frame, int callback_id, const std::string& response) {
+ std::string code = "chromium._dispatchCallback(";
+ code += IntToString(callback_id);
+ code += ", '";
+
+ size_t offset = code.length();
+ code += response;
+ ReplaceSubstringsAfterOffset(&code, offset, "\\", "\\\\");
+ ReplaceSubstringsAfterOffset(&code, offset, "'", "\\'");
+ code += "')";
+
+ frame->ExecuteScript(webkit_glue::WebScriptSource(code));
+}
+
+} // namespace extensions_v8
diff --git a/chrome/renderer/extensions/extension_process_bindings.h b/chrome/renderer/extensions/extension_process_bindings.h
new file mode 100644
index 0000000..cbdd0bd
--- /dev/null
+++ b/chrome/renderer/extensions/extension_process_bindings.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2009 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.
+
+// Exposes extension APIs into the extension process.
+
+#ifndef CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
+#define CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
+
+#include <string>
+
+#include "v8/include/v8.h"
+
+class WebFrame;
+
+namespace extensions_v8 {
+
+class ExtensionProcessBindings {
+ public:
+ static v8::Extension* Get();
+ static void ExecuteCallbackInFrame(WebFrame* frame, int callback_id,
+ const std::string& response);
+};
+
+} // namespace extensions_v8
+
+#endif // CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index 96e239c..165af40 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -23,6 +23,7 @@
#include "chrome/plugin/plugin_channel_base.h"
#include "webkit/glue/weburlrequest.h"
#endif
+#include "chrome/renderer/extensions/extension_process_bindings.h"
#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/renderer/net/render_dns_master.h"
#include "chrome/renderer/render_process.h"
@@ -250,6 +251,9 @@ void RenderThread::EnsureWebKitInitialized() {
WebKit::registerExtension(extensions_v8::IntervalExtension::Get());
WebKit::registerExtension(extensions_v8::RendererExtensionBindings::Get());
+ WebKit::registerExtension(extensions_v8::ExtensionProcessBindings::Get(),
+ WebKit::WebString::fromUTF8(chrome::kExtensionScheme));
+
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kPlaybackMode) ||
command_line.HasSwitch(switches::kRecordMode)) {
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index e6899dc..dfd2897 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -29,6 +29,7 @@
#include "chrome/renderer/debug_message_handler.h"
#include "chrome/renderer/devtools_agent.h"
#include "chrome/renderer/devtools_client.h"
+#include "chrome/renderer/extensions/extension_process_bindings.h"
#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/renderer/localized_error.h"
#include "chrome/renderer/media/audio_renderer_impl.h"
@@ -428,6 +429,7 @@ void RenderView::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted)
IPC_MESSAGE_HANDLER(ViewMsg_HandleExtensionMessage,
OnHandleExtensionMessage)
+ IPC_MESSAGE_HANDLER(ViewMsg_ExtensionResponse, OnExtensionResponse)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(RenderWidget::OnMessageReceived(message))
@@ -1450,6 +1452,25 @@ void RenderView::DidCancelClientRedirect(WebView* webview,
WebFrame* frame) {
}
+void RenderView::WillCloseFrame(WebView* view, WebFrame* frame) {
+ // Remove all the pending extension callbacks for this frame.
+ if (pending_extension_callbacks_.IsEmpty())
+ return;
+
+ std::vector<int> orphaned_callbacks;
+ for (IDMap<WebFrame>::const_iterator iter =
+ pending_extension_callbacks_.begin();
+ iter != pending_extension_callbacks_.end(); ++iter) {
+ if (iter->second == frame)
+ orphaned_callbacks.push_back(iter->first);
+ }
+
+ for (std::vector<int>::const_iterator iter = orphaned_callbacks.begin();
+ iter != orphaned_callbacks.end(); ++iter) {
+ pending_extension_callbacks_.Remove(*iter);
+ }
+}
+
void RenderView::DidCompleteClientRedirect(WebView* webview,
WebFrame* frame,
const GURL& source) {
@@ -2944,3 +2965,28 @@ void RenderView::OnHandleExtensionMessage(const std::string& message,
extensions_v8::RendererExtensionBindings::HandleExtensionMessage(
webview()->GetMainFrame(), message, channel_id);
}
+
+void RenderView::SendExtensionRequest(const std::string& name,
+ const std::string& args,
+ int callback_id,
+ WebFrame* callback_frame) {
+ DCHECK(RenderThread::current()->message_loop() == MessageLoop::current());
+
+ if (callback_id != -1) {
+ DCHECK(callback_frame) << "Callback specified without frame";
+ pending_extension_callbacks_.AddWithID(callback_frame, callback_id);
+ }
+
+ Send(new ViewHostMsg_ExtensionRequest(routing_id_, name, args, callback_id));
+}
+
+void RenderView::OnExtensionResponse(int callback_id,
+ const std::string& response) {
+ WebFrame* web_frame = pending_extension_callbacks_.Lookup(callback_id);
+ if (!web_frame)
+ return; // The frame went away.
+
+ extensions_v8::ExtensionProcessBindings::ExecuteCallbackInFrame(
+ web_frame, callback_id, response);
+ pending_extension_callbacks_.Remove(callback_id);
+}
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index da75f93..83612d8 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -218,6 +218,7 @@ class RenderView : public RenderWidget,
virtual void DidCompleteClientRedirect(WebView* webview,
WebFrame* frame,
const GURL& source);
+ virtual void WillCloseFrame(WebView* webview, WebFrame* frame);
virtual void WillSendRequest(WebView* webview,
uint32 identifier,
WebRequest* request);
@@ -367,6 +368,10 @@ class RenderView : public RenderWidget,
void GetAudioVolume(int stream_id);
void SetAudioVolume(int stream_id, double left, double right);
+ void SendExtensionRequest(const std::string& name, const std::string& args,
+ int callback_id, WebFrame* web_frame);
+ void OnExtensionResponse(int callback_id, const std::string& response);
+
protected:
// RenderWidget override.
virtual void OnResize(const gfx::Size& new_size,
@@ -797,6 +802,9 @@ class RenderView : public RenderWidget,
// A set of audio renderers registered to use IPC for audio output.
IDMap<AudioRendererImpl> audio_renderers_;
+ // Maps pending callback IDs to their frames.
+ IDMap<WebFrame> pending_extension_callbacks_;
+
DISALLOW_COPY_AND_ASSIGN(RenderView);
};
diff --git a/chrome/renderer/renderer.scons b/chrome/renderer/renderer.scons
index 9cfa1585..25d309f 100644
--- a/chrome/renderer/renderer.scons
+++ b/chrome/renderer/renderer.scons
@@ -58,6 +58,8 @@ input_files = ChromeFileList([
'net/render_dns_queue.h',
]),
MSVSFilter('extensions', [
+ 'extensions/extension_process_bindings.cc',
+ 'extensions/extension_process_bindings.h',
'extensions/renderer_extension_bindings.cc',
'extensions/renderer_extension_bindings.h',
]),
diff --git a/chrome/renderer/renderer.vcproj b/chrome/renderer/renderer.vcproj
index db4ec9c..e9e6a52 100644
--- a/chrome/renderer/renderer.vcproj
+++ b/chrome/renderer/renderer.vcproj
@@ -192,6 +192,14 @@
RelativePath=".\extensions\renderer_extension_bindings.h"
>
</File>
+ <File
+ RelativePath=".\extensions\extension_process_bindings.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\extensions\extension_process_bindings.h"
+ >
+ </File>
</Filter>
<File
RelativePath=".\about_handler.cc"
diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd
index 6db6ffa..48bd7b4 100755
--- a/chrome/renderer/renderer_resources.grd
+++ b/chrome/renderer/renderer_resources.grd
@@ -13,6 +13,7 @@
<include name="IDR_INSECURE_CONTENT_STAMP" file="resources\insecure_content_stamp.png" type="BINDATA" />
<include name="IDR_ERROR_NO_DETAILS_HTML" file="resources\error_no_details.html" type="BINDATA" />
<include name="IDR_GREASEMONKEY_API_JS" file="resources\greasemonkey_api.js" type="BINDATA" />
+ <include name="IDR_EXTENSION_PROCESS_BINDINGS_JS" file="resources\extension_process_bindings.js" type="BINDATA" />
</includes>
</release>
</grit> \ No newline at end of file
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
new file mode 100644
index 0000000..3031d85
--- /dev/null
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -0,0 +1,71 @@
+var chromium;
+(function() {
+ if (!chromium)
+ chromium = {};
+
+ // callback handling
+ var callbacks = [];
+ chromium._dispatchCallback = function(callbackId, str) {
+ // We shouldn't be receiving evil JSON unless the browser is owned, but just
+ // to be safe, we sanitize it. This regex mania was borrowed from json2,
+ // from json.org.
+ if (!/^[\],:{}\s]*$/.test(
+ str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+ replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+ replace(/(?:^|:|,)(?:\s*\[)+/g, '')))
+ throw new Error("Unexpected characters in incoming JSON response.");
+
+ // This is lame. V8 disallows direct access to eval() in extensions (see:
+ // v8::internal::Parser::ParseLeftHandSideExpression()). So we must use
+ // this supa-jank hack instead. We really need native JSON.
+ str = 'return ' + str;
+ callbacks[callbackId](new Function(str)());
+ delete callbacks[callbackId];
+ };
+
+ // Quick and dirty json serialization.
+ // TODO(aa): Did I mention we need native JSON?
+ function serialize(thing) {
+ switch (typeof thing) {
+ case 'string':
+ return '\"' + thing.replace('\\', '\\\\').replace('\"', '\\\"') + '\"';
+ case 'boolean':
+ case 'number':
+ return String(thing);
+ case 'object':
+ if (thing === null)
+ return String(thing)
+ var items = [];
+ if (thing.constructor == Array) {
+ for (var i = 0; i < thing.length; i++)
+ items.push(serialize(thing[i]));
+ return '[' + items.join(',') + ']';
+ } else {
+ for (var p in thing)
+ items.push(serialize(p) + ':' + serialize(thing[p]));
+ return '{' + items.join(',') + '}';
+ }
+ default:
+ return '';
+ }
+ }
+
+ // Send an API request and optionally register a callback.
+ function sendRequest(request, args, callback) {
+ var sargs = serialize(args);
+ var callbackId = -1;
+ if (callback) {
+ native function GetNextCallbackId();
+ callbackId = GetNextCallbackId();
+ callbacks[callbackId] = callback;
+ }
+ request(sargs, callbackId);
+ }
+
+ // Tabs
+ chromium.tabs = {};
+ chromium.tabs.createTab = function(tab, callback) {
+ native function CreateTab();
+ sendRequest(CreateTab, tab, callback);
+ };
+})();
diff --git a/webkit/glue/webframe.h b/webkit/glue/webframe.h
index 76b50c6..8f38362 100644
--- a/webkit/glue/webframe.h
+++ b/webkit/glue/webframe.h
@@ -32,6 +32,8 @@ class WebFrame {
public:
WebFrame() {}
+ static WebFrame* RetrieveActiveFrame();
+
// Binds a C++ class to a JavaScript property of the window object. This
// should generally be used via CppBoundClass::BindToJavascript() instead of
// calling it directly.
diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc
index 49a6a08..818d272 100644
--- a/webkit/glue/webframe_impl.cc
+++ b/webkit/glue/webframe_impl.cc
@@ -321,6 +321,15 @@ class ChromePrintContext : public WebCore::PrintContext {
int WebFrameImpl::live_object_count_ = 0;
+// static
+WebFrame* WebFrame::RetrieveActiveFrame() {
+ WebCore::Frame* frame = WebCore::ScriptController::retrieveActiveFrame();
+ if (frame)
+ return WebFrameImpl::FromFrame(frame);
+ else
+ return NULL;
+}
+
WebFrameImpl::WebFrameImpl()
// Don't complain about using "this" in initializer list.
MSVC_PUSH_DISABLE_WARNING(4355)
diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp
index f36f836..91733b3 100644
--- a/webkit/port/bindings/v8/v8_proxy.cpp
+++ b/webkit/port/bindings/v8/v8_proxy.cpp
@@ -2346,12 +2346,15 @@ v8::Persistent<v8::Context> V8Proxy::createNewContext(
// Dynamically tell v8 about our extensions now.
const char** extensionNames = new const char*[m_extensions.size()];
int index = 0;
- V8ExtensionList::iterator it = m_extensions.begin();
- while (it != m_extensions.end()) {
- extensionNames[index++] = (*it)->name();
- ++it;
+ for (V8ExtensionList::iterator it = m_extensions.begin();
+ it != m_extensions.end(); ++it) {
+ if (it->scheme.length() > 0 &&
+ it->scheme != m_frame->document()->url().protocol())
+ continue;
+
+ extensionNames[index++] = it->extension->name();
}
- v8::ExtensionConfiguration extensions(m_extensions.size(), extensionNames);
+ v8::ExtensionConfiguration extensions(index, extensionNames);
result = v8::Context::New(&extensions, globalTemplate, global);
delete [] extensionNames;
extensionNames = 0;
@@ -3604,9 +3607,11 @@ String V8Proxy::GetSourceName() {
return ToWebCoreString(v8::Debug::Call(frame_source_name));
}
-void V8Proxy::RegisterExtension(v8::Extension* extension) {
+void V8Proxy::RegisterExtension(v8::Extension* extension,
+ const String& schemeRestriction) {
v8::RegisterExtension(extension);
- m_extensions.push_back(extension);
+ V8ExtensionInfo info = {schemeRestriction, extension};
+ m_extensions.push_back(info);
}
} // namespace WebCore
diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h
index 9d0336a..e403751 100644
--- a/webkit/port/bindings/v8/v8_proxy.h
+++ b/webkit/port/bindings/v8/v8_proxy.h
@@ -74,7 +74,6 @@ class SVGElementInstance;
class V8EventListener;
class V8ObjectEventListener;
typedef std::list<V8EventListener*> V8EventListenerList;
-typedef std::list<v8::Extension*> V8ExtensionList;
// TODO(fqian): use standard logging facilities in WebCore.
void log_info(Frame* frame, const String& msg, const String& url);
@@ -132,7 +131,7 @@ void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst,
const BatchedAttribute* attrs,
size_t num_attrs);
-// BhatchedConstant translates into calls to Set() for setting up an object's
+// BatchedConstant translates into calls to Set() for setting up an object's
// constants. It sets the constant on both the FunctionTemplate |desc| and the
// ObjectTemplate |proto|. PropertyAttributes is always ReadOnly.
struct BatchedConstant {
@@ -149,6 +148,15 @@ DOMWrapperMap<void>& GetDOMObjectMap();
const int kMaxRecursionDepth = 20;
+// Information about an extension that is registered for use with V8. If scheme
+// is non-empty, it contains the URL scheme the extension should be used with.
+// Otherwise, the extension is used with all schemes.
+struct V8ExtensionInfo {
+ String scheme;
+ v8::Extension* extension;
+};
+typedef std::list<V8ExtensionInfo> V8ExtensionList;
+
class V8Proxy {
public:
// The types of javascript errors that can be thrown.
@@ -452,9 +460,12 @@ class V8Proxy {
return v8::Local<v8::Context>::New(m_context);
}
- // Register extensions before initializing the context. Once the context
- // is initialized, extensions cannot be registered.
- static void RegisterExtension(v8::Extension* extension);
+ // Registers an extension to be available on webpages with a particular scheme
+ // If the scheme argument is empty, the extension is available on all pages.
+ // Will only affect v8 contexts initialized after this call. Takes ownership
+ // of the v8::Extension object passed.
+ static void RegisterExtension(v8::Extension* extension,
+ const String& schemeRestriction);
private:
v8::Persistent<v8::Context> createNewContext(v8::Handle<v8::Object> global);