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.
5 #include "extensions/renderer/content_watcher.h"
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/WebLocalFrame.h"
13 #include "third_party/WebKit/public/web/WebScriptBindings.h"
14 #include "third_party/WebKit/public/web/WebView.h"
16 namespace extensions
{
18 using blink::WebString
;
19 using blink::WebVector
;
22 ContentWatcher::ContentWatcher() {}
23 ContentWatcher::~ContentWatcher() {}
25 void 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
])
40 css_selectors_
.swap(new_css_selectors
);
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
) {}
49 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_
);
54 return true; // Continue visiting.
57 const WebVector
<WebString
>& css_selectors_
;
59 WatchSelectors
visitor(css_selectors_
);
60 content::RenderView::ForEach(&visitor
);
63 void ContentWatcher::DidCreateDocumentElement(blink::WebLocalFrame
* frame
) {
64 frame
->document().watchCSSSelectors(css_selectors_
);
67 void ContentWatcher::DidMatchCSS(
68 blink::WebLocalFrame
* 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());
77 if (frame_selectors
.empty())
78 matching_selectors_
.erase(frame
);
80 NotifyBrowserOfChange(frame
);
83 void ContentWatcher::NotifyBrowserOfChange(
84 blink::WebLocalFrame
* changed_frame
) const {
85 blink::WebFrame
* const top_frame
= changed_frame
->top();
86 const blink::WebSecurityOrigin top_origin
= top_frame
->securityOrigin();
87 // Want to aggregate matched selectors from all frames where an
88 // extension with access to top_origin could run on the frame.
89 if (!top_origin
.canAccess(changed_frame
->document().securityOrigin())) {
90 // If the changed frame can't be accessed by the top frame, then
91 // no change in it could affect the set of selectors we'd send back.
95 std::set
<base::StringPiece
> transitive_selectors
;
96 for (blink::WebFrame
* frame
= top_frame
; frame
;
97 frame
= frame
->traverseNext(/*wrap=*/false)) {
98 if (top_origin
.canAccess(frame
->document().securityOrigin())) {
99 std::map
<blink::WebFrame
*, std::set
<std::string
> >::const_iterator
100 frame_selectors
= matching_selectors_
.find(frame
);
101 if (frame_selectors
!= matching_selectors_
.end()) {
102 transitive_selectors
.insert(frame_selectors
->second
.begin(),
103 frame_selectors
->second
.end());
107 std::vector
<std::string
> selector_strings
;
108 for (std::set
<base::StringPiece
>::const_iterator it
=
109 transitive_selectors
.begin();
110 it
!= transitive_selectors
.end();
112 selector_strings
.push_back(it
->as_string());
113 content::RenderView
* view
=
114 content::RenderView::FromWebView(top_frame
->view());
115 view
->Send(new ExtensionHostMsg_OnWatchedPageChange(view
->GetRoutingID(),
119 } // namespace extensions