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

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

Issue 19045002: Use Blink support to watch CSS selectors directly instead of using a MutationObserver. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Initial Created 7 years, 2 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
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/renderer/extensions/content_watcher.h"
6
5 #include "chrome/common/extensions/extension_messages.h" 7 #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" 8 #include "content/public/renderer/render_view.h"
11 #include "content/public/renderer/render_view_visitor.h" 9 #include "content/public/renderer/render_view_visitor.h"
12 #include "third_party/WebKit/public/web/WebDocument.h" 10 #include "third_party/WebKit/public/web/WebDocument.h"
13 #include "third_party/WebKit/public/web/WebElement.h" 11 #include "third_party/WebKit/public/web/WebElement.h"
14 #include "third_party/WebKit/public/web/WebFrame.h" 12 #include "third_party/WebKit/public/web/WebFrame.h"
13 #include "third_party/WebKit/public/web/WebScriptBindings.h"
15 #include "third_party/WebKit/public/web/WebView.h" 14 #include "third_party/WebKit/public/web/WebView.h"
16 15
17 namespace extensions { 16 namespace extensions {
18 17
19 namespace { 18 using WebKit::WebString;
19 using WebKit::WebVector;
20 using WebKit::WebView;
20 21
21 class MutationHandler : public ChromeV8Extension { 22 ContentWatcher::ContentWatcher() {}
22 public: 23 ContentWatcher::~ContentWatcher() {}
23 explicit MutationHandler(Dispatcher* dispatcher, 24
24 ChromeV8Context* context, 25 void ContentWatcher::OnWatchPages(
25 base::WeakPtr<ContentWatcher> content_watcher) 26 const std::vector<std::string>& new_css_selectors_utf8) {
26 : ChromeV8Extension(dispatcher, context), 27 std::vector<WebKit::WebString> new_css_selectors(
27 content_watcher_(content_watcher) { 28 new_css_selectors_utf8.size());
28 RouteFunction("FrameMutated", 29 bool unchanged = new_css_selectors.size() == css_selectors_.size();
Matt Perry 2013/10/02 22:20:22 nit: negative bools always confuse me. how about "
Jeffrey Yasskin 2013/10/03 00:31:57 Sounds good. Done.
29 base::Bind(&MutationHandler::FrameMutated, 30 for (size_t i = 0; i < new_css_selectors.size(); ++i) {
30 base::Unretained(this))); 31 new_css_selectors[i] =
32 WebKit::WebString::fromUTF8(new_css_selectors_utf8[i]);
33 if (unchanged && new_css_selectors[i] != css_selectors_[i])
34 unchanged = false;
31 } 35 }
32 36
33 private: 37 if (unchanged)
34 void FrameMutated(const v8::FunctionCallbackInfo<v8::Value>& args) {
35 if (content_watcher_.get()) {
36 content_watcher_->ScanAndNotify(
37 WebKit::WebFrame::frameForContext(context()->v8_context()));
38 }
39 }
40
41 base::WeakPtr<ContentWatcher> content_watcher_;
42 };
43
44 } // namespace
45
46 ContentWatcher::ContentWatcher(Dispatcher* dispatcher)
47 : weak_ptr_factory_(this),
48 dispatcher_(dispatcher) {}
49 ContentWatcher::~ContentWatcher() {}
50
51 scoped_ptr<NativeHandler> ContentWatcher::MakeNatives(
52 ChromeV8Context* context) {
53 return scoped_ptr<NativeHandler>(new MutationHandler(
54 dispatcher_, context, weak_ptr_factory_.GetWeakPtr()));
55 }
56
57 void ContentWatcher::OnWatchPages(
58 const std::vector<std::string>& new_css_selectors) {
59 if (new_css_selectors == css_selectors_)
60 return; 38 return;
61 39
62 matching_selectors_.clear();
63 css_selectors_ = new_css_selectors; 40 css_selectors_ = new_css_selectors;
Matt Perry 2013/10/02 22:20:22 more efficient to do css_selectors_.swap(new_css_s
Jeffrey Yasskin 2013/10/03 00:31:57 Ah, it does work now to build new_css_selectors as
64 41
65 // For each top-level frame, inform the browser about its new matching set of 42 // Tell each frame's document about the new set of watched selectors. These
66 // selectors. 43 // will trigger calls to DidMatchCSS after Blink has a chance to apply the new
44 // style, which will in turn notify the browser about the changes.
67 struct WatchSelectors : public content::RenderViewVisitor { 45 struct WatchSelectors : public content::RenderViewVisitor {
68 explicit WatchSelectors(ContentWatcher* watcher) : watcher_(watcher) {} 46 explicit WatchSelectors(const WebVector<WebString>& css_selectors)
47 : css_selectors_(css_selectors) {}
48
69 virtual bool Visit(content::RenderView* view) OVERRIDE { 49 virtual bool Visit(content::RenderView* view) OVERRIDE {
70 for (WebKit::WebFrame* frame = view->GetWebView()->mainFrame(); frame; 50 for (WebKit::WebFrame* frame = view->GetWebView()->mainFrame(); frame;
71 frame = frame->traverseNext(/*wrap=*/false)) { 51 frame = frame->traverseNext(/*wrap=*/false))
72 if (!watcher_->css_selectors_.empty()) 52 frame->document().watchCSSSelectors(css_selectors_);
73 watcher_->EnsureWatchingMutations(frame);
74 53
75 watcher_->matching_selectors_[frame] =
76 watcher_->FindMatchingSelectors(frame);
77 }
78 watcher_->NotifyBrowserOfChange(view->GetWebView()->mainFrame());
79 return true; // Continue visiting. 54 return true; // Continue visiting.
80 } 55 }
81 ContentWatcher* watcher_; 56
57 const WebVector<WebString>& css_selectors_;
82 }; 58 };
83 WatchSelectors visitor(this); 59 WatchSelectors visitor(css_selectors_);
84 content::RenderView::ForEach(&visitor); 60 content::RenderView::ForEach(&visitor);
85 } 61 }
86 62
87 void ContentWatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) { 63 void ContentWatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) {
88 if (!css_selectors_.empty()) { 64 frame->document().watchCSSSelectors(css_selectors_);
89 EnsureWatchingMutations(frame);
90 }
91 } 65 }
92 66
93 void ContentWatcher::EnsureWatchingMutations(WebKit::WebFrame* frame) { 67 void ContentWatcher::DidMatchCSS(
94 v8::HandleScope scope(v8::Isolate::GetCurrent()); 68 WebKit::WebFrame* frame,
95 v8::Context::Scope context_scope(frame->mainWorldScriptContext()); 69 const WebVector<WebString>& newlyMatchingSelectors,
96 if (ModuleSystem* module_system = GetModuleSystem(frame)) { 70 const WebVector<WebString>& stoppedMatchingSelectors) {
97 ModuleSystem::NativesEnabledScope scope(module_system); 71 std::set<std::string>& frame_selectors = matching_selectors_[frame];
98 module_system->Require("contentWatcher"); 72 for (size_t i = 0; i < stoppedMatchingSelectors.size(); ++i)
99 } 73 frame_selectors.erase(stoppedMatchingSelectors[i].utf8());
100 } 74 for (size_t i = 0; i < newlyMatchingSelectors.size(); ++i)
75 frame_selectors.insert(newlyMatchingSelectors[i].utf8());
101 76
102 ModuleSystem* ContentWatcher::GetModuleSystem(WebKit::WebFrame* frame) const { 77 if (frame_selectors.empty())
103 ChromeV8Context* v8_context = 78 matching_selectors_.erase(frame);
104 dispatcher_->v8_context_set().GetByV8Context(
105 frame->mainWorldScriptContext());
106 79
107 if (!v8_context)
108 return NULL;
109 return v8_context->module_system();
110 }
111
112 void ContentWatcher::ScanAndNotify(WebKit::WebFrame* frame) {
113 std::vector<base::StringPiece> new_matches = FindMatchingSelectors(frame);
114 std::vector<base::StringPiece>& old_matches = matching_selectors_[frame];
115 if (new_matches == old_matches)
116 return;
117
118 using std::swap;
119 swap(old_matches, new_matches);
120 NotifyBrowserOfChange(frame); 80 NotifyBrowserOfChange(frame);
121 } 81 }
122 82
123 std::vector<base::StringPiece> ContentWatcher::FindMatchingSelectors( 83 std::set<std::string> ContentWatcher::FindMatchingSelectors(
Matt Perry 2013/10/02 22:20:22 I don't see this method called anywhere in this CL
Jeffrey Yasskin 2013/10/03 00:31:57 You're right, it's obsolete. Deleted.
124 WebKit::WebFrame* frame) const { 84 WebKit::WebFrame* frame) const {
125 std::vector<base::StringPiece> result; 85 std::set<std::string> result;
126 WebKit::WebDocument document = frame->document(); 86 WebKit::WebDocument document = frame->document();
127 for (size_t i = 0; i < css_selectors_.size(); ++i) { 87 for (size_t i = 0; i < css_selectors_.size(); ++i) {
128 WebKit::WebExceptionCode exception = 0; 88 WebKit::WebExceptionCode exception = 0;
129 if (!document.querySelector(WebKit::WebString::fromUTF8(css_selectors_[i]), 89 if (!document.querySelector(css_selectors_[i],
130 exception).isNull()) 90 exception).isNull())
131 result.push_back(css_selectors_[i]); 91 result.insert(css_selectors_[i].utf8());
132 DCHECK_EQ(0, exception) 92 DCHECK_EQ(0, exception)
133 << "We should already have checked that the selectors are valid."; 93 << "We should already have checked that the selectors are valid.";
134 } 94 }
135 return result; 95 return result;
136 } 96 }
137 97
138 void ContentWatcher::NotifyBrowserOfChange( 98 void ContentWatcher::NotifyBrowserOfChange(
139 WebKit::WebFrame* changed_frame) const { 99 WebKit::WebFrame* changed_frame) const {
140 WebKit::WebFrame* const top_frame = changed_frame->top(); 100 WebKit::WebFrame* const top_frame = changed_frame->top();
141 const WebKit::WebSecurityOrigin top_origin = 101 const WebKit::WebSecurityOrigin top_origin =
142 top_frame->document().securityOrigin(); 102 top_frame->document().securityOrigin();
143 // Want to aggregate matched selectors from all frames where an 103 // Want to aggregate matched selectors from all frames where an
144 // extension with access to top_origin could run on the frame. 104 // extension with access to top_origin could run on the frame.
145 if (!top_origin.canAccess(changed_frame->document().securityOrigin())) { 105 if (!top_origin.canAccess(changed_frame->document().securityOrigin())) {
146 // If the changed frame can't be accessed by the top frame, then 106 // If the changed frame can't be accessed by the top frame, then
147 // no change in it could affect the set of selectors we'd send back. 107 // no change in it could affect the set of selectors we'd send back.
148 return; 108 return;
149 } 109 }
150 110
151 std::set<base::StringPiece> transitive_selectors; 111 std::set<base::StringPiece> transitive_selectors;
152 for (WebKit::WebFrame* frame = top_frame; frame; 112 for (WebKit::WebFrame* frame = top_frame; frame;
153 frame = frame->traverseNext(/*wrap=*/false)) { 113 frame = frame->traverseNext(/*wrap=*/false)) {
154 if (top_origin.canAccess(frame->document().securityOrigin())) { 114 if (top_origin.canAccess(frame->document().securityOrigin())) {
155 std::map<WebKit::WebFrame*, 115 std::map<WebKit::WebFrame*, std::set<std::string> >::const_iterator
156 std::vector<base::StringPiece> >::const_iterator
157 frame_selectors = matching_selectors_.find(frame); 116 frame_selectors = matching_selectors_.find(frame);
158 if (frame_selectors != matching_selectors_.end()) { 117 if (frame_selectors != matching_selectors_.end()) {
159 transitive_selectors.insert(frame_selectors->second.begin(), 118 transitive_selectors.insert(frame_selectors->second.begin(),
160 frame_selectors->second.end()); 119 frame_selectors->second.end());
161 } 120 }
162 } 121 }
163 } 122 }
164 std::vector<std::string> selector_strings; 123 std::vector<std::string> selector_strings;
165 for (std::set<base::StringPiece>::const_iterator 124 for (std::set<base::StringPiece>::const_iterator
166 it = transitive_selectors.begin(); 125 it = transitive_selectors.begin();
167 it != transitive_selectors.end(); ++it) 126 it != transitive_selectors.end(); ++it)
168 selector_strings.push_back(it->as_string()); 127 selector_strings.push_back(it->as_string());
169 content::RenderView* view = 128 content::RenderView* view =
170 content::RenderView::FromWebView(top_frame->view()); 129 content::RenderView::FromWebView(top_frame->view());
171 view->Send(new ExtensionHostMsg_OnWatchedPageChange( 130 view->Send(new ExtensionHostMsg_OnWatchedPageChange(
172 view->GetRoutingID(), selector_strings)); 131 view->GetRoutingID(), selector_strings));
173 } 132 }
174 133
175 } // namespace extensions 134 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698