diff --git a/DEPS b/DEPS index ffebe5e..75cfadb 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'c1eee0356bdae023dd05c15e27f02c5db0b17e49', + 'v8_revision': '4bfecb6a9f37d83262c493545f43112266698e9a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other.
diff --git a/chrome/browser/history/web_history_service_factory.cc b/chrome/browser/history/web_history_service_factory.cc index d0149fddb..a63cedc 100644 --- a/chrome/browser/history/web_history_service_factory.cc +++ b/chrome/browser/history/web_history_service_factory.cc
@@ -20,9 +20,8 @@ bool IsHistorySyncEnabled(Profile* profile) { browser_sync::ProfileSyncService* sync = ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); - return sync && - sync->IsSyncActive() && - sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES); + return sync && sync->IsSyncActive() && !sync->IsLocalSyncEnabled() && + sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES); } } // namespace
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc index 9138af4c..1f19e9d6 100644 --- a/chrome/browser/prefs/chrome_command_line_pref_store.cc +++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -83,7 +83,7 @@ #endif {switches::kUnsafePacUrl, prefs::kPacHttpsUrlStrippingEnabled, false}, {switches::kEnableLocalSyncBackend, - syncer::prefs::kEnableLocalSyncBackend, false}, + syncer::prefs::kEnableLocalSyncBackend, true}, }; const CommandLinePrefStore::SwitchToPreferenceMapEntry
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc index ce61b07..f9c8481 100644 --- a/chrome/browser/sync/profile_sync_service_factory.cc +++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -74,6 +74,11 @@ latency, base::TimeTicks::Now())); } +#if defined(OS_WIN) +static const base::FilePath::CharType kLoopbackServerBackendFilename[] = + FILE_PATH_LITERAL("profile.pb"); +#endif + } // anonymous namespace // static @@ -142,33 +147,68 @@ Profile* profile = Profile::FromBrowserContext(context); - SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile); + init_params.network_time_update_callback = base::Bind(&UpdateNetworkTime); + init_params.base_directory = profile->GetPath(); + init_params.url_request_context = profile->GetRequestContext(); + init_params.debug_identifier = profile->GetDebugName(); + init_params.channel = chrome::GetChannel(); + init_params.blocking_pool = content::BrowserThread::GetBlockingPool(); - // Always create the GCMProfileService instance such that we can listen to - // the profile notifications and purge the GCM store when the profile is - // being signed out. - gcm::GCMProfileServiceFactory::GetForProfile(profile); + bool local_sync_backend_enabled = false; - // TODO(atwilson): Change AboutSigninInternalsFactory to load on startup - // once http://crbug.com/171406 has been fixed. - AboutSigninInternalsFactory::GetForProfile(profile); +// Since the local sync backend is currently only supported on Windows don't +// even check the pref on other os-es. +#if defined(OS_WIN) + syncer::SyncPrefs prefs(profile->GetPrefs()); + local_sync_backend_enabled = prefs.IsLocalSyncEnabled(); + if (local_sync_backend_enabled) { + // This code as it is now will assume the same profile order is present on + // all machines, which is not a given. It is to be defined if only the + // Default profile should get this treatment or all profile as is the case + // now. The solution for now will be to assume profiles are created in the + // same order on all machines and in the future decide if only the Default + // one should be considered roamed. + init_params.local_sync_backend_folder = prefs.GetLocalSyncBackendDir(); + init_params.local_sync_backend_folder = + init_params.local_sync_backend_folder.Append( + init_params.base_directory.BaseName()); + init_params.local_sync_backend_folder = + init_params.local_sync_backend_folder.Append( + kLoopbackServerBackendFilename); - init_params.signin_wrapper = - base::MakeUnique<SupervisedUserSigninManagerWrapper>(profile, signin); - init_params.oauth2_token_service = - ProfileOAuth2TokenServiceFactory::GetForProfile(profile); - init_params.gaia_cookie_manager_service = - GaiaCookieManagerServiceFactory::GetForProfile(profile); + init_params.start_behavior = ProfileSyncService::AUTO_START; + } +#endif // defined(OS_WIN) - // TODO(tim): Currently, AUTO/MANUAL settings refer to the *first* time sync - // is set up and *not* a browser restart for a manual-start platform (where - // sync has already been set up, and should be able to start without user - // intervention). We can get rid of the browser_default eventually, but - // need to take care that ProfileSyncService doesn't get tripped up between - // those two cases. Bug 88109. - init_params.start_behavior = browser_defaults::kSyncAutoStarts - ? ProfileSyncService::AUTO_START - : ProfileSyncService::MANUAL_START; + if (!local_sync_backend_enabled) { + SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile); + + // Always create the GCMProfileService instance such that we can listen to + // the profile notifications and purge the GCM store when the profile is + // being signed out. + gcm::GCMProfileServiceFactory::GetForProfile(profile); + + // TODO(atwilson): Change AboutSigninInternalsFactory to load on startup + // once http://crbug.com/171406 has been fixed. + AboutSigninInternalsFactory::GetForProfile(profile); + + init_params.signin_wrapper = + base::MakeUnique<SupervisedUserSigninManagerWrapper>(profile, signin); + init_params.oauth2_token_service = + ProfileOAuth2TokenServiceFactory::GetForProfile(profile); + init_params.gaia_cookie_manager_service = + GaiaCookieManagerServiceFactory::GetForProfile(profile); + + // TODO(tim): Currently, AUTO/MANUAL settings refer to the *first* time sync + // is set up and *not* a browser restart for a manual-start platform (where + // sync has already been set up, and should be able to start without user + // intervention). We can get rid of the browser_default eventually, but + // need to take care that ProfileSyncService doesn't get tripped up between + // those two cases. Bug 88109. + init_params.start_behavior = browser_defaults::kSyncAutoStarts + ? ProfileSyncService::AUTO_START + : ProfileSyncService::MANUAL_START; + } if (!client_factory_) { init_params.sync_client = @@ -177,13 +217,6 @@ init_params.sync_client = client_factory_->Run(profile); } - init_params.network_time_update_callback = base::Bind(&UpdateNetworkTime); - init_params.base_directory = profile->GetPath(); - init_params.url_request_context = profile->GetRequestContext(); - init_params.debug_identifier = profile->GetDebugName(); - init_params.channel = chrome::GetChannel(); - init_params.blocking_pool = content::BrowserThread::GetBlockingPool(); - auto pss = base::MakeUnique<ProfileSyncService>(std::move(init_params)); // Will also initialize the sync client.
diff --git a/chrome/browser/ui/sync/sync_promo_ui.cc b/chrome/browser/ui/sync/sync_promo_ui.cc index 3fa574b6..f84177a7 100644 --- a/chrome/browser/ui/sync/sync_promo_ui.cc +++ b/chrome/browser/ui/sync/sync_promo_ui.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/signin_promo_util.h" +#include "components/sync/base/sync_prefs.h" bool SyncPromoUI::ShouldShowSyncPromo(Profile* profile) { // Don't show sync promo if the sign in promo should not be shown. @@ -13,8 +14,9 @@ return false; } - // Don't show if sync is not allowed to start. - if (!profile->IsSyncAllowed()) + syncer::SyncPrefs prefs(profile->GetPrefs()); + // Don't show if sync is not allowed to start or is running in local mode. + if (!profile->IsSyncAllowed() || prefs.IsLocalSyncEnabled()) return false; return true;
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc index ca5c58f..c17718f 100644 --- a/components/browser_sync/profile_sync_service.cc +++ b/components/browser_sync/profile_sync_service.cc
@@ -198,6 +198,7 @@ engine_initialized_(false), sync_disabled_by_admin_(false), is_auth_in_progress_(false), + local_sync_backend_folder_(init_params.local_sync_backend_folder), unrecoverable_error_reason_(ERROR_REASON_UNSET), expect_sync_configuration_aborted_(false), encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()), @@ -241,7 +242,8 @@ bool ProfileSyncService::CanSyncStart() const { DCHECK(thread_checker_.CalledOnValidThread()); - return IsSyncAllowed() && IsSyncRequested() && IsSignedIn(); + return (IsSyncAllowed() && IsSyncRequested() && + (IsLocalSyncEnabled() || IsSignedIn())); } void ProfileSyncService::Initialize() { @@ -308,7 +310,7 @@ sync_prefs_.AddSyncPrefObserver(this); SyncInitialState sync_state = CAN_START; - if (!IsSignedIn()) { + if (!IsLocalSyncEnabled() && !IsSignedIn()) { sync_state = NOT_SIGNED_IN; } else if (IsManaged()) { sync_state = IS_MANAGED; @@ -335,11 +337,13 @@ return; } - RegisterAuthNotifications(); + if (!IsLocalSyncEnabled()) { + RegisterAuthNotifications(); - if (!IsSignedIn()) { - // Clean up in case of previous crash during signout. - StopImpl(CLEAR_DATA); + if (!IsSignedIn()) { + // Clean up in case of previous crash during signout. + StopImpl(CLEAR_DATA); + } } #if defined(OS_CHROMEOS) @@ -362,8 +366,8 @@ sync_enabled_weak_factory_.GetWeakPtr())); startup_controller_->Reset(GetRegisteredDataTypes()); - // Auto-start means means the first time the profile starts up, sync should - // start up immediately. + // Auto-start means the first time the profile starts up, sync should start up + // immediately. if (start_behavior_ == AUTO_START && IsSyncRequested() && !IsFirstSetupComplete()) { startup_controller_->TryStartImmediately(); @@ -399,7 +403,8 @@ DCHECK(thread_checker_.CalledOnValidThread()); if (signin()) signin()->RemoveObserver(this); - oauth2_token_service_->RemoveObserver(this); + if (oauth2_token_service_) + oauth2_token_service_->RemoveObserver(this); } void ProfileSyncService::RegisterDataTypeController( @@ -475,6 +480,11 @@ SyncCredentials ProfileSyncService::GetCredentials() { SyncCredentials credentials; + + // No credentials exist or are needed for the local sync backend. + if (IsLocalSyncEnabled()) + return credentials; + credentials.account_id = signin_->GetAccountIdToUse(); DCHECK(!credentials.account_id.empty()); credentials.email = signin_->GetEffectiveUsername(); @@ -949,10 +959,15 @@ sync_js_controller_.AttachJsBackend(js_backend); debug_info_listener_ = debug_info_listener; - SigninClient* signin_client = signin_->GetOriginal()->signin_client(); - DCHECK(signin_client); - std::string signin_scoped_device_id = - signin_client->GetSigninScopedDeviceId(); + std::string signin_scoped_device_id; + if (IsLocalSyncEnabled()) { + signin_scoped_device_id = "local_device"; + } else { + SigninClient* signin_client = signin_->GetOriginal()->signin_client(); + DCHECK(signin_client); + std::string signin_scoped_device_id = + signin_client->GetSigninScopedDeviceId(); + } // Initialize local device info. local_device_->Initialize(cache_guid, signin_scoped_device_id, @@ -1002,6 +1017,10 @@ } NotifyObservers(); + + // Nobody will call us to start if no sign in is going to happen. + if (IsLocalSyncEnabled()) + RequestStart(); } void ProfileSyncService::OnSyncCycleCompleted() { @@ -1530,6 +1549,11 @@ data_type_manager_->state() != DataTypeManager::STOPPED; } +bool ProfileSyncService::IsLocalSyncEnabled() const { + DCHECK(thread_checker_.CalledOnValidThread()); + return sync_prefs_.IsLocalSyncEnabled(); +} + void ProfileSyncService::TriggerRefresh(const syncer::ModelTypeSet& types) { DCHECK(thread_checker_.CalledOnValidThread()); if (engine_initialized_) @@ -1542,6 +1566,8 @@ } bool ProfileSyncService::CanEngineStart() const { + if (IsLocalSyncEnabled()) + return true; return CanSyncStart() && oauth2_token_service_ && oauth2_token_service_->RefreshTokenIsAvailable( signin_->GetAccountIdToUse()); @@ -2498,7 +2524,7 @@ } void ProfileSyncService::UpdateFirstSyncTimePref() { - if (!IsSignedIn()) { + if (!IsLocalSyncEnabled() && !IsSignedIn()) { sync_prefs_.ClearFirstSyncTime(); } else if (sync_prefs_.GetFirstSyncTime().is_null()) { // Set if not set before and it's syncing now.
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h index 92356b51..8aaf07b 100644 --- a/components/browser_sync/profile_sync_service.h +++ b/components/browser_sync/profile_sync_service.h
@@ -245,6 +245,7 @@ std::string debug_identifier; version_info::Channel channel = version_info::Channel::UNKNOWN; base::SequencedWorkerPool* blocking_pool = nullptr; + base::FilePath local_sync_backend_folder; private: DISALLOW_COPY_AND_ASSIGN(InitParams); @@ -262,6 +263,7 @@ bool IsFirstSetupComplete() const override; bool IsSyncAllowed() const override; bool IsSyncActive() const override; + bool IsLocalSyncEnabled() const override; void TriggerRefresh(const syncer::ModelTypeSet& types) override; void OnDataTypeRequestsSyncStartup(syncer::ModelType type) override; bool CanSyncStart() const override; @@ -814,6 +816,9 @@ // engine to refresh its credentials. bool is_auth_in_progress_; + // The location where the local sync backend stores its data. + base::FilePath local_sync_backend_folder_; + // Information describing an unrecoverable error. UnrecoverableErrorReason unrecoverable_error_reason_; std::string unrecoverable_error_message_;
diff --git a/components/browser_sync/profile_sync_service_unittest.cc b/components/browser_sync/profile_sync_service_unittest.cc index abe8f86..dba0ea9 100644 --- a/components/browser_sync/profile_sync_service_unittest.cc +++ b/components/browser_sync/profile_sync_service_unittest.cc
@@ -211,14 +211,24 @@ base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS)); } -#if defined(OS_WIN) || defined(OS_MACOSX) || \ - (defined(OS_LINUX) && !defined(OS_CHROMEOS)) - void CreateServiceWithoutSignIn() { - CreateService(ProfileSyncService::AUTO_START); - signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST, - signin_metrics::SignoutDelete::IGNORE_METRIC); + void CreateServiceWithLocalSyncBackend() { + component_factory_ = profile_sync_service_bundle_.component_factory(); + ProfileSyncServiceBundle::SyncClientBuilder builder( + &profile_sync_service_bundle_); + ProfileSyncService::InitParams init_params = + profile_sync_service_bundle_.CreateBasicInitParams( + ProfileSyncService::AUTO_START, builder.Build()); + + prefs()->SetBoolean(syncer::prefs::kEnableLocalSyncBackend, true); + init_params.local_sync_backend_folder = + base::FilePath(FILE_PATH_LITERAL("dummyPath")); + init_params.oauth2_token_service = nullptr; + init_params.gaia_cookie_manager_service = nullptr; + + service_ = base::MakeUnique<ProfileSyncService>(std::move(init_params)); + service_->RegisterDataTypeController( + base::MakeUnique<syncer::FakeDataTypeController>(syncer::BOOKMARKS)); } -#endif void ShutdownAndDeleteService() { if (service_) @@ -372,6 +382,19 @@ EXPECT_TRUE(service()->IsSyncActive()); } +// Verify a successful initialization. +TEST_F(ProfileSyncServiceTest, SuccessfulLocalBackendInitialization) { + prefs()->SetManagedPref(syncer::prefs::kSyncManaged, + new base::FundamentalValue(false)); + IssueTestTokens(); + CreateServiceWithLocalSyncBackend(); + ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback()); + ExpectSyncEngineCreation(1); + InitializeForNthSync(); + EXPECT_FALSE(service()->IsManaged()); + EXPECT_TRUE(service()->IsSyncActive()); +} + // Verify that an initialization where first setup is not complete does not // start up the backend. TEST_F(ProfileSyncServiceTest, NeedsConfirmation) {
diff --git a/components/browsing_data/core/history_notice_utils_unittest.cc b/components/browsing_data/core/history_notice_utils_unittest.cc index 6c4363c0..2701c85 100644 --- a/components/browsing_data/core/history_notice_utils_unittest.cc +++ b/components/browsing_data/core/history_notice_utils_unittest.cc
@@ -28,9 +28,9 @@ class TestSyncService : public syncer::FakeSyncService { public: // Getters (FakeSyncService implementation). --------------------------------- - bool IsSyncActive() const override { - return sync_active_; - } + bool IsSyncActive() const override { return sync_active_; } + + bool IsLocalSyncEnabled() const override { return false; } syncer::ModelTypeSet GetActiveDataTypes() const override { return active_data_types_;
diff --git a/components/dom_distiller/ios/BUILD.gn b/components/dom_distiller/ios/BUILD.gn index fe60646..241042b3 100644 --- a/components/dom_distiller/ios/BUILD.gn +++ b/components/dom_distiller/ios/BUILD.gn
@@ -8,13 +8,14 @@ "distiller_page_factory_ios.mm", "distiller_page_ios.h", "distiller_page_ios.mm", + "favicon_web_state_dispatcher.h", ] deps = [ "//base", "//components/dom_distiller/core", "//components/dom_distiller/core/proto", - "//ios/public/provider/web", + "//components/favicon/ios", "//ios/web", "//url", ]
diff --git a/components/dom_distiller/ios/DEPS b/components/dom_distiller/ios/DEPS index 450c6e9..ea0729b 100644 --- a/components/dom_distiller/ios/DEPS +++ b/components/dom_distiller/ios/DEPS
@@ -1,4 +1,4 @@ include_rules = [ - "+ios/public/provider/web", + "+components/favicon/ios", "+ios/web/public", ]
diff --git a/components/dom_distiller/ios/distiller_page_factory_ios.h b/components/dom_distiller/ios/distiller_page_factory_ios.h index f3fb0e8..1f2250e 100644 --- a/components/dom_distiller/ios/distiller_page_factory_ios.h +++ b/components/dom_distiller/ios/distiller_page_factory_ios.h
@@ -9,18 +9,18 @@ #include "components/dom_distiller/core/distiller_page.h" -namespace web { -class BrowserState; -} - namespace dom_distiller { +class FaviconWebStateDispatcher; + // DistillerPageFactoryIOS is an iOS-specific implementation of the // DistillerPageFactory interface allowing the creation of DistillerPage // instances. class DistillerPageFactoryIOS : public DistillerPageFactory { public: - DistillerPageFactoryIOS(web::BrowserState* browser_state); + explicit DistillerPageFactoryIOS( + std::unique_ptr<FaviconWebStateDispatcher> web_state_dispatcher); + ~DistillerPageFactoryIOS() override; // Implementation of DistillerPageFactory: std::unique_ptr<DistillerPage> CreateDistillerPage( @@ -29,7 +29,9 @@ std::unique_ptr<SourcePageHandle> handle) const override; private: - web::BrowserState* browser_state_; + std::unique_ptr<FaviconWebStateDispatcher> web_state_dispatcher_; + + DISALLOW_COPY_AND_ASSIGN(DistillerPageFactoryIOS); }; } // namespace dom_distiller
diff --git a/components/dom_distiller/ios/distiller_page_factory_ios.mm b/components/dom_distiller/ios/distiller_page_factory_ios.mm index ad355f9..1e3f7f4 100644 --- a/components/dom_distiller/ios/distiller_page_factory_ios.mm +++ b/components/dom_distiller/ios/distiller_page_factory_ios.mm
@@ -6,24 +6,26 @@ #include "base/memory/ptr_util.h" #include "components/dom_distiller/ios/distiller_page_ios.h" +#include "components/dom_distiller/ios/favicon_web_state_dispatcher.h" #include "ios/web/public/browser_state.h" namespace dom_distiller { DistillerPageFactoryIOS::DistillerPageFactoryIOS( - web::BrowserState* browser_state) - : browser_state_(browser_state) { -} + std::unique_ptr<FaviconWebStateDispatcher> web_state_dispatcher) + : web_state_dispatcher_(std::move(web_state_dispatcher)) {} + +DistillerPageFactoryIOS::~DistillerPageFactoryIOS() {} std::unique_ptr<DistillerPage> DistillerPageFactoryIOS::CreateDistillerPage( const gfx::Size& view_size) const { - return base::WrapUnique<DistillerPage>(new DistillerPageIOS(browser_state_)); + return base::MakeUnique<DistillerPageIOS>(web_state_dispatcher_.get()); } std::unique_ptr<DistillerPage> DistillerPageFactoryIOS::CreateDistillerPageWithHandle( std::unique_ptr<SourcePageHandle> handle) const { - return base::WrapUnique<DistillerPage>(new DistillerPageIOS(browser_state_)); + return base::MakeUnique<DistillerPageIOS>(web_state_dispatcher_.get()); } } // namespace dom_distiller
diff --git a/components/dom_distiller/ios/distiller_page_ios.h b/components/dom_distiller/ios/distiller_page_ios.h index 9c79985..ddd55f3 100644 --- a/components/dom_distiller/ios/distiller_page_ios.h +++ b/components/dom_distiller/ios/distiller_page_ios.h
@@ -10,17 +10,10 @@ #include "base/memory/weak_ptr.h" #include "components/dom_distiller/core/distiller_page.h" +#include "components/dom_distiller/ios/favicon_web_state_dispatcher.h" #include "ios/web/public/web_state/web_state_observer.h" #include "url/gurl.h" -namespace ios { -class WebControllerProvider; -} - -namespace web { -class BrowserState; -} - namespace dom_distiller { class DistillerWebStateObserver; @@ -29,7 +22,7 @@ // content. class DistillerPageIOS : public DistillerPage { public: - explicit DistillerPageIOS(web::BrowserState* browser_state); + explicit DistillerPageIOS(FaviconWebStateDispatcher* web_state_dispatcher); ~DistillerPageIOS() override; protected: @@ -48,10 +41,10 @@ // Converts result of WKWebView script evaluation to base::Value std::unique_ptr<base::Value> ValueResultFromScriptResult(id wk_result); - web::BrowserState* browser_state_; GURL url_; std::string script_; - std::unique_ptr<ios::WebControllerProvider> provider_; + web::WebState* web_state_; + FaviconWebStateDispatcher* web_state_dispatcher_; std::unique_ptr<DistillerWebStateObserver> web_state_observer_; base::WeakPtrFactory<DistillerPageIOS> weak_ptr_factory_; };
diff --git a/components/dom_distiller/ios/distiller_page_ios.mm b/components/dom_distiller/ios/distiller_page_ios.mm index 8ae4962..8ffacdf 100644 --- a/components/dom_distiller/ios/distiller_page_ios.mm +++ b/components/dom_distiller/ios/distiller_page_ios.mm
@@ -13,10 +13,14 @@ #include "base/mac/foundation_util.h" #include "base/memory/ptr_util.h" #include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "base/values.h" -#include "ios/public/provider/web/web_controller_provider.h" -#include "ios/public/provider/web/web_controller_provider_factory.h" +#include "components/favicon/ios/web_favicon_driver.h" #include "ios/web/public/browser_state.h" +#import "ios/web/public/navigation_manager.h" +#import "ios/web/public/web_state/js/crw_js_injection_manager.h" +#import "ios/web/public/web_state/js/crw_js_injection_receiver.h" +#import "ios/web/public/web_state/web_state.h" namespace { @@ -105,6 +109,7 @@ // WebStateObserver implementation: void PageLoaded( web::PageLoadCompletionStatus load_completion_status) override; + void WebStateDestroyed() override; private: DistillerPageIOS* distiller_page_; // weak, owns this object. @@ -123,11 +128,15 @@ distiller_page_->OnLoadURLDone(load_completion_status); } +void DistillerWebStateObserver::WebStateDestroyed() { + distiller_page_->web_state_ = nullptr; +} + #pragma mark - -DistillerPageIOS::DistillerPageIOS(web::BrowserState* browser_state) - : browser_state_(browser_state), weak_ptr_factory_(this) { -} +DistillerPageIOS::DistillerPageIOS( + FaviconWebStateDispatcher* web_state_dispatcher) + : web_state_dispatcher_(web_state_dispatcher), weak_ptr_factory_(this) {} DistillerPageIOS::~DistillerPageIOS() { } @@ -143,44 +152,56 @@ url_ = url; script_ = script; - // Lazily create provider. - if (!provider_) { - if (ios::GetWebControllerProviderFactory()) { - provider_ = - ios::GetWebControllerProviderFactory()->CreateWebControllerProvider( - browser_state_); - web_state_observer_.reset( - new DistillerWebStateObserver(provider_->GetWebState(), this)); - } + web_state_ = web_state_dispatcher_->RequestWebState(); + + if (!web_state_) { + OnLoadURLDone(web::PageLoadCompletionStatus::FAILURE); + return; } - // Load page using provider. - if (provider_) - provider_->LoadURL(url_); - else - OnLoadURLDone(web::PageLoadCompletionStatus::FAILURE); + web_state_observer_ = + base::MakeUnique<DistillerWebStateObserver>(web_state_, this); + + // The favicon driver needs to know which URL is currently fetched. + favicon::WebFaviconDriver* favicon_driver = + favicon::WebFaviconDriver::FromWebState(web_state_); + favicon_driver->FetchFavicon(url_); + + // Load page using WebState. + web::NavigationManager::WebLoadParams params(url_); + web_state_->SetWebUsageEnabled(true); + web_state_->GetNavigationManager()->LoadURLWithParams(params); + // GetView is needed because the view is not created (but needed) when + // loading the page. + web_state_->GetView(); } void DistillerPageIOS::OnLoadURLDone( web::PageLoadCompletionStatus load_completion_status) { // Don't attempt to distill if the page load failed or if there is no - // provider. + // WebState. if (load_completion_status == web::PageLoadCompletionStatus::FAILURE || - !provider_) { + !web_state_) { HandleJavaScriptResult(nil); return; } // Inject the script. base::WeakPtr<DistillerPageIOS> weak_this = weak_ptr_factory_.GetWeakPtr(); - provider_->InjectScript(script_, ^(id result, NSError* error) { - DistillerPageIOS* distiller_page = weak_this.get(); - if (distiller_page) - distiller_page->HandleJavaScriptResult(result); - }); + + [[web_state_->GetJSInjectionReceiver() + instanceOfClass:[CRWJSInjectionManager class]] + executeJavaScript:base::SysUTF8ToNSString(script_) + completionHandler:^(id result, NSError* error) { + DistillerPageIOS* distiller_page = weak_this.get(); + if (distiller_page) + distiller_page->HandleJavaScriptResult(result); + }]; } void DistillerPageIOS::HandleJavaScriptResult(id result) { + web_state_dispatcher_->ReturnWebState(web_state_); + web_state_ = nullptr; std::unique_ptr<base::Value> resultValue = base::Value::CreateNullValue(); if (result) { resultValue = ValueResultFromScriptResult(result);
diff --git a/components/dom_distiller/ios/favicon_web_state_dispatcher.h b/components/dom_distiller/ios/favicon_web_state_dispatcher.h new file mode 100644 index 0000000..c34e6985 --- /dev/null +++ b/components/dom_distiller/ios/favicon_web_state_dispatcher.h
@@ -0,0 +1,34 @@ +// Copyright 2016 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 COMPONENTS_DOM_DISTILLER_IOS_FAVICON_WEB_STATE_DISPATCHER_H_ +#define COMPONENTS_DOM_DISTILLER_IOS_FAVICON_WEB_STATE_DISPATCHER_H_ + +namespace web { +class WebState; +} + +namespace dom_distiller { + +// Dispatcher for WebState having a Favicon Driver, with BookmarkModel and +// HistoryService attached, as observer. The Webstates are kept alive between +// their creation and their return. After a WebState is returned, the dispatcher +// keeps it alive long enough for it to download the favicons. +class FaviconWebStateDispatcher { + public: + FaviconWebStateDispatcher() {} + virtual ~FaviconWebStateDispatcher() {} + // Returns a WebState with a Favicon Driver attached. + virtual web::WebState* RequestWebState() = 0; + // Called to return a WebState. The WebState should not be used after being + // returned. + virtual void ReturnWebState(web::WebState* web_state) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(FaviconWebStateDispatcher); +}; + +} // namespace dom_distiller + +#endif // COMPONENTS_DOM_DISTILLER_IOS_FAVICON_WEB_STATE_DISPATCHER_H_
diff --git a/components/precache/content/precache_manager.cc b/components/precache/content/precache_manager.cc index 204ab49..1bb6820 100644 --- a/components/precache/content/precache_manager.cc +++ b/components/precache/content/precache_manager.cc
@@ -123,10 +123,11 @@ return AllowedType::PENDING; // SyncService delegates to SyncPrefs, which must be called on the UI thread. - if (history_service_ && + if (history_service_ && !sync_service_->IsLocalSyncEnabled() && sync_service_->GetActiveDataTypes().Has(syncer::SESSIONS) && - !sync_service_->GetEncryptedDataTypes().Has(syncer::SESSIONS)) + !sync_service_->GetEncryptedDataTypes().Has(syncer::SESSIONS)) { return AllowedType::ALLOWED; + } return AllowedType::DISALLOWED; }
diff --git a/components/suggestions/suggestions_service_impl.cc b/components/suggestions/suggestions_service_impl.cc index ae792b1..f181599c 100644 --- a/components/suggestions/suggestions_service_impl.cc +++ b/components/suggestions/suggestions_service_impl.cc
@@ -66,7 +66,7 @@ }; SyncState GetSyncState(syncer::SyncService* sync) { - if (!sync || !sync->CanSyncStart()) + if (!sync || !sync->CanSyncStart() || sync->IsLocalSyncEnabled()) return SYNC_OR_HISTORY_SYNC_DISABLED; if (!sync->IsSyncActive() || !sync->ConfigurationDone()) return NOT_INITIALIZED_ENABLED;
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index 8a9d6df..3c047ea 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -336,6 +336,20 @@ "engine_impl/js_sync_encryption_handler_observer.h", "engine_impl/js_sync_manager_observer.cc", "engine_impl/js_sync_manager_observer.h", + "engine_impl/loopback_server/loopback_connection_manager.cc", + "engine_impl/loopback_server/loopback_connection_manager.h", + "engine_impl/loopback_server/loopback_server.cc", + "engine_impl/loopback_server/loopback_server.h", + "engine_impl/loopback_server/loopback_server_entity.cc", + "engine_impl/loopback_server/loopback_server_entity.h", + "engine_impl/loopback_server/persistent_bookmark_entity.cc", + "engine_impl/loopback_server/persistent_bookmark_entity.h", + "engine_impl/loopback_server/persistent_permanent_entity.cc", + "engine_impl/loopback_server/persistent_permanent_entity.h", + "engine_impl/loopback_server/persistent_tombstone_entity.cc", + "engine_impl/loopback_server/persistent_tombstone_entity.h", + "engine_impl/loopback_server/persistent_unique_client_entity.cc", + "engine_impl/loopback_server/persistent_unique_client_entity.h", "engine_impl/model_type_connector_proxy.cc", "engine_impl/model_type_connector_proxy.h", "engine_impl/model_type_registry.cc", @@ -607,25 +621,6 @@ ] } - if (is_win) { - sources += [ - "engine_impl/loopback_server/loopback_connection_manager.cc", - "engine_impl/loopback_server/loopback_connection_manager.h", - "engine_impl/loopback_server/loopback_server.cc", - "engine_impl/loopback_server/loopback_server.h", - "engine_impl/loopback_server/loopback_server_entity.cc", - "engine_impl/loopback_server/loopback_server_entity.h", - "engine_impl/loopback_server/persistent_bookmark_entity.cc", - "engine_impl/loopback_server/persistent_bookmark_entity.h", - "engine_impl/loopback_server/persistent_permanent_entity.cc", - "engine_impl/loopback_server/persistent_permanent_entity.h", - "engine_impl/loopback_server/persistent_tombstone_entity.cc", - "engine_impl/loopback_server/persistent_tombstone_entity.h", - "engine_impl/loopback_server/persistent_unique_client_entity.cc", - "engine_impl/loopback_server/persistent_unique_client_entity.h", - ] - } - if (!is_ios) { sources += [ "driver/sync_policy_handler.cc",
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc index e0adcb3..25b54cf 100644 --- a/components/sync/base/sync_prefs.cc +++ b/components/sync/base/sync_prefs.cc
@@ -5,7 +5,9 @@ #include "components/sync/base/sync_prefs.h" #include "base/base64.h" +#include "base/files/file_path.h" #include "base/logging.h" +#include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" #include "components/pref_registry/pref_registry_syncable.h" @@ -553,7 +555,20 @@ } base::FilePath SyncPrefs::GetLocalSyncBackendDir() const { - return pref_service_->GetFilePath(prefs::kLocalSyncBackendDir); + base::FilePath local_sync_backend_folder = + pref_service_->GetFilePath(prefs::kLocalSyncBackendDir); + +#if defined(OS_WIN) + if (local_sync_backend_folder.empty()) { + // TODO(pastarmovj): Add DIR_ROAMING_USER_DATA to PathService to simplify + // this code and move the logic in its right place. See crbug/657810. + CHECK( + base::PathService::Get(base::DIR_APP_DATA, &local_sync_backend_folder)); + local_sync_backend_folder = + local_sync_backend_folder.Append(FILE_PATH_LITERAL("Chrome/User Data")); + } +#endif // defined(OS_WIN) + return local_sync_backend_folder; } } // namespace syncer
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc index fcc3d69c..71abee3 100644 --- a/components/sync/driver/fake_sync_service.cc +++ b/components/sync/driver/fake_sync_service.cc
@@ -30,6 +30,10 @@ return false; } +bool FakeSyncService::IsLocalSyncEnabled() const { + return false; +} + void FakeSyncService::TriggerRefresh(const ModelTypeSet& types) {} ModelTypeSet FakeSyncService::GetActiveDataTypes() const {
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h index fa031a83..543a382 100644 --- a/components/sync/driver/fake_sync_service.h +++ b/components/sync/driver/fake_sync_service.h
@@ -28,6 +28,7 @@ bool IsFirstSetupComplete() const override; bool IsSyncAllowed() const override; bool IsSyncActive() const override; + bool IsLocalSyncEnabled() const override; void TriggerRefresh(const ModelTypeSet& types) override; ModelTypeSet GetActiveDataTypes() const override; SyncClient* GetSyncClient() const override;
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h index a07f5d5e..364ec99 100644 --- a/components/sync/driver/sync_service.h +++ b/components/sync/driver/sync_service.h
@@ -108,6 +108,12 @@ // datetypes are actually syncing, see GetActiveTypes() below. virtual bool IsSyncActive() const = 0; + // Returns true if the local sync backend server has been enabled through a + // command line flag or policy. In this case sync is considered active but any + // implied consent for further related services e.g. Suggestions, Web History + // etc. is considered not granted. + virtual bool IsLocalSyncEnabled() const = 0; + // Triggers a GetUpdates call for the specified |types|, pulling any new data // from the sync server. virtual void TriggerRefresh(const ModelTypeSet& types) = 0;
diff --git a/components/sync/driver/sync_service_base.cc b/components/sync/driver/sync_service_base.cc index 37eacd8..b534aba 100644 --- a/components/sync/driver/sync_service_base.cc +++ b/components/sync/driver/sync_service_base.cc
@@ -136,6 +136,7 @@ // solution for now will be to assume profiles are created in the same order // on all machines and in the future decide if only the Default one should be // considered roamed. + // See http://crbug.com/674928. *local_sync_backend_folder = local_sync_backend_folder->Append(base_directory_.BaseName()); *local_sync_backend_folder =
diff --git a/components/sync/engine/engine_components_factory.h b/components/sync/engine/engine_components_factory.h index fb80d03..70c6b1f 100644 --- a/components/sync/engine/engine_components_factory.h +++ b/components/sync/engine/engine_components_factory.h
@@ -90,7 +90,8 @@ virtual std::unique_ptr<SyncScheduler> BuildScheduler( const std::string& name, SyncCycleContext* context, - CancelationSignal* cancelation_signal) = 0; + CancelationSignal* cancelation_signal, + bool ignore_auth_credentials) = 0; virtual std::unique_ptr<SyncCycleContext> BuildContext( ServerConnectionManager* connection_manager,
diff --git a/components/sync/engine/engine_components_factory_impl.cc b/components/sync/engine/engine_components_factory_impl.cc index d3d3a88..dd913f9 100644 --- a/components/sync/engine/engine_components_factory_impl.cc +++ b/components/sync/engine/engine_components_factory_impl.cc
@@ -28,7 +28,8 @@ std::unique_ptr<SyncScheduler> EngineComponentsFactoryImpl::BuildScheduler( const std::string& name, SyncCycleContext* context, - CancelationSignal* cancelation_signal) { + CancelationSignal* cancelation_signal, + bool ignore_auth_credentials) { std::unique_ptr<BackoffDelayProvider> delay( BackoffDelayProvider::FromDefaults()); @@ -38,7 +39,8 @@ std::unique_ptr<SyncSchedulerImpl> scheduler = base::MakeUnique<SyncSchedulerImpl>(name, delay.release(), context, - new Syncer(cancelation_signal)); + new Syncer(cancelation_signal), + ignore_auth_credentials); if (switches_.nudge_delay == NudgeDelay::SHORT_NUDGE_DELAY) { // Set the default nudge delay to 0 because the default is used as a floor // for override values, and we don't want the below override to be ignored.
diff --git a/components/sync/engine/engine_components_factory_impl.h b/components/sync/engine/engine_components_factory_impl.h index 6bf4ef9..a16cc5e 100644 --- a/components/sync/engine/engine_components_factory_impl.h +++ b/components/sync/engine/engine_components_factory_impl.h
@@ -24,7 +24,8 @@ std::unique_ptr<SyncScheduler> BuildScheduler( const std::string& name, SyncCycleContext* context, - CancelationSignal* cancelation_signal) override; + CancelationSignal* cancelation_signal, + bool ignore_auth_credentials) override; std::unique_ptr<SyncCycleContext> BuildContext( ServerConnectionManager* connection_manager,
diff --git a/components/sync/engine/test_engine_components_factory.cc b/components/sync/engine/test_engine_components_factory.cc index 116c6d2b..d71f1b53 100644 --- a/components/sync/engine/test_engine_components_factory.cc +++ b/components/sync/engine/test_engine_components_factory.cc
@@ -25,7 +25,8 @@ std::unique_ptr<SyncScheduler> TestEngineComponentsFactory::BuildScheduler( const std::string& name, SyncCycleContext* context, - CancelationSignal* cancelation_signal) { + CancelationSignal* cancelation_signal, + bool ignore_auth_credentials) { return std::unique_ptr<SyncScheduler>(new FakeSyncScheduler()); }
diff --git a/components/sync/engine/test_engine_components_factory.h b/components/sync/engine/test_engine_components_factory.h index 575f8c5..0f2ec77 100644 --- a/components/sync/engine/test_engine_components_factory.h +++ b/components/sync/engine/test_engine_components_factory.h
@@ -24,7 +24,8 @@ std::unique_ptr<SyncScheduler> BuildScheduler( const std::string& name, SyncCycleContext* context, - CancelationSignal* cancelation_signal) override; + CancelationSignal* cancelation_signal, + bool ignore_auth_credentials) override; std::unique_ptr<SyncCycleContext> BuildContext( ServerConnectionManager* connection_manager,
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc index 87dd222..cbacc993 100644 --- a/components/sync/engine_impl/sync_manager_impl.cc +++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -30,6 +30,7 @@ #include "components/sync/engine/net/http_post_provider_factory.h" #include "components/sync/engine/polling_constants.h" #include "components/sync/engine_impl/cycle/directory_type_debug_info_emitter.h" +#include "components/sync/engine_impl/loopback_server/loopback_connection_manager.h" #include "components/sync/engine_impl/model_type_connector_proxy.h" #include "components/sync/engine_impl/net/sync_server_connection_manager.h" #include "components/sync/engine_impl/sync_scheduler.h" @@ -47,9 +48,6 @@ #include "components/sync/syncable/write_node.h" #include "components/sync/syncable/write_transaction.h" -#if defined(OS_WIN) -#include "components/sync/engine_impl/loopback_server/loopback_connection_manager.h" -#endif using base::TimeDelta; using sync_pb::GetUpdatesCallerInfo; @@ -212,9 +210,11 @@ CHECK(!initialized_); DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(args->post_factory.get()); - DCHECK(!args->credentials.account_id.empty()); - DCHECK(!args->credentials.sync_token.empty()); - DCHECK(!args->credentials.scope_set.empty()); + if (!args->enable_local_sync_backend) { + DCHECK(!args->credentials.account_id.empty()); + DCHECK(!args->credentials.sync_token.empty()); + DCHECK(!args->credentials.scope_set.empty()); + } DCHECK(args->cancelation_signal); DVLOG(1) << "SyncManager starting Init..."; @@ -276,13 +276,9 @@ } if (args->enable_local_sync_backend) { -#if defined(OS_WIN) VLOG(1) << "Running against local sync backend."; connection_manager_ = base::MakeUnique<LoopbackConnectionManager>( args->cancelation_signal, args->local_sync_backend_folder); -#else - NOTREACHED(); -#endif // defined(OS_WIN) } else { connection_manager_ = base::MakeUnique<SyncServerConnectionManager>( args->service_url.host() + args->service_url.path(), @@ -316,17 +312,22 @@ listeners, &debug_info_event_listener_, model_type_registry_.get(), args->invalidator_client_id); scheduler_ = args->engine_components_factory->BuildScheduler( - name_, cycle_context_.get(), args->cancelation_signal); + name_, cycle_context_.get(), args->cancelation_signal, + args->enable_local_sync_backend); scheduler_->Start(SyncScheduler::CONFIGURATION_MODE, base::Time()); initialized_ = true; - net::NetworkChangeNotifier::AddIPAddressObserver(this); - net::NetworkChangeNotifier::AddConnectionTypeObserver(this); - observing_network_connectivity_changes_ = true; + if (!args->enable_local_sync_backend) { + net::NetworkChangeNotifier::AddIPAddressObserver(this); + net::NetworkChangeNotifier::AddConnectionTypeObserver(this); + observing_network_connectivity_changes_ = true; - UpdateCredentials(args->credentials); + UpdateCredentials(args->credentials); + } else { + scheduler_->OnCredentialsUpdated(); + } NotifyInitializationSuccess(); }
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc index 5f9db5d8..afaab93 100644 --- a/components/sync/engine_impl/sync_manager_impl_unittest.cc +++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -996,8 +996,7 @@ virtual ~SyncManagerTest() {} - // Test implementation. - void SetUp() { + virtual void DoSetUp(bool enable_local_sync_backend) { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); extensions_activity_ = new ExtensionsActivity(); @@ -1035,8 +1034,11 @@ args.workers = workers; args.extensions_activity = extensions_activity_.get(), args.change_delegate = this; - args.credentials = credentials; + if (!enable_local_sync_backend) + args.credentials = credentials; args.invalidator_client_id = "fake_invalidator_client_id"; + args.enable_local_sync_backend = enable_local_sync_backend; + args.local_sync_backend_folder = temp_dir_.GetPath(); args.engine_components_factory.reset(GetFactory()); args.encryptor = &encryptor_; args.unrecoverable_error_handler = @@ -1060,6 +1062,9 @@ PumpLoop(); } + // Test implementation. + void SetUp() { DoSetUp(false); } + void TearDown() { sync_manager_.RemoveObserver(&manager_observer_); sync_manager_.ShutdownOnSyncThread(STOP_SYNC); @@ -2692,6 +2697,38 @@ } } +class SyncManagerWithLocalBackendTest : public SyncManagerTest { + protected: + void SetUp() override { DoSetUp(true); } +}; + +// This test checks that we can successfully initialize without credentials in +// the local backend case. +TEST_F(SyncManagerWithLocalBackendTest, StartSyncInLocalMode) { + EXPECT_TRUE(SetUpEncryption(WRITE_TO_NIGORI, DEFAULT_ENCRYPTION)); + EXPECT_CALL(encryption_observer_, OnEncryptionComplete()); + EXPECT_CALL(encryption_observer_, OnCryptographerStateChanged(_)); + EXPECT_CALL(encryption_observer_, OnEncryptedTypesChanged(_, false)); + + sync_manager_.GetEncryptionHandler()->Init(); + PumpLoop(); + + const ModelTypeSet encrypted_types = GetEncryptedTypes(); + EXPECT_TRUE(encrypted_types.Has(PASSWORDS)); + EXPECT_FALSE(IsEncryptEverythingEnabledForTest()); + + { + ReadTransaction trans(FROM_HERE, sync_manager_.GetUserShare()); + ReadNode node(&trans); + EXPECT_EQ(BaseNode::INIT_OK, node.InitByIdLookup(GetIdForDataType(NIGORI))); + sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); + EXPECT_TRUE(nigori.has_encryption_keybag()); + Cryptographer* cryptographer = trans.GetCryptographer(); + EXPECT_TRUE(cryptographer->is_ready()); + EXPECT_TRUE(cryptographer->CanDecrypt(nigori.encryption_keybag())); + } +} + class MockSyncScheduler : public FakeSyncScheduler { public: MockSyncScheduler() : FakeSyncScheduler() {} @@ -2717,7 +2754,8 @@ std::unique_ptr<SyncScheduler> BuildScheduler( const std::string& name, SyncCycleContext* context, - CancelationSignal* stop_handle) override { + CancelationSignal* stop_handle, + bool local_sync_backend_enabled) override { *cycle_context_ = context; return std::move(scheduler_to_use_); }
diff --git a/components/sync/engine_impl/sync_scheduler_impl.cc b/components/sync/engine_impl/sync_scheduler_impl.cc index edc26fc..69559b51 100644 --- a/components/sync/engine_impl/sync_scheduler_impl.cc +++ b/components/sync/engine_impl/sync_scheduler_impl.cc
@@ -151,7 +151,8 @@ SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name, BackoffDelayProvider* delay_provider, SyncCycleContext* context, - Syncer* syncer) + Syncer* syncer, + bool ignore_auth_credentials) : name_(name), started_(false), syncer_short_poll_interval_seconds_( @@ -163,6 +164,7 @@ syncer_(syncer), cycle_context_(context), next_sync_cycle_job_priority_(NORMAL_PRIORITY), + ignore_auth_credentials_(ignore_auth_credentials), weak_ptr_factory_(this), weak_ptr_factory_for_weak_handle_(this) { weak_handle_this_ = @@ -337,7 +339,8 @@ return false; } - if (cycle_context_->connection_manager()->HasInvalidAuthToken()) { + if (!ignore_auth_credentials_ && + cycle_context_->connection_manager()->HasInvalidAuthToken()) { SDVLOG(1) << "Unable to run a job because we have no valid auth token."; return false; }
diff --git a/components/sync/engine_impl/sync_scheduler_impl.h b/components/sync/engine_impl/sync_scheduler_impl.h index 6a6208a..c9fe0bd 100644 --- a/components/sync/engine_impl/sync_scheduler_impl.h +++ b/components/sync/engine_impl/sync_scheduler_impl.h
@@ -40,7 +40,8 @@ SyncSchedulerImpl(const std::string& name, BackoffDelayProvider* delay_provider, SyncCycleContext* context, - Syncer* syncer); + Syncer* syncer, + bool ignore_auth_credentials); // Calls Stop(). ~SyncSchedulerImpl() override; @@ -291,6 +292,9 @@ // One-shot timer for scheduling GU retry according to delay set by server. base::OneShotTimer retry_timer_; + // Dictates if the scheduler should wait for authentication to happen or not. + bool ignore_auth_credentials_; + base::WeakPtrFactory<SyncSchedulerImpl> weak_ptr_factory_; // A second factory specially for weak_handle_this_, to allow the handle
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc index 94f7e78..d4d6734 100644 --- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc +++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -159,7 +159,7 @@ context_->set_account_name("Test"); scheduler_ = base::MakeUnique<SyncSchedulerImpl>( "TestSyncScheduler", BackoffDelayProvider::FromDefaults(), context(), - syncer_); + syncer_, false); scheduler_->SetDefaultNudgeDelay(default_delay()); } @@ -283,6 +283,15 @@ tracker_it->second->wait_interval_->mode = mode; } + void NewSchedulerForLocalBackend() { + // The old syncer is destroyed with the scheduler that owns it. + syncer_ = new testing::StrictMock<MockSyncer>(); + scheduler_ = base::MakeUnique<SyncSchedulerImpl>( + "TestSyncScheduler", BackoffDelayProvider::FromDefaults(), context(), + syncer_, true); + scheduler_->SetDefaultNudgeDelay(default_delay()); + } + private: syncable::Directory* directory() { return test_user_share_.user_share()->directory.get(); @@ -468,6 +477,56 @@ ASSERT_EQ(0, retry_counter.times_called()); } +// Verify that in the absence of valid auth token the command will fail. +TEST_F(SyncSchedulerImplTest, ConfigNoAuthToken) { + SyncShareTimes times; + const ModelTypeSet model_types(THEMES); + + connection()->ResetAuthToken(); + + StartSyncConfiguration(); + + CallbackCounter ready_counter; + CallbackCounter retry_counter; + ConfigurationParams params( + GetUpdatesCallerInfo::RECONFIGURATION, model_types, + TypesToRoutingInfo(model_types), + base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), + base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); + scheduler()->ScheduleConfiguration(params); + PumpLoop(); + ASSERT_EQ(0, ready_counter.times_called()); + ASSERT_EQ(1, retry_counter.times_called()); +} + +// Verify that in the absence of valid auth token the command will pass if local +// sync backend is used. +TEST_F(SyncSchedulerImplTest, ConfigNoAuthTokenLocalSync) { + SyncShareTimes times; + const ModelTypeSet model_types(THEMES); + + NewSchedulerForLocalBackend(); + connection()->ResetAuthToken(); + + EXPECT_CALL(*syncer(), ConfigureSyncShare(_, _, _)) + .WillOnce(DoAll(Invoke(test_util::SimulateConfigureSuccess), + RecordSyncShare(×, true))); + + StartSyncConfiguration(); + + CallbackCounter ready_counter; + CallbackCounter retry_counter; + ConfigurationParams params( + GetUpdatesCallerInfo::RECONFIGURATION, model_types, + TypesToRoutingInfo(model_types), + base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)), + base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter))); + scheduler()->ScheduleConfiguration(params); + PumpLoop(); + ASSERT_EQ(1, ready_counter.times_called()); + ASSERT_EQ(0, retry_counter.times_called()); +} + // Issue a nudge when the config has failed. Make sure both the config and // nudge are executed. TEST_F(SyncSchedulerImplTest, NudgeWithConfigWithBackingOff) {
diff --git a/components/sync/engine_impl/syncer_unittest.cc b/components/sync/engine_impl/syncer_unittest.cc index 627e673..c07f91a 100644 --- a/components/sync/engine_impl/syncer_unittest.cc +++ b/components/sync/engine_impl/syncer_unittest.cc
@@ -302,7 +302,7 @@ "TestSyncScheduler", BackoffDelayProvider::FromDefaults(), context_.get(), // scheduler_ owned syncer_ now and will manage the memory of syncer_ - syncer_); + syncer_, false); syncable::ReadTransaction trans(FROM_HERE, directory()); Directory::Metahandles children;
diff --git a/components/sync/test/engine/mock_connection_manager.h b/components/sync/test/engine/mock_connection_manager.h index 37e42bc..46fc150 100644 --- a/components/sync/test/engine/mock_connection_manager.h +++ b/components/sync/test/engine/mock_connection_manager.h
@@ -272,6 +272,8 @@ // Adds a new progress marker to the last update. sync_pb::DataTypeProgressMarker* AddUpdateProgressMarker(); + void ResetAuthToken() { auth_token_.clear(); } + private: sync_pb::SyncEntity* AddUpdateFull(syncable::Id id, syncable::Id parentid,
diff --git a/ios/chrome/browser/dom_distiller/BUILD.gn b/ios/chrome/browser/dom_distiller/BUILD.gn index 67b4e9e..809293d9 100644 --- a/ios/chrome/browser/dom_distiller/BUILD.gn +++ b/ios/chrome/browser/dom_distiller/BUILD.gn
@@ -8,19 +8,44 @@ "distiller_viewer.h", "dom_distiller_service_factory.cc", "dom_distiller_service_factory.h", + "favicon_web_state_dispatcher_impl.h", + "favicon_web_state_dispatcher_impl.mm", ] deps = [ "//base", - "//components/dom_distiller/core", "//components/dom_distiller/ios", + "//components/favicon/core", + "//components/favicon/ios", "//components/keyed_service/core", "//components/keyed_service/ios", "//components/leveldb_proto", + "//ios/chrome/browser/bookmarks", "//ios/chrome/browser/browser_state", + "//ios/chrome/browser/favicon", + "//ios/chrome/browser/history", + "//ios/public/provider/web", "//ios/web", "//ui/gfx", + "//url", ] public_deps = [ "//components/dom_distiller/core", ] } + +source_set("unit_tests") { + testonly = true + sources = [ + "favicon_web_state_dispatcher_impl_unittest.mm", + ] + deps = [ + ":dom_distiller", + "//base", + "//components/favicon/ios", + "//ios/chrome/browser/browser_state:test_support", + "//ios/testing:ios_test_support", + "//ios/web", + "//ios/web:test_support", + "//testing/gtest", + ] +}
diff --git a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc index 2367b128..23a86a1 100644 --- a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc +++ b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -20,17 +20,20 @@ #include "components/keyed_service/ios/browser_state_dependency_manager.h" #include "components/leveldb_proto/proto_database.h" #include "components/leveldb_proto/proto_database_impl.h" +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.h" +#include "ios/chrome/browser/favicon/favicon_service_factory.h" +#include "ios/chrome/browser/history/history_service_factory.h" #include "ios/web/public/browser_state.h" #include "ios/web/public/web_thread.h" namespace { // A simple wrapper for DomDistillerService to expose it as a // KeyedService. -class DomDistillerKeyedService - : public KeyedService, - public dom_distiller::DomDistillerService { +class DomDistillerKeyedService : public KeyedService, + public dom_distiller::DomDistillerService { public: DomDistillerKeyedService( std::unique_ptr<dom_distiller::DomDistillerStoreInterface> store, @@ -68,10 +71,12 @@ : BrowserStateKeyedServiceFactory( "DomDistillerService", BrowserStateDependencyManager::GetInstance()) { + DependsOn(ios::FaviconServiceFactory::GetInstance()); + DependsOn(ios::HistoryServiceFactory::GetInstance()); + DependsOn(ios::BookmarkModelFactory::GetInstance()); } -DomDistillerServiceFactory::~DomDistillerServiceFactory() { -} +DomDistillerServiceFactory::~DomDistillerServiceFactory() {} std::unique_ptr<KeyedService> DomDistillerServiceFactory::BuildServiceInstanceFor( @@ -80,27 +85,33 @@ web::WebThread::GetBlockingPool()->GetSequencedTaskRunner( web::WebThread::GetBlockingPool()->GetSequenceToken()); - std::unique_ptr<leveldb_proto::ProtoDatabaseImpl<ArticleEntry>> db( - new leveldb_proto::ProtoDatabaseImpl<ArticleEntry>( - background_task_runner)); + std::unique_ptr<leveldb_proto::ProtoDatabaseImpl<ArticleEntry>> db = + base::MakeUnique<leveldb_proto::ProtoDatabaseImpl<ArticleEntry>>( + background_task_runner); base::FilePath database_dir( context->GetStatePath().Append(FILE_PATH_LITERAL("Articles"))); - std::unique_ptr<DomDistillerStore> dom_distiller_store( - new DomDistillerStore(std::move(db), database_dir)); + std::unique_ptr<DomDistillerStore> dom_distiller_store = + base::MakeUnique<DomDistillerStore>(std::move(db), database_dir); - std::unique_ptr<DistillerPageFactory> distiller_page_factory( - new DistillerPageFactoryIOS(context)); - std::unique_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory( - new DistillerURLFetcherFactory(context->GetRequestContext())); + std::unique_ptr<FaviconWebStateDispatcher> web_state_dispatcher = + base::MakeUnique<FaviconWebStateDispatcherImpl>(context, -1); + std::unique_ptr<DistillerPageFactory> distiller_page_factory = + base::MakeUnique<DistillerPageFactoryIOS>( + std::move(web_state_dispatcher)); + + std::unique_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory = + base::MakeUnique<DistillerURLFetcherFactory>( + context->GetRequestContext()); dom_distiller::proto::DomDistillerOptions options; - std::unique_ptr<DistillerFactory> distiller_factory(new DistillerFactoryImpl( - std::move(distiller_url_fetcher_factory), options)); - std::unique_ptr<DistilledPagePrefs> distilled_page_prefs( - new DistilledPagePrefs( - ios::ChromeBrowserState::FromBrowserState(context)->GetPrefs())); + std::unique_ptr<DistillerFactory> distiller_factory = + base::MakeUnique<DistillerFactoryImpl>( + std::move(distiller_url_fetcher_factory), options); + std::unique_ptr<DistilledPagePrefs> distilled_page_prefs = + base::MakeUnique<DistilledPagePrefs>( + ios::ChromeBrowserState::FromBrowserState(context)->GetPrefs()); return base::MakeUnique<DomDistillerKeyedService>( std::move(dom_distiller_store), std::move(distiller_factory),
diff --git a/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.h b/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.h new file mode 100644 index 0000000..d2e976813 --- /dev/null +++ b/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.h
@@ -0,0 +1,44 @@ +// Copyright 2016 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 IOS_CHROME_BROWSER_DOM_DISTILLER_FAVICON_WEB_STATE_DISPATCHER_IMPL_H_ +#define IOS_CHROME_BROWSER_DOM_DISTILLER_FAVICON_WEB_STATE_DISPATCHER_IMPL_H_ + +#include <memory> +#include <vector> + +#include "base/memory/weak_ptr.h" +#include "components/dom_distiller/ios/favicon_web_state_dispatcher.h" + +namespace web { +class BrowserState; +} + +namespace dom_distiller { + +// Implementation of the FaviconWebStateDispatcher. +class FaviconWebStateDispatcherImpl : public FaviconWebStateDispatcher { + public: + // Constructor for keeping the WebStates alive for |keep_alive_second| + // seconds. If |keep_alive_second| < 0 then the default value is used. + FaviconWebStateDispatcherImpl(web::BrowserState* browser_state, + int64_t keep_alive_second); + ~FaviconWebStateDispatcherImpl() override; + + // FaviconWebStateDispatcher implementation. + web::WebState* RequestWebState() override; + void ReturnWebState(web::WebState* web_state) override; + + private: + web::BrowserState* browser_state_; + // Map of the WebStates currently alive. + std::vector<std::unique_ptr<web::WebState>> web_states_; + // Time during which the WebState will be kept alive after being returned. + int64_t keep_alive_second_; + base::WeakPtrFactory<FaviconWebStateDispatcherImpl> weak_ptr_factory_; +}; + +} // namespace dom_distiller + +#endif // IOS_CHROME_BROWSER_DOM_DISTILLER_FAVICON_WEB_STATE_DISPATCHER_IMPL_H_
diff --git a/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.mm b/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.mm new file mode 100644 index 0000000..e74431d1 --- /dev/null +++ b/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.mm
@@ -0,0 +1,77 @@ +// Copyright 2016 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 "ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.h" + +#include "components/favicon/ios/web_favicon_driver.h" +#include "components/keyed_service/core/service_access_type.h" +#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" +#include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#include "ios/chrome/browser/favicon/favicon_service_factory.h" +#include "ios/chrome/browser/history/history_service_factory.h" +#import "ios/web/public/web_state/web_state.h" + +namespace { +// Default delay to download the favicon when the WebState is handed back. +const int64_t kDefaultDelayFaviconSecond = 10; +} + +namespace dom_distiller { + +FaviconWebStateDispatcherImpl::FaviconWebStateDispatcherImpl( + web::BrowserState* browser_state, + int64_t keep_alive_second) + : FaviconWebStateDispatcher(), + browser_state_(browser_state), + keep_alive_second_(keep_alive_second), + weak_ptr_factory_(this) { + if (keep_alive_second_ < 0) + keep_alive_second_ = kDefaultDelayFaviconSecond; +} + +FaviconWebStateDispatcherImpl::~FaviconWebStateDispatcherImpl() {} + +web::WebState* FaviconWebStateDispatcherImpl::RequestWebState() { + const web::WebState::CreateParams web_state_create_params(browser_state_); + std::unique_ptr<web::WebState> web_state_unique = + web::WebState::Create(web_state_create_params); + web::WebState* web_state = web_state_unique.get(); + + web_states_.push_back(std::move(web_state_unique)); + + ios::ChromeBrowserState* original_browser_state = + ios::ChromeBrowserState::FromBrowserState(browser_state_); + + favicon::WebFaviconDriver::CreateForWebState( + web_state, + ios::FaviconServiceFactory::GetForBrowserState( + original_browser_state, ServiceAccessType::EXPLICIT_ACCESS), + ios::HistoryServiceFactory::GetForBrowserState( + original_browser_state, ServiceAccessType::EXPLICIT_ACCESS), + ios::BookmarkModelFactory::GetForBrowserState(original_browser_state)); + + return web_state; +} + +void FaviconWebStateDispatcherImpl::ReturnWebState(web::WebState* web_state) { + base::WeakPtr<FaviconWebStateDispatcherImpl> weak_this = + weak_ptr_factory_.GetWeakPtr(); + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, keep_alive_second_ * NSEC_PER_SEC), + dispatch_get_main_queue(), ^{ + FaviconWebStateDispatcherImpl* web_state_dispatcher = weak_this.get(); + if (web_state_dispatcher) { + auto it = find_if( + web_state_dispatcher->web_states_.begin(), + web_state_dispatcher->web_states_.end(), + [web_state](std::unique_ptr<web::WebState>& unique_web_state) { + return unique_web_state.get() == web_state; + }); + if (it != web_state_dispatcher->web_states_.end()) + web_state_dispatcher->web_states_.erase(it); + } + }); +} + +} // namespace dom_distiller
diff --git a/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl_unittest.mm b/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl_unittest.mm new file mode 100644 index 0000000..2c791ee --- /dev/null +++ b/ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl_unittest.mm
@@ -0,0 +1,76 @@ +// Copyright 2016 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. + +#import "ios/chrome/browser/dom_distiller/favicon_web_state_dispatcher_impl.h" + +#include "base/memory/ptr_util.h" +#include "components/favicon/ios/web_favicon_driver.h" +#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#import "ios/testing/wait_util.h" +#include "ios/web/public/test/test_web_thread_bundle.h" +#include "ios/web/public/web_state/web_state_observer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +namespace dom_distiller { + +// Test class. +class FaviconWebStateDispatcherTest : public PlatformTest { + public: + FaviconWebStateDispatcherTest() : web_state_destroyed_(false) { + TestChromeBrowserState::Builder builder; + browser_state_ = builder.Build(); + } + + web::BrowserState* GetBrowserState() { return browser_state_.get(); } + + bool IsWebStateDestroyed() { return web_state_destroyed_; } + void WebStateDestroyed() { web_state_destroyed_ = true; } + + private: + web::TestWebThreadBundle thread_bundle_; + std::unique_ptr<TestChromeBrowserState> browser_state_; + bool web_state_destroyed_; +}; + +// Observer for the test. +class TestFaviconWebStateDispatcherObserver : public web::WebStateObserver { + public: + TestFaviconWebStateDispatcherObserver(web::WebState* web_state, + FaviconWebStateDispatcherTest* owner) + : web::WebStateObserver(web_state), owner_(owner) {} + + // WebStateObserver implementation: + void WebStateDestroyed() override { owner_->WebStateDestroyed(); }; + + private: + FaviconWebStateDispatcherTest* owner_; // weak, owns this object. +}; + +// Tests that RequestWebState returns a WebState with a FaviconDriver attached. +TEST_F(FaviconWebStateDispatcherTest, RequestWebState) { + FaviconWebStateDispatcherImpl dispatcher(GetBrowserState(), -1); + web::WebState* web_state = dispatcher.RequestWebState(); + + favicon::WebFaviconDriver* driver = + favicon::WebFaviconDriver::FromWebState(web_state); + EXPECT_NE(driver, nullptr); +} + +// Tests that the WebState returned will be destroyed after a delay. +TEST_F(FaviconWebStateDispatcherTest, ReturnWebState) { + FaviconWebStateDispatcherImpl dispatcher(GetBrowserState(), 0); + web::WebState* web_state = dispatcher.RequestWebState(); + + TestFaviconWebStateDispatcherObserver observer(web_state, this); + + ConditionBlock condition = ^{ + return IsWebStateDestroyed(); + }; + + dispatcher.ReturnWebState(web_state); + + ASSERT_TRUE(testing::WaitUntilConditionOrTimeout(0.5, condition)); +} +} // namespace dom_distiller
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn index 4dd78dcb..77b7009 100644 --- a/ios/chrome/test/BUILD.gn +++ b/ios/chrome/test/BUILD.gn
@@ -112,6 +112,7 @@ "//ios/chrome/browser/browsing_data:unit_tests", "//ios/chrome/browser/crash_report:unit_tests", "//ios/chrome/browser/device_sharing:unit_tests", + "//ios/chrome/browser/dom_distiller:unit_tests", "//ios/chrome/browser/favicon:unit_tests", "//ios/chrome/browser/geolocation:unit_tests", "//ios/chrome/browser/itunes_links:unit_tests",
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java index d33bfa43..3abbe46d 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -500,8 +500,6 @@ status = MEDIA_CODEC_OK; index = indexOrStatus; } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { - // TODO(crbug.com/665478) - // assert Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT; mOutputBuffers = mMediaCodec.getOutputBuffers(); status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED; } else if (indexOrStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
diff --git a/media/midi/java/src/org/chromium/midi/MidiManagerAndroid.java b/media/midi/java/src/org/chromium/midi/MidiManagerAndroid.java index e657d17..e0d208d9 100644 --- a/media/midi/java/src/org/chromium/midi/MidiManagerAndroid.java +++ b/media/midi/java/src/org/chromium/midi/MidiManagerAndroid.java
@@ -67,8 +67,7 @@ * @param nativeManagerPointer The native pointer to a midi::MidiManagerAndroid object. */ private MidiManagerAndroid(Context context, long nativeManagerPointer) { - // TODO(crbug.com/665157) - // assert ThreadUtils.runningOnUiThread(); + assert !ThreadUtils.runningOnUiThread(); mManager = (MidiManager) context.getSystemService(Context.MIDI_SERVICE); mHandler = new Handler(ThreadUtils.getUiThreadLooper());
diff --git a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck_test.js b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck_test.js index e221b6d..95d1035a 100644 --- a/third_party/WebKit/LayoutTests/editing/spelling/spellcheck_test.js +++ b/third_party/WebKit/LayoutTests/editing/spelling/spellcheck_test.js
@@ -275,15 +275,6 @@ } } -/** - * @param {!Document} document - * @return {boolean} - */ -function hasPendingSpellCheckRequest(document) { - return internals.lastSpellCheckRequestSequence(document) !== - internals.lastSpellCheckProcessedSequence(document); -} - /** @type {string} */ const kTitle = 'title'; /** @type {string} */ @@ -291,6 +282,46 @@ /** @type {string} */ const kIsSpellcheckTest = 'isSpellcheckTest'; +/** + * @param {!Test} testObject + * @param {!Sample} sample + * @param {string} expectedText + * @param {number} remainingRetry + * @param {number} retryInterval + */ +function verifyMarkers( + testObject, sample, expectedText, remainingRetry, retryInterval) { + assert_not_equals( + window.internals, undefined, + 'window.internals is required for running automated spellcheck tests.'); + + /** @type {!MarkerSerializer} */ + const serializer = new MarkerSerializer({ + spelling: '#', + grammar: '~'}); + + try { + assert_equals(serializer.serialize(sample.document), expectedText); + testObject.done(); + } catch (error) { + if (remainingRetry <= 0) + throw error; + + // Force invoking idle time spellchecker in case it has not been run yet. + if (window.testRunner) + window.testRunner.runIdleTasks(() => {}); + + // TODO(xiaochengh): We should make SpellCheckRequester::didCheck trigger + // something in JavaScript (e.g., a |Promise|), so that we can actively + // know the completion of spellchecking instead of passively waiting for + // markers to appear or disappear. + testObject.step_timeout( + () => verifyMarkers(testObject, sample, expectedText, + remainingRetry - 1, retryInterval), + retryInterval); + } +} + // Spellchecker gets triggered not only by text and selection change, but also // by focus change. For example, misspelling markers in <INPUT> disappear when // the window loses focus, even though the selection does not change. @@ -304,37 +335,6 @@ /** @type {!Array<!Object>} */ const testQueue = []; -// We need to ensure correct usage of testRunner.runIdleTasks() that: -// 1. We don't call runIdleTasks if another runIdleTasks is called but the -// callback has not been invoked yet; Otherwise, the current call is ignored. -// 2. When the callback is invoked, we only verify test cases whose testers -// finished before calling runIdleTasks(); Otherwise, the idle time spell -// check may have not been invoked at the verification time. - -/** @type {boolean} */ -var runIdleTasksRequested = false; -/** - * @type {!Array<!Function>} Verification functions of test cases whose idle - * idle spell checkers are requested before the current call of runIdleTasks. - */ -var idleVerificationReadyQueue = []; -/** - * @type {!Array<!Function>} Verification functions of test cases whose idle - * idle spell checkers are requested after the current call of runIdleTasks. - */ -var idleVerificationWaitingQueue = []; - -function batchIdleVerification() { - runIdleTasksRequested = false; - idleVerificationReadyQueue.forEach(func => func()); - idleVerificationReadyQueue = idleVerificationWaitingQueue; - idleVerificationWaitingQueue = []; - if (idleVerificationReadyQueue.length) { - runIdleTasksRequested = true; - testRunner.runIdleTasks(batchIdleVerification); - } -} - /** * @param {!Test} testObject * @param {!Sample|string} input @@ -359,41 +359,19 @@ assert_unreached(`Invalid tester: ${tester}`); } - assert_not_equals( - window.testRunner, undefined, - 'window.testRunner is required for automated spellcheck tests.'); - assert_not_equals( - window.internals, undefined, - 'window.internals is required for automated spellcheck tests.'); + /** @type {number} */ + const kMaxRetry = 10; + /** @type {number} */ + const kRetryInterval = 50; - /** @type {!Function} */ - const verification = () => { - testObject.step(() => { - if (hasPendingSpellCheckRequest(sample.document)) - return; - - /** @type {!MarkerSerializer} */ - const serializer = new MarkerSerializer({ - spelling: '#', - grammar: '~'}); - - assert_equals(serializer.serialize(sample.document), expectedText); - testObject.done(); - }); - } - - // Verify when all spell check requests are resolved. - testRunner.setSpellCheckResolvedCallback(verification); - - // For tests that do not expect new markers, verify with runIdleTasks. - if (runIdleTasksRequested) { - idleVerificationWaitingQueue.push(verification); - return; - } - - idleVerificationReadyQueue.push(verification); - runIdleTasksRequested = true; - testRunner.runIdleTasks(batchIdleVerification); + // TODO(xiaochengh): We should make SpellCheckRequester::didCheck trigger + // something in JavaScript (e.g., a |Promise|), so that we can actively know + // the completion of spellchecking instead of passively waiting for markers + // to appear or disappear. + testObject.step_timeout( + () => verifyMarkers(testObject, sample, expectedText, + kMaxRetry, kRetryInterval), + kRetryInterval); }); } @@ -416,22 +394,15 @@ if (shouldRemoveSample) testObj.sample.remove(); - // We may be in a spellCheckResolvedCallback here, so removing the callback - // (and hence, all remaining tasks) must be done asynchronously. - setTimeout(() => { - if (window.testRunner) - testRunner.removeSpellCheckResolvedCallback(); + // This is the earliest timing when a new spellcheck_test can be started. + spellcheckTestRunning = false; - // This is the earliest timing when a new spellcheck_test can be started. - spellcheckTestRunning = false; - - /** @type {Object} */ - const next = testQueue.shift(); - if (next === undefined) - return; - invokeSpellcheckTest(next.testObject, next.input, - next.tester, next.expectedText); - }, 0); + /** @type {Object} */ + const next = testQueue.shift(); + if (next === undefined) + return; + invokeSpellcheckTest(next.testObject, next.input, + next.tester, next.expectedText); }); /**
diff --git a/third_party/WebKit/LayoutTests/fast/frames/viewsource/viewsource-8-expected.txt b/third_party/WebKit/LayoutTests/fast/frames/viewsource/viewsource-8-expected.txt new file mode 100644 index 0000000..2293822 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/frames/viewsource/viewsource-8-expected.txt
@@ -0,0 +1 @@ +<html><head></head><body><div class="line-gutter-backdrop"></div><table><tbody><tr><td class="line-number" value="1"></td><td class="line-content"><span class="html-doctype"><!DOCTYPE html></span></td></tr><tr><td class="line-number" value="2"></td><td class="line-content"><span class="html-tag"><html></span></td></tr><tr><td class="line-number" value="3"></td><td class="line-content"><span class="html-tag"><body></span></td></tr><tr><td class="line-number" value="4"></td><td class="line-content"><span class="html-tag"><img <span class="html-attribute-name">src</span>="<a class="html-attribute-value html-resource-link" target="_blank" href="img.png">img.png</a>" /></span></td></tr><tr><td class="line-number" value="5"></td><td class="line-content"><span class="html-tag"><img <span class="html-attribute-name">srcset</span>="<a class="html-attribute-value html-resource-link" target="_blank" href="img.png">img.png</a>,<a class="html-attribute-value html-resource-link" target="_blank" href="img2.png"> img2.png</a>" /></span></td></tr><tr><td class="line-number" value="6"></td><td class="line-content"><span class="html-tag"><img <span class="html-attribute-name">src</span>="<a class="html-attribute-value html-resource-link" target="_blank" href="img.png">img.png</a>" <span class="html-attribute-name">srcset</span>="<a class="html-attribute-value html-resource-link" target="_blank" href="img.png">img.png 1x</a>,<a class="html-attribute-value html-resource-link" target="_blank" href="img2.png"> img2.png 2x</a>,<a class="html-attribute-value html-resource-link" target="_blank" href="img3.png"> img3.png 3x</a>" /></span></td></tr><tr><td class="line-number" value="7"></td><td class="line-content"><span class="html-tag"><img <span class="html-attribute-name">srcset</span>="<a class="html-attribute-value html-resource-link" target="_blank" href="img.png">img.png 480w</a>,<a class="html-attribute-value html-resource-link" target="_blank" href="img2.png"> img2.png 640w</a>,<a class="html-attribute-value html-resource-link" target="_blank" href="img3.png"> img3.png 1024w</a>" /></span></td></tr><tr><td class="line-number" value="8"></td><td class="line-content"><span class="html-tag"></body></span></td></tr><tr><td class="line-number" value="9"></td><td class="line-content"><span class="html-tag"></html></span></td></tr><tr><td class="line-number" value="10"></td><td class="line-content"><span class="html-end-of-file"></span></td></tr></tbody></table></body></html>
diff --git a/third_party/WebKit/LayoutTests/fast/frames/viewsource/viewsource-8.html b/third_party/WebKit/LayoutTests/fast/frames/viewsource/viewsource-8.html new file mode 100644 index 0000000..3545290 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/frames/viewsource/viewsource-8.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<body> +<img src="img.png" /> +<img srcset="img.png, img2.png" /> +<img src="img.png" srcset="img.png 1x, img2.png 2x, img3.png 3x" /> +<img srcset="img.png 480w, img2.png 640w, img3.png 1024w" /> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-getStats-promise.html b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-getStats-promise.html index 79e9c67e..8d24cbd4 100644 --- a/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-getStats-promise.html +++ b/third_party/WebKit/LayoutTests/fast/peerconnection/RTCPeerConnection-getStats-promise.html
@@ -46,26 +46,22 @@ } promise_test(function() { + let test = this; return navigator.mediaDevices.getUserMedia({audio:true, video:true}) .then(function(mediaStream) { pc.addStream(mediaStream); var selector = pc.getLocalStreams()[0].getVideoTracks()[0]; assert_not_equals(selector, null); - return pc.getStats(selector) - .then(function(report) { - assert_expected_report(report); - }); + return promise_rejects(test, new TypeError(), pc.getStats(selector)); }); }, 'getStats(MediaStreamTrack selector)'); promise_test(function() { + let test = this; return navigator.mediaDevices.getUserMedia({audio:true, video:true}) .then(function(mediaStream) { pc.addStream(mediaStream); - return pc.getStats(null) - .then(function(report) { - assert_expected_report(report); - }); + return promise_rejects(test, new TypeError(), pc.getStats(null)); }); }, 'getStats(null)');
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h index 4387453..eaaeacd 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
@@ -126,12 +126,23 @@ // objects or if we are outside of object construction. if (!IsGarbageCollectedMixin<T>::value || !threadState->isMixinInConstruction()) { + // If the wrapper is already marked we can bail out here. if (TraceTrait<T>::heapObjectHeader(dstObject)->isWrapperHeaderMarked()) return; + // Otherwise, eagerly mark the wrapper header and put the object on the + // marking deque for further processing. + WrapperVisitor* const visitor = currentVisitor(threadState->isolate()); + TraceTrait<T>::markWrapperNoTracing(visitor, dstObject); + visitor->pushToMarkingDeque(TraceTrait<T>::traceMarkedWrapper, + TraceTrait<T>::heapObjectHeader, dstObject); + return; } + // We cannot eagerly mark the wrapper header because of mixin + // construction. Delay further processing until AdvanceMarking, which has to + // be in a non-construction state. This path may result in duplicates. currentVisitor(threadState->isolate()) - ->pushToMarkingDeque(TraceTrait<T>::markWrapper, + ->pushToMarkingDeque(TraceTrait<T>::markAndTraceWrapper, TraceTrait<T>::heapObjectHeader, dstObject); }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp index 0442037..15cad2e 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
@@ -188,7 +188,7 @@ ScriptWrappableVisitor* visitor = V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor(); visitor->pushToMarkingDeque( - TraceTrait<DeathAwareScriptWrappable>::markWrapper, + TraceTrait<DeathAwareScriptWrappable>::markAndTraceWrapper, TraceTrait<DeathAwareScriptWrappable>::heapObjectHeader, object); EXPECT_EQ(visitor->getMarkingDeque()->first().rawObjectPointer(), object); @@ -282,6 +282,7 @@ visitor->getMarkingDeque()->clear(); visitor->getVerifierDeque()->clear(); + visitor->getHeadersToUnmark()->clear(); } namespace {
diff --git a/third_party/WebKit/Source/core/frame/DOMWindowProperty.h b/third_party/WebKit/Source/core/frame/DOMWindowProperty.h index 06257b3..283f23b 100644 --- a/third_party/WebKit/Source/core/frame/DOMWindowProperty.h +++ b/third_party/WebKit/Source/core/frame/DOMWindowProperty.h
@@ -37,7 +37,7 @@ public: explicit DOMWindowProperty(LocalFrame*); - virtual void frameDestroyed(); + void frameDestroyed(); LocalFrame* frame() const { return m_frame; }
diff --git a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp index f385cd8..1187e24 100644 --- a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp +++ b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp
@@ -162,9 +162,13 @@ index = addRange(source, index, iter->valueRange().start - token.startIndex(), emptyAtom); - bool isLink = name == srcAttr || name == hrefAttr; - index = addRange(source, index, iter->valueRange().end - token.startIndex(), - "html-attribute-value", isLink, tagName == aTag, value); + if (name == srcsetAttr) { + index = addSrcset(source, index, iter->valueRange().end - token.startIndex()); + } else { + bool isLink = name == srcAttr || name == hrefAttr; + index = addRange(source, index, iter->valueRange().end - token.startIndex(), + "html-attribute-value", isLink, tagName == aTag, value); + } ++iter; } @@ -312,6 +316,30 @@ return anchor; } +int HTMLViewSourceDocument::addSrcset(const String& source, + int start, + int end) { + String srcset = source.substring(start, end-start); + Vector<String> srclist; + srcset.split(',', true, srclist); + unsigned size = srclist.size(); + for (unsigned i = 0; i < size; i++) { + Vector<String> tmp; + srclist[i].split(' ', tmp); + if (tmp.size() > 0) { + AtomicString link(tmp[0]); + m_current = addLink(link, false); + addText(srclist[i], "html-attribute-value"); + m_current = toElement(m_current->parentNode()); + } else { + addText(srclist[i], "html-attribute-value"); + } + if (i + 1 < size) + addText(",", "html-attribute-value"); + } + return end; +} + void HTMLViewSourceDocument::maybeAddSpanForAnnotation( SourceAnnotation annotation) { if (annotation == AnnotateSourceAsXSS) {
diff --git a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h index bac36aa..daa2a87 100644 --- a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h +++ b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h
@@ -74,6 +74,9 @@ bool isLink = false, bool isAnchor = false, const AtomicString& link = nullAtom); + int addSrcset(const String& source, + int start, + int end); void maybeAddSpanForAnnotation(SourceAnnotation); Element* addLink(const AtomicString& url, bool isAnchor);
diff --git a/third_party/WebKit/Source/devtools/.gitignore b/third_party/WebKit/Source/devtools/.gitignore index 49b6d02..46c94cb 100644 --- a/third_party/WebKit/Source/devtools/.gitignore +++ b/third_party/WebKit/Source/devtools/.gitignore
@@ -1,5 +1,6 @@ *.Makefile *.mk +*.pyc *.rules *.sln *.tmp @@ -16,4 +17,4 @@ /scripts/local_node/runtimes /front_end/protocol_externs.js /front_end/InspectorBackendCommands.js -/front_end/SupportedCSSProperties.js \ No newline at end of file +/front_end/SupportedCSSProperties.js
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js b/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js index 75cde63..f9f4664 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js
@@ -39,17 +39,16 @@ constructor(name, visibleByDefault) { super(); this.registerRequiredCSS('ui/filter.css'); - this._filtersShown = false; this._enabled = true; this.element.classList.add('filter-bar'); - this._filterButton = new UI.ToolbarToggle(Common.UIString('Filter'), 'largeicon-filter'); - this._filterButton.addEventListener(UI.ToolbarButton.Events.Click, this._handleFilterButtonClick, this); + this._stateSetting = Common.settings.createSetting('filterBar-' + name + '-toggled', !!visibleByDefault); + this._filterButton = new UI.ToolbarSettingToggle(this._stateSetting, 'largeicon-filter', Common.UIString('Filter')); this._filters = []; - this._stateSetting = Common.settings.createSetting('filterBar-' + name + '-toggled', !!visibleByDefault); - this._setState(this._stateSetting.get()); + this._updateFilterBar(); + this._stateSetting.addChangeListener(this._updateFilterBar.bind(this)); } /** @@ -81,27 +80,30 @@ } /** - * @override - */ - wasShown() { - this._updateFilterBar(); - } - - /** * @param {!Common.Event} event */ _filterChanged(event) { this._updateFilterButton(); } + /** + * @override + */ + wasShown() { + super.wasShown(); + this._updateFilterBar(); + } + _updateFilterBar() { if (!this.parentWidget()) return; - var visible = this._alwaysShowFilters || (this._filtersShown && this._enabled); - if (visible) + var visible = this._alwaysShowFilters || (this._stateSetting.get() && this._enabled); + if (visible) { this.showWidget(); - else + this._focusTextField(); + } else { this.hideWidget(); + } } _focusTextField() { @@ -115,41 +117,11 @@ } _updateFilterButton() { - if (this._filtersShown) { - this._filterButton.setToggled(true); - this._filterButton.setToggleWithRedColor(false); - return; - } - this._filterButton.setToggleWithRedColor(true); var isActive = false; for (var filter of this._filters) isActive = isActive || filter.isActive(); - this._filterButton.setToggled(isActive); - } - - /** - * @param {!Common.Event} event - */ - _handleFilterButtonClick(event) { - this._setState(!this._filtersShown); - } - - /** - * @param {boolean} filtersShown - */ - _setState(filtersShown) { - if (this._filtersShown === filtersShown) - return; - - this._filtersShown = filtersShown; - if (this._stateSetting) - this._stateSetting.set(filtersShown); - - this._updateFilterButton(); - this._updateFilterBar(); - if (this._filtersShown) - this._focusTextField(); - this.dispatchEventToListeners(UI.FilterBar.Events.Toggled); + this._filterButton.setDefaultWithRedColor(isActive); + this._filterButton.setToggleWithRedColor(isActive); } clear() { @@ -165,11 +137,6 @@ Shown: 'on' }; -/** @enum {symbol} */ -UI.FilterBar.Events = { - Toggled: Symbol('Toggled') -}; - /** * @interface * @extends {Common.EventTarget}
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp index 7645e41..de940f2e 100644 --- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp +++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.cpp
@@ -1147,8 +1147,7 @@ return promise; } -ScriptPromise RTCPeerConnection::getStats(ScriptState* scriptState, - MediaStreamTrack* selector) { +ScriptPromise RTCPeerConnection::getStats(ScriptState* scriptState) { ExecutionContext* context = scriptState->getExecutionContext(); UseCounter::count(context, UseCounter::RTCPeerConnectionGetStats);
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h index 443aa91..746fba4 100644 --- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h +++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.h
@@ -147,7 +147,7 @@ ScriptPromise getStats(ScriptState*, RTCStatsCallback* successCallback, MediaStreamTrack* selector = nullptr); - ScriptPromise getStats(ScriptState*, MediaStreamTrack* selector = nullptr); + ScriptPromise getStats(ScriptState*); RTCDataChannel* createDataChannel(ExecutionContext*, String label,
diff --git a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl index de9f6a4..8394fc8f 100644 --- a/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl +++ b/third_party/WebKit/Source/modules/peerconnection/RTCPeerConnection.idl
@@ -107,7 +107,10 @@ // non-optional) argument, and there should be a third failureCallback // argument. [CallWith=ScriptState, LegacyInterfaceTypeChecking] Promise<void> getStats(RTCStatsCallback successCallback, optional MediaStreamTrack? selector); - [CallWith=ScriptState, RuntimeEnabled=RTCPeerConnectionNewGetStats] Promise<RTCStatsReport> getStats(optional MediaStreamTrack? selector); + // TODO(hbos): The spec has an optional |selector| argument that is not + // supported yet. There is a discussion about what to do with it (clarify + // spec, remove it or change it?): https://github.com/w3c/webrtc-stats/issues/116 + [CallWith=ScriptState, RuntimeEnabled=RTCPeerConnectionNewGetStats] Promise<RTCStatsReport> getStats(); // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api // TODO(guidou): The label argument should have [TreatNullAs=EmptyString]
diff --git a/third_party/WebKit/Source/platform/heap/GarbageCollected.h b/third_party/WebKit/Source/platform/heap/GarbageCollected.h index 42f78a3..e814c8c0 100644 --- a/third_party/WebKit/Source/platform/heap/GarbageCollected.h +++ b/third_party/WebKit/Source/platform/heap/GarbageCollected.h
@@ -77,7 +77,9 @@ virtual void trace(Visitor*) {} virtual void adjustAndMark(InlinedGlobalMarkingVisitor) const = 0; virtual void trace(InlinedGlobalMarkingVisitor); - virtual void adjustAndMarkWrapper(const WrapperVisitor*) const = 0; + virtual void adjustAndMarkAndTraceWrapper(const WrapperVisitor*) const = 0; + virtual void adjustAndMarkWrapperNoTracing(const WrapperVisitor*) const = 0; + virtual void adjustAndTraceMarkedWrapper(const WrapperVisitor*) const = 0; virtual bool isHeapObjectAlive() const = 0; virtual HeapObjectHeader* adjustAndGetHeapObjectHeader() const = 0; }; @@ -102,29 +104,45 @@ \ private: -#define DEFINE_GARBAGE_COLLECTED_MIXIN_WRAPPER_METHODS(TYPE) \ - public: \ - void adjustAndMarkWrapper(const WrapperVisitor* visitor) const override { \ - typedef WTF::IsSubclassOfTemplate<typename std::remove_const<TYPE>::type, \ - blink::GarbageCollected> \ - IsSubclassOfGarbageCollected; \ - static_assert( \ - IsSubclassOfGarbageCollected::value, \ - "only garbage collected objects can have garbage collected mixins"); \ - AdjustAndMarkTrait<TYPE>::markWrapper(visitor, \ - static_cast<const TYPE*>(this)); \ - } \ - HeapObjectHeader* adjustAndGetHeapObjectHeader() const override { \ - typedef WTF::IsSubclassOfTemplate<typename std::remove_const<TYPE>::type, \ - blink::GarbageCollected> \ - IsSubclassOfGarbageCollected; \ - static_assert( \ - IsSubclassOfGarbageCollected::value, \ - "only garbage collected objects can have garbage collected mixins"); \ - return AdjustAndMarkTrait<TYPE>::heapObjectHeader( \ - static_cast<const TYPE*>(this)); \ - } \ - \ +#define DEFINE_GARBAGE_COLLECTED_MIXIN_WRAPPER_METHODS(TYPE) \ + private: \ + typedef WTF::IsSubclassOfTemplate<typename std::remove_const<TYPE>::type, \ + blink::GarbageCollected> \ + IsSubclassOfGarbageCollected; \ + \ + public: \ + void adjustAndMarkAndTraceWrapper(const WrapperVisitor* visitor) \ + const override { \ + static_assert( \ + IsSubclassOfGarbageCollected::value, \ + "only garbage collected objects can have garbage collected mixins"); \ + return AdjustAndMarkTrait<TYPE>::markAndTraceWrapper( \ + visitor, static_cast<const TYPE*>(this)); \ + } \ + void adjustAndMarkWrapperNoTracing(const WrapperVisitor* visitor) \ + const override { \ + static_assert( \ + IsSubclassOfGarbageCollected::value, \ + "only garbage collected objects can have garbage collected mixins"); \ + return AdjustAndMarkTrait<TYPE>::markWrapperNoTracing( \ + visitor, static_cast<const TYPE*>(this)); \ + } \ + void adjustAndTraceMarkedWrapper(const WrapperVisitor* visitor) \ + const override { \ + static_assert( \ + IsSubclassOfGarbageCollected::value, \ + "only garbage collected objects can have garbage collected mixins"); \ + AdjustAndMarkTrait<TYPE>::traceMarkedWrapper( \ + visitor, static_cast<const TYPE*>(this)); \ + } \ + HeapObjectHeader* adjustAndGetHeapObjectHeader() const override { \ + static_assert( \ + IsSubclassOfGarbageCollected::value, \ + "only garbage collected objects can have garbage collected mixins"); \ + return AdjustAndMarkTrait<TYPE>::heapObjectHeader( \ + static_cast<const TYPE*>(this)); \ + } \ + \ private: // A C++ object's vptr will be initialized to its leftmost base's vtable after
diff --git a/third_party/WebKit/Source/platform/heap/TraceTraits.h b/third_party/WebKit/Source/platform/heap/TraceTraits.h index a56ccf1..8e37a659 100644 --- a/third_party/WebKit/Source/platform/heap/TraceTraits.h +++ b/third_party/WebKit/Source/platform/heap/TraceTraits.h
@@ -47,12 +47,24 @@ STATIC_ONLY(AdjustAndMarkTrait); public: - static void markWrapper(const WrapperVisitor* visitor, const T* t) { + static void markAndTraceWrapper(const WrapperVisitor* visitor, const T* t) { if (visitor->markWrapperHeader(heapObjectHeader(t))) { visitor->markWrappersInAllWorlds(t); visitor->dispatchTraceWrappers(t); } } + static void markWrapperNoTracing(const WrapperVisitor* visitor, const T* t) { + DCHECK(!heapObjectHeader(t)->isWrapperHeaderMarked()); + visitor->markWrapperHeader(heapObjectHeader(t)); + } + static void traceMarkedWrapper(const WrapperVisitor* visitor, const T* t) { + DCHECK(heapObjectHeader(t)->isWrapperHeaderMarked()); + // The term *mark* is misleading here as we effectively trace through the + // API boundary, i.e., tell V8 that an object is alive. Actual marking + // will be done in V8. + visitor->markWrappersInAllWorlds(t); + visitor->dispatchTraceWrappers(t); + } static HeapObjectHeader* heapObjectHeader(const T* t) { return HeapObjectHeader::fromPayload(t); } @@ -99,8 +111,14 @@ STATIC_ONLY(AdjustAndMarkTrait); public: - static void markWrapper(const WrapperVisitor* visitor, const T* t) { - t->adjustAndMarkWrapper(visitor); + static void markAndTraceWrapper(const WrapperVisitor* visitor, const T* t) { + t->adjustAndMarkAndTraceWrapper(visitor); + } + static void markWrapperNoTracing(const WrapperVisitor* visitor, const T* t) { + t->adjustAndMarkWrapperNoTracing(visitor); + } + static void traceMarkedWrapper(const WrapperVisitor* visitor, const T* t) { + t->adjustAndTraceMarkedWrapper(visitor); } static HeapObjectHeader* heapObjectHeader(const T* t) { return t->adjustAndGetHeapObjectHeader(); @@ -205,11 +223,28 @@ static void trace(Visitor*, void* self); static void trace(InlinedGlobalMarkingVisitor, void* self); - static void markWrapper(const WrapperVisitor* visitor, const void* t) { + static void markAndTraceWrapper(const WrapperVisitor* visitor, + const void* t) { static_assert(CanTraceWrappers<T>::value, "T should be able to trace wrappers. See " "dispatchTraceWrappers in WrapperVisitor.h"); - AdjustAndMarkTrait<T>::markWrapper(visitor, reinterpret_cast<const T*>(t)); + AdjustAndMarkTrait<T>::markAndTraceWrapper(visitor, + reinterpret_cast<const T*>(t)); + } + static void markWrapperNoTracing(const WrapperVisitor* visitor, + const void* t) { + static_assert(CanTraceWrappers<T>::value, + "T should be able to trace wrappers. See " + "dispatchTraceWrappers in WrapperVisitor.h"); + AdjustAndMarkTrait<T>::markWrapperNoTracing(visitor, + reinterpret_cast<const T*>(t)); + } + static void traceMarkedWrapper(const WrapperVisitor* visitor, const void* t) { + static_assert(CanTraceWrappers<T>::value, + "T should be able to trace wrappers. See " + "dispatchTraceWrappers in WrapperVisitor.h"); + AdjustAndMarkTrait<T>::traceMarkedWrapper(visitor, + reinterpret_cast<const T*>(t)); } static HeapObjectHeader* heapObjectHeader(const void* t) { static_assert(CanTraceWrappers<T>::value,
diff --git a/third_party/WebKit/Source/platform/heap/WrapperVisitor.h b/third_party/WebKit/Source/platform/heap/WrapperVisitor.h index f85668a..6315aad 100644 --- a/third_party/WebKit/Source/platform/heap/WrapperVisitor.h +++ b/third_party/WebKit/Source/platform/heap/WrapperVisitor.h
@@ -93,10 +93,9 @@ template <typename T> void traceWrappers(const T* traceable) const { static_assert(sizeof(T), "T must be fully defined"); - // Ideally, we'd assert that we can cast to TraceWrapperBase here. - static_assert( - IsGarbageCollectedType<T>::value, - "Only garbage collected objects can be used in traceWrappers()."); + static_assert(CanTraceWrappers<T>::value, + "T should be able to trace wrappers. See " + "dispatchTraceWrappers in WrapperVisitor.h"); if (!traceable) { return; @@ -106,7 +105,8 @@ return; } - pushToMarkingDeque(TraceTrait<T>::markWrapper, + TraceTrait<T>::markWrapperNoTracing(this, traceable); + pushToMarkingDeque(TraceTrait<T>::traceMarkedWrapper, TraceTrait<T>::heapObjectHeader, traceable); }