diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-09 20:37:35 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-09 20:37:35 +0000 |
commit | 0938d3cb82dfd2424117f73573e757424ebede00 (patch) | |
tree | f1d0503af86c6c8bf6be409c1744437384d7cb86 /chrome/renderer/user_script_slave.cc | |
parent | 4f2321dbb2e034601fed172d222a90009e4674a0 (diff) | |
download | chromium_src-0938d3cb82dfd2424117f73573e757424ebede00.zip chromium_src-0938d3cb82dfd2424117f73573e757424ebede00.tar.gz chromium_src-0938d3cb82dfd2424117f73573e757424ebede00.tar.bz2 |
This is a rename of the term 'Greasemonkey' to 'user script' in Chromium.
I'm doing this to avoid confusion with the Firefox version of Greasemonkey and
also because 'user script' is really the correct generic term.
At the same time, I also moved user_script_master* into extensions/ because I want these two pieces to get closer and closer such that standalone user scripts are just a very small extension. Also extensions will be relying on most of the user script code.
Review URL: http://codereview.chromium.org/17281
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7827 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/user_script_slave.cc')
-rw-r--r-- | chrome/renderer/user_script_slave.cc | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/chrome/renderer/user_script_slave.cc b/chrome/renderer/user_script_slave.cc new file mode 100644 index 0000000..80cc329 --- /dev/null +++ b/chrome/renderer/user_script_slave.cc @@ -0,0 +1,170 @@ +// 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/user_script_slave.h" + +#include "base/logging.h" +#include "base/pickle.h" +#include "base/shared_memory.h" +#include "googleurl/src/gurl.h" + + +// UserScript + +void UserScript::Parse(const StringPiece& script_text) { + ParseMetadata(script_text); + + // TODO(aa): Set body to just the part after the metadata block? This would + // significantly cut down on the size of the injected script in some cases. + // Would require remembering the line number the body begins at, for correct + // error line number reporting. + body_ = script_text; +} + +bool UserScript::MatchesUrl(const GURL& url) { + for (std::vector<std::string>::iterator pattern = include_patterns_.begin(); + pattern != include_patterns_.end(); ++pattern) { + if (MatchPattern(url.spec(), *pattern)) { + return true; + } + } + + return false; +} + +void UserScript::ParseMetadata(const StringPiece& script_text) { + // http://wiki.greasespot.net/Metadata_block + StringPiece line; + size_t line_start = 0; + size_t line_end = 0; + bool in_metadata = false; + + static const StringPiece kUserScriptBegin("// ==UserScript=="); + static const StringPiece kUserScriptEng("// ==/UserScript=="); + static const StringPiece kIncludeDeclaration("// @include "); + + while (line_start < script_text.length()) { + line_end = script_text.find('\n', line_start); + + // Handle the case where there is no trailing newline in the file. + if (line_end == std::string::npos) { + line_end = script_text.length() - 1; + } + + line.set(script_text.data() + line_start, line_end - line_start); + + if (!in_metadata) { + if (line.starts_with(kUserScriptBegin)) { + in_metadata = true; + } + } else { + if (line.starts_with(kUserScriptEng)) { + break; + } + + if (line.starts_with(kIncludeDeclaration)) { + std::string pattern(line.data() + kIncludeDeclaration.length(), + line.length() - kIncludeDeclaration.length()); + std::string pattern_trimmed; + TrimWhitespace(pattern, TRIM_ALL, &pattern_trimmed); + AddInclude(pattern_trimmed); + } + + // TODO(aa): Handle more types of metadata. + } + + line_start = line_end + 1; + } + + // If no @include patterns were specified, default to @include *. + // This is what Greasemonkey does. + if (include_patterns_.size() == 0) { + AddInclude("*"); + } +} + +void UserScript::AddInclude(const std::string &glob_pattern) { + include_patterns_.push_back(EscapeGlob(glob_pattern)); +} + +std::string UserScript::EscapeGlob(const std::string& input_pattern) { + std::string output_pattern; + + for (size_t i = 0; i < input_pattern.length(); ++i) { + switch (input_pattern[i]) { + // These characters have special meaning to the MatchPattern() function, + // so we escape them. + case '\\': + case '?': + output_pattern += '\\'; + // fall through + + default: + output_pattern += input_pattern[i]; + } + } + + return output_pattern; +} + + +// UserScriptSlave +UserScriptSlave::UserScriptSlave() : shared_memory_(NULL) { +} + +bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { + scripts_.clear(); + + // Create the shared memory object (read only). + shared_memory_.reset(new base::SharedMemory(shared_memory, true)); + 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* url = NULL; + int url_length = 0; + const char* body = NULL; + int body_length = 0; + + pickle.ReadData(&iter, &url, &url_length); + pickle.ReadData(&iter, &body, &body_length); + + scripts_.push_back(UserScript(StringPiece(url, url_length))); + UserScript& script = scripts_.back(); + script.Parse(StringPiece(body, body_length)); + } + + return true; +} + +bool UserScriptSlave::InjectScripts(WebFrame* frame) { + for (std::vector<UserScript>::iterator script = scripts_.begin(); + script != scripts_.end(); ++script) { + if (script->MatchesUrl(frame->GetURL())) { + frame->ExecuteJavaScript(script->GetBody().as_string(), + GURL(script->GetURL().as_string())); + } + } + + return true; +} |