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

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

Issue 1166393002: Reland "Encapsulate CSS selector declarative content condition tracking" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: crash fixes and tests 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,
43 content::NotificationService::AllBrowserContextsAndSources());
44 registrar_.Add(this,
45 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 40 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
46 content::NotificationService::AllBrowserContextsAndSources()); 41 content::NotificationService::AllBrowserContextsAndSources());
47 } 42 }
48 43
49 void ChromeContentRulesRegistry::Observe( 44 void ChromeContentRulesRegistry::Observe(
50 int type, 45 int type,
51 const content::NotificationSource& source, 46 const content::NotificationSource& source,
52 const content::NotificationDetails& details) { 47 const content::NotificationDetails& details) {
53 switch (type) { 48 switch (type) {
54 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
55 content::RenderProcessHost* process =
56 content::Source<content::RenderProcessHost>(source).ptr();
57 InstructRenderProcessIfSameBrowserContext(process);
58 break;
59 }
60 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { 49 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
61 content::WebContents* tab = 50 content::WebContents* tab =
62 content::Source<content::WebContents>(source).ptr(); 51 content::Source<content::WebContents>(source).ptr();
63 // Note that neither non-tab WebContents nor tabs from other browser 52 // Note that neither non-tab WebContents nor tabs from other browser
64 // contexts will be in the map. 53 // contexts will be in the map.
65 active_rules_.erase(tab); 54 active_rules_.erase(tab);
66 matching_css_selectors_.erase(tab);
67 break; 55 break;
68 } 56 }
69 } 57 }
70 } 58 }
71 59
72 void ChromeContentRulesRegistry::Apply( 60 void ChromeContentRulesRegistry::RequestEvaluation(
73 content::WebContents* contents, 61 content::WebContents* contents) {
74 const std::vector<std::string>& matching_css_selectors) { 62 EvaluateConditionsForTab(contents);
75 matching_css_selectors_[contents] = matching_css_selectors; 63 }
76 64
77 EvaluateConditionsForTab(contents); 65 bool ChromeContentRulesRegistry::ShouldManageConditionsForBrowserContext(
66 content::BrowserContext* context) {
67 return ManagingRulesForBrowserContext(context);
68 }
69
70 void ChromeContentRulesRegistry::MonitorWebContentsForRuleEvaluation(
71 content::WebContents* contents) {
72 // We rely on active_rules_ to have a key-value pair for |contents| to know
73 // which WebContents we are working with.
74 active_rules_[contents] = std::set<const ContentRule*>();
75 css_condition_tracker_.TrackForWebContents(contents);
78 } 76 }
79 77
80 void ChromeContentRulesRegistry::DidNavigateMainFrame( 78 void ChromeContentRulesRegistry::DidNavigateMainFrame(
81 content::WebContents* contents, 79 content::WebContents* contents,
82 const content::LoadCommittedDetails& details, 80 const content::LoadCommittedDetails& details,
83 const content::FrameNavigateParams& params) { 81 const content::FrameNavigateParams& params) {
84 OnTabNavigation(contents, details.is_in_page); 82 if (ContainsKey(active_rules_, contents))
85 } 83 css_condition_tracker_.OnWebContentsNavigation(contents, details, params);
86
87 void ChromeContentRulesRegistry::DidNavigateMainFrameOfOriginalContext(
88 content::WebContents* contents,
89 const content::LoadCommittedDetails& details,
90 const content::FrameNavigateParams& params) {
91 DCHECK(browser_context()->IsOffTheRecord());
92 OnTabNavigation(contents, details.is_in_page);
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 } 84 }
111 85
112 bool ChromeContentRulesRegistry::ManagingRulesForBrowserContext( 86 bool ChromeContentRulesRegistry::ManagingRulesForBrowserContext(
113 content::BrowserContext* context) { 87 content::BrowserContext* context) {
114 // Manage both the normal context and incognito contexts associated with it. 88 // Manage both the normal context and incognito contexts associated with it.
115 return Profile::FromBrowserContext(context)->GetOriginalProfile() == 89 return Profile::FromBrowserContext(context)->GetOriginalProfile() ==
116 Profile::FromBrowserContext(browser_context()); 90 Profile::FromBrowserContext(browser_context());
117 } 91 }
118 92
119 std::set<const ContentRule*> ChromeContentRulesRegistry::GetMatches( 93 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_. 186 // Register url patterns in url_matcher_.
213 URLMatcherConditionSet::Vector all_new_condition_sets; 187 URLMatcherConditionSet::Vector all_new_condition_sets;
214 for (const std::pair<ContentRule::GlobalRuleId, 188 for (const std::pair<ContentRule::GlobalRuleId,
215 linked_ptr<const ContentRule>>& rule_id_rule_pair : 189 linked_ptr<const ContentRule>>& rule_id_rule_pair :
216 new_content_rules) { 190 new_content_rules) {
217 const linked_ptr<const ContentRule>& rule = rule_id_rule_pair.second; 191 const linked_ptr<const ContentRule>& rule = rule_id_rule_pair.second;
218 rule->conditions().GetURLMatcherConditionSets(&all_new_condition_sets); 192 rule->conditions().GetURLMatcherConditionSets(&all_new_condition_sets);
219 } 193 }
220 url_matcher_.AddConditionSets(all_new_condition_sets); 194 url_matcher_.AddConditionSets(all_new_condition_sets);
221 195
222 UpdateConditionCache(); 196 UpdateCssSelectorsFromRules();
223 EvaluateConditionsForAllTabs(); 197 EvaluateConditionsForAllTabs();
224 198
225 return std::string(); 199 return std::string();
226 } 200 }
227 201
228 std::string ChromeContentRulesRegistry::RemoveRulesImpl( 202 std::string ChromeContentRulesRegistry::RemoveRulesImpl(
229 const std::string& extension_id, 203 const std::string& extension_id,
230 const std::vector<std::string>& rule_identifiers) { 204 const std::vector<std::string>& rule_identifiers) {
231 // URLMatcherConditionSet IDs that can be removed from URLMatcher. 205 // URLMatcherConditionSet IDs that can be removed from URLMatcher.
232 std::vector<URLMatcherConditionSet::ID> remove_from_url_matcher; 206 std::vector<URLMatcherConditionSet::ID> remove_from_url_matcher;
(...skipping 26 matching lines...) Expand all
259 } 233 }
260 } 234 }
261 235
262 // Remove reference to actual rule. 236 // Remove reference to actual rule.
263 content_rules_.erase(content_rules_entry); 237 content_rules_.erase(content_rules_entry);
264 } 238 }
265 239
266 // Clear URLMatcher based on condition_set_ids that are not needed any more. 240 // Clear URLMatcher based on condition_set_ids that are not needed any more.
267 url_matcher_.RemoveConditionSets(remove_from_url_matcher); 241 url_matcher_.RemoveConditionSets(remove_from_url_matcher);
268 242
269 UpdateConditionCache(); 243 UpdateCssSelectorsFromRules();
270 244
271 return std::string(); 245 return std::string();
272 } 246 }
273 247
274 std::string ChromeContentRulesRegistry::RemoveAllRulesImpl( 248 std::string ChromeContentRulesRegistry::RemoveAllRulesImpl(
275 const std::string& extension_id) { 249 const std::string& extension_id) {
276 // Search all identifiers of rules that belong to extension |extension_id|. 250 // Search all identifiers of rules that belong to extension |extension_id|.
277 std::vector<std::string> rule_identifiers; 251 std::vector<std::string> rule_identifiers;
278 for (const std::pair<ContentRule::GlobalRuleId, 252 for (const std::pair<ContentRule::GlobalRuleId,
279 linked_ptr<const ContentRule>>& rule_id_rule_pair : 253 linked_ptr<const ContentRule>>& rule_id_rule_pair :
280 content_rules_) { 254 content_rules_) {
281 const ContentRule::GlobalRuleId& global_rule_id = rule_id_rule_pair.first; 255 const ContentRule::GlobalRuleId& global_rule_id = rule_id_rule_pair.first;
282 if (global_rule_id.first == extension_id) 256 if (global_rule_id.first == extension_id)
283 rule_identifiers.push_back(global_rule_id.second); 257 rule_identifiers.push_back(global_rule_id.second);
284 } 258 }
285 259
286 return RemoveRulesImpl(extension_id, rule_identifiers); 260 return RemoveRulesImpl(extension_id, rule_identifiers);
287 } 261 }
288 262
289 void ChromeContentRulesRegistry::UpdateConditionCache() { 263 void ChromeContentRulesRegistry::UpdateCssSelectorsFromRules() {
290 std::set<std::string> css_selectors; // We rely on this being sorted. 264 std::set<std::string> css_selectors; // We rely on this being sorted.
291 for (const std::pair<ContentRule::GlobalRuleId, 265 for (const std::pair<ContentRule::GlobalRuleId,
292 linked_ptr<const ContentRule>>& rule_id_rule_pair : 266 linked_ptr<const ContentRule>>& rule_id_rule_pair :
293 content_rules_) { 267 content_rules_) {
294 const ContentRule& rule = *rule_id_rule_pair.second; 268 const ContentRule& rule = *rule_id_rule_pair.second;
295 for (const linked_ptr<const ContentCondition>& condition : 269 for (const linked_ptr<const ContentCondition>& condition :
296 rule.conditions()) { 270 rule.conditions()) {
297 const std::vector<std::string>& condition_css_selectors = 271 const std::vector<std::string>& condition_css_selectors =
298 condition->css_selectors(); 272 condition->css_selectors();
299 css_selectors.insert(condition_css_selectors.begin(), 273 css_selectors.insert(condition_css_selectors.begin(),
300 condition_css_selectors.end()); 274 condition_css_selectors.end());
301 } 275 }
302 } 276 }
303 277
304 if (css_selectors.size() != watched_css_selectors_.size() || 278 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 } 279 }
325 280
326 void ChromeContentRulesRegistry::EvaluateConditionsForTab( 281 void ChromeContentRulesRegistry::EvaluateConditionsForTab(
327 content::WebContents* tab) { 282 content::WebContents* tab) {
328 extensions::RendererContentMatchData renderer_data; 283 extensions::RendererContentMatchData renderer_data;
329 renderer_data.page_url_matches = url_matcher_.MatchURL(tab->GetURL()); 284 renderer_data.page_url_matches = url_matcher_.MatchURL(tab->GetURL());
330 renderer_data.css_selectors.insert(matching_css_selectors_[tab].begin(), 285 css_condition_tracker_.GetMatchingCssSelectors(tab,
331 matching_css_selectors_[tab].end()); 286 &renderer_data.css_selectors);
332 std::set<const ContentRule*> matching_rules = 287 std::set<const ContentRule*> matching_rules =
333 GetMatches(renderer_data, tab->GetBrowserContext()->IsOffTheRecord()); 288 GetMatches(renderer_data, tab->GetBrowserContext()->IsOffTheRecord());
334 if (matching_rules.empty() && !ContainsKey(active_rules_, tab)) 289 if (matching_rules.empty() && !ContainsKey(active_rules_, tab))
335 return; 290 return;
336 291
337 std::set<const ContentRule*>& prev_matching_rules = active_rules_[tab]; 292 std::set<const ContentRule*>& prev_matching_rules = active_rules_[tab];
338 ContentAction::ApplyInfo apply_info = {browser_context(), tab}; 293 ContentAction::ApplyInfo apply_info = {browser_context(), tab};
339 for (const ContentRule* rule : matching_rules) { 294 for (const ContentRule* rule : matching_rules) {
340 apply_info.priority = rule->priority(); 295 apply_info.priority = rule->priority();
341 if (!ContainsKey(prev_matching_rules, rule)) { 296 if (!ContainsKey(prev_matching_rules, rule)) {
342 rule->actions().Apply(rule->extension_id(), base::Time(), &apply_info); 297 rule->actions().Apply(rule->extension_id(), base::Time(), &apply_info);
343 } else { 298 } else {
344 rule->actions().Reapply(rule->extension_id(), base::Time(), &apply_info); 299 rule->actions().Reapply(rule->extension_id(), base::Time(), &apply_info);
345 } 300 }
346 } 301 }
347 for (const ContentRule* rule : prev_matching_rules) { 302 for (const ContentRule* rule : prev_matching_rules) {
348 if (!ContainsKey(matching_rules, rule)) { 303 if (!ContainsKey(matching_rules, rule)) {
349 apply_info.priority = rule->priority(); 304 apply_info.priority = rule->priority();
350 rule->actions().Revert(rule->extension_id(), base::Time(), &apply_info); 305 rule->actions().Revert(rule->extension_id(), base::Time(), &apply_info);
351 } 306 }
352 } 307 }
353 308
354 if (matching_rules.empty()) 309 if (matching_rules.empty())
355 active_rules_.erase(tab); 310 active_rules_[tab].clear();
356 else 311 else
357 swap(matching_rules, prev_matching_rules); 312 swap(matching_rules, prev_matching_rules);
358 } 313 }
359 314
360 void ChromeContentRulesRegistry::EvaluateConditionsForAllTabs() { 315 void ChromeContentRulesRegistry::EvaluateConditionsForAllTabs() {
361 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 316 for (const auto& web_contents_active_rules_pair : active_rules_)
362 Browser* browser = *it; 317 EvaluateConditionsForTab(web_contents_active_rules_pair.first);
363 if (!ManagingRulesForBrowserContext(browser->profile()))
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 } 318 }
372 319
373 bool ChromeContentRulesRegistry::IsEmpty() const { 320 bool ChromeContentRulesRegistry::IsEmpty() const {
374 return match_id_to_rule_.empty() && content_rules_.empty() && 321 return match_id_to_rule_.empty() && content_rules_.empty() &&
375 url_matcher_.IsEmpty(); 322 url_matcher_.IsEmpty();
376 } 323 }
377 324
325 void ChromeContentRulesRegistry::UpdateMatchingCssSelectorsForTesting(
326 content::WebContents* contents,
327 const std::vector<std::string>& matching_css_selectors) {
328 css_condition_tracker_.UpdateMatchingCssSelectorsForTesting(
329 contents,
330 matching_css_selectors);
331 }
332
333 size_t ChromeContentRulesRegistry::GetActiveRulesCountForTesting() {
334 size_t count = 0;
335 for (auto web_contents_rules_pair : active_rules_)
336 count += web_contents_rules_pair.second.size();
337 return count;
338 }
339
378 ChromeContentRulesRegistry::~ChromeContentRulesRegistry() { 340 ChromeContentRulesRegistry::~ChromeContentRulesRegistry() {
379 } 341 }
380 342
381 base::Time ChromeContentRulesRegistry::GetExtensionInstallationTime( 343 base::Time ChromeContentRulesRegistry::GetExtensionInstallationTime(
382 const std::string& extension_id) const { 344 const std::string& extension_id) const {
383 if (!extension_info_map_.get()) // May be NULL during testing. 345 if (!extension_info_map_.get()) // May be NULL during testing.
384 return base::Time(); 346 return base::Time();
385 347
386 return extension_info_map_->GetInstallTime(extension_id); 348 return extension_info_map_->GetInstallTime(extension_id);
387 } 349 }
388 350
389 } // namespace extensions 351 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698