OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/user_script_slave.h" | 5 #include "chrome/renderer/user_script_slave.h" |
6 | 6 |
7 #include "app/resource_bundle.h" | 7 #include "app/resource_bundle.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/histogram.h" | 9 #include "base/histogram.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/perftimer.h" | 11 #include "base/perftimer.h" |
12 #include "base/pickle.h" | 12 #include "base/pickle.h" |
13 #include "base/shared_memory.h" | 13 #include "base/shared_memory.h" |
14 #include "base/string_util.h" | 14 #include "base/string_util.h" |
15 #include "chrome/common/chrome_switches.h" | 15 #include "chrome/common/chrome_switches.h" |
16 #include "chrome/common/extensions/extension.h" | 16 #include "chrome/common/extensions/extension.h" |
17 #include "chrome/common/extensions/extension_constants.h" | 17 #include "chrome/common/extensions/extension_constants.h" |
| 18 #include "chrome/common/extensions/extension_message_bundle.h" |
| 19 #include "chrome/common/render_messages.h" |
18 #include "chrome/renderer/extension_groups.h" | 20 #include "chrome/renderer/extension_groups.h" |
19 #include "chrome/renderer/render_thread.h" | 21 #include "chrome/renderer/render_thread.h" |
20 #include "googleurl/src/gurl.h" | 22 #include "googleurl/src/gurl.h" |
21 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" | 23 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" |
22 | 24 |
23 #include "grit/renderer_resources.h" | 25 #include "grit/renderer_resources.h" |
24 | 26 |
25 using WebKit::WebFrame; | 27 using WebKit::WebFrame; |
26 using WebKit::WebString; | 28 using WebKit::WebString; |
27 | 29 |
(...skipping 20 matching lines...) Expand all Loading... |
48 | 50 |
49 int new_id = g_next_isolated_world_id; | 51 int new_id = g_next_isolated_world_id; |
50 ++g_next_isolated_world_id; | 52 ++g_next_isolated_world_id; |
51 | 53 |
52 // This map will tend to pile up over time, but realistically, you're never | 54 // This map will tend to pile up over time, but realistically, you're never |
53 // going to have enough extensions for it to matter. | 55 // going to have enough extensions for it to matter. |
54 g_isolated_world_ids[extension_id] = new_id; | 56 g_isolated_world_ids[extension_id] = new_id; |
55 return new_id; | 57 return new_id; |
56 } | 58 } |
57 | 59 |
58 UserScriptSlave::UserScriptSlave() | 60 UserScriptSlave::UserScriptSlave(RenderThreadBase* message_sender) |
59 : shared_memory_(NULL), | 61 : shared_memory_(NULL), |
60 script_deleter_(&scripts_) { | 62 script_deleter_(&scripts_), |
| 63 render_thread_(message_sender) { |
61 api_js_ = ResourceBundle::GetSharedInstance().GetRawDataResource( | 64 api_js_ = ResourceBundle::GetSharedInstance().GetRawDataResource( |
62 IDR_GREASEMONKEY_API_JS); | 65 IDR_GREASEMONKEY_API_JS); |
63 } | 66 } |
64 | 67 |
65 void UserScriptSlave::GetActiveExtensions(std::set<std::string>* extension_ids)
{ | 68 void UserScriptSlave::GetActiveExtensions(std::set<std::string>* extension_ids)
{ |
66 for (size_t i = 0; i < scripts_.size(); ++i) { | 69 for (size_t i = 0; i < scripts_.size(); ++i) { |
67 DCHECK(!scripts_[i]->extension_id().empty()); | 70 DCHECK(!scripts_[i]->extension_id().empty()); |
68 extension_ids->insert(scripts_[i]->extension_id()); | 71 extension_ids->insert(scripts_[i]->extension_id()); |
69 } | 72 } |
70 } | 73 } |
71 | 74 |
72 bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { | 75 // Fetches l10n messages from browser, and populates the map. |
| 76 // Returns empty map if extension_id is empty or content script doesn't have |
| 77 // css scripts. |
| 78 static void GetL10nMessagesForExtension( |
| 79 const UserScript* script, |
| 80 RenderThreadBase* message_sender, |
| 81 L10nMessagesMap* messages) { |
| 82 DCHECK(script); |
| 83 DCHECK(message_sender); |
| 84 DCHECK(messages); |
| 85 const std::string extension_id = script->extension_id(); |
| 86 if (!extension_id.empty() && !script->css_scripts().empty()) { |
| 87 // Always fetch messages, since files were updated. We don't want to have |
| 88 // stale content. |
| 89 message_sender->Send(new ViewHostMsg_GetExtensionMessageBundle( |
| 90 extension_id, messages)); |
| 91 } |
| 92 } |
| 93 |
| 94 // Sets external content for each js/css script file. |
| 95 // Message placeholders are replaced in scripts if localization catalog is |
| 96 // available and should_localize is true. |
| 97 static void SetExternalContent(const Pickle& pickle, |
| 98 void** iter, |
| 99 const L10nMessagesMap& l10n_messages, |
| 100 UserScript::File* script, |
| 101 bool should_localize) { |
| 102 const char* body = NULL; |
| 103 int body_length = 0; |
| 104 CHECK(pickle.ReadData(iter, &body, &body_length)); |
| 105 std::string localized_body(body, body_length); |
| 106 std::string error; |
| 107 if (!l10n_messages.empty() && should_localize) { |
| 108 ExtensionMessageBundle::ReplaceMessagesWithExternalDictionary( |
| 109 l10n_messages, &localized_body, &error); |
| 110 } |
| 111 script->set_external_content( |
| 112 base::StringPiece(localized_body.data(), localized_body.length())); |
| 113 } |
| 114 |
| 115 bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory, |
| 116 bool is_incognito_process) { |
73 scripts_.clear(); | 117 scripts_.clear(); |
74 | 118 |
75 bool only_inject_incognito = RenderThread::current()->is_incognito_process(); | |
76 | |
77 // Create the shared memory object (read only). | 119 // Create the shared memory object (read only). |
78 shared_memory_.reset(new base::SharedMemory(shared_memory, true)); | 120 shared_memory_.reset(new base::SharedMemory(shared_memory, true)); |
79 if (!shared_memory_.get()) | 121 if (!shared_memory_.get()) |
80 return false; | 122 return false; |
81 | 123 |
82 // First get the size of the memory block. | 124 // First get the size of the memory block. |
83 if (!shared_memory_->Map(sizeof(Pickle::Header))) | 125 if (!shared_memory_->Map(sizeof(Pickle::Header))) |
84 return false; | 126 return false; |
85 Pickle::Header* pickle_header = | 127 Pickle::Header* pickle_header = |
86 reinterpret_cast<Pickle::Header*>(shared_memory_->memory()); | 128 reinterpret_cast<Pickle::Header*>(shared_memory_->memory()); |
87 | 129 |
88 // Now map in the rest of the block. | 130 // Now map in the rest of the block. |
89 int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size; | 131 int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size; |
90 shared_memory_->Unmap(); | 132 shared_memory_->Unmap(); |
91 if (!shared_memory_->Map(pickle_size)) | 133 if (!shared_memory_->Map(pickle_size)) |
92 return false; | 134 return false; |
93 | 135 |
94 // Unpickle scripts. | 136 // Unpickle scripts. |
95 void* iter = NULL; | 137 void* iter = NULL; |
96 size_t num_scripts = 0; | 138 size_t num_scripts = 0; |
97 Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), | 139 Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), |
98 pickle_size); | 140 pickle_size); |
99 pickle.ReadSize(&iter, &num_scripts); | 141 pickle.ReadSize(&iter, &num_scripts); |
100 | |
101 scripts_.reserve(num_scripts); | 142 scripts_.reserve(num_scripts); |
102 for (size_t i = 0; i < num_scripts; ++i) { | 143 for (size_t i = 0; i < num_scripts; ++i) { |
103 scripts_.push_back(new UserScript()); | 144 scripts_.push_back(new UserScript()); |
104 UserScript* script = scripts_.back(); | 145 UserScript* script = scripts_.back(); |
105 script->Unpickle(pickle, &iter); | 146 script->Unpickle(pickle, &iter); |
106 | 147 |
| 148 // We need to fetch message catalogs for each script that has extension id |
| 149 // and at least one css script. |
| 150 L10nMessagesMap l10n_messages; |
| 151 GetL10nMessagesForExtension(script, render_thread_, &l10n_messages); |
| 152 |
107 // Note that this is a pointer into shared memory. We don't own it. It gets | 153 // Note that this is a pointer into shared memory. We don't own it. It gets |
108 // cleared up when the last renderer or browser process drops their | 154 // cleared up when the last renderer or browser process drops their |
109 // reference to the shared memory. | 155 // reference to the shared memory. |
110 for (size_t j = 0; j < script->js_scripts().size(); ++j) { | 156 for (size_t j = 0; j < script->js_scripts().size(); ++j) { |
111 const char* body = NULL; | 157 SetExternalContent( |
112 int body_length = 0; | 158 pickle, &iter, l10n_messages, &script->js_scripts()[j], false); |
113 CHECK(pickle.ReadData(&iter, &body, &body_length)); | |
114 script->js_scripts()[j].set_external_content( | |
115 base::StringPiece(body, body_length)); | |
116 } | 159 } |
117 for (size_t j = 0; j < script->css_scripts().size(); ++j) { | 160 for (size_t j = 0; j < script->css_scripts().size(); ++j) { |
118 const char* body = NULL; | 161 SetExternalContent( |
119 int body_length = 0; | 162 pickle, &iter, l10n_messages, &script->css_scripts()[j], true); |
120 CHECK(pickle.ReadData(&iter, &body, &body_length)); | |
121 script->css_scripts()[j].set_external_content( | |
122 base::StringPiece(body, body_length)); | |
123 } | 163 } |
124 | 164 |
125 if (only_inject_incognito && !script->is_incognito_enabled()) { | 165 if (is_incognito_process && !script->is_incognito_enabled()) { |
126 // This script shouldn't run in an incognito tab. | 166 // This script shouldn't run in an incognito tab. |
127 delete script; | 167 delete script; |
128 scripts_.pop_back(); | 168 scripts_.pop_back(); |
129 } | 169 } |
130 } | 170 } |
131 | 171 |
132 return true; | 172 return true; |
133 } | 173 } |
134 | 174 |
135 // static | 175 // static |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 if (num_scripts) | 276 if (num_scripts) |
237 UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", timer.Elapsed()); | 277 UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", timer.Elapsed()); |
238 } else { | 278 } else { |
239 NOTREACHED(); | 279 NOTREACHED(); |
240 } | 280 } |
241 | 281 |
242 LOG(INFO) << "Injected " << num_scripts << " scripts and " << num_css << | 282 LOG(INFO) << "Injected " << num_scripts << " scripts and " << num_css << |
243 "css files into " << frame->url().spec().data(); | 283 "css files into " << frame->url().spec().data(); |
244 return true; | 284 return true; |
245 } | 285 } |
OLD | NEW |