1 // Copyright 2015 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 "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
9 #include "base/stl_util.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/api/declarative_content/declarative_content_condition_tracker_delegate.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "content/public/browser/navigation_details.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "extensions/common/extension_messages.h"
18 #include "ipc/ipc_message.h"
19 #include "ipc/ipc_message_macros.h"
21 namespace extensions
{
24 // PerWebContentsTracker
27 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
28 PerWebContentsTracker(
29 content::WebContents
* contents
,
30 const RequestEvaluationCallback
& request_evaluation
,
31 const WebContentsDestroyedCallback
& web_contents_destroyed
)
32 : WebContentsObserver(contents
),
33 request_evaluation_(request_evaluation
),
34 web_contents_destroyed_(web_contents_destroyed
) {
37 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
38 ~PerWebContentsTracker() {
41 void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
42 OnWebContentsNavigation(const content::LoadCommittedDetails
& details
,
43 const content::FrameNavigateParams
& params
) {
44 if (details
.is_in_page
) {
45 // Within-page navigations don't change the set of elements that
46 // exist, and we only support filtering on the top-level URL, so
47 // this can't change which rules match.
51 // Top-level navigation produces a new document. Initially, the
52 // document's empty, so no CSS rules match. The renderer will send
53 // an ExtensionHostMsg_OnWatchedPageChange later if any CSS rules
55 matching_css_selectors_
.clear();
56 request_evaluation_
.Run(web_contents());
59 void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
60 UpdateMatchingCssSelectorsForTesting(
61 const std::vector
<std::string
>& matching_css_selectors
) {
62 matching_css_selectors_
= matching_css_selectors
;
63 request_evaluation_
.Run(web_contents());
67 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
69 const IPC::Message
& message
) {
71 IPC_BEGIN_MESSAGE_MAP(PerWebContentsTracker
, message
)
72 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange
,
74 IPC_MESSAGE_UNHANDLED(handled
= false)
79 void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
80 WebContentsDestroyed() {
81 web_contents_destroyed_
.Run(web_contents());
85 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
87 const std::vector
<std::string
>& css_selectors
) {
88 matching_css_selectors_
= css_selectors
;
89 request_evaluation_
.Run(web_contents());
93 // DeclarativeContentCssConditionTracker
96 DeclarativeContentCssConditionTracker::DeclarativeContentCssConditionTracker(
97 content::BrowserContext
* context
,
98 DeclarativeContentConditionTrackerDelegate
* delegate
)
100 delegate_(delegate
) {
102 content::NOTIFICATION_RENDERER_PROCESS_CREATED
,
103 content::NotificationService::AllBrowserContextsAndSources());
106 DeclarativeContentCssConditionTracker::
107 ~DeclarativeContentCssConditionTracker() {}
109 // We use the sorted propery of the set for equality checks with
110 // watched_css_selectors_, which is guaranteed to be sorted because it's set
111 // from the set contents.
112 void DeclarativeContentCssConditionTracker::SetWatchedCssSelectors(
113 const std::set
<std::string
>& new_watched_css_selectors
) {
114 if (new_watched_css_selectors
.size() != watched_css_selectors_
.size() ||
115 !std::equal(new_watched_css_selectors
.begin(),
116 new_watched_css_selectors
.end(),
117 watched_css_selectors_
.begin())) {
118 watched_css_selectors_
.assign(new_watched_css_selectors
.begin(),
119 new_watched_css_selectors
.end());
121 for (content::RenderProcessHost::iterator
it(
122 content::RenderProcessHost::AllHostsIterator());
125 InstructRenderProcessIfManagingBrowserContext(it
.GetCurrentValue());
130 void DeclarativeContentCssConditionTracker::TrackForWebContents(
131 content::WebContents
* contents
) {
132 per_web_contents_tracker_
[contents
] =
133 make_linked_ptr(new PerWebContentsTracker(
135 base::Bind(&DeclarativeContentConditionTrackerDelegate::
137 base::Unretained(delegate_
)),
138 base::Bind(&DeclarativeContentCssConditionTracker::
139 DeletePerWebContentsTracker
,
140 base::Unretained(this))));
141 // Note: the condition is always false until we receive OnWatchedPageChange,
142 // so there's no need to evaluate it here.
145 void DeclarativeContentCssConditionTracker::OnWebContentsNavigation(
146 content::WebContents
* contents
,
147 const content::LoadCommittedDetails
& details
,
148 const content::FrameNavigateParams
& params
) {
149 DCHECK(ContainsKey(per_web_contents_tracker_
, contents
));
150 per_web_contents_tracker_
[contents
]->OnWebContentsNavigation(details
, params
);
153 void DeclarativeContentCssConditionTracker::GetMatchingCssSelectors(
154 content::WebContents
* contents
,
155 base::hash_set
<std::string
>* css_selectors
) {
156 DCHECK(ContainsKey(per_web_contents_tracker_
, contents
));
157 const std::vector
<std::string
>& matching_css_selectors
=
158 per_web_contents_tracker_
[contents
]->matching_css_selectors();
159 css_selectors
->insert(matching_css_selectors
.begin(),
160 matching_css_selectors
.end());
163 void DeclarativeContentCssConditionTracker::
164 UpdateMatchingCssSelectorsForTesting(
165 content::WebContents
* contents
,
166 const std::vector
<std::string
>& matching_css_selectors
) {
167 DCHECK(ContainsKey(per_web_contents_tracker_
, contents
));
168 per_web_contents_tracker_
[contents
]->
169 UpdateMatchingCssSelectorsForTesting(matching_css_selectors
);
172 void DeclarativeContentCssConditionTracker::Observe(
174 const content::NotificationSource
& source
,
175 const content::NotificationDetails
& details
) {
177 case content::NOTIFICATION_RENDERER_PROCESS_CREATED
: {
178 content::RenderProcessHost
* process
=
179 content::Source
<content::RenderProcessHost
>(source
).ptr();
180 InstructRenderProcessIfManagingBrowserContext(process
);
186 void DeclarativeContentCssConditionTracker::
187 InstructRenderProcessIfManagingBrowserContext(
188 content::RenderProcessHost
* process
) {
189 if (delegate_
->ShouldManageConditionsForBrowserContext(
190 process
->GetBrowserContext())) {
191 process
->Send(new ExtensionMsg_WatchPages(watched_css_selectors_
));
195 void DeclarativeContentCssConditionTracker::DeletePerWebContentsTracker(
196 content::WebContents
* contents
) {
197 DCHECK(ContainsKey(per_web_contents_tracker_
, contents
));
198 per_web_contents_tracker_
.erase(contents
);
201 } // namespace extensions