Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / chrome / browser / extensions / api / declarative_content / declarative_content_css_condition_tracker.cc
blob635b2b703fadfb93e49e77a38e5aef9a3a15b359
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"
7 #include <algorithm>
9 #include "base/stl_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/extensions/api/declarative_content/content_constants.h"
14 #include "chrome/browser/extensions/api/declarative_content/declarative_content_condition_tracker_delegate.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "content/public/browser/navigation_details.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_source.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "extensions/common/extension_messages.h"
21 #include "ipc/ipc_message.h"
22 #include "ipc/ipc_message_macros.h"
24 namespace extensions {
26 namespace {
28 const char kInvalidTypeOfParameter[] = "Attribute '%s' has an invalid type";
30 } // namespace
33 // DeclarativeContentCssPredicate
36 DeclarativeContentCssPredicate::~DeclarativeContentCssPredicate() {
39 bool DeclarativeContentCssPredicate::Evaluate(
40 const base::hash_set<std::string>& matched_css_selectors) const {
41 // All attributes must be fulfilled for a fulfilled condition.
42 for (const std::string& css_selector : css_selectors_) {
43 if (!ContainsKey(matched_css_selectors, css_selector))
44 return false;
47 return true;
50 // static
51 scoped_ptr<DeclarativeContentCssPredicate>
52 DeclarativeContentCssPredicate::Create(
53 const base::Value& value,
54 std::string* error) {
55 std::vector<std::string> css_rules;
56 const base::ListValue* css_rules_value = nullptr;
57 if (value.GetAsList(&css_rules_value)) {
58 for (size_t i = 0; i < css_rules_value->GetSize(); ++i) {
59 std::string css_rule;
60 if (!css_rules_value->GetString(i, &css_rule)) {
61 *error = base::StringPrintf(kInvalidTypeOfParameter,
62 declarative_content_constants::kCss);
63 return scoped_ptr<DeclarativeContentCssPredicate>();
65 css_rules.push_back(css_rule);
67 } else {
68 *error = base::StringPrintf(kInvalidTypeOfParameter,
69 declarative_content_constants::kCss);
70 return scoped_ptr<DeclarativeContentCssPredicate>();
73 return !css_rules.empty() ?
74 make_scoped_ptr(new DeclarativeContentCssPredicate(css_rules)) :
75 scoped_ptr<DeclarativeContentCssPredicate>();
78 DeclarativeContentCssPredicate::DeclarativeContentCssPredicate(
79 const std::vector<std::string>& css_selectors)
80 : css_selectors_(css_selectors) {
81 DCHECK(!css_selectors.empty());
85 // PerWebContentsTracker
88 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
89 PerWebContentsTracker(
90 content::WebContents* contents,
91 const RequestEvaluationCallback& request_evaluation,
92 const WebContentsDestroyedCallback& web_contents_destroyed)
93 : WebContentsObserver(contents),
94 request_evaluation_(request_evaluation),
95 web_contents_destroyed_(web_contents_destroyed) {
98 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
99 ~PerWebContentsTracker() {
102 scoped_ptr<DeclarativeContentCssPredicate>
103 DeclarativeContentCssConditionTracker::CreatePredicate(
104 const Extension* extension,
105 const base::Value& value,
106 std::string* error) {
107 return DeclarativeContentCssPredicate::Create(value, error);
110 void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
111 OnWebContentsNavigation(const content::LoadCommittedDetails& details,
112 const content::FrameNavigateParams& params) {
113 if (details.is_in_page) {
114 // Within-page navigations don't change the set of elements that
115 // exist, and we only support filtering on the top-level URL, so
116 // this can't change which rules match.
117 return;
120 // Top-level navigation produces a new document. Initially, the
121 // document's empty, so no CSS rules match. The renderer will send
122 // an ExtensionHostMsg_OnWatchedPageChange later if any CSS rules
123 // match.
124 matching_css_selectors_.clear();
125 request_evaluation_.Run(web_contents());
128 void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
129 UpdateMatchingCssSelectorsForTesting(
130 const std::vector<std::string>& matching_css_selectors) {
131 matching_css_selectors_ = matching_css_selectors;
132 request_evaluation_.Run(web_contents());
135 bool
136 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
137 OnMessageReceived(
138 const IPC::Message& message) {
139 bool handled = true;
140 IPC_BEGIN_MESSAGE_MAP(PerWebContentsTracker, message)
141 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
142 OnWatchedPageChange)
143 IPC_MESSAGE_UNHANDLED(handled = false)
144 IPC_END_MESSAGE_MAP()
145 return handled;
148 void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
149 WebContentsDestroyed() {
150 web_contents_destroyed_.Run(web_contents());
153 void
154 DeclarativeContentCssConditionTracker::PerWebContentsTracker::
155 OnWatchedPageChange(
156 const std::vector<std::string>& css_selectors) {
157 matching_css_selectors_ = css_selectors;
158 request_evaluation_.Run(web_contents());
162 // DeclarativeContentCssConditionTracker
165 DeclarativeContentCssConditionTracker::DeclarativeContentCssConditionTracker(
166 content::BrowserContext* context,
167 DeclarativeContentConditionTrackerDelegate* delegate)
168 : context_(context),
169 delegate_(delegate) {
170 registrar_.Add(this,
171 content::NOTIFICATION_RENDERER_PROCESS_CREATED,
172 content::NotificationService::AllBrowserContextsAndSources());
175 DeclarativeContentCssConditionTracker::
176 ~DeclarativeContentCssConditionTracker() {}
178 // We use the sorted propery of the set for equality checks with
179 // watched_css_selectors_, which is guaranteed to be sorted because it's set
180 // from the set contents.
181 void DeclarativeContentCssConditionTracker::SetWatchedCssSelectors(
182 const std::set<std::string>& new_watched_css_selectors) {
183 if (new_watched_css_selectors.size() != watched_css_selectors_.size() ||
184 !std::equal(new_watched_css_selectors.begin(),
185 new_watched_css_selectors.end(),
186 watched_css_selectors_.begin())) {
187 watched_css_selectors_.assign(new_watched_css_selectors.begin(),
188 new_watched_css_selectors.end());
190 for (content::RenderProcessHost::iterator it(
191 content::RenderProcessHost::AllHostsIterator());
192 !it.IsAtEnd();
193 it.Advance()) {
194 InstructRenderProcessIfManagingBrowserContext(it.GetCurrentValue());
199 void DeclarativeContentCssConditionTracker::TrackForWebContents(
200 content::WebContents* contents) {
201 per_web_contents_tracker_[contents] =
202 make_linked_ptr(new PerWebContentsTracker(
203 contents,
204 base::Bind(&DeclarativeContentConditionTrackerDelegate::
205 RequestEvaluation,
206 base::Unretained(delegate_)),
207 base::Bind(&DeclarativeContentCssConditionTracker::
208 DeletePerWebContentsTracker,
209 base::Unretained(this))));
210 // Note: the condition is always false until we receive OnWatchedPageChange,
211 // so there's no need to evaluate it here.
214 void DeclarativeContentCssConditionTracker::OnWebContentsNavigation(
215 content::WebContents* contents,
216 const content::LoadCommittedDetails& details,
217 const content::FrameNavigateParams& params) {
218 DCHECK(ContainsKey(per_web_contents_tracker_, contents));
219 per_web_contents_tracker_[contents]->OnWebContentsNavigation(details, params);
222 void DeclarativeContentCssConditionTracker::GetMatchingCssSelectors(
223 content::WebContents* contents,
224 base::hash_set<std::string>* css_selectors) {
225 DCHECK(ContainsKey(per_web_contents_tracker_, contents));
226 const std::vector<std::string>& matching_css_selectors =
227 per_web_contents_tracker_[contents]->matching_css_selectors();
228 css_selectors->insert(matching_css_selectors.begin(),
229 matching_css_selectors.end());
232 void DeclarativeContentCssConditionTracker::
233 UpdateMatchingCssSelectorsForTesting(
234 content::WebContents* contents,
235 const std::vector<std::string>& matching_css_selectors) {
236 DCHECK(ContainsKey(per_web_contents_tracker_, contents));
237 per_web_contents_tracker_[contents]->
238 UpdateMatchingCssSelectorsForTesting(matching_css_selectors);
241 void DeclarativeContentCssConditionTracker::Observe(
242 int type,
243 const content::NotificationSource& source,
244 const content::NotificationDetails& details) {
245 switch (type) {
246 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
247 content::RenderProcessHost* process =
248 content::Source<content::RenderProcessHost>(source).ptr();
249 InstructRenderProcessIfManagingBrowserContext(process);
250 break;
255 void DeclarativeContentCssConditionTracker::
256 InstructRenderProcessIfManagingBrowserContext(
257 content::RenderProcessHost* process) {
258 if (delegate_->ShouldManageConditionsForBrowserContext(
259 process->GetBrowserContext())) {
260 process->Send(new ExtensionMsg_WatchPages(watched_css_selectors_));
264 void DeclarativeContentCssConditionTracker::DeletePerWebContentsTracker(
265 content::WebContents* contents) {
266 DCHECK(ContainsKey(per_web_contents_tracker_, contents));
267 per_web_contents_tracker_.erase(contents);
270 } // namespace extensions