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

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

Issue 12326052: Using the new webkit CSS change notification instead of a mutation observer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months 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
« no previous file with comments | « chrome/renderer/extensions/content_watcher.h ('k') | chrome/renderer/extensions/dispatcher.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/common/extensions/extension_messages.h" 5 #include "chrome/common/extensions/extension_messages.h"
6 #include "chrome/renderer/extensions/chrome_v8_context.h" 6 #include "chrome/renderer/extensions/chrome_v8_context.h"
7 #include "chrome/renderer/extensions/chrome_v8_extension.h" 7 #include "chrome/renderer/extensions/chrome_v8_extension.h"
8 #include "chrome/renderer/extensions/content_watcher.h" 8 #include "chrome/renderer/extensions/content_watcher.h"
9 #include "chrome/renderer/extensions/dispatcher.h" 9 #include "chrome/renderer/extensions/dispatcher.h"
10 #include "content/public/renderer/render_view.h" 10 #include "content/public/renderer/render_view.h"
11 #include "content/public/renderer/render_view_visitor.h" 11 #include "content/public/renderer/render_view_visitor.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" 12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" 13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" 14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
15 15
16 namespace extensions { 16 namespace extensions {
17 17
18 namespace { 18 using WebKit::WebString;
19 class MutationHandler : public ChromeV8Extension { 19 using WebKit::WebVector;
20 public: 20 using WebKit::WebView;
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 21
44 ContentWatcher::ContentWatcher(Dispatcher* dispatcher) 22 ContentWatcher::ContentWatcher(Dispatcher* dispatcher)
45 : weak_ptr_factory_(this), 23 : weak_ptr_factory_(this),
46 dispatcher_(dispatcher) {} 24 dispatcher_(dispatcher) {}
47 ContentWatcher::~ContentWatcher() {} 25 ContentWatcher::~ContentWatcher() {}
48 26
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( 27 void ContentWatcher::OnWatchPages(
55 const std::vector<std::string>& new_css_selectors) { 28 const std::vector<std::string>& new_css_selectors) {
56 if (new_css_selectors == css_selectors_) 29 if (new_css_selectors == css_selectors_)
57 return; 30 return;
58 31
32 std::string rules;
33 // Turn off callbacks for old selectors.
34 for (size_t i = 0; i < css_selectors_.size(); ++i) {
35 rules.append(css_selectors_[i]);
36 rules.append("{callback:none}\n");
37 }
38
59 css_selectors_ = new_css_selectors; 39 css_selectors_ = new_css_selectors;
60 40
61 for (std::map<WebKit::WebFrame*, 41 // Turn on callbacks for new selectors.
62 std::vector<base::StringPiece> >::iterator 42 for (size_t i = 0; i < css_selectors_.size(); ++i) {
43 rules.append(css_selectors_[i]);
44 rules.append("{-webkit-callback:-webkit-presence}\n");
45 }
46
47 for (std::map<WebKit::WebFrame*, std::set<std::string> >::iterator
63 it = matching_selectors_.begin(); 48 it = matching_selectors_.begin();
64 it != matching_selectors_.end(); ++it) { 49 it != matching_selectors_.end(); ++it) {
65 WebKit::WebFrame* frame = it->first; 50 WebKit::WebFrame* frame = it->first;
66 if (!css_selectors_.empty()) 51 if (!css_selectors_.empty())
67 EnsureWatchingMutations(frame); 52 EnsureWatchingMutations(frame);
68 53
69 // Make sure to replace the contents of it->second because it contains 54 // Update the contents of it->second since css_selectors_ could have changed
70 // dangling StringPieces that referred into the old css_selectors_ content. 55 // completely.
71 it->second = FindMatchingSelectors(frame); 56 it->second = FindMatchingSelectors(frame);
72 } 57 }
73 58
74 // For each top-level frame, inform the browser about its new matching set of 59 // For each top-level frame, inform the browser about its new matching set of
75 // selectors. 60 // selectors, and set a user style sheet to watch for changes in the future.
76 struct NotifyVisitor : public content::RenderViewVisitor { 61 struct NotifyVisitor : public content::RenderViewVisitor {
77 explicit NotifyVisitor(ContentWatcher* watcher) : watcher_(watcher) {} 62 explicit NotifyVisitor(ContentWatcher* watcher, WebString rules)
63 : watcher_(watcher),
64 rules_(rules) {}
78 virtual bool Visit(content::RenderView* view) OVERRIDE { 65 virtual bool Visit(content::RenderView* view) OVERRIDE {
79 watcher_->NotifyBrowserOfChange(view->GetWebView()->mainFrame()); 66 WebView* web_view = view->GetWebView();
67 // Notify of the matching selectors found above.
68 watcher_->NotifyBrowserOfChange(web_view->mainFrame());
69
70 // Watch for future changes.
71 web_view->addUserStyleSheet(rules_,
72 WebKit::WebVector<WebString>(), // All URLs.
73 WebView::UserContentInjectInAllFrames,
74 WebView::UserStyleInjectInExistingDocuments);
80 return true; // Continue visiting. 75 return true; // Continue visiting.
81 } 76 }
82 ContentWatcher* watcher_; 77 ContentWatcher* watcher_;
78 WebString rules_;
83 }; 79 };
84 NotifyVisitor visitor(this); 80 NotifyVisitor visitor(this, WebString::fromUTF8(rules));
85 content::RenderView::ForEach(&visitor); 81 content::RenderView::ForEach(&visitor);
86 } 82 }
87 83
84 void ContentWatcher::OnWebViewCreated(WebKit::WebView* view) {
85 std::string rules;
86 // Turn on callbacks for watched selectors.
87 for (size_t i = 0; i < css_selectors_.size(); ++i) {
88 rules.append(css_selectors_[i]);
89 rules.append("{-webkit-callback:-webkit-presence}\n");
90 }
91
92 view->addUserStyleSheet(WebString::fromUTF8(rules),
93 WebKit::WebVector<WebString>(), // All URLs.
94 WebView::UserContentInjectInAllFrames,
95 WebView::UserStyleInjectInExistingDocuments);
96 }
97
88 void ContentWatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) { 98 void ContentWatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) {
89 // Make sure the frame is represented in the matching_selectors_ map. 99 // Make sure the frame is represented in the matching_selectors_ map.
90 matching_selectors_[frame]; 100 matching_selectors_[frame];
91 101
92 if (!css_selectors_.empty()) { 102 if (!css_selectors_.empty()) {
93 EnsureWatchingMutations(frame); 103 EnsureWatchingMutations(frame);
94 } 104 }
95 } 105 }
96 106
97 void ContentWatcher::EnsureWatchingMutations(WebKit::WebFrame* frame) { 107 void ContentWatcher::EnsureWatchingMutations(WebKit::WebFrame* frame) {
98 v8::HandleScope scope; 108 v8::HandleScope scope;
99 v8::Context::Scope context_scope(frame->mainWorldScriptContext()); 109 v8::Context::Scope context_scope(frame->mainWorldScriptContext());
100 if (ModuleSystem* module_system = GetModuleSystem(frame)) { 110 if (ModuleSystem* module_system = GetModuleSystem(frame)) {
101 ModuleSystem::NativesEnabledScope scope(module_system); 111 ModuleSystem::NativesEnabledScope scope(module_system);
102 module_system->Require("contentWatcher"); 112 module_system->Require("contentWatcher");
103 } 113 }
104 } 114 }
105 115
106 ModuleSystem* ContentWatcher::GetModuleSystem(WebKit::WebFrame* frame) const { 116 ModuleSystem* ContentWatcher::GetModuleSystem(WebKit::WebFrame* frame) const {
107 ChromeV8Context* v8_context = 117 ChromeV8Context* v8_context =
108 dispatcher_->v8_context_set().GetByV8Context( 118 dispatcher_->v8_context_set().GetByV8Context(
109 frame->mainWorldScriptContext()); 119 frame->mainWorldScriptContext());
110 120
111 if (!v8_context) 121 if (!v8_context)
112 return NULL; 122 return NULL;
113 return v8_context->module_system(); 123 return v8_context->module_system();
114 } 124 }
115 125
116 void ContentWatcher::ScanAndNotify(WebKit::WebFrame* frame) { 126 void ContentWatcher::CssMatches(
117 std::vector<base::StringPiece> new_matches = FindMatchingSelectors(frame); 127 WebKit::WebFrame* frame,
118 std::vector<base::StringPiece>& old_matches = matching_selectors_[frame]; 128 const WebVector<WebString>& newlyMatchingSelectors,
119 if (new_matches == old_matches) 129 const WebVector<WebString>& stoppedMatchingSelectors) {
120 return; 130 std::set<std::string>& frame_selectors = matching_selectors_[frame];
131 for (size_t i = 0; i < stoppedMatchingSelectors.size(); ++i)
132 frame_selectors.erase(stoppedMatchingSelectors[i].utf8());
133 for (size_t i = 0; i < newlyMatchingSelectors.size(); ++i)
134 frame_selectors.insert(newlyMatchingSelectors[i].utf8());
121 135
122 using std::swap; 136 if (frame_selectors.empty())
123 swap(old_matches, new_matches); 137 matching_selectors_.erase(frame);
138
124 NotifyBrowserOfChange(frame); 139 NotifyBrowserOfChange(frame);
125 } 140 }
126 141
127 std::vector<base::StringPiece> ContentWatcher::FindMatchingSelectors( 142 std::set<std::string> ContentWatcher::FindMatchingSelectors(
128 WebKit::WebFrame* frame) const { 143 WebKit::WebFrame* frame) const {
129 std::vector<base::StringPiece> result; 144 std::set<std::string> result;
130 v8::HandleScope scope; 145 v8::HandleScope scope;
131 146
132 // Get the indices within |css_selectors_| that match elements in 147 // Get the indices within |css_selectors_| that match elements in
133 // |frame|, as a JS Array. 148 // |frame|, as a JS Array.
134 v8::Local<v8::Value> selector_indices; 149 v8::Local<v8::Value> selector_indices;
135 if (ModuleSystem* module_system = GetModuleSystem(frame)) { 150 if (ModuleSystem* module_system = GetModuleSystem(frame)) {
136 v8::Context::Scope context_scope(frame->mainWorldScriptContext()); 151 v8::Context::Scope context_scope(frame->mainWorldScriptContext());
137 v8::Local<v8::Array> js_css_selectors = 152 v8::Local<v8::Array> js_css_selectors =
138 v8::Array::New(css_selectors_.size()); 153 v8::Array::New(css_selectors_.size());
139 for (size_t i = 0; i < css_selectors_.size(); ++i) { 154 for (size_t i = 0; i < css_selectors_.size(); ++i) {
140 js_css_selectors->Set(i, v8::String::New(css_selectors_[i].data(), 155 js_css_selectors->Set(i, v8::String::New(css_selectors_[i].data(),
141 css_selectors_[i].size())); 156 css_selectors_[i].size()));
142 } 157 }
143 std::vector<v8::Handle<v8::Value> > find_selectors_args; 158 std::vector<v8::Handle<v8::Value> > find_selectors_args;
144 find_selectors_args.push_back(js_css_selectors); 159 find_selectors_args.push_back(js_css_selectors);
145 selector_indices = module_system->CallModuleMethod("contentWatcher", 160 selector_indices = module_system->CallModuleMethod("contentWatcher",
146 "FindMatchingSelectors", 161 "FindMatchingSelectors",
147 &find_selectors_args); 162 &find_selectors_args);
148 } 163 }
149 if (selector_indices.IsEmpty() || !selector_indices->IsArray()) 164 if (selector_indices.IsEmpty() || !selector_indices->IsArray())
150 return result; 165 return result;
151 166
152 // Iterate over the array, and extract the indices, laboriously 167 // Iterate over the array, and extract the indices, laboriously
153 // converting them back to integers. 168 // converting them back to integers.
154 v8::Local<v8::Array> index_array = selector_indices.As<v8::Array>(); 169 v8::Local<v8::Array> index_array = selector_indices.As<v8::Array>();
155 const size_t length = index_array->Length(); 170 const size_t length = index_array->Length();
156 result.reserve(length);
157 for (size_t i = 0; i < length; ++i) { 171 for (size_t i = 0; i < length; ++i) {
158 v8::Local<v8::Value> index_value = index_array->Get(i); 172 v8::Local<v8::Value> index_value = index_array->Get(i);
159 if (!index_value->IsNumber()) 173 if (!index_value->IsNumber())
160 continue; 174 continue;
161 double index = index_value->NumberValue(); 175 double index = index_value->NumberValue();
162 // Make sure the index is within bounds. 176 // Make sure the index is within bounds.
163 if (index < 0 || css_selectors_.size() <= index) 177 if (index < 0 || css_selectors_.size() <= index)
164 continue; 178 continue;
165 // Push a StringPiece referring to the CSS selector onto the result. 179 // Add the CSS selector to the result.
166 result.push_back( 180 result.insert(css_selectors_[static_cast<size_t>(index)]);
167 base::StringPiece(css_selectors_[static_cast<size_t>(index)]));
168 } 181 }
169 return result; 182 return result;
170 } 183 }
171 184
172 void ContentWatcher::NotifyBrowserOfChange( 185 void ContentWatcher::NotifyBrowserOfChange(
173 WebKit::WebFrame* changed_frame) const { 186 WebKit::WebFrame* changed_frame) const {
174 WebKit::WebFrame* const top_frame = changed_frame->top(); 187 WebKit::WebFrame* const top_frame = changed_frame->top();
175 const WebKit::WebSecurityOrigin top_origin = 188 const WebKit::WebSecurityOrigin top_origin =
176 top_frame->document().securityOrigin(); 189 top_frame->document().securityOrigin();
177 // Want to aggregate matched selectors from all frames where an 190 // Want to aggregate matched selectors from all frames where an
178 // extension with access to top_origin could run on the frame. 191 // extension with access to top_origin could run on the frame.
179 if (!top_origin.canAccess(changed_frame->document().securityOrigin())) { 192 if (!top_origin.canAccess(changed_frame->document().securityOrigin())) {
180 // If the changed frame can't be accessed by the top frame, then 193 // If the changed frame can't be accessed by the top frame, then
181 // no change in it could affect the set of selectors we'd send back. 194 // no change in it could affect the set of selectors we'd send back.
182 return; 195 return;
183 } 196 }
184 197
185 std::set<base::StringPiece> transitive_selectors; 198 std::set<base::StringPiece> transitive_selectors;
186 for (WebKit::WebFrame* frame = top_frame; frame; 199 for (WebKit::WebFrame* frame = top_frame; frame;
187 frame = frame->traverseNext(/*wrap=*/false)) { 200 frame = frame->traverseNext(/*wrap=*/false)) {
188 if (top_origin.canAccess(frame->document().securityOrigin())) { 201 if (top_origin.canAccess(frame->document().securityOrigin())) {
189 std::map<WebKit::WebFrame*, 202 std::map<WebKit::WebFrame*, std::set<std::string> >::const_iterator
190 std::vector<base::StringPiece> >::const_iterator
191 frame_selectors = matching_selectors_.find(frame); 203 frame_selectors = matching_selectors_.find(frame);
192 if (frame_selectors != matching_selectors_.end()) { 204 if (frame_selectors != matching_selectors_.end()) {
193 transitive_selectors.insert(frame_selectors->second.begin(), 205 transitive_selectors.insert(frame_selectors->second.begin(),
194 frame_selectors->second.end()); 206 frame_selectors->second.end());
195 } 207 }
196 } 208 }
197 } 209 }
198 std::vector<std::string> selector_strings; 210 std::vector<std::string> selector_strings;
199 for (std::set<base::StringPiece>::const_iterator 211 for (std::set<base::StringPiece>::const_iterator
200 it = transitive_selectors.begin(); 212 it = transitive_selectors.begin();
201 it != transitive_selectors.end(); ++it) 213 it != transitive_selectors.end(); ++it)
202 selector_strings.push_back(it->as_string()); 214 selector_strings.push_back(it->as_string());
203 content::RenderView* view = 215 content::RenderView* view =
204 content::RenderView::FromWebView(top_frame->view()); 216 content::RenderView::FromWebView(top_frame->view());
205 view->Send(new ExtensionHostMsg_OnWatchedPageChange( 217 view->Send(new ExtensionHostMsg_OnWatchedPageChange(
206 view->GetRoutingID(), selector_strings)); 218 view->GetRoutingID(), selector_strings));
207 } 219 }
208 220
209 } // namespace extensions 221 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/content_watcher.h ('k') | chrome/renderer/extensions/dispatcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698