1 // Copyright 2014 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 "extensions/renderer/content_watcher.h" 6 7 #include "content/public/renderer/render_view.h" 8 #include "content/public/renderer/render_view_visitor.h" 9 #include "extensions/common/extension_messages.h" 10 #include "third_party/WebKit/public/web/WebDocument.h" 11 #include "third_party/WebKit/public/web/WebElement.h" 12 #include "third_party/WebKit/public/web/WebFrame.h" 13 #include "third_party/WebKit/public/web/WebScriptBindings.h" 14 #include "third_party/WebKit/public/web/WebView.h" 15 16 namespace extensions { 17 18 using blink::WebString; 19 using blink::WebVector; 20 using blink::WebView; 21 ContentWatcher()22ContentWatcher::ContentWatcher() {} ~ContentWatcher()23ContentWatcher::~ContentWatcher() {} 24 OnWatchPages(const std::vector<std::string> & new_css_selectors_utf8)25void ContentWatcher::OnWatchPages( 26 const std::vector<std::string>& new_css_selectors_utf8) { 27 blink::WebVector<blink::WebString> new_css_selectors( 28 new_css_selectors_utf8.size()); 29 bool changed = new_css_selectors.size() != css_selectors_.size(); 30 for (size_t i = 0; i < new_css_selectors.size(); ++i) { 31 new_css_selectors[i] = 32 blink::WebString::fromUTF8(new_css_selectors_utf8[i]); 33 if (!changed && new_css_selectors[i] != css_selectors_[i]) 34 changed = true; 35 } 36 37 if (!changed) 38 return; 39 40 css_selectors_.swap(new_css_selectors); 41 42 // Tell each frame's document about the new set of watched selectors. These 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. 45 struct WatchSelectors : public content::RenderViewVisitor { 46 explicit WatchSelectors(const WebVector<WebString>& css_selectors) 47 : css_selectors_(css_selectors) {} 48 49 virtual bool Visit(content::RenderView* view) OVERRIDE { 50 for (blink::WebFrame* frame = view->GetWebView()->mainFrame(); frame; 51 frame = frame->traverseNext(/*wrap=*/false)) 52 frame->document().watchCSSSelectors(css_selectors_); 53 54 return true; // Continue visiting. 55 } 56 57 const WebVector<WebString>& css_selectors_; 58 }; 59 WatchSelectors visitor(css_selectors_); 60 content::RenderView::ForEach(&visitor); 61 } 62 DidCreateDocumentElement(blink::WebFrame * frame)63void ContentWatcher::DidCreateDocumentElement(blink::WebFrame* frame) { 64 frame->document().watchCSSSelectors(css_selectors_); 65 } 66 DidMatchCSS(blink::WebFrame * frame,const WebVector<WebString> & newly_matching_selectors,const WebVector<WebString> & stopped_matching_selectors)67void ContentWatcher::DidMatchCSS( 68 blink::WebFrame* frame, 69 const WebVector<WebString>& newly_matching_selectors, 70 const WebVector<WebString>& stopped_matching_selectors) { 71 std::set<std::string>& frame_selectors = matching_selectors_[frame]; 72 for (size_t i = 0; i < stopped_matching_selectors.size(); ++i) 73 frame_selectors.erase(stopped_matching_selectors[i].utf8()); 74 for (size_t i = 0; i < newly_matching_selectors.size(); ++i) 75 frame_selectors.insert(newly_matching_selectors[i].utf8()); 76 77 if (frame_selectors.empty()) 78 matching_selectors_.erase(frame); 79 80 NotifyBrowserOfChange(frame); 81 } 82 NotifyBrowserOfChange(blink::WebFrame * changed_frame) const83void ContentWatcher::NotifyBrowserOfChange( 84 blink::WebFrame* changed_frame) const { 85 blink::WebFrame* const top_frame = changed_frame->top(); 86 const blink::WebSecurityOrigin top_origin = 87 top_frame->document().securityOrigin(); 88 // Want to aggregate matched selectors from all frames where an 89 // extension with access to top_origin could run on the frame. 90 if (!top_origin.canAccess(changed_frame->document().securityOrigin())) { 91 // If the changed frame can't be accessed by the top frame, then 92 // no change in it could affect the set of selectors we'd send back. 93 return; 94 } 95 96 std::set<base::StringPiece> transitive_selectors; 97 for (blink::WebFrame* frame = top_frame; frame; 98 frame = frame->traverseNext(/*wrap=*/false)) { 99 if (top_origin.canAccess(frame->document().securityOrigin())) { 100 std::map<blink::WebFrame*, std::set<std::string> >::const_iterator 101 frame_selectors = matching_selectors_.find(frame); 102 if (frame_selectors != matching_selectors_.end()) { 103 transitive_selectors.insert(frame_selectors->second.begin(), 104 frame_selectors->second.end()); 105 } 106 } 107 } 108 std::vector<std::string> selector_strings; 109 for (std::set<base::StringPiece>::const_iterator it = 110 transitive_selectors.begin(); 111 it != transitive_selectors.end(); 112 ++it) 113 selector_strings.push_back(it->as_string()); 114 content::RenderView* view = 115 content::RenderView::FromWebView(top_frame->view()); 116 view->Send(new ExtensionHostMsg_OnWatchedPageChange(view->GetRoutingID(), 117 selector_strings)); 118 } 119 120 } // namespace extensions 121