Revert of Encapsulate CSS selector declarative content condition tracking (patchset #6 id:140001 of https://codereview.chromium.org/1159733004/)
Reason for revert: Stability sheriff here; I'm speculatively rolling this out because I suspect it caused Issue 497586. Original issue's description: > Encapsulate CSS selector declarative content condition tracking > > This is the first step in a refactoring of the declarativeContent API > implementation. The goal is to facilitate profile state matching by > providing abstractions for conditions and condition state tracking > and evaluation. > > This CL consists of steps 1 and 2 described in the associated bug: > by-hand instantiation of DeclarativeRule as DeclarativeContentRule to > decouple changes from the web request declarative API implementation, > and encapsulation of CSS selector condition tracking logic. No > functional change is intended. > > BUG=492946 > > Committed: https://crrev.com/fe76220cf0a1cdcfe74ca7daeae9f1da2b91cc6b > Cr-Commit-Position: refs/heads/master@{#333144} TBR=kalman@chromium.org,jyasskin@chromium.org,wittman@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=492946 Review URL: https://codereview.chromium.org/1159623014 Cr-Commit-Position: refs/heads/master@{#333238}
This commit is contained in:
chrome
browser
extensions
extensions/browser/api/declarative_content
@ -8,6 +8,7 @@
|
||||
#include "chrome/browser/extensions/api/declarative_content/content_action.h"
|
||||
#include "chrome/browser/extensions/api/declarative_content/content_condition.h"
|
||||
#include "chrome/browser/extensions/api/declarative_content/content_constants.h"
|
||||
#include "chrome/browser/extensions/extension_tab_util.h"
|
||||
#include "chrome/browser/extensions/extension_util.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
@ -16,29 +17,17 @@
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/notification_service.h"
|
||||
#include "content/public/browser/notification_source.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "extensions/browser/api/declarative/rules_registry_service.h"
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "extensions/browser/extension_system.h"
|
||||
#include "extensions/common/extension_messages.h"
|
||||
|
||||
using url_matcher::URLMatcherConditionSet;
|
||||
|
||||
namespace extensions {
|
||||
|
||||
template <class Func>
|
||||
void ChromeContentRulesRegistry::ForEachWebContents(const Func& func) {
|
||||
for (chrome::BrowserIterator it; !it.done(); it.Next()) {
|
||||
Browser* browser = *it;
|
||||
if (!ManagingRulesForBrowserContext(browser->profile()))
|
||||
continue;
|
||||
|
||||
for (int i = 0, tab_count = browser->tab_strip_model()->count();
|
||||
i < tab_count; ++i) {
|
||||
func(browser->tab_strip_model()->GetWebContentsAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChromeContentRulesRegistry::ChromeContentRulesRegistry(
|
||||
content::BrowserContext* browser_context,
|
||||
RulesCacheDelegate* cache_delegate)
|
||||
@ -46,18 +35,12 @@ ChromeContentRulesRegistry::ChromeContentRulesRegistry(
|
||||
declarative_content_constants::kOnPageChanged,
|
||||
content::BrowserThread::UI,
|
||||
cache_delegate,
|
||||
RulesRegistryService::kDefaultRulesRegistryID),
|
||||
css_condition_tracker_(browser_context, this) {
|
||||
RulesRegistryService::kDefaultRulesRegistryID) {
|
||||
extension_info_map_ = ExtensionSystem::Get(browser_context)->info_map();
|
||||
|
||||
// Set up rule tracking for any existing WebContents.
|
||||
ForEachWebContents([this](content::WebContents* contents) {
|
||||
TrackRulesForWebContents(contents);
|
||||
});
|
||||
|
||||
registrar_.Add(this,
|
||||
chrome::NOTIFICATION_TAB_ADDED,
|
||||
content::NotificationService::AllSources());
|
||||
content::NOTIFICATION_RENDERER_PROCESS_CREATED,
|
||||
content::NotificationService::AllBrowserContextsAndSources());
|
||||
registrar_.Add(this,
|
||||
content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
|
||||
content::NotificationService::AllBrowserContextsAndSources());
|
||||
@ -68,10 +51,10 @@ void ChromeContentRulesRegistry::Observe(
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) {
|
||||
switch (type) {
|
||||
case chrome::NOTIFICATION_TAB_ADDED: {
|
||||
content::WebContents* contents =
|
||||
content::Details<content::WebContents>(details).ptr();
|
||||
TrackRulesForWebContents(contents);
|
||||
case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
|
||||
content::RenderProcessHost* process =
|
||||
content::Source<content::RenderProcessHost>(source).ptr();
|
||||
InstructRenderProcessIfSameBrowserContext(process);
|
||||
break;
|
||||
}
|
||||
case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
|
||||
@ -80,27 +63,25 @@ void ChromeContentRulesRegistry::Observe(
|
||||
// Note that neither non-tab WebContents nor tabs from other browser
|
||||
// contexts will be in the map.
|
||||
active_rules_.erase(tab);
|
||||
matching_css_selectors_.erase(tab);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::RequestEvaluation(
|
||||
content::WebContents* contents) {
|
||||
EvaluateConditionsForTab(contents);
|
||||
}
|
||||
void ChromeContentRulesRegistry::Apply(
|
||||
content::WebContents* contents,
|
||||
const std::vector<std::string>& matching_css_selectors) {
|
||||
matching_css_selectors_[contents] = matching_css_selectors;
|
||||
|
||||
bool ChromeContentRulesRegistry::ShouldManageConditionsForBrowserContext(
|
||||
content::BrowserContext* context) {
|
||||
return ManagingRulesForBrowserContext(context);
|
||||
EvaluateConditionsForTab(contents);
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::DidNavigateMainFrame(
|
||||
content::WebContents* contents,
|
||||
const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params) {
|
||||
if (ContainsKey(active_rules_, contents))
|
||||
css_condition_tracker_.OnWebContentsNavigation(contents, details, params);
|
||||
OnTabNavigation(contents, details.is_in_page);
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::DidNavigateMainFrameOfOriginalContext(
|
||||
@ -108,16 +89,24 @@ void ChromeContentRulesRegistry::DidNavigateMainFrameOfOriginalContext(
|
||||
const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params) {
|
||||
DCHECK(browser_context()->IsOffTheRecord());
|
||||
if (ContainsKey(active_rules_, contents))
|
||||
css_condition_tracker_.OnWebContentsNavigation(contents, details, params);
|
||||
OnTabNavigation(contents, details.is_in_page);
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::TrackRulesForWebContents(
|
||||
content::WebContents* contents) {
|
||||
// We rely on the_rules_ to have a key-value pair for |contents| to know which
|
||||
// WebContents we are working with.
|
||||
active_rules_[contents] = std::set<const ContentRule*>();
|
||||
css_condition_tracker_.TrackForWebContents(contents);
|
||||
void ChromeContentRulesRegistry::OnTabNavigation(content::WebContents* tab,
|
||||
bool is_in_page_navigation) {
|
||||
if (is_in_page_navigation) {
|
||||
// Within-page navigations don't change the set of elements that
|
||||
// exist, and we only support filtering on the top-level URL, so
|
||||
// this can't change which rules match.
|
||||
return;
|
||||
}
|
||||
|
||||
// Top-level navigation produces a new document. Initially, the
|
||||
// document's empty, so no CSS rules match. The renderer will send
|
||||
// an ExtensionHostMsg_OnWatchedPageChange later if any CSS rules
|
||||
// match.
|
||||
matching_css_selectors_[tab].clear();
|
||||
EvaluateConditionsForTab(tab);
|
||||
}
|
||||
|
||||
bool ChromeContentRulesRegistry::ManagingRulesForBrowserContext(
|
||||
@ -230,7 +219,7 @@ std::string ChromeContentRulesRegistry::AddRulesImpl(
|
||||
}
|
||||
url_matcher_.AddConditionSets(all_new_condition_sets);
|
||||
|
||||
UpdateCssSelectorsFromRules();
|
||||
UpdateConditionCache();
|
||||
EvaluateConditionsForAllTabs();
|
||||
|
||||
return std::string();
|
||||
@ -277,7 +266,7 @@ std::string ChromeContentRulesRegistry::RemoveRulesImpl(
|
||||
// Clear URLMatcher based on condition_set_ids that are not needed any more.
|
||||
url_matcher_.RemoveConditionSets(remove_from_url_matcher);
|
||||
|
||||
UpdateCssSelectorsFromRules();
|
||||
UpdateConditionCache();
|
||||
|
||||
return std::string();
|
||||
}
|
||||
@ -297,7 +286,7 @@ std::string ChromeContentRulesRegistry::RemoveAllRulesImpl(
|
||||
return RemoveRulesImpl(extension_id, rule_identifiers);
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::UpdateCssSelectorsFromRules() {
|
||||
void ChromeContentRulesRegistry::UpdateConditionCache() {
|
||||
std::set<std::string> css_selectors; // We rely on this being sorted.
|
||||
for (const std::pair<ContentRule::GlobalRuleId,
|
||||
linked_ptr<const ContentRule>>& rule_id_rule_pair :
|
||||
@ -312,15 +301,34 @@ void ChromeContentRulesRegistry::UpdateCssSelectorsFromRules() {
|
||||
}
|
||||
}
|
||||
|
||||
css_condition_tracker_.SetWatchedCssSelectors(css_selectors);
|
||||
if (css_selectors.size() != watched_css_selectors_.size() ||
|
||||
!std::equal(css_selectors.begin(),
|
||||
css_selectors.end(),
|
||||
watched_css_selectors_.begin())) {
|
||||
watched_css_selectors_.assign(css_selectors.begin(), css_selectors.end());
|
||||
|
||||
for (content::RenderProcessHost::iterator it(
|
||||
content::RenderProcessHost::AllHostsIterator());
|
||||
!it.IsAtEnd();
|
||||
it.Advance()) {
|
||||
content::RenderProcessHost* process = it.GetCurrentValue();
|
||||
InstructRenderProcessIfSameBrowserContext(process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::InstructRenderProcessIfSameBrowserContext(
|
||||
content::RenderProcessHost* process) {
|
||||
if (ManagingRulesForBrowserContext(process->GetBrowserContext()))
|
||||
process->Send(new ExtensionMsg_WatchPages(watched_css_selectors_));
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::EvaluateConditionsForTab(
|
||||
content::WebContents* tab) {
|
||||
extensions::RendererContentMatchData renderer_data;
|
||||
renderer_data.page_url_matches = url_matcher_.MatchURL(tab->GetURL());
|
||||
css_condition_tracker_.GetMatchingCssSelectors(tab,
|
||||
&renderer_data.css_selectors);
|
||||
renderer_data.css_selectors.insert(matching_css_selectors_[tab].begin(),
|
||||
matching_css_selectors_[tab].end());
|
||||
std::set<const ContentRule*> matching_rules =
|
||||
GetMatches(renderer_data, tab->GetBrowserContext()->IsOffTheRecord());
|
||||
if (matching_rules.empty() && !ContainsKey(active_rules_, tab))
|
||||
@ -344,15 +352,22 @@ void ChromeContentRulesRegistry::EvaluateConditionsForTab(
|
||||
}
|
||||
|
||||
if (matching_rules.empty())
|
||||
active_rules_[tab].clear();
|
||||
active_rules_.erase(tab);
|
||||
else
|
||||
swap(matching_rules, prev_matching_rules);
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::EvaluateConditionsForAllTabs() {
|
||||
ForEachWebContents([this](content::WebContents* contents) {
|
||||
EvaluateConditionsForTab(contents);
|
||||
});
|
||||
for (chrome::BrowserIterator it; !it.done(); it.Next()) {
|
||||
Browser* browser = *it;
|
||||
if (!ManagingRulesForBrowserContext(browser->profile()))
|
||||
continue;
|
||||
|
||||
for (int i = 0, tab_count = browser->tab_strip_model()->count();
|
||||
i < tab_count;
|
||||
++i)
|
||||
EvaluateConditionsForTab(browser->tab_strip_model()->GetWebContentsAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
bool ChromeContentRulesRegistry::IsEmpty() const {
|
||||
@ -360,21 +375,6 @@ bool ChromeContentRulesRegistry::IsEmpty() const {
|
||||
url_matcher_.IsEmpty();
|
||||
}
|
||||
|
||||
void ChromeContentRulesRegistry::UpdateMatchingCssSelectorsForTesting(
|
||||
content::WebContents* contents,
|
||||
const std::vector<std::string>& matching_css_selectors) {
|
||||
css_condition_tracker_.UpdateMatchingCssSelectorsForTesting(
|
||||
contents,
|
||||
matching_css_selectors);
|
||||
}
|
||||
|
||||
size_t ChromeContentRulesRegistry::GetActiveRulesCountForTesting() {
|
||||
size_t count = 0;
|
||||
for (auto web_contents_rules_pair : active_rules_)
|
||||
count += web_contents_rules_pair.second.size();
|
||||
return count;
|
||||
}
|
||||
|
||||
ChromeContentRulesRegistry::~ChromeContentRulesRegistry() {
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/extensions/api/declarative_content/content_action.h"
|
||||
#include "chrome/browser/extensions/api/declarative_content/content_condition.h"
|
||||
#include "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
|
||||
#include "components/url_matcher/url_matcher.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
@ -67,17 +66,20 @@ typedef DeclarativeRule<ContentCondition, ContentAction> ContentRule;
|
||||
// side of split-mode extensions to incognito tabs. The non-incognito instance
|
||||
// handles incognito tabs for spanning-mode extensions, plus all non-incognito
|
||||
// tabs.
|
||||
class ChromeContentRulesRegistry
|
||||
: public ContentRulesRegistry,
|
||||
public content::NotificationObserver,
|
||||
public DeclarativeContentCssConditionTrackerDelegate {
|
||||
class ChromeContentRulesRegistry : public ContentRulesRegistry,
|
||||
public content::NotificationObserver {
|
||||
public:
|
||||
// For testing, |ui_part| can be NULL. In that case it constructs the
|
||||
// registry with storage functionality suspended.
|
||||
ChromeContentRulesRegistry(content::BrowserContext* browser_context,
|
||||
RulesCacheDelegate* cache_delegate);
|
||||
|
||||
// ContentRulesRegistry:
|
||||
// ChromeContentRulesRegistry implementation:
|
||||
// Applies all content rules given an update (CSS match change or
|
||||
// page navigation, for now) from the renderer.
|
||||
void Apply(content::WebContents* contents,
|
||||
const std::vector<std::string>& matching_css_selectors) override;
|
||||
|
||||
// Applies all content rules given that a tab was just navigated.
|
||||
void DidNavigateMainFrame(
|
||||
content::WebContents* tab,
|
||||
@ -92,7 +94,7 @@ class ChromeContentRulesRegistry
|
||||
const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params) override;
|
||||
|
||||
// RulesRegistry:
|
||||
// Implementation of RulesRegistry:
|
||||
std::string AddRulesImpl(
|
||||
const std::string& extension_id,
|
||||
const std::vector<linked_ptr<RulesRegistry::Rule>>& rules) override;
|
||||
@ -101,31 +103,14 @@ class ChromeContentRulesRegistry
|
||||
const std::vector<std::string>& rule_identifiers) override;
|
||||
std::string RemoveAllRulesImpl(const std::string& extension_id) override;
|
||||
|
||||
// content::NotificationObserver:
|
||||
// content::NotificationObserver implementation.
|
||||
void Observe(int type,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) override;
|
||||
|
||||
// DeclarativeContentCssConditionTrackerDelegate:
|
||||
void RequestEvaluation(content::WebContents* contents) override;
|
||||
bool ShouldManageConditionsForBrowserContext(
|
||||
content::BrowserContext* context) override;
|
||||
|
||||
// Returns true if this object retains no allocated data. Only for debugging.
|
||||
bool IsEmpty() const;
|
||||
|
||||
// TODO(wittman): Remove once DeclarativeChromeContentRulesRegistry no longer
|
||||
// depends on concrete condition implementations. At that point
|
||||
// DeclarativeChromeContentRulesRegistryTest.ActiveRulesDoesntGrow will be
|
||||
// able to use a test condition object and not need to depend on force setting
|
||||
// matching CSS seleectors.
|
||||
void UpdateMatchingCssSelectorsForTesting(
|
||||
content::WebContents* contents,
|
||||
const std::vector<std::string>& matching_css_selectors);
|
||||
|
||||
// Returns the number of active rules.
|
||||
size_t GetActiveRulesCountForTesting();
|
||||
|
||||
protected:
|
||||
~ChromeContentRulesRegistry() override;
|
||||
|
||||
@ -134,22 +119,27 @@ class ChromeContentRulesRegistry
|
||||
const std::string& extension_id) const;
|
||||
|
||||
private:
|
||||
// Utility function for iterating a lambda over the relevant WebContents.
|
||||
template <class Func>
|
||||
void ForEachWebContents(const Func& func);
|
||||
|
||||
// Set up the state to track rules for |contents|.
|
||||
void TrackRulesForWebContents(content::WebContents* contents);
|
||||
friend class DeclarativeChromeContentRulesRegistryTest;
|
||||
|
||||
// True if this object is managing the rules for |context|.
|
||||
bool ManagingRulesForBrowserContext(content::BrowserContext* context);
|
||||
|
||||
// Applies all content rules given that a tab was just navigated.
|
||||
void OnTabNavigation(content::WebContents* tab, bool is_in_page_navigation);
|
||||
|
||||
std::set<const ContentRule*> GetMatches(
|
||||
const RendererContentMatchData& renderer_data,
|
||||
bool is_incognito_renderer) const;
|
||||
|
||||
// Updates the condition evaluator with the current watched CSS selectors.
|
||||
void UpdateCssSelectorsFromRules();
|
||||
// Scans the rules for the set of conditions they're watching. If the set has
|
||||
// changed, calls InstructRenderProcess() for each RenderProcessHost in the
|
||||
// current browser_context.
|
||||
void UpdateConditionCache();
|
||||
|
||||
// If the renderer process is associated with our browser context, tells it
|
||||
// what page attributes to watch for using an ExtensionMsg_WatchPages.
|
||||
void InstructRenderProcessIfSameBrowserContext(
|
||||
content::RenderProcessHost* process);
|
||||
|
||||
// Evaluates the conditions for |tab| based on the tab state and matching CSS
|
||||
// selectors.
|
||||
@ -162,6 +152,8 @@ class ChromeContentRulesRegistry
|
||||
URLMatcherIdToRule;
|
||||
typedef std::map<ContentRule::GlobalRuleId, linked_ptr<const ContentRule>>
|
||||
RulesMap;
|
||||
typedef std::map<content::WebContents*, std::vector<std::string>>
|
||||
CssSelectors;
|
||||
|
||||
// Map that tells us which ContentRules may match under the condition that
|
||||
// the URLMatcherConditionSet::ID was returned by the |url_matcher_|.
|
||||
@ -170,22 +162,23 @@ class ChromeContentRulesRegistry
|
||||
RulesMap content_rules_;
|
||||
|
||||
// Maps a WebContents to the set of rules that match on that WebContents.
|
||||
// This lets us call Revert as appropriate. Note that this is expected to have
|
||||
// a key-value pair for every WebContents the registry is tracking, even if
|
||||
// the value is the empty set.
|
||||
// This lets us call Revert as appropriate.
|
||||
std::map<content::WebContents*, std::set<const ContentRule*>> active_rules_;
|
||||
|
||||
// Matches URLs for the page_url condition.
|
||||
url_matcher::URLMatcher url_matcher_;
|
||||
|
||||
// Responsible for evaluating the declarative content conditions.
|
||||
DeclarativeContentCssConditionTracker css_condition_tracker_;
|
||||
// All CSS selectors any rule's conditions watch for.
|
||||
std::vector<std::string> watched_css_selectors_;
|
||||
|
||||
// Manages our notification registrations.
|
||||
content::NotificationRegistrar registrar_;
|
||||
|
||||
scoped_refptr<InfoMap> extension_info_map_;
|
||||
|
||||
// Maps tab_id to the matching CSS selectors for the tab.
|
||||
CssSelectors matching_css_selectors_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ChromeContentRulesRegistry);
|
||||
};
|
||||
|
||||
|
@ -7,12 +7,10 @@
|
||||
#include <string>
|
||||
|
||||
#include "base/test/values_test_util.h"
|
||||
#include "chrome/browser/chrome_notification_types.h"
|
||||
#include "chrome/browser/extensions/extension_tab_util.h"
|
||||
#include "chrome/browser/extensions/test_extension_environment.h"
|
||||
#include "chrome/test/base/testing_profile.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/notification_details.h"
|
||||
#include "content/public/browser/notification_source.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/frame_navigate_params.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
@ -20,27 +18,42 @@
|
||||
|
||||
namespace extensions {
|
||||
|
||||
TEST(DeclarativeChromeContentRulesRegistryTest, ActiveRulesDoesntGrow) {
|
||||
using base::test::ParseJson;
|
||||
using testing::HasSubstr;
|
||||
using content::WebContents;
|
||||
|
||||
// Must be outside the anonymous namespace to be a friend of
|
||||
// ContentRulesRegistry.
|
||||
class DeclarativeChromeContentRulesRegistryTest : public testing::Test {
|
||||
protected:
|
||||
using RulesMap =
|
||||
std::map<content::WebContents*, std::set<const ContentRule*>>;
|
||||
static const RulesMap& active_rules(
|
||||
const ChromeContentRulesRegistry& registry) {
|
||||
return registry.active_rules_;
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
TEST_F(DeclarativeChromeContentRulesRegistryTest, ActiveRulesDoesntGrow) {
|
||||
TestExtensionEnvironment env;
|
||||
|
||||
scoped_refptr<ChromeContentRulesRegistry> registry(
|
||||
new ChromeContentRulesRegistry(env.profile(), NULL));
|
||||
|
||||
EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
|
||||
EXPECT_EQ(0u, active_rules(*registry.get()).size());
|
||||
|
||||
scoped_ptr<content::WebContents> tab = env.MakeTab();
|
||||
// Let the registry know about the tab.
|
||||
registry->Observe(chrome::NOTIFICATION_TAB_ADDED,
|
||||
content::Source<content::WebContentsDelegate>(nullptr),
|
||||
content::Details<content::WebContents>(tab.get()));
|
||||
registry->DidNavigateMainFrame(tab.get(), content::LoadCommittedDetails(),
|
||||
content::FrameNavigateParams());
|
||||
EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
|
||||
content::LoadCommittedDetails load_details;
|
||||
content::FrameNavigateParams navigate_params;
|
||||
scoped_ptr<WebContents> tab = env.MakeTab();
|
||||
registry->DidNavigateMainFrame(tab.get(), load_details, navigate_params);
|
||||
EXPECT_EQ(0u, active_rules(*registry.get()).size());
|
||||
|
||||
// Add a rule.
|
||||
linked_ptr<RulesRegistry::Rule> rule(new RulesRegistry::Rule);
|
||||
RulesRegistry::Rule::Populate(
|
||||
*base::test::ParseJson(
|
||||
*ParseJson(
|
||||
"{\n"
|
||||
" \"id\": \"rule1\",\n"
|
||||
" \"priority\": 100,\n"
|
||||
@ -57,35 +70,30 @@ TEST(DeclarativeChromeContentRulesRegistryTest, ActiveRulesDoesntGrow) {
|
||||
std::vector<linked_ptr<RulesRegistry::Rule> > rules;
|
||||
rules.push_back(rule);
|
||||
|
||||
const Extension* extension = env.MakeExtension(*base::test::ParseJson(
|
||||
const Extension* extension = env.MakeExtension(*ParseJson(
|
||||
"{\"page_action\": {}}"));
|
||||
registry->AddRulesImpl(extension->id(), rules);
|
||||
|
||||
registry->DidNavigateMainFrame(tab.get(), content::LoadCommittedDetails(),
|
||||
content::FrameNavigateParams());
|
||||
EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
|
||||
registry->DidNavigateMainFrame(tab.get(), load_details, navigate_params);
|
||||
EXPECT_EQ(0u, active_rules(*registry.get()).size());
|
||||
|
||||
std::vector<std::string> css_selectors;
|
||||
css_selectors.push_back("input");
|
||||
registry->UpdateMatchingCssSelectorsForTesting(tab.get(), css_selectors);
|
||||
EXPECT_EQ(1u, registry->GetActiveRulesCountForTesting());
|
||||
registry->Apply(tab.get(), css_selectors);
|
||||
EXPECT_EQ(1u, active_rules(*registry.get()).size());
|
||||
|
||||
// Closing the tab should erase its entry from active_rules_.
|
||||
tab.reset();
|
||||
EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
|
||||
EXPECT_EQ(0u, active_rules(*registry.get()).size());
|
||||
|
||||
tab = env.MakeTab();
|
||||
// Let the registry know about the tab.
|
||||
registry->Observe(chrome::NOTIFICATION_TAB_ADDED,
|
||||
content::Source<content::WebContentsDelegate>(nullptr),
|
||||
content::Details<content::WebContents>(tab.get()));
|
||||
registry->UpdateMatchingCssSelectorsForTesting(tab.get(), css_selectors);
|
||||
EXPECT_EQ(1u, registry->GetActiveRulesCountForTesting());
|
||||
registry->Apply(tab.get(), css_selectors);
|
||||
EXPECT_EQ(1u, active_rules(*registry.get()).size());
|
||||
// Navigating the tab should erase its entry from active_rules_ if
|
||||
// it no longer matches.
|
||||
registry->DidNavigateMainFrame(tab.get(), content::LoadCommittedDetails(),
|
||||
content::FrameNavigateParams());
|
||||
EXPECT_EQ(0u, registry->GetActiveRulesCountForTesting());
|
||||
registry->DidNavigateMainFrame(tab.get(), load_details, navigate_params);
|
||||
EXPECT_EQ(0u, active_rules(*registry.get()).size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace extensions
|
||||
|
@ -16,7 +16,6 @@
|
||||
namespace base {
|
||||
class Time;
|
||||
class Value;
|
||||
class DictionaryValue;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_CONTENT_CONDITION_H_
|
||||
#define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_CONTENT_CONDITION_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -12,17 +13,12 @@
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/values.h"
|
||||
#include "components/url_matcher/url_matcher.h"
|
||||
#include "extensions/browser/api/declarative/declarative_rule.h"
|
||||
|
||||
namespace base {
|
||||
class Value;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
|
||||
class Extension;
|
||||
|
||||
struct RendererContentMatchData {
|
||||
RendererContentMatchData();
|
||||
~RendererContentMatchData();
|
||||
|
@ -1,254 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "chrome/browser/chrome_notification_types.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/notification_service.h"
|
||||
#include "content/public/browser/notification_source.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "extensions/common/extension_messages.h"
|
||||
#include "ipc/ipc_message.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
//
|
||||
// PerWebContentsTracker
|
||||
//
|
||||
|
||||
// Monitors CSS selector matching state on one WebContents.
|
||||
class DeclarativeContentCssConditionTracker::
|
||||
PerWebContentsTracker : public content::WebContentsObserver {
|
||||
public:
|
||||
using RequestEvaluationCallback =
|
||||
DeclarativeContentCssConditionTrackerDelegate::WebContentsCallback;
|
||||
using DestroyingCallback =
|
||||
base::Callback<void(PerWebContentsTracker*)>;
|
||||
|
||||
PerWebContentsTracker(
|
||||
content::WebContents* contents,
|
||||
const RequestEvaluationCallback& request_evaluation,
|
||||
const DestroyingCallback& destroying);
|
||||
~PerWebContentsTracker() override;
|
||||
|
||||
void OnWebContentsNavigation(const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params);
|
||||
|
||||
// See comment on similar function above.
|
||||
void UpdateMatchingCssSelectorsForTesting(
|
||||
const std::vector<std::string>& matching_css_selectors);
|
||||
|
||||
const std::vector<std::string>& matching_css_selectors() const {
|
||||
return matching_css_selectors_;
|
||||
}
|
||||
|
||||
private:
|
||||
// content::WebContentsObserver overrides.
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
void WebContentsDestroyed() override;
|
||||
|
||||
void OnWatchedPageChange(const std::vector<std::string>& css_selectors);
|
||||
|
||||
const RequestEvaluationCallback request_evaluation_;
|
||||
const DestroyingCallback destroying_;
|
||||
|
||||
std::vector<std::string> matching_css_selectors_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PerWebContentsTracker);
|
||||
};
|
||||
|
||||
DeclarativeContentCssConditionTracker::PerWebContentsTracker::
|
||||
PerWebContentsTracker(
|
||||
content::WebContents* contents,
|
||||
const RequestEvaluationCallback& request_evaluation,
|
||||
const DestroyingCallback& destroying)
|
||||
: WebContentsObserver(contents),
|
||||
request_evaluation_(request_evaluation),
|
||||
destroying_(destroying) {
|
||||
}
|
||||
|
||||
DeclarativeContentCssConditionTracker::PerWebContentsTracker::
|
||||
~PerWebContentsTracker() {
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
|
||||
OnWebContentsNavigation(const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params) {
|
||||
if (details.is_in_page) {
|
||||
// Within-page navigations don't change the set of elements that
|
||||
// exist, and we only support filtering on the top-level URL, so
|
||||
// this can't change which rules match.
|
||||
return;
|
||||
}
|
||||
|
||||
// Top-level navigation produces a new document. Initially, the
|
||||
// document's empty, so no CSS rules match. The renderer will send
|
||||
// an ExtensionHostMsg_OnWatchedPageChange later if any CSS rules
|
||||
// match.
|
||||
matching_css_selectors_.clear();
|
||||
request_evaluation_.Run(web_contents());
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
|
||||
UpdateMatchingCssSelectorsForTesting(
|
||||
const std::vector<std::string>& matching_css_selectors) {
|
||||
matching_css_selectors_ = matching_css_selectors;
|
||||
request_evaluation_.Run(web_contents());
|
||||
}
|
||||
|
||||
bool
|
||||
DeclarativeContentCssConditionTracker::PerWebContentsTracker::
|
||||
OnMessageReceived(
|
||||
const IPC::Message& message) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(PerWebContentsTracker, message)
|
||||
IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
|
||||
OnWatchedPageChange)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
return handled;
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::PerWebContentsTracker::
|
||||
WebContentsDestroyed() {
|
||||
destroying_.Run(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
void
|
||||
DeclarativeContentCssConditionTracker::PerWebContentsTracker::
|
||||
OnWatchedPageChange(
|
||||
const std::vector<std::string>& css_selectors) {
|
||||
matching_css_selectors_ = css_selectors;
|
||||
request_evaluation_.Run(web_contents());
|
||||
}
|
||||
|
||||
//
|
||||
// DeclarativeContentCssConditionTrackerDelegate
|
||||
//
|
||||
|
||||
DeclarativeContentCssConditionTrackerDelegate::
|
||||
DeclarativeContentCssConditionTrackerDelegate() {}
|
||||
|
||||
DeclarativeContentCssConditionTrackerDelegate::
|
||||
~DeclarativeContentCssConditionTrackerDelegate() {}
|
||||
|
||||
//
|
||||
// DeclarativeContentCssConditionTracker
|
||||
//
|
||||
|
||||
DeclarativeContentCssConditionTracker::DeclarativeContentCssConditionTracker(
|
||||
content::BrowserContext* context,
|
||||
DeclarativeContentCssConditionTrackerDelegate* delegate)
|
||||
: context_(context),
|
||||
delegate_(delegate) {
|
||||
registrar_.Add(this,
|
||||
content::NOTIFICATION_RENDERER_PROCESS_CREATED,
|
||||
content::NotificationService::AllBrowserContextsAndSources());
|
||||
}
|
||||
|
||||
DeclarativeContentCssConditionTracker::
|
||||
~DeclarativeContentCssConditionTracker() {
|
||||
// All monitored WebContents are expected to be destroyed before this object.
|
||||
CHECK(per_web_contents_tracker_.empty());
|
||||
}
|
||||
|
||||
// We use the sorted propery of the set for equality checks with
|
||||
// watched_css_selectors_, which is guaranteed to be sorted because it's set
|
||||
// from the set contents.
|
||||
void DeclarativeContentCssConditionTracker::SetWatchedCssSelectors(
|
||||
const std::set<std::string>& new_watched_css_selectors) {
|
||||
if (new_watched_css_selectors.size() != watched_css_selectors_.size() ||
|
||||
!std::equal(new_watched_css_selectors.begin(),
|
||||
new_watched_css_selectors.end(),
|
||||
watched_css_selectors_.begin())) {
|
||||
watched_css_selectors_.assign(new_watched_css_selectors.begin(),
|
||||
new_watched_css_selectors.end());
|
||||
|
||||
for (content::RenderProcessHost::iterator it(
|
||||
content::RenderProcessHost::AllHostsIterator());
|
||||
!it.IsAtEnd();
|
||||
it.Advance()) {
|
||||
InstructRenderProcessIfManagingBrowserContext(it.GetCurrentValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::TrackForWebContents(
|
||||
content::WebContents* contents) {
|
||||
CreatePerWebContentsTracker(contents);
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::OnWebContentsNavigation(
|
||||
content::WebContents* contents,
|
||||
const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params) {
|
||||
per_web_contents_tracker_[contents]->OnWebContentsNavigation(details, params);
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::GetMatchingCssSelectors(
|
||||
content::WebContents* contents,
|
||||
base::hash_set<std::string>* css_selectors) {
|
||||
const std::vector<std::string>& matching_css_selectors =
|
||||
per_web_contents_tracker_[contents]->matching_css_selectors();
|
||||
css_selectors->insert(matching_css_selectors.begin(),
|
||||
matching_css_selectors.end());
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::
|
||||
UpdateMatchingCssSelectorsForTesting(
|
||||
content::WebContents* contents,
|
||||
const std::vector<std::string>& matching_css_selectors) {
|
||||
per_web_contents_tracker_[contents]->
|
||||
UpdateMatchingCssSelectorsForTesting(matching_css_selectors);
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::CreatePerWebContentsTracker(
|
||||
content::WebContents* contents) {
|
||||
// This is a weak pointer; PerWebContentsTracker owns itself.
|
||||
per_web_contents_tracker_[contents] =
|
||||
new PerWebContentsTracker(
|
||||
contents,
|
||||
base::Bind(&DeclarativeContentCssConditionTrackerDelegate::
|
||||
RequestEvaluation,
|
||||
base::Unretained(delegate_)),
|
||||
base::Bind(&DeclarativeContentCssConditionTracker::
|
||||
RemovePerWebContentsTracker,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::Observe(
|
||||
int type,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) {
|
||||
switch (type) {
|
||||
case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
|
||||
content::RenderProcessHost* process =
|
||||
content::Source<content::RenderProcessHost>(source).ptr();
|
||||
InstructRenderProcessIfManagingBrowserContext(process);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::
|
||||
InstructRenderProcessIfManagingBrowserContext(
|
||||
content::RenderProcessHost* process) {
|
||||
if (delegate_->ShouldManageConditionsForBrowserContext(
|
||||
process->GetBrowserContext())) {
|
||||
process->Send(new ExtensionMsg_WatchPages(watched_css_selectors_));
|
||||
}
|
||||
}
|
||||
|
||||
void DeclarativeContentCssConditionTracker::RemovePerWebContentsTracker(
|
||||
PerWebContentsTracker* tracker) {
|
||||
per_web_contents_tracker_.erase(tracker->web_contents());
|
||||
}
|
||||
|
||||
} // namespace extensions
|
@ -1,137 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_DECLARATIVE_CONTENT_CSS_CONDITION_TRACKER_H_
|
||||
#define CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_DECLARATIVE_CONTENT_CSS_CONDITION_TRACKER_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
struct FrameNavigateParams;
|
||||
struct LoadCommittedDetails;
|
||||
class RenderProcessHost;
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// Interface that allows the DeclarativeContentCssConditionTracker to request
|
||||
// condition evaluation, and shields it from having to know about Browsers.
|
||||
class DeclarativeContentCssConditionTrackerDelegate {
|
||||
public:
|
||||
// Callback for per-tab invocations.
|
||||
using WebContentsCallback =
|
||||
base::Callback<void(content::WebContents* content)>;
|
||||
|
||||
// Requests re-evaluation of conditions for |contents|.
|
||||
virtual void RequestEvaluation(content::WebContents* contents) = 0;
|
||||
|
||||
// Returns true if the evaluator should manage condition state for |context|.
|
||||
virtual bool ShouldManageConditionsForBrowserContext(
|
||||
content::BrowserContext* context) = 0;
|
||||
|
||||
protected:
|
||||
DeclarativeContentCssConditionTrackerDelegate();
|
||||
virtual ~DeclarativeContentCssConditionTrackerDelegate();
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTrackerDelegate);
|
||||
};
|
||||
|
||||
// Supports watching of CSS selectors to across tab contents in a browser
|
||||
// context, and querying for the matching CSS selectors for a context.
|
||||
class DeclarativeContentCssConditionTracker
|
||||
: public content::NotificationObserver {
|
||||
public:
|
||||
DeclarativeContentCssConditionTracker(
|
||||
content::BrowserContext* context,
|
||||
DeclarativeContentCssConditionTrackerDelegate* delegate);
|
||||
~DeclarativeContentCssConditionTracker() override;
|
||||
|
||||
// Sets the set of CSS selectors to watch for CSS condition evaluation.
|
||||
void SetWatchedCssSelectors(
|
||||
const std::set<std::string>& watched_css_selectors);
|
||||
|
||||
// Requests that CSS conditions be tracked for |contents|.
|
||||
void TrackForWebContents(content::WebContents* contents);
|
||||
|
||||
// Handles navigation of |contents|. We depend on the caller to notify us of
|
||||
// this event rather than listening for it ourselves, so that the caller can
|
||||
// coordinate evaluation with all the trackers that respond to it. If we
|
||||
// listened ourselves and requested rule evaluation before another tracker
|
||||
// received the notification, our conditions would be evaluated based on the
|
||||
// new URL while the other tracker's conditions would still be evaluated based
|
||||
// on the previous URL.
|
||||
void OnWebContentsNavigation(content::WebContents* contents,
|
||||
const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params);
|
||||
|
||||
// Inserts the currently-matching CSS selectors into |css_selectors|. We use
|
||||
// hash_set for maximally efficient lookup.
|
||||
void GetMatchingCssSelectors(content::WebContents* contents,
|
||||
base::hash_set<std::string>* css_selectors);
|
||||
|
||||
// TODO(wittman): Remove once DeclarativeChromeContentRulesRegistry no longer
|
||||
// depends on concrete condition implementations. At that point
|
||||
// DeclarativeChromeContentRulesRegistryTest.ActiveRulesDoesntGrow will be
|
||||
// able to use a test condition object and not need to depend on force setting
|
||||
// matching CSS seleectors.
|
||||
void UpdateMatchingCssSelectorsForTesting(
|
||||
content::WebContents* contents,
|
||||
const std::vector<std::string>& matching_css_selectors);
|
||||
|
||||
private:
|
||||
class PerWebContentsTracker;
|
||||
|
||||
// Instantiate a PerWebContentsTracker watching |contents|.
|
||||
void CreatePerWebContentsTracker(content::WebContents* contents);
|
||||
|
||||
// content::NotificationObserver implementation.
|
||||
void Observe(int type,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) override;
|
||||
|
||||
// If the renderer process is associated with our browser context, tells it
|
||||
// what page attributes to watch for using an ExtensionMsg_WatchPages.
|
||||
void InstructRenderProcessIfManagingBrowserContext(
|
||||
content::RenderProcessHost* process);
|
||||
|
||||
// Called by PerWebContentsTracker on destruction.
|
||||
void RemovePerWebContentsTracker(PerWebContentsTracker* tracker);
|
||||
|
||||
// The context whose state we're monitoring for evaluation.
|
||||
content::BrowserContext* context_;
|
||||
|
||||
// All CSS selectors that are watched for by any rule's conditions. This
|
||||
// vector is sorted by construction.
|
||||
std::vector<std::string> watched_css_selectors_;
|
||||
|
||||
// Maps WebContents to the tracker for that WebContents
|
||||
// state. PerWebContentsTracker owns itself, so this pointer is weak.
|
||||
std::map<content::WebContents*, PerWebContentsTracker*>
|
||||
per_web_contents_tracker_;
|
||||
|
||||
// Weak.
|
||||
DeclarativeContentCssConditionTrackerDelegate* delegate_;
|
||||
|
||||
// Manages our notification registrations.
|
||||
content::NotificationRegistrar registrar_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTracker);
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // CHROME_BROWSER_EXTENSIONS_API_DECLARATIVE_CONTENT_DECLARATIVE_CONTENT_CSS_CONDITION_TRACKER_H_
|
@ -1,199 +0,0 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h"
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/scoped_vector.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "chrome/test/base/testing_profile.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/test/browser_test_utils.h"
|
||||
#include "content/public/test/mock_render_process_host.h"
|
||||
#include "content/public/test/test_browser_thread_bundle.h"
|
||||
#include "content/public/test/test_renderer_host.h"
|
||||
#include "content/public/test/web_contents_tester.h"
|
||||
#include "extensions/common/extension_messages.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
using testing::UnorderedElementsAreArray;
|
||||
|
||||
class DeclarativeContentCssConditionTrackerTest : public testing::Test {
|
||||
public:
|
||||
DeclarativeContentCssConditionTrackerTest()
|
||||
: profile_(new TestingProfile),
|
||||
delegate_(web_contents_) {
|
||||
}
|
||||
|
||||
~DeclarativeContentCssConditionTrackerTest() override {
|
||||
web_contents_.clear();
|
||||
// MockRenderProcessHosts are deleted from the message loop, and their
|
||||
// deletion must complete before RenderViewHostTestEnabler's destructor is
|
||||
// run.
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
protected:
|
||||
class Delegate : public DeclarativeContentCssConditionTrackerDelegate {
|
||||
public:
|
||||
Delegate(const ScopedVector<content::WebContents>& web_contents)
|
||||
: web_contents_(web_contents),
|
||||
evaluation_requests_(0) {
|
||||
}
|
||||
|
||||
int evaluation_requests() { return evaluation_requests_; }
|
||||
|
||||
// DeclarativeContentCssConditionTrackerDelegate:
|
||||
void RequestEvaluation(content::WebContents* contents) override {
|
||||
++evaluation_requests_;
|
||||
}
|
||||
|
||||
bool ShouldManageConditionsForBrowserContext(
|
||||
content::BrowserContext* context) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Reference to the test's WebContents vector.
|
||||
const ScopedVector<content::WebContents>& web_contents_;
|
||||
int evaluation_requests_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Delegate);
|
||||
};
|
||||
|
||||
// Creates a new DeclarativeContentCssConditionTracker and retains ownership.
|
||||
DeclarativeContentCssConditionTracker* MakeTracker() {
|
||||
trackers_.push_back(
|
||||
new DeclarativeContentCssConditionTracker(profile(), delegate()));
|
||||
return trackers_.back();
|
||||
}
|
||||
|
||||
// Creates a new WebContents and retains ownership.
|
||||
content::WebContents* MakeTab() {
|
||||
web_contents_.push_back(
|
||||
content::WebContentsTester::CreateTestWebContents(profile_.get(),
|
||||
nullptr));
|
||||
return web_contents_.back();
|
||||
}
|
||||
|
||||
// Expect an ExtensionMsg_WatchPages message in |sink| with |selectors| as the
|
||||
// param, after invoking |func|.
|
||||
template <class Func>
|
||||
void ExpectWatchPagesMessage(IPC::TestSink& sink,
|
||||
const std::set<std::string>& selectors,
|
||||
const Func& func) {
|
||||
sink.ClearMessages();
|
||||
func();
|
||||
EXPECT_EQ(1u, sink.message_count());
|
||||
const IPC::Message* message =
|
||||
sink.GetUniqueMessageMatching(ExtensionMsg_WatchPages::ID);
|
||||
ASSERT_TRUE(message);
|
||||
ExtensionMsg_WatchPages::Param params;
|
||||
ExtensionMsg_WatchPages::Read(message, ¶ms);
|
||||
EXPECT_THAT(base::get<0>(params), UnorderedElementsAreArray(selectors));
|
||||
}
|
||||
|
||||
// Sends an OnWatchedPageChange message to the tab.
|
||||
void SendOnWatchedPageChangeMessage(
|
||||
content::WebContents* tab,
|
||||
const std::vector<std::string>& selectors) {
|
||||
ExtensionHostMsg_OnWatchedPageChange page_change(tab->GetRoutingID(),
|
||||
selectors);
|
||||
content::MockRenderProcessHost* process =
|
||||
static_cast<content::MockRenderProcessHost*>(
|
||||
tab->GetRenderViewHost()->GetProcess());
|
||||
|
||||
EXPECT_TRUE(process->OnMessageReceived(page_change));
|
||||
}
|
||||
|
||||
Profile* profile() { return profile_.get(); }
|
||||
Delegate* delegate() { return &delegate_; }
|
||||
|
||||
private:
|
||||
content::TestBrowserThreadBundle thread_bundle_;
|
||||
|
||||
// Enables MockRenderProcessHosts.
|
||||
content::RenderViewHostTestEnabler render_view_host_test_enabler_;
|
||||
|
||||
const scoped_ptr<TestingProfile> profile_;
|
||||
ScopedVector<DeclarativeContentCssConditionTracker> trackers_;
|
||||
ScopedVector<content::WebContents> web_contents_;
|
||||
Delegate delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DeclarativeContentCssConditionTrackerTest);
|
||||
};
|
||||
|
||||
// Tests the basic flow of operations on the
|
||||
// DeclarativeContentCssConditionTracker.
|
||||
TEST_F(DeclarativeContentCssConditionTrackerTest, Basic) {
|
||||
DeclarativeContentCssConditionTracker *tracker = MakeTracker();
|
||||
int expected_evaluation_requests = 0;
|
||||
|
||||
content::WebContents* const tab = MakeTab();
|
||||
tracker->TrackForWebContents(tab);
|
||||
EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
||||
|
||||
content::MockRenderProcessHost* process =
|
||||
static_cast<content::MockRenderProcessHost*>(
|
||||
tab->GetRenderViewHost()->GetProcess());
|
||||
|
||||
// Check that calling SetWatchedCssSelectors sends a WatchPages message with
|
||||
// the selectors to the tab's RenderProcessHost.
|
||||
std::set<std::string> watched_selectors;
|
||||
watched_selectors.insert("a");
|
||||
watched_selectors.insert("div");
|
||||
ExpectWatchPagesMessage(process->sink(), watched_selectors,
|
||||
[&tracker, &watched_selectors]() {
|
||||
tracker->SetWatchedCssSelectors(watched_selectors);
|
||||
});
|
||||
EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
||||
|
||||
// Check that receiving an OnWatchedPageChange message from the tab results in
|
||||
// a request for condition evaluation.
|
||||
const std::vector<std::string> matched_selectors(1, "div");
|
||||
SendOnWatchedPageChangeMessage(tab, matched_selectors);
|
||||
EXPECT_EQ(++expected_evaluation_requests, delegate()->evaluation_requests());
|
||||
|
||||
// Check that GetMatchingCssSelectors produces the same matched selectors as
|
||||
// were sent by the OnWatchedPageChange message.
|
||||
base::hash_set<std::string> matching_selectors;
|
||||
tracker->GetMatchingCssSelectors(tab, &matching_selectors);
|
||||
EXPECT_THAT(matching_selectors,
|
||||
UnorderedElementsAreArray(matched_selectors));
|
||||
EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
||||
|
||||
// Check that an in-page navigation has no effect on the matching selectors.
|
||||
{
|
||||
content::LoadCommittedDetails details;
|
||||
details.is_in_page = true;
|
||||
content::FrameNavigateParams params;
|
||||
tracker->OnWebContentsNavigation(tab, details, params);
|
||||
matching_selectors.clear();
|
||||
tracker->GetMatchingCssSelectors(tab, &matching_selectors);
|
||||
EXPECT_THAT(matching_selectors,
|
||||
UnorderedElementsAreArray(matched_selectors));
|
||||
EXPECT_EQ(expected_evaluation_requests, delegate()->evaluation_requests());
|
||||
}
|
||||
|
||||
// Check that a non in-page navigation clears the matching selectors and
|
||||
// requests condition evaluation.
|
||||
{
|
||||
content::LoadCommittedDetails details;
|
||||
details.is_in_page = false;
|
||||
content::FrameNavigateParams params;
|
||||
tracker->OnWebContentsNavigation(tab, details, params);
|
||||
matching_selectors.clear();
|
||||
tracker->GetMatchingCssSelectors(tab, &matching_selectors);
|
||||
EXPECT_TRUE(matching_selectors.empty());
|
||||
EXPECT_EQ(++expected_evaluation_requests,
|
||||
delegate()->evaluation_requests());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extensions
|
@ -264,6 +264,8 @@ bool TabHelper::OnMessageReceived(const IPC::Message& message) {
|
||||
IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
|
||||
IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting,
|
||||
OnContentScriptsExecuting)
|
||||
IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
|
||||
OnWatchedPageChange)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
return handled;
|
||||
@ -431,6 +433,15 @@ void TabHelper::OnContentScriptsExecuting(
|
||||
OnScriptsExecuted(web_contents(), executing_scripts_map, on_url));
|
||||
}
|
||||
|
||||
void TabHelper::OnWatchedPageChange(
|
||||
const std::vector<std::string>& css_selectors) {
|
||||
if (ExtensionSystem::Get(profile_)->extension_service() &&
|
||||
RulesRegistryService::Get(profile_)) {
|
||||
RulesRegistryService::Get(profile_)->content_rules_registry()->Apply(
|
||||
web_contents(), css_selectors);
|
||||
}
|
||||
}
|
||||
|
||||
void TabHelper::OnDetailedConsoleMessageAdded(
|
||||
const base::string16& message,
|
||||
const base::string16& source,
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
@ -170,6 +171,7 @@ class TabHelper : public content::WebContentsObserver,
|
||||
void OnContentScriptsExecuting(
|
||||
const ScriptExecutionObserver::ExecutingScriptsMap& extension_ids,
|
||||
const GURL& on_url);
|
||||
void OnWatchedPageChange(const std::vector<std::string>& css_selectors);
|
||||
void OnDetailedConsoleMessageAdded(const base::string16& message,
|
||||
const base::string16& source,
|
||||
const StackTrace& stack_trace,
|
||||
|
@ -213,8 +213,6 @@
|
||||
'browser/extensions/api/declarative_content/content_condition.h',
|
||||
'browser/extensions/api/declarative_content/content_constants.cc',
|
||||
'browser/extensions/api/declarative_content/content_constants.h',
|
||||
'browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.cc',
|
||||
'browser/extensions/api/declarative_content/declarative_content_css_condition_tracker.h',
|
||||
'browser/extensions/api/desktop_capture/desktop_capture_api.cc',
|
||||
'browser/extensions/api/desktop_capture/desktop_capture_api.h',
|
||||
'browser/extensions/api/desktop_capture/desktop_capture_base.cc',
|
||||
|
@ -656,7 +656,6 @@
|
||||
'browser/extensions/api/declarative_content/chrome_content_rules_registry_unittest.cc',
|
||||
'browser/extensions/api/declarative_content/content_action_unittest.cc',
|
||||
'browser/extensions/api/declarative_content/content_condition_unittest.cc',
|
||||
'browser/extensions/api/declarative_content/declarative_content_css_condition_tracker_unittest.cc',
|
||||
'browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc',
|
||||
'browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc',
|
||||
'browser/extensions/api/developer_private/developer_private_api_unittest.cc',
|
||||
|
@ -36,6 +36,12 @@ class ContentRulesRegistry : public RulesRegistry {
|
||||
cache_delegate,
|
||||
rules_registry_id) {}
|
||||
|
||||
// Applies all content rules given an update (CSS match change or
|
||||
// page navigation, for now) from the renderer.
|
||||
virtual void Apply(
|
||||
content::WebContents* contents,
|
||||
const std::vector<std::string>& matching_css_selectors) = 0;
|
||||
|
||||
// Applies all content rules given that a tab was just navigated.
|
||||
virtual void DidNavigateMainFrame(
|
||||
content::WebContents* tab,
|
||||
|
Reference in New Issue
Block a user