summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraa@google.com <aa@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-16 23:57:47 +0000
committeraa@google.com <aa@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-16 23:57:47 +0000
commit1e0f70402b410a9e274e8d23eeab236b43810a00 (patch)
tree43ebd89055f4666ab3104554551a2177413382db
parentc2dacc9ec41232903ba700c6aef5ef98bfcb8af8 (diff)
downloadchromium_src-1e0f70402b410a9e274e8d23eeab236b43810a00.zip
chromium_src-1e0f70402b410a9e274e8d23eeab236b43810a00.tar.gz
chromium_src-1e0f70402b410a9e274e8d23eeab236b43810a00.tar.bz2
Adds a bit of Greasemonkey support hidden behind the --enable-greasemonkey flag. Implementation follows the pattern of the visited links system.
Things still to be done: - stop using a hardcoded script directory - watch script directory and update shared memory when necessary - move file io to background thread - support for @include patterns -- now, all scripts are applied to all pages Review URL: http://codereview.chromium.org/7254 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3496 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser.vcproj8
-rw-r--r--chrome/browser/greasemonkey_master.cc73
-rw-r--r--chrome/browser/greasemonkey_master.h47
-rw-r--r--chrome/browser/render_process_host.cc70
-rw-r--r--chrome/common/chrome_paths.cc5
-rw-r--r--chrome/common/chrome_paths.h1
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h2
-rw-r--r--chrome/common/render_messages_internal.h5
-rw-r--r--chrome/renderer/greasemonkey_slave.cc66
-rw-r--r--chrome/renderer/greasemonkey_slave.h62
-rw-r--r--chrome/renderer/render_thread.cc15
-rw-r--r--chrome/renderer/render_thread.h7
-rw-r--r--chrome/renderer/render_view.cc17
-rw-r--r--chrome/renderer/render_view.h3
-rw-r--r--chrome/renderer/renderer.vcproj8
-rw-r--r--webkit/glue/webframe.h6
-rw-r--r--webkit/glue/webframe_impl.cc7
-rw-r--r--webkit/glue/webframe_impl.h2
19 files changed, 389 insertions, 18 deletions
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index be4e198..743e775 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -2143,6 +2143,14 @@
>
</File>
<File
+ RelativePath=".\greasemonkey_master.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\greasemonkey_master.h"
+ >
+ </File>
+ <File
RelativePath=".\interstitial_page.cc"
>
</File>
diff --git a/chrome/browser/greasemonkey_master.cc b/chrome/browser/greasemonkey_master.cc
new file mode 100644
index 0000000..829b47b
--- /dev/null
+++ b/chrome/browser/greasemonkey_master.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2008 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/greasemonkey_master.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/pickle.h"
+#include "base/string_util.h"
+#include "chrome/common/chrome_paths.h"
+
+bool GreasemonkeyMaster::UpdateScripts() {
+ std::vector<std::string> scripts;
+ std::wstring path;
+
+ PathService::Get(chrome::DIR_USER_SCRIPTS, &path);
+ file_util::FileEnumerator enumerator(path, false,
+ file_util::FileEnumerator::FILES,
+ L"*.user.js");
+ for (std::wstring file = enumerator.Next(); !file.empty();
+ file = enumerator.Next()) {
+ // TODO(aa): Support unicode script files.
+ std::string contents;
+ file_util::ReadFileToString(file, &contents);
+ scripts.push_back(contents);
+ }
+
+ // Pickle scripts data.
+ Pickle pickle;
+ pickle.WriteSize(scripts.size());
+ for (std::vector<std::string>::iterator script = scripts.begin();
+ script != scripts.end(); ++script) {
+ // Write script body as 'data' so that we can read it out in the slave
+ // without allocating a new string.
+ pickle.WriteData(script->c_str(), script->size());
+ }
+
+ // Create the shared memory object.
+ scoped_ptr<SharedMemory> temp_shared_memory(new SharedMemory());
+ if (!temp_shared_memory.get()) {
+ return false;
+ }
+
+ shared_memory_serial_++;
+ if (!temp_shared_memory->Create(std::wstring(), // anonymous
+ false, // read-only
+ false, // open existing
+ pickle.size())) {
+ return false;
+ }
+
+ // Map into our process.
+ if (!temp_shared_memory->Map(pickle.size())) {
+ return false;
+ }
+
+ // Copy the pickle to shared memory.
+ memcpy(temp_shared_memory->memory(), pickle.data(), pickle.size());
+
+ shared_memory_.reset(temp_shared_memory.release());
+ return true;
+}
+
+bool GreasemonkeyMaster::ShareToProcess(ProcessHandle process,
+ SharedMemoryHandle* new_handle) {
+ if (shared_memory_.get())
+ return shared_memory_->ShareToProcess(process, new_handle);
+
+ NOTREACHED();
+ return false;
+}
diff --git a/chrome/browser/greasemonkey_master.h b/chrome/browser/greasemonkey_master.h
new file mode 100644
index 0000000..6dcbc6e
--- /dev/null
+++ b/chrome/browser/greasemonkey_master.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2008 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_GREASEMONKEY_MASTER_H__
+#define CHROME_BROWSER_GREASEMONKEY_MASTER_H__
+
+#include <vector>
+
+#include "base/process.h"
+#include "base/scoped_ptr.h"
+#include "base/shared_memory.h"
+
+// Manages a segment of shared memory that contains the Greasemonkey scripts the
+// user has installed.
+class GreasemonkeyMaster {
+ public:
+ GreasemonkeyMaster()
+ : shared_memory_serial_(0) {}
+
+ // Reloads scripts from disk into a new chunk of shared memory and notifies
+ // renderers.
+ bool UpdateScripts();
+
+ // Creates a handle to the shared memory that can be used in the specified
+ // process.
+ bool ShareToProcess(ProcessHandle process, SharedMemoryHandle* new_handle);
+
+ // Gets the segment of shared memory for the scripts.
+ SharedMemory* GetSharedMemory() const {
+ return shared_memory_.get();
+ }
+
+ private:
+ // Contains the scripts that were found the last time UpdateScripts() was
+ // called.
+ scoped_ptr<SharedMemory> shared_memory_;
+
+ // A counter that is incremented each time a new shared memory segment is
+ // created. This is used to uniquely identify segments created at different
+ // times by this class.
+ int shared_memory_serial_;
+
+ DISALLOW_COPY_AND_ASSIGN(GreasemonkeyMaster);
+};
+
+#endif // CHROME_BROWSER_GREASEMONKEY_MASTER_H__
diff --git a/chrome/browser/render_process_host.cc b/chrome/browser/render_process_host.cc
index bcf5d72..62a73ee 100644
--- a/chrome/browser/render_process_host.cc
+++ b/chrome/browser/render_process_host.cc
@@ -21,6 +21,7 @@
#include "base/process_util.h"
#include "base/rand_util.h"
#include "base/shared_memory.h"
+#include "base/singleton.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/thread.h"
@@ -38,6 +39,7 @@
#include "chrome/browser/sandbox_policy.h"
#include "chrome/browser/spellchecker.h"
#include "chrome/browser/visitedlink_master.h"
+#include "chrome/browser/greasemonkey_master.h"
#include "chrome/browser/web_contents.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
@@ -268,6 +270,7 @@ bool RenderProcessHost::Init() {
switches::kDisablePopupBlocking,
switches::kUseLowFragHeapCrt,
switches::kGearsInRenderer,
+ switches::kEnableGreasemonkey,
};
for (int i = 0; i < arraysize(switch_names); ++i) {
@@ -423,29 +426,66 @@ bool RenderProcessHost::Init() {
// Now that the process is created, set it's backgrounding accordingly.
SetBackgrounded(backgrounded_);
- VisitedLinkMaster* visitedlink_master = profile_->GetVisitedLinkMaster();
- if (visitedlink_master) {
- std::wstring history_table_name = visitedlink_master->GetSharedMemoryName();
- SharedMemoryHandle handle_for_process = NULL;
- HANDLE target_process = process_.handle();
- if (!target_process) {
- // Target process can be null if it's started with the --single-process
- // flag.
- target_process = GetCurrentProcess();
- }
-
- visitedlink_master->ShareToProcess(target_process, &handle_for_process);
- DCHECK(handle_for_process);
-
- channel_->Send(new ViewMsg_VisitedLink_NewTable(handle_for_process));
+ // Send the process its initial VisitedLink and Greasemonkey data.
+ HANDLE target_process = process_.handle();
+ if (!target_process) {
+ // Target process can be null if it's started with the --single-process
+ // flag.
+ target_process = GetCurrentProcess();
}
+ InitVisitedLinks(target_process);
+ InitGreasemonkeyScripts(target_process);
+
if (max_page_id_ != -1)
channel_->Send(new ViewMsg_SetNextPageID(max_page_id_ + 1));
return true;
}
+void RenderProcessHost::InitVisitedLinks(HANDLE target_process) {
+ VisitedLinkMaster* visitedlink_master = profile_->GetVisitedLinkMaster();
+ if (!visitedlink_master) {
+ return;
+ }
+
+ SharedMemoryHandle handle_for_process = NULL;
+ visitedlink_master->ShareToProcess(target_process, &handle_for_process);
+ DCHECK(handle_for_process);
+ if (handle_for_process) {
+ channel_->Send(new ViewMsg_VisitedLink_NewTable(handle_for_process));
+ }
+}
+
+void RenderProcessHost::InitGreasemonkeyScripts(HANDLE target_process) {
+ CommandLine command_line;
+ if (!command_line.HasSwitch(switches::kEnableGreasemonkey)) {
+ return;
+ }
+
+ // TODO(aa): Figure out lifetime and ownership of this object
+ // - VisitedLinkMaster is owned by Profile, but there has been talk of
+ // having scripts live elsewhere besides the profile.
+ // - File IO should be asynchronous (see VisitedLinkMaster), but how do we
+ // get scripts to the first renderer without blocking startup? Should we
+ // cache some information across restarts?
+ GreasemonkeyMaster* greasemonkey_master =
+ Singleton<GreasemonkeyMaster>::get();
+ if (!greasemonkey_master) {
+ return;
+ }
+
+ // TODO(aa): This does blocking IO. Move to background thread.
+ greasemonkey_master->UpdateScripts();
+
+ SharedMemoryHandle handle_for_process = NULL;
+ greasemonkey_master->ShareToProcess(target_process, &handle_for_process);
+ DCHECK(handle_for_process);
+ if (handle_for_process) {
+ channel_->Send(new ViewMsg_Greasemonkey_NewScripts(handle_for_process));
+ }
+}
+
void RenderProcessHost::Attach(IPC::Channel::Listener* listener,
int routing_id) {
listeners_.AddWithID(listener, routing_id);
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 2e6d0bb..9d6da38 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -129,6 +129,11 @@ bool PathProvider(int key, std::wstring* result) {
return false;
file_util::AppendToPath(&cur, L"Dictionaries");
break;
+ case chrome::DIR_USER_SCRIPTS:
+ // TODO(aa): Figure out where the script directory should live.
+ cur = L"C:\\SCRIPTS\\";
+ exists = true; // don't trigger directory creation code
+ break;
case chrome::FILE_LOCAL_STATE:
if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
return false;
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 02b14ae..8128122 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -24,6 +24,7 @@ enum {
DIR_LOCALES, // directory where locale resources are stored
DIR_APP_DICTIONARIES, // directory where the global dictionaries are
DIR_USER_DOCUMENTS, // directory for a user's "My Documents"
+ DIR_USER_SCRIPTS, // directory where Greasemonkey user scripts are stored
FILE_RESOURCE_MODULE, // full path and filename of the module that contains
// embedded resources (version, strings, images, etc.)
FILE_LOCAL_STATE, // path and filename to the file in which machine/
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 1cfc40e7..3428318 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -330,6 +330,9 @@ const wchar_t kEnableP13n[] = L"enable-p13n";
// SDCH is currently only supported server-side for searches on google.com.
const wchar_t kSdchFilter[] = L"enable-sdch";
+// Enable Greasemonkey script support.
+const wchar_t kEnableGreasemonkey[] = L"enable-greasemonkey";
+
// Causes the browser to launch directly in incognito mode.
const wchar_t kIncognito[] = L"incognito";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 4c76cdc..19b3ae6 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -128,6 +128,8 @@ extern const wchar_t kEnableP13n[];
extern const wchar_t kSdchFilter[];
+extern const wchar_t kEnableGreasemonkey[];
+
extern const wchar_t kIncognito[];
extern const wchar_t kUseNewSafeBrowsing[];
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index b7966ac..1b28898 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -155,6 +155,11 @@ IPC_BEGIN_MESSAGES(View, 1)
// handle. This handle is valid in the context of the renderer
IPC_MESSAGE_CONTROL1(ViewMsg_VisitedLink_NewTable, SharedMemoryHandle)
+ // Notification that the Greasemonkey scripts have been updated. It has one
+ // SharedMemoryHandle argument consisting of the pickled script data. This
+ // handle is valid in the context of the renderer.
+ IPC_MESSAGE_CONTROL1(ViewMsg_Greasemonkey_NewScripts, SharedMemoryHandle)
+
// Sent when the user wants to search for a word on the page (find in page).
// Request parameters are passed in as a FindInPageMsg_Request struct.
IPC_MESSAGE_ROUTED1(ViewMsg_Find, FindInPageRequest)
diff --git a/chrome/renderer/greasemonkey_slave.cc b/chrome/renderer/greasemonkey_slave.cc
new file mode 100644
index 0000000..7a23017
--- /dev/null
+++ b/chrome/renderer/greasemonkey_slave.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2008 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/greasemonkey_slave.h"
+
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/shared_memory.h"
+
+GreasemonkeySlave::GreasemonkeySlave() : shared_memory_(NULL) {
+}
+
+bool GreasemonkeySlave::UpdateScripts(SharedMemoryHandle shared_memory) {
+ scripts_.clear();
+
+ // Create the shared memory object.
+ shared_memory_.reset(new SharedMemory(shared_memory, true)); // read-only
+ if (!shared_memory_.get())
+ return false;
+
+ // First get the size of the memory block.
+ if (!shared_memory_->Map(sizeof(Pickle::Header)))
+ return false;
+ Pickle::Header* pickle_header =
+ reinterpret_cast<Pickle::Header*>(shared_memory_->memory());
+
+ // Now map in the rest of the block.
+ int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
+ shared_memory_->Unmap();
+ if (!shared_memory_->Map(pickle_size))
+ return false;
+
+ // Unpickle scripts.
+ void* iter = NULL;
+ int num_scripts = 0;
+ Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()),
+ pickle_size);
+ pickle.ReadInt(&iter, &num_scripts);
+
+ for (int i = 0; i < num_scripts; ++i) {
+ const char* data = NULL;
+ int data_length = 0;
+ pickle.ReadData(&iter, &data, &data_length);
+
+ GreasemonkeyScript script;
+ if (script.Parse(StringPiece(data, data_length))) {
+ scripts_.push_back(script);
+ }
+ }
+
+ return true;
+}
+
+bool GreasemonkeySlave::InjectScripts(WebFrame* frame) {
+ // TODO(aa): Check script patterns here
+
+ for (std::vector<GreasemonkeyScript>::iterator script = scripts_.begin();
+ script != scripts_.end(); ++script) {
+ // TODO(aa): Pass in URL to script when we have it.
+ frame->ExecuteJavaScript(script->GetBody().as_string(),
+ "Greasemonkey Script");
+ }
+
+ return true;
+}
diff --git a/chrome/renderer/greasemonkey_slave.h b/chrome/renderer/greasemonkey_slave.h
new file mode 100644
index 0000000..7f35cec
--- /dev/null
+++ b/chrome/renderer/greasemonkey_slave.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2008 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_RENDERER_GREASEMONKEY_SLAVE_H__
+#define CHROME_RENDERER_GREASEMONKEY_SLAVE_H__
+
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "base/shared_memory.h"
+#include "base/string_piece.h"
+#include "webkit/glue/webframe.h"
+
+// Parsed representation of a Greasemonkey script.
+class GreasemonkeyScript {
+ public:
+ // TODO(aa): Pass in filename script came from, for errors. Needs to be in
+ // shared memory.
+ GreasemonkeyScript() {}
+
+ const StringPiece& GetBody() const {
+ return body_;
+ }
+
+ bool Parse(const StringPiece& script_text) {
+ // TODO(aa): Parse out includes, convert to regexes.
+ body_ = script_text;
+ return true;
+ }
+
+ private:
+ // References the body of the script in shared memory. The underlying memory
+ // is valid until shared_memory_ is either deleted or Unmap()'d.
+ StringPiece body_;
+};
+
+
+// Manages installed GreasemonkeyScripts for a render process.
+class GreasemonkeySlave {
+ public:
+ GreasemonkeySlave();
+
+ // Update the parsed scripts from shared memory.
+ bool UpdateScripts(SharedMemoryHandle shared_memory);
+
+ // Inject the appropriate scripts into a frame based on its URL.
+ // TODO(aa): Extract a GreasemonkeyFrame interface out of this to improve
+ // testability.
+ bool InjectScripts(WebFrame* frame);
+
+ private:
+ // Shared memory containing raw script data.
+ scoped_ptr<SharedMemory> shared_memory_;
+
+ // Parsed script data.
+ std::vector<GreasemonkeyScript> scripts_;
+
+ DISALLOW_COPY_AND_ASSIGN(GreasemonkeySlave);
+};
+
+#endif // CHROME_RENDERER_GREASEMONKEY_SLAVE_H__
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index c389860..56ed3a8 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -15,6 +15,7 @@
#include "chrome/common/notification_service.h"
#include "chrome/plugin/plugin_channel.h"
#include "chrome/renderer/net/render_dns_master.h"
+#include "chrome/renderer/greasemonkey_slave.h"
#include "chrome/renderer/render_process.h"
#include "chrome/renderer/render_view.h"
#include "chrome/renderer/visitedlink_slave.h"
@@ -41,6 +42,7 @@ RenderThread::RenderThread(const std::wstring& channel_name)
channel_name_(channel_name),
owner_loop_(MessageLoop::current()),
visited_link_slave_(NULL),
+ greasemonkey_slave_(NULL),
render_dns_master_(NULL),
in_send_(0) {
DCHECK(owner_loop_);
@@ -111,9 +113,8 @@ void RenderThread::Init() {
// The renderer thread should wind-up COM.
CoInitialize(0);
- // TODO(darin): We should actually try to share this object between
- // RenderThread instances.
visited_link_slave_ = new VisitedLinkSlave();
+ greasemonkey_slave_ = new GreasemonkeySlave();
render_dns_master_.reset(new RenderDnsMaster());
@@ -141,6 +142,9 @@ void RenderThread::CleanUp() {
delete visited_link_slave_;
visited_link_slave_ = NULL;
+ delete greasemonkey_slave_;
+ greasemonkey_slave_ = NULL;
+
CoUninitialize();
}
@@ -149,6 +153,11 @@ void RenderThread::OnUpdateVisitedLinks(SharedMemoryHandle table) {
visited_link_slave_->Init(table);
}
+void RenderThread::OnUpdateGreasemonkeyScripts(SharedMemoryHandle scripts) {
+ DCHECK(scripts) << "Bad scripts handle";
+ greasemonkey_slave_->UpdateScripts(scripts);
+}
+
void RenderThread::OnMessageReceived(const IPC::Message& msg) {
// NOTE: We could subclass router_ to intercept OnControlMessageReceived, but
// it seems simpler to just process any control messages that we care about
@@ -163,6 +172,8 @@ void RenderThread::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats,
OnGetCacheResourceStats)
IPC_MESSAGE_HANDLER(ViewMsg_PluginMessage, OnPluginMessage)
+ IPC_MESSAGE_HANDLER(ViewMsg_Greasemonkey_NewScripts,
+ OnUpdateGreasemonkeyScripts)
// send the rest to the router
IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg))
IPC_END_MESSAGE_MAP()
diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h
index 2d1c198..38fd144 100644
--- a/chrome/renderer/render_thread.h
+++ b/chrome/renderer/render_thread.h
@@ -18,6 +18,7 @@ class VisitedLinkSlave;
struct WebPreferences;
class RenderDnsMaster;
class NotificationService;
+class GreasemonkeySlave;
// The RenderThreadBase is the minimal interface that a RenderWidget expects
// from a render thread. The interface basically abstracts a way to send and
@@ -64,8 +65,12 @@ class RenderThread : public IPC::Channel::Listener,
// The RenderThread instance for the current thread.
static RenderThread* current();
+ // Gets the VisitedLinkSlave instance for this thread
VisitedLinkSlave* visited_link_slave() const { return visited_link_slave_; }
+ // Gets the GreasemonkeySlave instance for this thread
+ GreasemonkeySlave* greasemonkey_slave() const { return greasemonkey_slave_; }
+
// Do DNS prefetch resolution of a hostname.
void Resolve(const char* name, size_t length);
@@ -89,6 +94,7 @@ class RenderThread : public IPC::Channel::Listener,
private:
void OnUpdateVisitedLinks(SharedMemoryHandle table);
+ void OnUpdateGreasemonkeyScripts(SharedMemoryHandle table);
void OnPluginMessage(const std::wstring& dll_path,
const std::vector<uint8>& data);
@@ -120,6 +126,7 @@ class RenderThread : public IPC::Channel::Listener,
// These objects live solely on the render thread.
VisitedLinkSlave* visited_link_slave_;
+ GreasemonkeySlave* greasemonkey_slave_;
scoped_ptr<RenderDnsMaster> render_dns_master_;
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index ef69bb6..528120b 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -31,6 +31,7 @@
#include "chrome/renderer/about_handler.h"
#include "chrome/renderer/chrome_plugin_host.h"
#include "chrome/renderer/debug_message_handler.h"
+#include "chrome/renderer/greasemonkey_slave.h"
#include "chrome/renderer/localized_error.h"
#include "chrome/renderer/renderer_resources.h"
#include "chrome/renderer/visitedlink_slave.h"
@@ -150,7 +151,8 @@ RenderView::RenderView()
history_back_list_count_(0),
history_forward_list_count_(0),
disable_popup_blocking_(false),
- has_unload_listener_(false) {
+ has_unload_listener_(false),
+ greasemonkey_enabled_(false) {
resource_dispatcher_ = new ResourceDispatcher(this);
#ifdef CHROME_PERSONALIZATION
personalization_ = Personalization::CreateRendererPersonalization();
@@ -261,6 +263,8 @@ void RenderView::Init(HWND parent_hwnd,
command_line.HasSwitch(switches::kDomAutomationController);
disable_popup_blocking_ =
command_line.HasSwitch(switches::kDisablePopupBlocking);
+ greasemonkey_enabled_ =
+ command_line.HasSwitch(switches::kEnableGreasemonkey);
debug_message_handler_ = new DebugMessageHandler(this);
RenderThread::current()->AddFilter(debug_message_handler_);
@@ -1369,6 +1373,17 @@ void RenderView::DidFinishDocumentLoadForFrame(WebView* webview,
WebFrame* frame) {
// Check whether we have new encoding name.
UpdateEncoding(frame, webview->GetMainFrameEncodingName());
+
+ // Inject any Greasemonkey scripts. Do not inject into chrome UI pages, but
+ // do inject into any other document.
+ if (greasemonkey_enabled_) {
+ const GURL &gurl = frame->GetURL();
+ if (gurl.SchemeIs("file") ||
+ gurl.SchemeIs("http") ||
+ gurl.SchemeIs("https")) {
+ RenderThread::current()->greasemonkey_slave()->InjectScripts(frame);
+ }
+ }
}
void RenderView::DidHandleOnloadEventsForFrame(WebView* webview,
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index a59f328..d307e48 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -623,6 +623,9 @@ class RenderView : public RenderWidget, public WebViewDelegate,
// maintains the cache and other features of the accessibility tree.
scoped_ptr<GlueAccessibility> glue_accessibility_;
+ // True if Greasemonkey is enabled in this process.
+ bool greasemonkey_enabled_;
+
DISALLOW_COPY_AND_ASSIGN(RenderView);
};
diff --git a/chrome/renderer/renderer.vcproj b/chrome/renderer/renderer.vcproj
index 9d82fecb..2fa8d0c 100644
--- a/chrome/renderer/renderer.vcproj
+++ b/chrome/renderer/renderer.vcproj
@@ -202,6 +202,14 @@
>
</File>
<File
+ RelativePath=".\greasemonkey_slave.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\greasemonkey_slave.h"
+ >
+ </File>
+ <File
RelativePath=".\localized_error.cc"
>
</File>
diff --git a/webkit/glue/webframe.h b/webkit/glue/webframe.h
index 2169549..c8d73af 100644
--- a/webkit/glue/webframe.h
+++ b/webkit/glue/webframe.h
@@ -91,6 +91,12 @@ class WebFrame : public base::RefCounted<WebFrame> {
bool replace,
const GURL& fake_url) = 0;
+ // Executes a string of JavaScript in the web frame. The script_url param is
+ // the URL where the script in question can be found, if any. The renderer may
+ // request this URL to show the developer the source of the error.
+ virtual void ExecuteJavaScript(const std::string& js_code,
+ const std::string& script_url) = 0;
+
// Returns a string representing the state of the previous page load for
// later use when loading as well as the uri and title of the page. The
// previous page is the page that was loaded before DidCommitLoadForFrame was
diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc
index 4710e21..ca8997e 100644
--- a/webkit/glue/webframe_impl.cc
+++ b/webkit/glue/webframe_impl.cc
@@ -1595,6 +1595,13 @@ void WebFrameImpl::LoadAlternateHTMLErrorPage(const WebRequest* request,
error_page_url));
}
+void WebFrameImpl::ExecuteJavaScript(const std::string& js_code,
+ const std::string& script_url) {
+ frame_->loader()->executeScript(webkit_glue::StdStringToString(script_url),
+ 1, // base line number (for errors)
+ webkit_glue::StdStringToString(js_code));
+}
+
std::wstring WebFrameImpl::GetName() {
return webkit_glue::StringToStdWString(frame_->tree()->name());
}
diff --git a/webkit/glue/webframe_impl.h b/webkit/glue/webframe_impl.h
index fd887d5..9a8afdb 100644
--- a/webkit/glue/webframe_impl.h
+++ b/webkit/glue/webframe_impl.h
@@ -94,6 +94,8 @@ class WebFrameImpl : public WebFrame {
const GURL& error_page_url,
bool replace,
const GURL& fake_url);
+ virtual void ExecuteJavaScript(const std::string& js_code,
+ const std::string& script_url);
virtual bool GetPreviousState(GURL* url, std::wstring* title,
std::string* history_state) const;
virtual bool GetCurrentState(GURL* url, std::wstring* title,