Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: chrome/renderer/extensions/content_watcher.cc

Issue 11547033: Implement declarativeContent API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/common/extensions/extension_messages.h"
6 #include "chrome/renderer/extensions/chrome_v8_context.h"
7 #include "chrome/renderer/extensions/chrome_v8_extension.h"
8 #include "chrome/renderer/extensions/content_watcher.h"
9 #include "chrome/renderer/extensions/dispatcher.h"
10 #include "content/public/renderer/render_view.h"
11 #include "content/public/renderer/render_view_visitor.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
15
16 namespace extensions {
17
18 namespace {
19 class MutationHandler : public ChromeV8Extension {
20 public:
21 explicit MutationHandler(Dispatcher* dispatcher,
22 base::WeakPtr<ContentWatcher> content_watcher)
23 : ChromeV8Extension(dispatcher),
24 content_watcher_(content_watcher) {
25 RouteFunction("FrameMutated",
26 base::Bind(&MutationHandler::FrameMutated,
27 base::Unretained(this)));
28 }
29
30 private:
31 v8::Handle<v8::Value> FrameMutated(const v8::Arguments& args) {
32 if (content_watcher_) {
33 content_watcher_->ScanAndNotify(
34 WebKit::WebFrame::frameForCurrentContext());
35 }
36 return v8::Undefined();
37 }
38
39 base::WeakPtr<ContentWatcher> content_watcher_;
40 };
41
42 } // namespace
43
44 ContentWatcher::ContentWatcher(Dispatcher* dispatcher)
45 : weak_ptr_factory_(this),
46 dispatcher_(dispatcher) {}
47 ContentWatcher::~ContentWatcher() {}
48
49 scoped_ptr<NativeHandler> ContentWatcher::MakeNatives() {
50 return scoped_ptr<NativeHandler>(
51 new MutationHandler(dispatcher_, weak_ptr_factory_.GetWeakPtr()));
52 }
53
54 void ContentWatcher::OnWatchPages(
55 const std::vector<std::string>& new_css_selectors) {
56 if (new_css_selectors == css_selectors_)
57 return;
58
59 css_selectors_ = new_css_selectors;
60
61 for (std::map<WebKit::WebFrame*,
62 std::vector<base::StringPiece> >::iterator
63 it = matching_selectors_.begin();
64 it != matching_selectors_.end(); ++it) {
65 WebKit::WebFrame* frame = it->first;
66 if (!css_selectors_.empty())
67 EnsureWatchingMutations(frame);
68
69 // Make sure to replace the contents of it->second because it contains
70 // dangling StringPieces that referred into the old css_selectors_ content.
71 it->second = FindMatchingSelectors(frame);
72 }
73
74 // For each top-level frame, inform the browser about its new matching set of
75 // selectors.
76 struct NotifyVisitor : public content::RenderViewVisitor {
77 explicit NotifyVisitor(ContentWatcher* watcher) : watcher_(watcher) {}
78 virtual bool Visit(content::RenderView* view) {
79 watcher_->NotifyBrowserOfChange(view->GetWebView()->mainFrame());
80 return true; // Continue visiting.
81 }
82 ContentWatcher* watcher_;
83 };
84 NotifyVisitor visitor(this);
85 content::RenderView::ForEach(&visitor);
86 }
87
88 void ContentWatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) {
89 // Make sure the frame is represented in the matching_selectors_ map.
90 matching_selectors_[frame];
91
92 if (!css_selectors_.empty()) {
93 EnsureWatchingMutations(frame);
94 }
95 }
96
97 void ContentWatcher::EnsureWatchingMutations(WebKit::WebFrame* frame) {
98 v8::HandleScope scope;
99 v8::Context::Scope context_scope(frame->mainWorldScriptContext());
100 if (ModuleSystem* module_system = GetModuleSystem(frame)) {
101 ModuleSystem::NativesEnabledScope scope(module_system);
102 module_system->Require("contentWatcher");
103 }
104 }
105
106 ModuleSystem* ContentWatcher::GetModuleSystem(WebKit::WebFrame* frame) const {
107 ChromeV8Context* v8_context =
108 dispatcher_->v8_context_set().GetByV8Context(
109 frame->mainWorldScriptContext());
110
111 if (!v8_context)
112 return NULL;
113 return v8_context->module_system();
114 }
115
116 void ContentWatcher::ScanAndNotify(WebKit::WebFrame* frame) {
117 std::vector<base::StringPiece> new_matches = FindMatchingSelectors(frame);
118 std::vector<base::StringPiece>& old_matches = matching_selectors_[frame];
119 if (new_matches == old_matches)
120 return;
121
122 old_matches = new_matches;
123 NotifyBrowserOfChange(frame);
124 }
125
126 std::vector<base::StringPiece> ContentWatcher::FindMatchingSelectors(
127 WebKit::WebFrame* frame) const {
128 std::vector<base::StringPiece> result;
129 v8::HandleScope scope;
130
131 // Get the indices within |css_selectors_| that match elements in
132 // |frame|, as a JS Array.
133 v8::Local<v8::Value> selector_indices;
134 if (ModuleSystem* module_system = GetModuleSystem(frame)) {
135 v8::Context::Scope context_scope(frame->mainWorldScriptContext());
136 v8::Local<v8::Array> js_css_selectors =
137 v8::Array::New(css_selectors_.size());
138 for (size_t i = 0; i < css_selectors_.size(); ++i) {
139 js_css_selectors->Set(i, v8::String::New(css_selectors_[i].c_str(),
140 css_selectors_[i].size()));
141 }
142 std::vector<v8::Handle<v8::Value> > find_selectors_args;
143 find_selectors_args.push_back(js_css_selectors);
144 selector_indices = module_system->CallModuleMethod("contentWatcher",
145 "FindMatchingSelectors",
146 &find_selectors_args);
147 }
148 if (selector_indices.IsEmpty() || !selector_indices->IsArray())
149 return result;
150
151 // Iterate over the array, and extract the indices, laboriously
152 // converting them back to integers.
153 v8::Local<v8::Array> index_array = selector_indices.As<v8::Array>();
154 const size_t length = index_array->Length();
155 result.reserve(length);
156 for (size_t i = 0; i < length; ++i) {
157 v8::Local<v8::Value> index_value = index_array->Get(i);
158 if (!index_value->IsNumber())
159 continue;
160 double index = index_value->NumberValue();
161 // Make sure the index is within bounds.
162 if (index < 0 || css_selectors_.size() <= index)
163 continue;
164 // Push a StringPiece referring to the CSS selector onto the result.
165 result.push_back(
166 base::StringPiece(css_selectors_[static_cast<size_t>(index)]));
167 }
168 return result;
169 }
170
171 void ContentWatcher::NotifyBrowserOfChange(
172 WebKit::WebFrame* changed_frame) const {
173 WebKit::WebFrame* const top_frame = changed_frame->top();
174 const WebKit::WebSecurityOrigin top_origin =
175 top_frame->document().securityOrigin();
176 // Want to aggregate matched selectors from all frames where an
177 // extension with access to top_origin could run on the frame.
178 if (!top_origin.canAccess(changed_frame->document().securityOrigin())) {
179 // If the changed frame can't be accessed by the top frame, than
180 // no change in it could affect the set of selectors we'd send back.
181 return;
182 }
183
184 std::set<base::StringPiece> transitive_selectors;
185 for (WebKit::WebFrame* frame = top_frame; frame;
186 frame = frame->traverseNext(/*wrap=*/false)) {
187 if (top_origin.canAccess(frame->document().securityOrigin())) {
188 std::map<WebKit::WebFrame*,
189 std::vector<base::StringPiece> >::const_iterator
190 frame_selectors = matching_selectors_.find(frame);
191 if (frame_selectors != matching_selectors_.end()) {
192 transitive_selectors.insert(frame_selectors->second.begin(),
193 frame_selectors->second.end());
194 }
195 }
196 }
197 std::vector<std::string> selector_strings;
198 for (std::set<base::StringPiece>::const_iterator
199 it = transitive_selectors.begin();
200 it != transitive_selectors.end(); ++it)
201 selector_strings.push_back(it->as_string());
202 content::RenderView* view =
203 content::RenderView::FromWebView(top_frame->view());
204 view->Send(new ExtensionHostMsg_OnWatchedPageChange(
205 view->GetRoutingID(), selector_strings));
206 }
207
208 #if 0
209 void RunHelperJs(WebKit::WebFrame* frame) {
210 v8::HandleScope handle_scope;
211
212 ResourceBundleSourceMap source_map_;
213 std::string module_name = "contentWatcher";
214 source_map_.RegisterSource(module_name, IDR_CONTENT_WATCHER_JS);
215
216 v8::Handle<v8::Value> source = source_map_->GetSource(module_name);
217
218 v8::Handle<v8::Function> func =
219 v8::Handle<v8::Function>::Cast(RunString(source, module_name));
220
221 exports = v8::Object::New();
222 v8::Handle<v8::Object> natives(NewInstance());
223 v8::Handle<v8::Value> args[] = {
224 natives->Get(v8::String::NewSymbol("require")),
225 natives->Get(v8::String::NewSymbol("requireNative")),
226 exports,
227 };
228 {
229 WebKit::WebScopedMicrotaskSuppression suppression;
230 v8::TryCatch try_catch;
231 try_catch.SetCaptureMessage(true);
232 func->Call(global, 3, args);
233 if (try_catch.HasCaught()) {
234 DumpException(try_catch);
235 return v8::Undefined();
236 }
237 }
238 v8::Handle<v8::Function> find_matching_selectors =
239 exports.Get("FindMatchingSelectors");
240 }
241 #endif
242
243 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698