summaryrefslogtreecommitdiff
path: root/chromium/extensions/renderer/content_watcher.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/extensions/renderer/content_watcher.cc')
-rw-r--r--chromium/extensions/renderer/content_watcher.cc125
1 files changed, 125 insertions, 0 deletions
diff --git a/chromium/extensions/renderer/content_watcher.cc b/chromium/extensions/renderer/content_watcher.cc
new file mode 100644
index 00000000000..8c99e11364c
--- /dev/null
+++ b/chromium/extensions/renderer/content_watcher.cc
@@ -0,0 +1,125 @@
+// Copyright 2014 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 "extensions/renderer/content_watcher.h"
+
+#include <stddef.h>
+
+#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/render_view_visitor.h"
+#include "extensions/common/extension_messages.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebView.h"
+
+namespace extensions {
+
+using blink::WebString;
+using blink::WebVector;
+using blink::WebView;
+
+ContentWatcher::ContentWatcher() {}
+ContentWatcher::~ContentWatcher() {}
+
+void ContentWatcher::OnWatchPages(
+ const std::vector<std::string>& new_css_selectors_utf8) {
+ blink::WebVector<blink::WebString> new_css_selectors(
+ new_css_selectors_utf8.size());
+ bool changed = new_css_selectors.size() != css_selectors_.size();
+ for (size_t i = 0; i < new_css_selectors.size(); ++i) {
+ new_css_selectors[i] =
+ blink::WebString::fromUTF8(new_css_selectors_utf8[i]);
+ if (!changed && new_css_selectors[i] != css_selectors_[i])
+ changed = true;
+ }
+
+ if (!changed)
+ return;
+
+ css_selectors_.swap(new_css_selectors);
+
+ // Tell each frame's document about the new set of watched selectors. These
+ // will trigger calls to DidMatchCSS after Blink has a chance to apply the new
+ // style, which will in turn notify the browser about the changes.
+ struct WatchSelectors : public content::RenderViewVisitor {
+ explicit WatchSelectors(const WebVector<WebString>& css_selectors)
+ : css_selectors_(css_selectors) {}
+
+ bool Visit(content::RenderView* view) override {
+ // TODO(dcheng): This should be rewritten to be frame-oriented. It
+ // probably breaks declarative content for OOPI.
+ for (blink::WebFrame* frame = view->GetWebView()->mainFrame(); frame;
+ frame = frame->traverseNext(/*wrap=*/false)) {
+ if (frame->isWebRemoteFrame())
+ continue;
+ frame->toWebLocalFrame()->document().watchCSSSelectors(css_selectors_);
+ }
+
+ return true; // Continue visiting.
+ }
+
+ const WebVector<WebString>& css_selectors_;
+ };
+ WatchSelectors visitor(css_selectors_);
+ content::RenderView::ForEach(&visitor);
+}
+
+void ContentWatcher::DidCreateDocumentElement(blink::WebLocalFrame* frame) {
+ frame->document().watchCSSSelectors(css_selectors_);
+}
+
+void ContentWatcher::DidMatchCSS(
+ blink::WebLocalFrame* frame,
+ const WebVector<WebString>& newly_matching_selectors,
+ const WebVector<WebString>& stopped_matching_selectors) {
+ std::set<std::string>& frame_selectors = matching_selectors_[frame];
+ for (size_t i = 0; i < stopped_matching_selectors.size(); ++i)
+ frame_selectors.erase(stopped_matching_selectors[i].utf8());
+ for (size_t i = 0; i < newly_matching_selectors.size(); ++i)
+ frame_selectors.insert(newly_matching_selectors[i].utf8());
+
+ if (frame_selectors.empty())
+ matching_selectors_.erase(frame);
+
+ NotifyBrowserOfChange(frame);
+}
+
+void ContentWatcher::NotifyBrowserOfChange(
+ blink::WebLocalFrame* changed_frame) const {
+ blink::WebFrame* const top_frame = changed_frame->top();
+ const blink::WebSecurityOrigin top_origin = top_frame->getSecurityOrigin();
+ // Want to aggregate matched selectors from all frames where an
+ // extension with access to top_origin could run on the frame.
+ if (!top_origin.canAccess(changed_frame->document().getSecurityOrigin())) {
+ // If the changed frame can't be accessed by the top frame, then
+ // no change in it could affect the set of selectors we'd send back.
+ return;
+ }
+
+ std::set<base::StringPiece> transitive_selectors;
+ for (blink::WebFrame* frame = top_frame; frame;
+ frame = frame->traverseNext(/*wrap=*/false)) {
+ if (top_origin.canAccess(frame->getSecurityOrigin())) {
+ std::map<blink::WebFrame*, std::set<std::string> >::const_iterator
+ frame_selectors = matching_selectors_.find(frame);
+ if (frame_selectors != matching_selectors_.end()) {
+ transitive_selectors.insert(frame_selectors->second.begin(),
+ frame_selectors->second.end());
+ }
+ }
+ }
+ std::vector<std::string> selector_strings;
+ for (std::set<base::StringPiece>::const_iterator it =
+ transitive_selectors.begin();
+ it != transitive_selectors.end();
+ ++it)
+ selector_strings.push_back(it->as_string());
+ content::RenderView* view =
+ content::RenderView::FromWebView(top_frame->view());
+ view->Send(new ExtensionHostMsg_OnWatchedPageChange(view->GetRoutingID(),
+ selector_strings));
+}
+
+} // namespace extensions