Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(358)

Side by Side Diff: chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc

Issue 1159733004: Encapsulate CSS selector declarative content condition tracking (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@stars-declarative-content-range-for
Patch Set: multiple updates Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules _registry.h" 5 #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules _registry.h"
6 6
7 #include "chrome/browser/chrome_notification_types.h" 7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/api/declarative_content/content_action.h" 8 #include "chrome/browser/extensions/api/declarative_content/content_action.h"
9 #include "chrome/browser/extensions/api/declarative_content/content_condition.h" 9 #include "chrome/browser/extensions/api/declarative_content/content_condition.h"
10 #include "chrome/browser/extensions/api/declarative_content/content_constants.h" 10 #include "chrome/browser/extensions/api/declarative_content/content_constants.h"
11 #include "chrome/browser/extensions/extension_tab_util.h"
12 #include "chrome/browser/extensions/extension_util.h" 11 #include "chrome/browser/extensions/extension_util.h"
13 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_iterator.h" 14 #include "chrome/browser/ui/browser_iterator.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h" 15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "content/public/browser/navigation_details.h" 16 #include "content/public/browser/navigation_details.h"
18 #include "content/public/browser/notification_service.h" 17 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_source.h" 18 #include "content/public/browser/notification_source.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/web_contents.h" 19 #include "content/public/browser/web_contents.h"
22 #include "extensions/browser/api/declarative/rules_registry_service.h" 20 #include "extensions/browser/api/declarative/rules_registry_service.h"
23 #include "extensions/browser/extension_registry.h" 21 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_system.h" 22 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/extension_messages.h"
26 23
27 using url_matcher::URLMatcherConditionSet; 24 using url_matcher::URLMatcherConditionSet;
28 25
29 namespace extensions { 26 namespace extensions {
30 27
31 ChromeContentRulesRegistry::ChromeContentRulesRegistry( 28 ChromeContentRulesRegistry::ChromeContentRulesRegistry(
32 content::BrowserContext* browser_context, 29 content::BrowserContext* browser_context,
33 RulesCacheDelegate* cache_delegate) 30 RulesCacheDelegate* cache_delegate)
34 : ContentRulesRegistry(browser_context, 31 : ContentRulesRegistry(browser_context,
35 declarative_content_constants::kOnPageChanged, 32 declarative_content_constants::kOnPageChanged,
36 content::BrowserThread::UI, 33 content::BrowserThread::UI,
37 cache_delegate, 34 cache_delegate,
38 RulesRegistryService::kDefaultRulesRegistryID) { 35 RulesRegistryService::kDefaultRulesRegistryID),
36 css_condition_tracker_(browser_context, this) {
39 extension_info_map_ = ExtensionSystem::Get(browser_context)->info_map(); 37 extension_info_map_ = ExtensionSystem::Get(browser_context)->info_map();
40 38
41 registrar_.Add(this, 39 registrar_.Add(this,
42 content::NOTIFICATION_RENDERER_PROCESS_CREATED, 40 chrome::NOTIFICATION_TAB_ADDED,
43 content::NotificationService::AllBrowserContextsAndSources()); 41 content::NotificationService::AllSources());
44 registrar_.Add(this, 42 registrar_.Add(this,
45 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 43 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
46 content::NotificationService::AllBrowserContextsAndSources()); 44 content::NotificationService::AllBrowserContextsAndSources());
47 } 45 }
48 46
49 void ChromeContentRulesRegistry::Observe( 47 void ChromeContentRulesRegistry::Observe(
50 int type, 48 int type,
51 const content::NotificationSource& source, 49 const content::NotificationSource& source,
52 const content::NotificationDetails& details) { 50 const content::NotificationDetails& details) {
53 switch (type) { 51 switch (type) {
54 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: { 52 case chrome::NOTIFICATION_TAB_ADDED: {
55 content::RenderProcessHost* process = 53 content::WebContents* contents =
56 content::Source<content::RenderProcessHost>(source).ptr(); 54 content::Details<content::WebContents>(details).ptr();
57 InstructRenderProcessIfSameBrowserContext(process); 55 css_condition_tracker_.TrackForWebContents(contents);
58 break; 56 break;
59 } 57 }
60 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { 58 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
61 content::WebContents* tab = 59 content::WebContents* tab =
62 content::Source<content::WebContents>(source).ptr(); 60 content::Source<content::WebContents>(source).ptr();
63 // Note that neither non-tab WebContents nor tabs from other browser 61 // Note that neither non-tab WebContents nor tabs from other browser
64 // contexts will be in the map. 62 // contexts will be in the map.
65 active_rules_.erase(tab); 63 active_rules_.erase(tab);
66 matching_css_selectors_.erase(tab);
67 break; 64 break;
68 } 65 }
69 } 66 }
70 } 67 }
71 68
72 void ChromeContentRulesRegistry::Apply( 69 void ChromeContentRulesRegistry::RequestEvaluation(
70 content::WebContents* contents) {
71 EvaluateConditionsForTab(contents);
72 }
73
74 bool ChromeContentRulesRegistry::ShouldManageConditionsForBrowserContext(
75 content::BrowserContext* context) {
76 return ManagingRulesForBrowserContext(context);
77 }
78
79 void ChromeContentRulesRegistry::ForEachWebContents(
80 const WebContentsCallback& callback) {
81 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
82 Browser* browser = *it;
83 if (!ManagingRulesForBrowserContext(browser->profile()))
84 continue;
85
86 for (int i = 0, tab_count = browser->tab_strip_model()->count();
87 i < tab_count; ++i) {
88 callback.Run(browser->tab_strip_model()->GetWebContentsAt(i));
89 }
90 }
91 }
92
93 void ChromeContentRulesRegistry::UpdateMatchingCssSelectorsForTesting(
73 content::WebContents* contents, 94 content::WebContents* contents,
74 const std::vector<std::string>& matching_css_selectors) { 95 const std::vector<std::string>& matching_css_selectors) {
75 matching_css_selectors_[contents] = matching_css_selectors; 96 css_condition_tracker_.UpdateMatchingCssSelectorsForTesting(
76 97 contents,
77 EvaluateConditionsForTab(contents); 98 matching_css_selectors);
78 } 99 }
79 100
80 void ChromeContentRulesRegistry::DidNavigateMainFrame( 101 void ChromeContentRulesRegistry::DidNavigateMainFrame(
81 content::WebContents* contents, 102 content::WebContents* contents,
82 const content::LoadCommittedDetails& details, 103 const content::LoadCommittedDetails& details,
83 const content::FrameNavigateParams& params) { 104 const content::FrameNavigateParams& params) {
84 OnTabNavigation(contents, details.is_in_page); 105 css_condition_tracker_.OnWebContentsNavigation(contents, details, params);
85 } 106 }
86 107
87 void ChromeContentRulesRegistry::DidNavigateMainFrameOfOriginalContext( 108 void ChromeContentRulesRegistry::DidNavigateMainFrameOfOriginalContext(
88 content::WebContents* contents, 109 content::WebContents* contents,
89 const content::LoadCommittedDetails& details, 110 const content::LoadCommittedDetails& details,
90 const content::FrameNavigateParams& params) { 111 const content::FrameNavigateParams& params) {
91 DCHECK(browser_context()->IsOffTheRecord()); 112 DCHECK(browser_context()->IsOffTheRecord());
92 OnTabNavigation(contents, details.is_in_page); 113 css_condition_tracker_.OnWebContentsNavigation(contents, details, params);
93 }
94
95 void ChromeContentRulesRegistry::OnTabNavigation(content::WebContents* tab,
96 bool is_in_page_navigation) {
97 if (is_in_page_navigation) {
98 // Within-page navigations don't change the set of elements that
99 // exist, and we only support filtering on the top-level URL, so
100 // this can't change which rules match.
101 return;
102 }
103
104 // Top-level navigation produces a new document. Initially, the
105 // document's empty, so no CSS rules match. The renderer will send
106 // an ExtensionHostMsg_OnWatchedPageChange later if any CSS rules
107 // match.
108 matching_css_selectors_[tab].clear();
109 EvaluateConditionsForTab(tab);
110 } 114 }
111 115
112 bool ChromeContentRulesRegistry::ManagingRulesForBrowserContext( 116 bool ChromeContentRulesRegistry::ManagingRulesForBrowserContext(
113 content::BrowserContext* context) { 117 content::BrowserContext* context) {
114 // Manage both the normal context and incognito contexts associated with it. 118 // Manage both the normal context and incognito contexts associated with it.
115 return Profile::FromBrowserContext(context)->GetOriginalProfile() == 119 return Profile::FromBrowserContext(context)->GetOriginalProfile() ==
116 Profile::FromBrowserContext(browser_context()); 120 Profile::FromBrowserContext(browser_context());
117 } 121 }
118 122
119 std::set<const ContentRule*> ChromeContentRulesRegistry::GetMatches( 123 std::set<const ContentRule*> ChromeContentRulesRegistry::GetMatches(
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 // Register url patterns in url_matcher_. 216 // Register url patterns in url_matcher_.
213 URLMatcherConditionSet::Vector all_new_condition_sets; 217 URLMatcherConditionSet::Vector all_new_condition_sets;
214 for (const std::pair<ContentRule::GlobalRuleId, 218 for (const std::pair<ContentRule::GlobalRuleId,
215 linked_ptr<const ContentRule>>& rule_id_rule_pair : 219 linked_ptr<const ContentRule>>& rule_id_rule_pair :
216 new_content_rules) { 220 new_content_rules) {
217 const linked_ptr<const ContentRule>& rule = rule_id_rule_pair.second; 221 const linked_ptr<const ContentRule>& rule = rule_id_rule_pair.second;
218 rule->conditions().GetURLMatcherConditionSets(&all_new_condition_sets); 222 rule->conditions().GetURLMatcherConditionSets(&all_new_condition_sets);
219 } 223 }
220 url_matcher_.AddConditionSets(all_new_condition_sets); 224 url_matcher_.AddConditionSets(all_new_condition_sets);
221 225
222 UpdateConditionCache(); 226 UpdateCssSelectorsFromRules();
223 EvaluateConditionsForAllTabs(); 227 EvaluateConditionsForAllTabs();
224 228
225 return std::string(); 229 return std::string();
226 } 230 }
227 231
228 std::string ChromeContentRulesRegistry::RemoveRulesImpl( 232 std::string ChromeContentRulesRegistry::RemoveRulesImpl(
229 const std::string& extension_id, 233 const std::string& extension_id,
230 const std::vector<std::string>& rule_identifiers) { 234 const std::vector<std::string>& rule_identifiers) {
231 // URLMatcherConditionSet IDs that can be removed from URLMatcher. 235 // URLMatcherConditionSet IDs that can be removed from URLMatcher.
232 std::vector<URLMatcherConditionSet::ID> remove_from_url_matcher; 236 std::vector<URLMatcherConditionSet::ID> remove_from_url_matcher;
(...skipping 26 matching lines...) Expand all
259 } 263 }
260 } 264 }
261 265
262 // Remove reference to actual rule. 266 // Remove reference to actual rule.
263 content_rules_.erase(content_rules_entry); 267 content_rules_.erase(content_rules_entry);
264 } 268 }
265 269
266 // Clear URLMatcher based on condition_set_ids that are not needed any more. 270 // Clear URLMatcher based on condition_set_ids that are not needed any more.
267 url_matcher_.RemoveConditionSets(remove_from_url_matcher); 271 url_matcher_.RemoveConditionSets(remove_from_url_matcher);
268 272
269 UpdateConditionCache(); 273 UpdateCssSelectorsFromRules();
270 274
271 return std::string(); 275 return std::string();
272 } 276 }
273 277
274 std::string ChromeContentRulesRegistry::RemoveAllRulesImpl( 278 std::string ChromeContentRulesRegistry::RemoveAllRulesImpl(
275 const std::string& extension_id) { 279 const std::string& extension_id) {
276 // Search all identifiers of rules that belong to extension |extension_id|. 280 // Search all identifiers of rules that belong to extension |extension_id|.
277 std::vector<std::string> rule_identifiers; 281 std::vector<std::string> rule_identifiers;
278 for (const std::pair<ContentRule::GlobalRuleId, 282 for (const std::pair<ContentRule::GlobalRuleId,
279 linked_ptr<const ContentRule>>& rule_id_rule_pair : 283 linked_ptr<const ContentRule>>& rule_id_rule_pair :
280 content_rules_) { 284 content_rules_) {
281 const ContentRule::GlobalRuleId& global_rule_id = rule_id_rule_pair.first; 285 const ContentRule::GlobalRuleId& global_rule_id = rule_id_rule_pair.first;
282 if (global_rule_id.first == extension_id) 286 if (global_rule_id.first == extension_id)
283 rule_identifiers.push_back(global_rule_id.second); 287 rule_identifiers.push_back(global_rule_id.second);
284 } 288 }
285 289
286 return RemoveRulesImpl(extension_id, rule_identifiers); 290 return RemoveRulesImpl(extension_id, rule_identifiers);
287 } 291 }
288 292
289 void ChromeContentRulesRegistry::UpdateConditionCache() { 293 void ChromeContentRulesRegistry::UpdateCssSelectorsFromRules() {
290 std::set<std::string> css_selectors; // We rely on this being sorted. 294 std::set<std::string> css_selectors; // We rely on this being sorted.
291 for (const std::pair<ContentRule::GlobalRuleId, 295 for (const std::pair<ContentRule::GlobalRuleId,
292 linked_ptr<const ContentRule>>& rule_id_rule_pair : 296 linked_ptr<const ContentRule>>& rule_id_rule_pair :
293 content_rules_) { 297 content_rules_) {
294 const ContentRule& rule = *rule_id_rule_pair.second; 298 const ContentRule& rule = *rule_id_rule_pair.second;
295 for (const linked_ptr<const ContentCondition>& condition : 299 for (const linked_ptr<const ContentCondition>& condition :
296 rule.conditions()) { 300 rule.conditions()) {
297 const std::vector<std::string>& condition_css_selectors = 301 const std::vector<std::string>& condition_css_selectors =
298 condition->css_selectors(); 302 condition->css_selectors();
299 css_selectors.insert(condition_css_selectors.begin(), 303 css_selectors.insert(condition_css_selectors.begin(),
300 condition_css_selectors.end()); 304 condition_css_selectors.end());
301 } 305 }
302 } 306 }
303 307
304 if (css_selectors.size() != watched_css_selectors_.size() || 308 css_condition_tracker_.SetWatchedCssSelectors(css_selectors);
305 !std::equal(css_selectors.begin(),
306 css_selectors.end(),
307 watched_css_selectors_.begin())) {
308 watched_css_selectors_.assign(css_selectors.begin(), css_selectors.end());
309
310 for (content::RenderProcessHost::iterator it(
311 content::RenderProcessHost::AllHostsIterator());
312 !it.IsAtEnd();
313 it.Advance()) {
314 content::RenderProcessHost* process = it.GetCurrentValue();
315 InstructRenderProcessIfSameBrowserContext(process);
316 }
317 }
318 }
319
320 void ChromeContentRulesRegistry::InstructRenderProcessIfSameBrowserContext(
321 content::RenderProcessHost* process) {
322 if (ManagingRulesForBrowserContext(process->GetBrowserContext()))
323 process->Send(new ExtensionMsg_WatchPages(watched_css_selectors_));
324 } 309 }
325 310
326 void ChromeContentRulesRegistry::EvaluateConditionsForTab( 311 void ChromeContentRulesRegistry::EvaluateConditionsForTab(
327 content::WebContents* tab) { 312 content::WebContents* tab) {
328 extensions::RendererContentMatchData renderer_data; 313 extensions::RendererContentMatchData renderer_data;
329 renderer_data.page_url_matches = url_matcher_.MatchURL(tab->GetURL()); 314 renderer_data.page_url_matches = url_matcher_.MatchURL(tab->GetURL());
330 renderer_data.css_selectors.insert(matching_css_selectors_[tab].begin(), 315 css_condition_tracker_.GetMatchingCssSelectors(tab,
331 matching_css_selectors_[tab].end()); 316 &renderer_data.css_selectors);
332 std::set<const ContentRule*> matching_rules = 317 std::set<const ContentRule*> matching_rules =
333 GetMatches(renderer_data, tab->GetBrowserContext()->IsOffTheRecord()); 318 GetMatches(renderer_data, tab->GetBrowserContext()->IsOffTheRecord());
334 if (matching_rules.empty() && !ContainsKey(active_rules_, tab)) 319 if (matching_rules.empty() && !ContainsKey(active_rules_, tab))
335 return; 320 return;
336 321
337 std::set<const ContentRule*>& prev_matching_rules = active_rules_[tab]; 322 std::set<const ContentRule*>& prev_matching_rules = active_rules_[tab];
338 ContentAction::ApplyInfo apply_info = {browser_context(), tab}; 323 ContentAction::ApplyInfo apply_info = {browser_context(), tab};
339 for (const ContentRule* rule : matching_rules) { 324 for (const ContentRule* rule : matching_rules) {
340 apply_info.priority = rule->priority(); 325 apply_info.priority = rule->priority();
341 if (!ContainsKey(prev_matching_rules, rule)) { 326 if (!ContainsKey(prev_matching_rules, rule)) {
342 rule->actions().Apply(rule->extension_id(), base::Time(), &apply_info); 327 rule->actions().Apply(rule->extension_id(), base::Time(), &apply_info);
343 } else { 328 } else {
344 rule->actions().Reapply(rule->extension_id(), base::Time(), &apply_info); 329 rule->actions().Reapply(rule->extension_id(), base::Time(), &apply_info);
345 } 330 }
346 } 331 }
347 for (const ContentRule* rule : prev_matching_rules) { 332 for (const ContentRule* rule : prev_matching_rules) {
348 if (!ContainsKey(matching_rules, rule)) { 333 if (!ContainsKey(matching_rules, rule)) {
349 apply_info.priority = rule->priority(); 334 apply_info.priority = rule->priority();
350 rule->actions().Revert(rule->extension_id(), base::Time(), &apply_info); 335 rule->actions().Revert(rule->extension_id(), base::Time(), &apply_info);
351 } 336 }
352 } 337 }
353 338
354 if (matching_rules.empty()) 339 if (matching_rules.empty())
355 active_rules_.erase(tab); 340 active_rules_.erase(tab);
356 else 341 else
357 swap(matching_rules, prev_matching_rules); 342 swap(matching_rules, prev_matching_rules);
358 } 343 }
359 344
360 void ChromeContentRulesRegistry::EvaluateConditionsForAllTabs() { 345 void ChromeContentRulesRegistry::EvaluateConditionsForAllTabs() {
361 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 346 ForEachWebContents(base::Bind(
362 Browser* browser = *it; 347 &ChromeContentRulesRegistry::EvaluateConditionsForTab,
363 if (!ManagingRulesForBrowserContext(browser->profile())) 348 base::Unretained(this)));
364 continue;
365
366 for (int i = 0, tab_count = browser->tab_strip_model()->count();
367 i < tab_count;
368 ++i)
369 EvaluateConditionsForTab(browser->tab_strip_model()->GetWebContentsAt(i));
370 }
371 } 349 }
372 350
373 bool ChromeContentRulesRegistry::IsEmpty() const { 351 bool ChromeContentRulesRegistry::IsEmpty() const {
374 return match_id_to_rule_.empty() && content_rules_.empty() && 352 return match_id_to_rule_.empty() && content_rules_.empty() &&
375 url_matcher_.IsEmpty(); 353 url_matcher_.IsEmpty();
376 } 354 }
377 355
378 ChromeContentRulesRegistry::~ChromeContentRulesRegistry() { 356 ChromeContentRulesRegistry::~ChromeContentRulesRegistry() {
379 } 357 }
380 358
381 base::Time ChromeContentRulesRegistry::GetExtensionInstallationTime( 359 base::Time ChromeContentRulesRegistry::GetExtensionInstallationTime(
382 const std::string& extension_id) const { 360 const std::string& extension_id) const {
383 if (!extension_info_map_.get()) // May be NULL during testing. 361 if (!extension_info_map_.get()) // May be NULL during testing.
384 return base::Time(); 362 return base::Time();
385 363
386 return extension_info_map_->GetInstallTime(extension_id); 364 return extension_info_map_->GetInstallTime(extension_id);
387 } 365 }
388 366
389 } // namespace extensions 367 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698