diff --git a/DEPS b/DEPS index 97dd5d4..601db6c 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': '68d75c82961b0cddb8fdd97e7ffe991d5f2ec215', + 'v8_revision': '07efdd707852ef8b9aca212417e824a13652f8cb', # 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/app/bookmarks_strings.grdp b/chrome/app/bookmarks_strings.grdp index 31d520ee..a3a7135f 100644 --- a/chrome/app/bookmarks_strings.grdp +++ b/chrome/app/bookmarks_strings.grdp
@@ -439,6 +439,7 @@ </message> <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_ITEMS_DELETED" desc="Label displayed in toast popup message when two or more items are deleted."> {COUNT, plural, + =1 {1 bookmark deleted} other {# bookmarks deleted}} </message> <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_URL_COPIED" desc="Label displayed in toast popup message when a URL is copied."> @@ -449,6 +450,7 @@ </message> <message name="IDS_MD_BOOKMARK_MANAGER_TOAST_ITEMS_COPIED" desc="Label displayed in a toast popup message when two or more bookmark items are copied"> {COUNT, plural, + =1 {1 item copied} other {# items copied}} </message> <!-- End of material design Bookmarks Manager strings. -->
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc index 91e2224..940d8a4 100644 --- a/chrome/browser/chromeos/arc/arc_service_launcher.cc +++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -144,6 +144,7 @@ ArcDownloadsWatcherService::GetForBrowserContext(profile); ArcEnterpriseReportingService::GetForBrowserContext(profile); ArcFileSystemMounter::GetForBrowserContext(profile); + ArcFileSystemOperationRunner::GetForBrowserContext(profile); ArcImeService::GetForBrowserContext(profile); ArcIntentHelperBridge::GetForBrowserContext(profile); ArcMetricsService::GetForBrowserContext(profile); @@ -165,10 +166,6 @@ ArcWallpaperService::GetForBrowserContext(profile); GpuArcVideoServiceHost::GetForBrowserContext(profile); - arc_service_manager_->AddService( - base::MakeUnique<ArcFileSystemOperationRunner>( - arc_service_manager_->arc_bridge_service(), profile)); - // Kiosk apps should be run only for kiosk sessions. if (user_manager::UserManager::Get()->IsLoggedInAsArcKioskApp()) { // ArcKioskAppService is BrowserContextKeyedService so that it's destroyed
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util_unittest.cc index 9b95c908..f7702518 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util_unittest.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util_unittest.cc
@@ -15,9 +15,11 @@ #include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h" #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h" #include "chrome/browser/chromeos/fileapi/external_file_url_util.h" +#include "chrome/test/base/testing_profile.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_service_manager.h" #include "components/arc/test/fake_file_system_instance.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "content/public/test/test_browser_thread_bundle.h" #include "storage/browser/fileapi/file_system_url.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,6 +35,12 @@ constexpr char kData[] = "abcdef"; constexpr char kMimeType[] = "application/octet-stream"; +std::unique_ptr<KeyedService> CreateArcFileSystemOperationRunnerForTesting( + content::BrowserContext* context) { + return ArcFileSystemOperationRunner::CreateForTesting( + ArcServiceManager::Get()->arc_bridge_service()); +} + class ArcContentFileSystemAsyncFileUtilTest : public testing::Test { public: ArcContentFileSystemAsyncFileUtilTest() = default; @@ -43,11 +51,13 @@ File(kArcUrl, kData, kMimeType, File::Seekable::NO)); arc_service_manager_ = base::MakeUnique<ArcServiceManager>(); - arc_service_manager_->AddService( - ArcFileSystemOperationRunner::CreateForTesting( - arc_service_manager_->arc_bridge_service())); + arc_service_manager_->set_browser_context(&profile_); + ArcFileSystemOperationRunner::GetFactory()->SetTestingFactoryAndUse( + &profile_, &CreateArcFileSystemOperationRunnerForTesting); arc_service_manager_->arc_bridge_service()->file_system()->SetInstance( &fake_file_system_); + + async_file_util_ = base::MakeUnique<ArcContentFileSystemAsyncFileUtil>(); } protected: @@ -64,9 +74,10 @@ } content::TestBrowserThreadBundle thread_bundle_; + TestingProfile profile_; FakeFileSystemInstance fake_file_system_; std::unique_ptr<ArcServiceManager> arc_service_manager_; - ArcContentFileSystemAsyncFileUtil async_file_util_; + std::unique_ptr<ArcContentFileSystemAsyncFileUtil> async_file_util_; private: DISALLOW_COPY_AND_ASSIGN(ArcContentFileSystemAsyncFileUtilTest); @@ -78,7 +89,7 @@ GURL externalfile_url = ArcUrlToExternalFileUrl(GURL(kArcUrl)); base::RunLoop run_loop; - async_file_util_.GetFileInfo( + async_file_util_->GetFileInfo( std::unique_ptr<storage::FileSystemOperationContext>(), ExternalFileURLToFileSystemURL(externalfile_url), -1, // fields
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader_unittest.cc index 9fd8cb5..be7b0cb 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader_unittest.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader_unittest.cc
@@ -13,9 +13,11 @@ #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.h" #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h" +#include "chrome/test/base/testing_profile.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_service_manager.h" #include "components/arc/test/fake_file_system_instance.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "content/public/test/test_browser_thread_bundle.h" #include "net/base/io_buffer.h" #include "net/base/test_completion_callback.h" @@ -57,6 +59,12 @@ return true; } +std::unique_ptr<KeyedService> CreateFileSystemOperationRunnerForTesting( + content::BrowserContext* context) { + return ArcFileSystemOperationRunner::CreateForTesting( + ArcServiceManager::Get()->arc_bridge_service()); +} + class ArcContentFileSystemFileStreamReaderTest : public testing::Test { public: ArcContentFileSystemFileStreamReaderTest() = default; @@ -70,15 +78,16 @@ File(kArcUrlPipe, kData, kMimeType, File::Seekable::NO)); arc_service_manager_ = base::MakeUnique<ArcServiceManager>(); - arc_service_manager_->AddService( - ArcFileSystemOperationRunner::CreateForTesting( - arc_service_manager_->arc_bridge_service())); + arc_service_manager_->set_browser_context(&profile_); + ArcFileSystemOperationRunner::GetFactory()->SetTestingFactoryAndUse( + &profile_, &CreateFileSystemOperationRunnerForTesting); arc_service_manager_->arc_bridge_service()->file_system()->SetInstance( &fake_file_system_); } private: content::TestBrowserThreadBundle thread_bundle_; + TestingProfile profile_; FakeFileSystemInstance fake_file_system_; std::unique_ptr<ArcServiceManager> arc_service_manager_;
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root_unittest.cc index e9653d19..b09d223 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root_unittest.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root_unittest.cc
@@ -14,10 +14,12 @@ #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h" #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h" #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h" +#include "chrome/test/base/testing_profile.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_service_manager.h" #include "components/arc/common/file_system.mojom.h" #include "components/arc/test/fake_file_system_instance.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "content/public/test/test_browser_thread_bundle.h" #include "storage/browser/fileapi/watcher_manager.h" #include "storage/common/fileapi/directory_entry.h" @@ -106,6 +108,12 @@ static_cast<uint64_t>(info.creation_time.ToJavaTime())); } +std::unique_ptr<KeyedService> CreateFileSystemOperationRunnerForTesting( + content::BrowserContext* context) { + return ArcFileSystemOperationRunner::CreateForTesting( + ArcServiceManager::Get()->arc_bridge_service()); +} + class ArcDocumentsProviderRootTest : public testing::Test { public: ArcDocumentsProviderRootTest() = default; @@ -117,9 +125,9 @@ } arc_service_manager_ = base::MakeUnique<ArcServiceManager>(); - arc_service_manager_->AddService( - ArcFileSystemOperationRunner::CreateForTesting( - arc_service_manager_->arc_bridge_service())); + arc_service_manager_->set_browser_context(&profile_); + ArcFileSystemOperationRunner::GetFactory()->SetTestingFactoryAndUse( + &profile_, &CreateFileSystemOperationRunnerForTesting); arc_service_manager_->arc_bridge_service()->file_system()->SetInstance( &fake_file_system_); @@ -131,8 +139,15 @@ kRootSpec.document_id); } + void TearDown() override { + root_.reset(); + // Run all pending tasks before destroying testing profile. + base::RunLoop().RunUntilIdle(); + } + protected: content::TestBrowserThreadBundle thread_bundle_; + TestingProfile profile_; FakeFileSystemInstance fake_file_system_; std::unique_ptr<ArcServiceManager> arc_service_manager_; std::unique_ptr<ArcDocumentsProviderRoot> root_;
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc index 8b604a9..9d8eb84 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.cc
@@ -9,20 +9,53 @@ #include "base/bind.h" #include "base/location.h" #include "base/memory/ptr_util.h" +#include "base/memory/singleton.h" #include "base/optional.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/arc/arc_util.h" +#include "chrome/browser/profiles/profile.h" #include "components/arc/arc_bridge_service.h" +#include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "content/public/browser/browser_thread.h" #include "url/gurl.h" using content::BrowserThread; namespace arc { +namespace { + +// Singleton factory for ArcFileSystemOperationRunner. +class ArcFileSystemOperationRunnerFactory + : public internal::ArcBrowserContextKeyedServiceFactoryBase< + ArcFileSystemOperationRunner, + ArcFileSystemOperationRunnerFactory> { + public: + // Factory name used by ArcBrowserContextKeyedServiceFactoryBase. + static constexpr const char* kName = "ArcFileSystemOperationRunnerFactory"; + + static ArcFileSystemOperationRunnerFactory* GetInstance() { + return base::Singleton<ArcFileSystemOperationRunnerFactory>::get(); + } + + private: + friend base::DefaultSingletonTraits<ArcFileSystemOperationRunnerFactory>; + ArcFileSystemOperationRunnerFactory() = default; + ~ArcFileSystemOperationRunnerFactory() override = default; +}; + +} // namespace // static -const char ArcFileSystemOperationRunner::kArcServiceName[] = - "arc::ArcFileSystemOperationRunner"; +ArcFileSystemOperationRunner* +ArcFileSystemOperationRunner::GetForBrowserContext( + content::BrowserContext* context) { + return ArcFileSystemOperationRunnerFactory::GetForBrowserContext(context); +} + +// static +BrowserContextKeyedServiceFactory* ArcFileSystemOperationRunner::GetFactory() { + return ArcFileSystemOperationRunnerFactory::GetInstance(); +} // static std::unique_ptr<ArcFileSystemOperationRunner> @@ -31,29 +64,31 @@ // We can't use base::MakeUnique() here because we are calling a private // constructor. return base::WrapUnique<ArcFileSystemOperationRunner>( - new ArcFileSystemOperationRunner(bridge_service, nullptr, false)); + new ArcFileSystemOperationRunner(nullptr, bridge_service, false)); } ArcFileSystemOperationRunner::ArcFileSystemOperationRunner( - ArcBridgeService* bridge_service, - const Profile* profile) - : ArcFileSystemOperationRunner(bridge_service, profile, true) { - DCHECK(profile); + content::BrowserContext* context, + ArcBridgeService* bridge_service) + : ArcFileSystemOperationRunner(Profile::FromBrowserContext(context), + bridge_service, + true) { + DCHECK(context); } ArcFileSystemOperationRunner::ArcFileSystemOperationRunner( + content::BrowserContext* context, ArcBridgeService* bridge_service, - const Profile* profile, bool set_should_defer_by_events) - : ArcService(bridge_service), - profile_(profile), + : context_(context), + arc_bridge_service_(bridge_service), set_should_defer_by_events_(set_should_defer_by_events), binding_(this), weak_ptr_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // We need to observe FileSystemInstance even in unit tests to call Init(). - arc_bridge_service()->file_system()->AddObserver(this); + arc_bridge_service_->file_system()->AddObserver(this); // ArcSessionManager may not exist in unit tests. auto* arc_session_manager = ArcSessionManager::Get(); @@ -70,7 +105,12 @@ if (arc_session_manager) arc_session_manager->RemoveObserver(this); - arc_bridge_service()->file_system()->RemoveObserver(this); + // TODO(hidehiko): Currently, the lifetime of ArcBridgeService and + // BrowserContextKeyedService is not nested. + // If ArcServiceManager::Get() returns nullptr, it is already destructed, + // so do not touch it. + if (ArcServiceManager::Get()) + arc_bridge_service_->file_system()->RemoveObserver(this); // On destruction, deferred operations are discarded. } @@ -95,7 +135,7 @@ return; } auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service()->file_system(), GetFileSize); + arc_bridge_service_->file_system(), GetFileSize); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(callback, -1)); @@ -115,7 +155,7 @@ return; } auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service()->file_system(), GetMimeType); + arc_bridge_service_->file_system(), GetMimeType); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(callback, base::nullopt)); @@ -135,7 +175,7 @@ return; } auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service()->file_system(), OpenFileToRead); + arc_bridge_service_->file_system(), OpenFileToRead); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -157,7 +197,7 @@ return; } auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service()->file_system(), GetDocument); + arc_bridge_service_->file_system(), GetDocument); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -180,7 +220,7 @@ return; } auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service()->file_system(), GetChildDocuments); + arc_bridge_service_->file_system(), GetChildDocuments); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(callback, base::nullopt)); @@ -204,7 +244,7 @@ return; } auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service()->file_system(), AddWatcher); + arc_bridge_service_->file_system(), AddWatcher); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(callback, -1)); @@ -240,7 +280,7 @@ watcher_callbacks_.erase(iter); auto* file_system_instance = ARC_GET_INSTANCE_FOR_METHOD( - arc_bridge_service()->file_system(), AddWatcher); + arc_bridge_service_->file_system(), AddWatcher); if (!file_system_instance) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(callback, false)); @@ -270,7 +310,7 @@ void ArcFileSystemOperationRunner::OnInstanceReady() { DCHECK_CURRENTLY_ON(BrowserThread::UI); auto* file_system_instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service()->file_system(), Init); + ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->file_system(), Init); if (file_system_instance) { mojom::FileSystemHostPtr host_proxy; binding_.Bind(mojo::MakeRequest(&host_proxy)); @@ -309,8 +349,9 @@ void ArcFileSystemOperationRunner::OnStateChanged() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (set_should_defer_by_events_) { - SetShouldDefer(IsArcPlayStoreEnabledForProfile(profile_) && - !arc_bridge_service()->file_system()->has_instance()); + SetShouldDefer(IsArcPlayStoreEnabledForProfile( + Profile::FromBrowserContext(context_)) && + !arc_bridge_service_->file_system()->has_instance()); } }
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h index 6f40f97..4db37091 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h +++ b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner.h
@@ -20,11 +20,20 @@ #include "components/arc/arc_service.h" #include "components/arc/common/file_system.mojom.h" #include "components/arc/instance_holder.h" +#include "components/keyed_service/core/keyed_service.h" #include "mojo/public/cpp/bindings/binding.h" #include "storage/browser/fileapi/watcher_manager.h" +class BrowserContextKeyedServiceFactory; + +namespace content { +class BrowserContext; +} // namespace content + namespace arc { +class ArcBridgeService; + // Runs ARC file system operations. // // This is an abstraction layer on top of mojom::FileSystemInstance. All ARC @@ -49,7 +58,7 @@ // // All member functions must be called on the UI thread. class ArcFileSystemOperationRunner - : public ArcService, + : public KeyedService, public mojom::FileSystemHost, public ArcSessionManager::Observer, public InstanceHolder<mojom::FileSystemInstance>::Observer { @@ -78,8 +87,10 @@ virtual ~Observer() = default; }; - // For supporting ArcServiceManager::GetService<T>(). - static const char kArcServiceName[]; + // Returns singleton instance for the given BrowserContext, + // or nullptr if the browser |context| is not allowed to use ARC. + static ArcFileSystemOperationRunner* GetForBrowserContext( + content::BrowserContext* context); // Creates an instance suitable for unit tests. // This instance will run all operations immediately without deferring by @@ -88,10 +99,11 @@ static std::unique_ptr<ArcFileSystemOperationRunner> CreateForTesting( ArcBridgeService* bridge_service); - // The standard constructor. A production instance should be created by - // this constructor. - ArcFileSystemOperationRunner(ArcBridgeService* bridge_service, - const Profile* profile); + // Returns Factory instance for ArcFileSystemOperationRunner. + static BrowserContextKeyedServiceFactory* GetFactory(); + + ArcFileSystemOperationRunner(content::BrowserContext* context, + ArcBridgeService* bridge_service); ~ArcFileSystemOperationRunner() override; // Adds or removes observers. @@ -127,8 +139,8 @@ private: friend class ArcFileSystemOperationRunnerTest; - ArcFileSystemOperationRunner(ArcBridgeService* bridge_service, - const Profile* profile, + ArcFileSystemOperationRunner(content::BrowserContext* context, + ArcBridgeService* bridge_service, bool set_should_defer_by_events); void OnWatcherAdded(const WatcherCallback& watcher_callback, @@ -143,9 +155,9 @@ // deferring. void SetShouldDefer(bool should_defer); - // Profile this runner is associated with. This can be nullptr in - // unit tests. - const Profile* const profile_; + // Maybe nullptr in unittests. + content::BrowserContext* const context_; + ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager // Indicates if this instance should enable/disable deferring by events. // Usually true, but set to false in unit tests.
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_unittest.cc index c6aa025..355b081 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_unittest.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_unittest.cc
@@ -36,17 +36,14 @@ void SetUp() override { arc_service_manager_ = base::MakeUnique<ArcServiceManager>(); + runner_ = ArcFileSystemOperationRunner::CreateForTesting( + arc_service_manager_->arc_bridge_service()); arc_service_manager_->arc_bridge_service()->file_system()->SetInstance( &file_system_instance_); - arc_service_manager_->AddService( - ArcFileSystemOperationRunner::CreateForTesting( - arc_service_manager_->arc_bridge_service())); // Run the message loop until FileSystemInstance::Init() is called. base::RunLoop().RunUntilIdle(); ASSERT_TRUE(file_system_instance_.InitCalled()); - - runner_ = arc_service_manager_->GetService<ArcFileSystemOperationRunner>(); } protected: @@ -100,8 +97,7 @@ content::TestBrowserThreadBundle thread_bundle_; FakeFileSystemInstance file_system_instance_; std::unique_ptr<ArcServiceManager> arc_service_manager_; - // Owned by |arc_service_manager_|. - ArcFileSystemOperationRunner* runner_; + std::unique_ptr<ArcFileSystemOperationRunner> runner_; private: DISALLOW_COPY_AND_ASSIGN(ArcFileSystemOperationRunnerTest);
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc index 424894bfd..7a2d583 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.cc
@@ -19,6 +19,13 @@ namespace { +// TODO(crbug.com/745648): Use correct BrowserContext. +ArcFileSystemOperationRunner* GetArcFileSystemOperationRunner() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + return ArcFileSystemOperationRunner::GetForBrowserContext( + ArcServiceManager::Get()->browser_context()); +} + template <typename T> void PostToIOThread(const base::Callback<void(T)>& callback, T result) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -30,8 +37,7 @@ void GetFileSizeOnUIThread(const GURL& url, const GetFileSizeCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped."; @@ -44,8 +50,7 @@ void OpenFileToReadOnUIThread(const GURL& url, const OpenFileToReadCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped."; @@ -59,8 +64,7 @@ const std::string& document_id, const GetDocumentCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped."; @@ -74,8 +78,7 @@ const std::string& parent_document_id, const GetChildDocumentsCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped."; @@ -90,8 +93,7 @@ const WatcherCallback& watcher_callback, const AddWatcherCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped."; @@ -104,8 +106,7 @@ void RemoveWatcherOnUIThread(int64_t watcher_id, const RemoveWatcherCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped."; @@ -117,8 +118,7 @@ void AddObserverOnUIThread(scoped_refptr<ObserverIOThreadWrapper> observer) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped."; @@ -129,8 +129,7 @@ void RemoveObserverOnUIThread(scoped_refptr<ObserverIOThreadWrapper> observer) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - auto* runner = - ArcServiceManager::GetGlobalService<ArcFileSystemOperationRunner>(); + auto* runner = GetArcFileSystemOperationRunner(); if (!runner) { DLOG(ERROR) << "ArcFileSystemOperationRunner unavailable. " << "File system operations are dropped.";
diff --git a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc index 8a435cb..61731e9 100644 --- a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc +++ b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
@@ -201,8 +201,8 @@ if (arc::IsArcAllowedForProfile(profile) && base::FilePath(arc::kContentFileSystemMountPointPath).IsParent(path)) { GURL arc_url = arc::PathToArcUrl(path); - auto* runner = arc::ArcServiceManager::GetGlobalService< - arc::ArcFileSystemOperationRunner>(); + auto* runner = + arc::ArcFileSystemOperationRunner::GetForBrowserContext(profile); if (!runner) { content::BrowserThread::PostTask( content::BrowserThread::UI, FROM_HERE,
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter.cc b/chrome/browser/chromeos/net/tether_notification_presenter.cc index fa49f0a0..5f477a3 100644 --- a/chrome/browser/chromeos/net/tether_notification_presenter.cc +++ b/chrome/browser/chromeos/net/tether_notification_presenter.cc
@@ -74,14 +74,6 @@ "cros_tether_notification_ids.setup_required"; // static -constexpr const std::array<const char* const, 4> - TetherNotificationPresenter::kIdsWhichOpenSettingsOnClick{ - {TetherNotificationPresenter::kTetherNotifierId, - TetherNotificationPresenter::kActiveHostNotificationId, - TetherNotificationPresenter::kPotentialHotspotNotificationId, - TetherNotificationPresenter::kSetupRequiredNotificationId}}; - -// static std::unique_ptr<message_center::Notification> TetherNotificationPresenter::CreateNotificationWithMediumSignalStrengthIcon( const std::string& id, @@ -217,13 +209,7 @@ void TetherNotificationPresenter::OnNotificationClicked( const std::string& notification_id) { - auto* const* const it = std::find_if( - kIdsWhichOpenSettingsOnClick.begin(), kIdsWhichOpenSettingsOnClick.end(), - [notification_id](const char* id) { return notification_id == id; }); - if (it == kIdsWhichOpenSettingsOnClick.end()) { - return; - } - + PA_LOG(INFO) << "Notification with ID " << notification_id << " was clicked."; settings_ui_delegate_->ShowSettingsSubPageForProfile(profile_, kTetherSettingsSubpage); message_center_->RemoveNotification(notification_id, true /* by_user */);
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter.h b/chrome/browser/chromeos/net/tether_notification_presenter.h index 743491b..e883f987c 100644 --- a/chrome/browser/chromeos/net/tether_notification_presenter.h +++ b/chrome/browser/chromeos/net/tether_notification_presenter.h
@@ -71,15 +71,11 @@ }; private: - // IDs associated with Tether notification types. static const char kTetherNotifierId[]; static const char kPotentialHotspotNotificationId[]; static const char kActiveHostNotificationId[]; static const char kSetupRequiredNotificationId[]; - // IDs of all notifications which, when clicked, open mobile data settings. - static const std::array<const char* const, 4> kIdsWhichOpenSettingsOnClick; - static std::unique_ptr<message_center::Notification> CreateNotificationWithMediumSignalStrengthIcon(const std::string& id, const base::string16& title,
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc b/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc index 2bb8dbee..a5cd9f8 100644 --- a/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc +++ b/chrome/browser/chromeos/net/tether_notification_presenter_unittest.cc
@@ -410,12 +410,6 @@ VerifySettingsNotOpened(); } -TEST_F(TetherNotificationPresenterTest, - TestDoesNotOpenSettingsWhenOtherNotificationClicked) { - test_message_center_->NotifyNotificationTapped("otherNotificationId"); - VerifySettingsNotOpened(); -} - } // namespace tether } // namespace chromeos
diff --git a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc index 2eeeb74..d541f71 100644 --- a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc +++ b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc
@@ -19,8 +19,11 @@ OfflinePrefetchDownloadClient::~OfflinePrefetchDownloadClient() = default; void OfflinePrefetchDownloadClient::OnServiceInitialized( + bool state_lost, const std::vector<std::string>& outstanding_download_guids) { // TODO(jianli): Remove orphaned downloads. + // TODO(jianli, dtrainor): Handle service corruption and recovery if + // |state_lost| is |true|. PrefetchDownloader* downloader = GetPrefetchDownloader(); if (downloader) downloader->OnDownloadServiceReady();
diff --git a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h index 197c22f..867723d 100644 --- a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h +++ b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.h
@@ -24,6 +24,7 @@ private: // Overridden from Client: void OnServiceInitialized( + bool state_lost, const std::vector<std::string>& outstanding_download_guids) override; void OnServiceUnavailable() override; download::Client::ShouldDownload OnDownloadStarted(
diff --git a/chrome/browser/permissions/permission_request_manager.cc b/chrome/browser/permissions/permission_request_manager.cc index 8686773..678c50a 100644 --- a/chrome/browser/permissions/permission_request_manager.cc +++ b/chrome/browser/permissions/permission_request_manager.cc
@@ -194,19 +194,20 @@ continue; // We can simply erase the current entry in the request table if we aren't - // showing the dialog, or if we are showing it and it can accept the update. - bool can_erase = view_->CanAcceptRequestUpdate(); - if (can_erase) { - DeleteBubble(); + // showing the dialog (because we switched tabs with an active prompt), or + // if we are showing it and it can accept the update. + if (!view_ || view_->CanAcceptRequestUpdate()) { + // TODO(timloh): We should fix this at some point. + // Grouped (mic+camera) requests are currently never cancelled. + DCHECK_EQ(static_cast<size_t>(1), requests_.size()); + + if (view_) + DeleteBubble(); RequestFinishedIncludingDuplicates(*requests_iter); requests_.erase(requests_iter); - if (requests_.empty()) - DequeueRequestsAndShowBubble(); - else - ShowBubble(); - + DequeueRequestsAndShowBubble(); return; }
diff --git a/chrome/browser/permissions/permission_request_manager_unittest.cc b/chrome/browser/permissions/permission_request_manager_unittest.cc index 1d9f2207..4acacd9 100644 --- a/chrome/browser/permissions/permission_request_manager_unittest.cc +++ b/chrome/browser/permissions/permission_request_manager_unittest.cc
@@ -194,6 +194,17 @@ EXPECT_TRUE(request_camera_.granted()); } +TEST_F(PermissionRequestManagerTest, CancelAfterTabSwitch) { + manager_->AddRequest(&request1_); + manager_->DisplayPendingRequests(); + WaitForBubbleToBeShown(); + EXPECT_TRUE(prompt_factory_->is_visible()); + MockTabSwitchAway(); + EXPECT_FALSE(prompt_factory_->is_visible()); + manager_->CancelRequest(&request1_); + EXPECT_TRUE(request1_.finished()); +} + TEST_F(PermissionRequestManagerTest, NoRequests) { manager_->DisplayPendingRequests(); WaitForBubbleToBeShown();
diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc index f94be93..9732c48e 100644 --- a/chrome/browser/signin/easy_unlock_service_regular.cc +++ b/chrome/browser/signin/easy_unlock_service_regular.cc
@@ -192,6 +192,12 @@ void EasyUnlockServiceRegular::LaunchSetup() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); #if defined(OS_CHROMEOS) + // TODO(tengs): To keep login working for existing EasyUnlock users, we need + // to explicitly disable login here for new users who set up EasyUnlock. + // After a sufficient number of releases, we should make the default value + // false. + pref_manager_->SetIsChromeOSLoginEnabled(false); + // Force the user to reauthenticate by showing a modal overlay (similar to the // lock screen). The password obtained from the reauth is cached for a short // period of time and used to create the cryptohome keys for sign-in.
diff --git a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc index 991f1e63..9427fe30 100644 --- a/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc +++ b/chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.cc
@@ -34,8 +34,7 @@ DCHECK(event->IsKeyEvent()); ui::KeyEvent* key_event = event->AsKeyEvent(); if (!key_event->is_char()) { - input_method_chromeos_->DispatchKeyEvent( - key_event, base::MakeUnique<base::Callback<void(bool)>>(callback)); + input_method_chromeos_->DispatchKeyEvent(key_event, std::move(callback)); } else { const bool handled = false; callback.Run(handled);
diff --git a/components/download/internal/controller_impl.cc b/components/download/internal/controller_impl.cc index 692080ba..408f0b6 100644 --- a/components/download/internal/controller_impl.cc +++ b/components/download/internal/controller_impl.cc
@@ -322,7 +322,11 @@ AttemptToFinalizeSetup(); } -void ControllerImpl::OnDriverHardRecoverComplete(bool success) {} +void ControllerImpl::OnDriverHardRecoverComplete(bool success) { + DCHECK(!startup_status_.driver_ok.has_value()); + startup_status_.driver_ok = success; + AttemptToFinalizeSetup(); +} void ControllerImpl::OnDownloadCreated(const DriverEntry& download) { if (controller_state_ != State::READY) @@ -404,14 +408,22 @@ AttemptToFinalizeSetup(); } +void ControllerImpl::OnFileMonitorHardRecoverComplete(bool success) { + DCHECK(!startup_status_.file_monitor_ok.has_value()); + startup_status_.file_monitor_ok = success; + AttemptToFinalizeSetup(); +} + void ControllerImpl::OnModelReady(bool success) { DCHECK(!startup_status_.model_ok.has_value()); startup_status_.model_ok = success; AttemptToFinalizeSetup(); } -void ControllerImpl::OnHardRecoverComplete(bool success) { - // TODO(dtrainor): Support recovery. +void ControllerImpl::OnModelHardRecoverComplete(bool success) { + DCHECK(!startup_status_.model_ok.has_value()); + startup_status_.model_ok = success; + AttemptToFinalizeSetup(); } void ControllerImpl::OnItemAdded(bool success, @@ -469,23 +481,23 @@ } void ControllerImpl::AttemptToFinalizeSetup() { - DCHECK_EQ(controller_state_, State::INITIALIZING); + DCHECK(controller_state_ == State::INITIALIZING || + controller_state_ == State::RECOVERING); if (!startup_status_.Complete()) return; - stats::LogControllerStartupStatus(startup_status_); + bool in_recovery = controller_state_ == State::RECOVERING; + + stats::LogControllerStartupStatus(in_recovery, startup_status_); if (!startup_status_.Ok()) { - // TODO(dtrainor): Recover here. Try to clean up any disk state and, if - // possible, any DownloadDriver data and continue with initialization? - controller_state_ = State::UNAVAILABLE; + if (in_recovery) { + HandleUnrecoverableSetup(); + NotifyServiceOfStartup(); + } else { + StartHardRecoveryAttempt(); + } - // If we cannot recover, notify Clients that the service is unavailable. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&ControllerImpl::SendOnServiceUnavailable, - weak_ptr_factory_.GetWeakPtr())); - - NotifyServiceOfStartup(); return; } @@ -496,7 +508,7 @@ RemoveCleanupEligibleDownloads(); ResolveInitialRequestStates(); - NotifyClientsOfStartup(); + NotifyClientsOfStartup(in_recovery); controller_state_ = State::READY; @@ -509,8 +521,29 @@ ActivateMoreDownloads(); } +void ControllerImpl::HandleUnrecoverableSetup() { + controller_state_ = State::UNAVAILABLE; + + // If we cannot recover, notify Clients that the service is unavailable. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&ControllerImpl::SendOnServiceUnavailable, + weak_ptr_factory_.GetWeakPtr())); +} + +void ControllerImpl::StartHardRecoveryAttempt() { + startup_status_.Reset(); + controller_state_ = State::RECOVERING; + + driver_->HardRecover(); + model_->HardRecover(); + file_monitor_->HardRecover( + base::Bind(&ControllerImpl::OnFileMonitorHardRecoverComplete, + weak_ptr_factory_.GetWeakPtr())); +} + void ControllerImpl::PollActiveDriverDownloads() { - DCHECK_EQ(controller_state_, State::INITIALIZING); + DCHECK(controller_state_ == State::INITIALIZING || + controller_state_ == State::RECOVERING); std::set<std::string> guids = driver_->GetActiveDownloads(); @@ -521,7 +554,8 @@ } void ControllerImpl::CancelOrphanedRequests() { - DCHECK_EQ(controller_state_, State::INITIALIZING); + DCHECK(controller_state_ == State::INITIALIZING || + controller_state_ == State::RECOVERING); auto entries = model_->PeekEntries(); @@ -544,7 +578,8 @@ } void ControllerImpl::CleanupUnknownFiles() { - DCHECK_EQ(controller_state_, State::INITIALIZING); + DCHECK(controller_state_ == State::INITIALIZING || + controller_state_ == State::RECOVERING); auto entries = model_->PeekEntries(); std::vector<DriverEntry> driver_entries; @@ -558,7 +593,8 @@ } void ControllerImpl::ResolveInitialRequestStates() { - DCHECK_EQ(controller_state_, State::INITIALIZING); + DCHECK(controller_state_ == State::INITIALIZING || + controller_state_ == State::RECOVERING); auto entries = model_->PeekEntries(); for (auto* entry : entries) { @@ -731,7 +767,7 @@ } } -void ControllerImpl::NotifyClientsOfStartup() { +void ControllerImpl::NotifyClientsOfStartup(bool state_lost) { std::set<Entry::State> ignored_states = {Entry::State::COMPLETE}; auto categorized = util::MapEntriesToClients( clients_->GetRegisteredClients(), model_->PeekEntries(), ignored_states); @@ -740,7 +776,7 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&ControllerImpl::SendOnServiceInitialized, weak_ptr_factory_.GetWeakPtr(), client_id, - categorized[client_id])); + state_lost, categorized[client_id])); } } @@ -938,10 +974,11 @@ void ControllerImpl::SendOnServiceInitialized( DownloadClient client_id, + bool state_lost, const std::vector<std::string>& guids) { auto* client = clients_->GetClient(client_id); DCHECK(client); - client->OnServiceInitialized(guids); + client->OnServiceInitialized(state_lost, guids); } void ControllerImpl::SendOnServiceUnavailable() {
diff --git a/components/download/internal/controller_impl.h b/components/download/internal/controller_impl.h index ac21583..2b644de 100644 --- a/components/download/internal/controller_impl.h +++ b/components/download/internal/controller_impl.h
@@ -80,7 +80,7 @@ // Model::Client implementation. void OnModelReady(bool success) override; - void OnHardRecoverComplete(bool success) override; + void OnModelHardRecoverComplete(bool success) override; void OnItemAdded(bool success, DownloadClient client, const std::string& guid) override; @@ -94,6 +94,9 @@ // Called when the file monitor and download file directory are initialized. void OnFileMonitorReady(bool success); + // Called when the file monitor finishes attempting to recover itself. + void OnFileMonitorHardRecoverComplete(bool success); + // DeviceStatusListener::Observer implementation. void OnDeviceStatusChanged(const DeviceStatus& device_status) override; @@ -101,6 +104,14 @@ // internal state initialization. void AttemptToFinalizeSetup(); + // Called when setup and recovery failed. Shuts down the service and notifies + // the Clients. + void HandleUnrecoverableSetup(); + + // If initialization failed, try to reset the state of all components and + // restart them. If that attempt fails the service will be unavailable. + void StartHardRecoveryAttempt(); + // Checks for all the currently active driver downloads. This lets us know // which ones are active that we haven't tracked. void PollActiveDriverDownloads(); @@ -127,7 +138,7 @@ // Notifies all Client in |clients_| that this controller is initialized and // lets them know which download requests we are aware of for their // DownloadClient. - void NotifyClientsOfStartup(); + void NotifyClientsOfStartup(bool state_lost); // Notifies the service that the startup has completed so that it can start // processing any pending requests. @@ -161,6 +172,7 @@ // Postable methods meant to just be pass throughs to Client APIs. This is // meant to help prevent reentrancy. void SendOnServiceInitialized(DownloadClient client_id, + bool state_lost, const std::vector<std::string>& guids); void SendOnServiceUnavailable(); void SendOnDownloadUpdated(DownloadClient client_id,
diff --git a/components/download/internal/controller_impl_unittest.cc b/components/download/internal/controller_impl_unittest.cc index 15e52b382..88dce235 100644 --- a/components/download/internal/controller_impl_unittest.cc +++ b/components/download/internal/controller_impl_unittest.cc
@@ -83,6 +83,9 @@ MockFileMonitor() = default; ~MockFileMonitor() override = default; + void TriggerInit(bool success); + void TriggerHardRecover(bool success); + void Initialize(const FileMonitor::InitCallback& callback) override; MOCK_METHOD2(DeleteUnknownFiles, void(const Model::EntryList&, const std::vector<DriverEntry>&)); @@ -91,11 +94,27 @@ const base::Closure&)); MOCK_METHOD2(DeleteFiles, void(const std::set<base::FilePath>&, stats::FileCleanupReason)); - MOCK_METHOD1(HardRecover, void(const FileMonitor::InitCallback&)); + void HardRecover(const FileMonitor::InitCallback&) override; + + private: + FileMonitor::InitCallback init_callback_; + FileMonitor::InitCallback recover_callback_; }; +void MockFileMonitor::TriggerInit(bool success) { + init_callback_.Run(success); +} + +void MockFileMonitor::TriggerHardRecover(bool success) { + recover_callback_.Run(success); +} + void MockFileMonitor::Initialize(const FileMonitor::InitCallback& callback) { - callback.Run(true); + init_callback_ = callback; +} + +void MockFileMonitor::HardRecover(const FileMonitor::InitCallback& callback) { + recover_callback_ = callback; } class DownloadServiceControllerImplTest : public testing::Test { @@ -208,8 +227,7 @@ TEST_F(DownloadServiceControllerImplTest, SuccessfulInitModelFirst) { base::HistogramTester histogram_tester; - - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(0); EXPECT_EQ(controller_->GetState(), Controller::State::CREATED); InitializeController(); @@ -217,9 +235,10 @@ EXPECT_EQ(controller_->GetState(), Controller::State::INITIALIZING); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); EXPECT_EQ(controller_->GetState(), Controller::State::INITIALIZING); - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); @@ -229,13 +248,14 @@ task_runner_->RunUntilIdle(); histogram_tester.ExpectBucketCount( - "Download.Service.StartUpStatus", + "Download.Service.StartUpStatus.Initialization", static_cast<base::HistogramBase::Sample>(stats::StartUpResult::SUCCESS), 1); } TEST_F(DownloadServiceControllerImplTest, SuccessfulInitDriverFirst) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0); + base::HistogramTester histogram_tester; + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(0); EXPECT_EQ(controller_->GetState(), Controller::State::CREATED); InitializeController(); @@ -246,15 +266,122 @@ EXPECT_FALSE(init_callback_called_); EXPECT_EQ(controller_->GetState(), Controller::State::INITIALIZING); - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); EXPECT_EQ(controller_->GetState(), Controller::State::READY); task_runner_->RunUntilIdle(); EXPECT_TRUE(init_callback_called_); + + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Initialization", + static_cast<base::HistogramBase::Sample>(stats::StartUpResult::SUCCESS), + 1); +} + +TEST_F(DownloadServiceControllerImplTest, HardRecoveryAfterFailedModel) { + base::HistogramTester histogram_tester; + EXPECT_CALL(*client_, OnServiceInitialized(true, _)).Times(0); + EXPECT_EQ(controller_->GetState(), Controller::State::CREATED); + + InitializeController(); + driver_->MakeReady(); + store_->TriggerInit(false, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); + + EXPECT_EQ(controller_->GetState(), Controller::State::RECOVERING); + driver_->TriggerHardRecoverComplete(true); + store_->TriggerHardRecover(true); + file_monitor_->TriggerHardRecover(true); + + EXPECT_CALL(*client_, OnServiceInitialized(true, _)).Times(1); + task_runner_->RunUntilIdle(); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Initialization", + static_cast<base::HistogramBase::Sample>(stats::StartUpResult::FAILURE), + 1); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Initialization", + static_cast<base::HistogramBase::Sample>( + stats::StartUpResult::FAILURE_REASON_MODEL), + 1); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Recovery", + static_cast<base::HistogramBase::Sample>(stats::StartUpResult::SUCCESS), + 1); +} + +TEST_F(DownloadServiceControllerImplTest, HardRecoveryAfterFailedFileMonitor) { + base::HistogramTester histogram_tester; + EXPECT_CALL(*client_, OnServiceInitialized(true, _)).Times(0); + EXPECT_EQ(controller_->GetState(), Controller::State::CREATED); + + InitializeController(); + driver_->MakeReady(); + store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(false); + + EXPECT_EQ(controller_->GetState(), Controller::State::RECOVERING); + driver_->TriggerHardRecoverComplete(true); + store_->TriggerHardRecover(true); + file_monitor_->TriggerHardRecover(true); + + EXPECT_CALL(*client_, OnServiceInitialized(true, _)).Times(1); + task_runner_->RunUntilIdle(); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Initialization", + static_cast<base::HistogramBase::Sample>(stats::StartUpResult::FAILURE), + 1); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Initialization", + static_cast<base::HistogramBase::Sample>( + stats::StartUpResult::FAILURE_REASON_FILE_MONITOR), + 1); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Recovery", + static_cast<base::HistogramBase::Sample>(stats::StartUpResult::SUCCESS), + 1); +} + +TEST_F(DownloadServiceControllerImplTest, HardRecoveryFails) { + base::HistogramTester histogram_tester; + EXPECT_CALL(*client_, OnServiceInitialized(true, _)).Times(0); + EXPECT_EQ(controller_->GetState(), Controller::State::CREATED); + + InitializeController(); + driver_->MakeReady(); + store_->TriggerInit(false, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); + + EXPECT_EQ(controller_->GetState(), Controller::State::RECOVERING); + driver_->TriggerHardRecoverComplete(true); + store_->TriggerHardRecover(true); + file_monitor_->TriggerHardRecover(false); + + EXPECT_CALL(*client_, OnServiceUnavailable()).Times(1); + task_runner_->RunUntilIdle(); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Initialization", + static_cast<base::HistogramBase::Sample>(stats::StartUpResult::FAILURE), + 1); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Initialization", + static_cast<base::HistogramBase::Sample>( + stats::StartUpResult::FAILURE_REASON_MODEL), + 1); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Recovery", + static_cast<base::HistogramBase::Sample>(stats::StartUpResult::FAILURE), + 1); + histogram_tester.ExpectBucketCount( + "Download.Service.StartUpStatus.Recovery", + static_cast<base::HistogramBase::Sample>( + stats::StartUpResult::FAILURE_REASON_FILE_MONITOR), + 1); } TEST_F(DownloadServiceControllerImplTest, SuccessfulInitWithExistingDownload) { @@ -266,15 +393,16 @@ std::vector<Entry> entries = {entry1, entry2, entry3}; std::vector<std::string> expected_guids = {entry1.guid, entry2.guid}; - EXPECT_CALL( - *client_, - OnServiceInitialized(testing::UnorderedElementsAreArray(expected_guids))); + EXPECT_CALL(*client_, + OnServiceInitialized( + false, testing::UnorderedElementsAreArray(expected_guids))); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); InitializeController(); driver_->MakeReady(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); task_runner_->RunUntilIdle(); EXPECT_TRUE(init_callback_called_); @@ -301,6 +429,7 @@ InitializeController(); driver_->MakeReady(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); task_runner_->RunUntilIdle(); } @@ -318,46 +447,25 @@ InitializeController(); driver_->MakeReady(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); controller_->OnStartScheduledTask(DownloadTaskType::CLEANUP_TASK, base::Bind(&NotifyTaskFinished)); task_runner_->RunUntilIdle(); } -TEST_F(DownloadServiceControllerImplTest, FailedInitWithBadModel) { - base::HistogramTester histogram_tester; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0); - EXPECT_CALL(*client_, OnServiceUnavailable()).Times(1); - - InitializeController(); - store_->TriggerInit(false, base::MakeUnique<std::vector<Entry>>()); - driver_->MakeReady(); - - task_runner_->RunUntilIdle(); - histogram_tester.ExpectBucketCount( - "Download.Service.StartUpStatus", - static_cast<base::HistogramBase::Sample>(stats::StartUpResult::FAILURE), - 1); - histogram_tester.ExpectBucketCount( - "Download.Service.StartUpStatus", - static_cast<base::HistogramBase::Sample>( - stats::StartUpResult::FAILURE_REASON_MODEL), - 1); - - histogram_tester.ExpectTotalCount("Download.Service.StartUpStatus", 2); -} - TEST_F(DownloadServiceControllerImplTest, GetOwnerOfDownload) { Entry entry = test::BuildBasicEntry(); std::vector<Entry> entries = {entry}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); InitializeController(); driver_->MakeReady(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); task_runner_->RunUntilIdle(); @@ -367,13 +475,14 @@ } TEST_F(DownloadServiceControllerImplTest, AddDownloadAccepted) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); // Set up the Controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -399,7 +508,7 @@ } TEST_F(DownloadServiceControllerImplTest, AddDownloadFailsWithBackoff) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); @@ -409,6 +518,7 @@ // Set up the Controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -429,7 +539,7 @@ TEST_F(DownloadServiceControllerImplTest, AddDownloadFailsWithDuplicateGuidInModel) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); @@ -439,6 +549,7 @@ // Set up the Controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -459,11 +570,12 @@ EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); // Set up the Controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -489,13 +601,14 @@ } TEST_F(DownloadServiceControllerImplTest, AddDownloadFailsWithBadClient) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); // Set up the Controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -512,13 +625,14 @@ } TEST_F(DownloadServiceControllerImplTest, AddDownloadFailsWithClientCancel) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); // Set up the Controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -537,13 +651,14 @@ } TEST_F(DownloadServiceControllerImplTest, AddDownloadFailsWithInternalError) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); // Set up the Controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>()); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -569,7 +684,7 @@ entry3.state = Entry::State::COMPLETE; std::vector<Entry> entries = {entry1, entry2, entry3}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(3); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(3); @@ -577,6 +692,7 @@ // the scheduler. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); // Setup download driver test data. @@ -616,12 +732,13 @@ entry2.state = Entry::State::ACTIVE; std::vector<Entry> entries = {entry1, entry2}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(2); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(2); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); // Setup download driver test data. @@ -653,7 +770,7 @@ entry.state = Entry::State::ACTIVE; std::vector<Entry> entries = {entry}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*client_, OnDownloadFailed(entry.guid, Client::FailureReason::CANCELLED)) .Times(1); @@ -662,6 +779,7 @@ InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); DriverEntry driver_entry; @@ -679,7 +797,7 @@ entry.state = Entry::State::ACTIVE; std::vector<Entry> entries = {entry}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*client_, OnDownloadFailed(entry.guid, Client::FailureReason::NETWORK)) .Times(1); @@ -688,6 +806,7 @@ InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); DriverEntry driver_entry; @@ -710,7 +829,7 @@ BuildDriverEntry(entry2, DriverEntry::State::INTERRUPTED); std::vector<DriverEntry> dentries = {dentry1, dentry2}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); // Set up the Controller. device_status_listener_->SetDeviceStatus( @@ -719,6 +838,7 @@ driver_->AddTestData(dentries); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -747,13 +867,14 @@ entry.state = Entry::State::ACTIVE; std::vector<Entry> entries = {entry}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*client_, OnDownloadSucceeded(entry.guid, _, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(2); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(2); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); DriverEntry driver_entry; @@ -782,6 +903,7 @@ InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); DriverEntry driver_entry; @@ -804,12 +926,13 @@ entry.state = Entry::State::ACTIVE; std::vector<Entry> entries = {entry}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); EXPECT_CALL(*scheduler_, Next(_, _)).Times(1); EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); DriverEntry driver_entry; @@ -844,7 +967,7 @@ std::vector<Entry> entries = {entry1, entry2, entry3, entry4}; std::vector<DriverEntry> dentries = {dentry1, dentry3}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); // Test FailureReason::TIMEDOUT. EXPECT_CALL(*client_, @@ -855,6 +978,7 @@ driver_->AddTestData(dentries); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -884,7 +1008,7 @@ } TEST_F(DownloadServiceControllerImplTest, StartupRecovery) { - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); std::vector<Entry> entries; std::vector<DriverEntry> driver_entries; @@ -967,6 +1091,7 @@ driver_->MakeReady(); store_->AutomaticallyTriggerAllFutureCallbacks(true); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); // Allow the initialization routines and persistent layers to do their thing. task_runner_->RunUntilIdle(); @@ -1055,7 +1180,7 @@ std::vector<Entry> entries = {entry1, entry2, entry3}; std::vector<DriverEntry> dentries = {dentry1, dentry2}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); // Set up the Controller. device_status_listener_->SetDeviceStatus( @@ -1064,6 +1189,7 @@ driver_->AddTestData(dentries); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -1099,7 +1225,7 @@ std::vector<Entry> entries = {entry1, entry2}; std::vector<DriverEntry> dentries = {dentry1}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); // Set up the Controller. device_status_listener_->SetDeviceStatus( @@ -1108,6 +1234,7 @@ driver_->AddTestData(dentries); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -1181,10 +1308,11 @@ base::Time::Now() - base::TimeDelta::FromSeconds(2); std::vector<Entry> entries = {entry1, entry2}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); driver_->MakeReady(); task_runner_->RunUntilIdle(); @@ -1200,7 +1328,7 @@ Entry entry2 = test::BuildBasicEntry(Entry::State::ACTIVE); std::vector<Entry> entries = {entry1, entry2}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); // Setup the Configuration. config_->max_concurrent_downloads = 1u; @@ -1209,6 +1337,7 @@ // Setup the controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); store_->AutomaticallyTriggerAllFutureCallbacks(true); // Hit the max running configuration threshold, nothing should be called. @@ -1228,7 +1357,7 @@ Entry entry3 = test::BuildBasicEntry(Entry::State::PAUSED); std::vector<Entry> entries = {entry1, entry2, entry3}; - EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1); + EXPECT_CALL(*client_, OnServiceInitialized(false, _)).Times(1); // Setup the Configuration. config_->max_concurrent_downloads = 2u; @@ -1237,6 +1366,7 @@ // Setup the controller. InitializeController(); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); + file_monitor_->TriggerInit(true); store_->AutomaticallyTriggerAllFutureCallbacks(true); // Can have one more download due to max concurrent configuration.
diff --git a/components/download/internal/model.h b/components/download/internal/model.h index 8b5998b..c1b2ed0 100644 --- a/components/download/internal/model.h +++ b/components/download/internal/model.h
@@ -35,7 +35,7 @@ // Called asynchronously in response to a Model::HardRecover call. If // |success| is |false|, recovery of the Model and/or the underlying Store // failed. After this call there should be no entries stored in this Model. - virtual void OnHardRecoverComplete(bool success) = 0; + virtual void OnModelHardRecoverComplete(bool success) = 0; // Called when an Entry addition is complete. |success| determines whether // or not the entry has been successfully persisted to the Store.
diff --git a/components/download/internal/model_impl.cc b/components/download/internal/model_impl.cc index 1eee678..9a62961 100644 --- a/components/download/internal/model_impl.cc +++ b/components/download/internal/model_impl.cc
@@ -109,7 +109,7 @@ } void ModelImpl::OnHardRecoverFinished(bool success) { - client_->OnHardRecoverComplete(success); + client_->OnModelHardRecoverComplete(success); } void ModelImpl::OnAddFinished(DownloadClient client,
diff --git a/components/download/internal/model_impl_unittest.cc b/components/download/internal/model_impl_unittest.cc index 2367ac27..624715f7 100644 --- a/components/download/internal/model_impl_unittest.cc +++ b/components/download/internal/model_impl_unittest.cc
@@ -108,7 +108,7 @@ EXPECT_TRUE(store_->init_called()); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); - EXPECT_CALL(client_, OnHardRecoverComplete(true)); + EXPECT_CALL(client_, OnModelHardRecoverComplete(true)); model_->HardRecover(); store_->TriggerHardRecover(true); @@ -122,7 +122,7 @@ EXPECT_TRUE(store_->init_called()); store_->TriggerInit(false, base::MakeUnique<std::vector<Entry>>()); - EXPECT_CALL(client_, OnHardRecoverComplete(true)); + EXPECT_CALL(client_, OnModelHardRecoverComplete(true)); model_->HardRecover(); store_->TriggerHardRecover(true); @@ -140,7 +140,7 @@ EXPECT_TRUE(store_->init_called()); store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>(entries)); - EXPECT_CALL(client_, OnHardRecoverComplete(false)); + EXPECT_CALL(client_, OnModelHardRecoverComplete(false)); model_->HardRecover(); store_->TriggerHardRecover(false); @@ -154,7 +154,7 @@ EXPECT_TRUE(store_->init_called()); store_->TriggerInit(false, base::MakeUnique<std::vector<Entry>>()); - EXPECT_CALL(client_, OnHardRecoverComplete(false)); + EXPECT_CALL(client_, OnModelHardRecoverComplete(false)); model_->HardRecover(); store_->TriggerHardRecover(false);
diff --git a/components/download/internal/startup_status.cc b/components/download/internal/startup_status.cc index 6560cec..393e289 100644 --- a/components/download/internal/startup_status.cc +++ b/components/download/internal/startup_status.cc
@@ -9,6 +9,12 @@ StartupStatus::StartupStatus() = default; StartupStatus::~StartupStatus() = default; +void StartupStatus::Reset() { + driver_ok.reset(); + model_ok.reset(); + file_monitor_ok.reset(); +} + bool StartupStatus::Complete() const { return driver_ok.has_value() && model_ok.has_value() && file_monitor_ok.has_value();
diff --git a/components/download/internal/startup_status.h b/components/download/internal/startup_status.h index c9c0676..754428a 100644 --- a/components/download/internal/startup_status.h +++ b/components/download/internal/startup_status.h
@@ -20,6 +20,9 @@ base::Optional<bool> model_ok; base::Optional<bool> file_monitor_ok; + // Resets all startup state tracking. + void Reset(); + // Whether or not all components have finished initialization. Note that this // does not mean that all components were initialized successfully. bool Complete() const;
diff --git a/components/download/internal/stats.cc b/components/download/internal/stats.cc index 96d33b5..5b4f12c5 100644 --- a/components/download/internal/stats.cc +++ b/components/download/internal/stats.cc
@@ -117,9 +117,15 @@ } // Helper method to log StartUpResult. -void LogStartUpResult(StartUpResult result) { - base::UmaHistogramEnumeration("Download.Service.StartUpStatus", result, - StartUpResult::COUNT); +void LogStartUpResult(bool in_recovery, StartUpResult result) { + if (in_recovery) { + base::UmaHistogramEnumeration("Download.Service.StartUpStatus.Recovery", + result, StartUpResult::COUNT); + } else { + base::UmaHistogramEnumeration( + "Download.Service.StartUpStatus.Initialization", result, + StartUpResult::COUNT); + } } // Helper method to log the number of entries under a particular state. @@ -131,20 +137,20 @@ } // namespace -void LogControllerStartupStatus(const StartupStatus& status) { +void LogControllerStartupStatus(bool in_recovery, const StartupStatus& status) { DCHECK(status.Complete()); // Total counts for general success/failure rate. - LogStartUpResult(status.Ok() ? StartUpResult::SUCCESS - : StartUpResult::FAILURE); + LogStartUpResult(in_recovery, status.Ok() ? StartUpResult::SUCCESS + : StartUpResult::FAILURE); // Failure reasons. if (!status.driver_ok.value()) - LogStartUpResult(StartUpResult::FAILURE_REASON_DRIVER); + LogStartUpResult(in_recovery, StartUpResult::FAILURE_REASON_DRIVER); if (!status.model_ok.value()) - LogStartUpResult(StartUpResult::FAILURE_REASON_MODEL); + LogStartUpResult(in_recovery, StartUpResult::FAILURE_REASON_MODEL); if (!status.file_monitor_ok.value()) - LogStartUpResult(StartUpResult::FAILURE_REASON_FILE_MONITOR); + LogStartUpResult(in_recovery, StartUpResult::FAILURE_REASON_FILE_MONITOR); } void LogServiceApiAction(DownloadClient client, ServiceApiAction action) {
diff --git a/components/download/internal/stats.h b/components/download/internal/stats.h index c3bad31e..e100d35 100644 --- a/components/download/internal/stats.h +++ b/components/download/internal/stats.h
@@ -125,7 +125,7 @@ // Logs the results of starting up the Controller. Will log each failure reason // if |status| contains more than one initialization failure. -void LogControllerStartupStatus(const StartupStatus& status); +void LogControllerStartupStatus(bool in_recovery, const StartupStatus& status); // Logs an action taken on the service API. void LogServiceApiAction(DownloadClient client, ServiceApiAction action);
diff --git a/components/download/internal/test/empty_client.cc b/components/download/internal/test/empty_client.cc index 7f14c37..e27aeb0 100644 --- a/components/download/internal/test/empty_client.cc +++ b/components/download/internal/test/empty_client.cc
@@ -8,6 +8,7 @@ namespace test { void EmptyClient::OnServiceInitialized( + bool state_lost, const std::vector<std::string>& outstanding_download_guids) {} void EmptyClient::OnServiceUnavailable() {}
diff --git a/components/download/internal/test/empty_client.h b/components/download/internal/test/empty_client.h index 64fcc6a..d21eaa19 100644 --- a/components/download/internal/test/empty_client.h +++ b/components/download/internal/test/empty_client.h
@@ -18,6 +18,7 @@ // Client implementation. void OnServiceInitialized( + bool state_lost, const std::vector<std::string>& outstanding_download_guids) override; void OnServiceUnavailable() override; ShouldDownload OnDownloadStarted(
diff --git a/components/download/internal/test/mock_client.h b/components/download/internal/test/mock_client.h index ae8f21c..214fc91 100644 --- a/components/download/internal/test/mock_client.h +++ b/components/download/internal/test/mock_client.h
@@ -18,7 +18,8 @@ ~MockClient() override; // Client implementation. - MOCK_METHOD1(OnServiceInitialized, void(const std::vector<std::string>&)); + MOCK_METHOD2(OnServiceInitialized, + void(bool, const std::vector<std::string>&)); MOCK_METHOD0(OnServiceUnavailable, void()); MOCK_METHOD3( OnDownloadStarted,
diff --git a/components/download/internal/test/mock_model_client.h b/components/download/internal/test/mock_model_client.h index c8a33e99..c6cf3cf 100644 --- a/components/download/internal/test/mock_model_client.h +++ b/components/download/internal/test/mock_model_client.h
@@ -20,7 +20,7 @@ // Model::Client implementation. MOCK_METHOD1(OnModelReady, void(bool)); - MOCK_METHOD1(OnHardRecoverComplete, void(bool)); + MOCK_METHOD1(OnModelHardRecoverComplete, void(bool)); MOCK_METHOD3(OnItemAdded, void(bool, DownloadClient, const std::string&)); MOCK_METHOD3(OnItemUpdated, void(bool, DownloadClient, const std::string&)); MOCK_METHOD3(OnItemRemoved, void(bool, DownloadClient, const std::string&));
diff --git a/components/download/public/client.h b/components/download/public/client.h index 46d5cfb..518d7e22 100644 --- a/components/download/public/client.h +++ b/components/download/public/client.h
@@ -61,8 +61,12 @@ // Called when the DownloadService is initialized and ready to be interacted // with. |outstanding_download_guids| is a list of all downloads the - // DownloadService is aware of that are associated with this Client. + // DownloadService is aware of that are associated with this Client. If + // |state_lost| is |true|, the service ran into an error initializing and had + // to destroy all internal persisted state. At this point any saved files + // might not be available and any previously scheduled downloads are gone. virtual void OnServiceInitialized( + bool state_lost, const std::vector<std::string>& outstanding_download_guids) = 0; // Called when the DownloadService fails to initialize and should not be used.
diff --git a/components/proximity_auth/proximity_auth_pref_manager.cc b/components/proximity_auth/proximity_auth_pref_manager.cc index 39101cb..12a1c629 100644 --- a/components/proximity_auth/proximity_auth_pref_manager.cc +++ b/components/proximity_auth/proximity_auth_pref_manager.cc
@@ -31,6 +31,15 @@ registry->RegisterIntegerPref( prefs::kEasyUnlockProximityThreshold, 1, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); + + // TODO(tengs): For existing EasyUnlock users, we want to maintain their + // current behaviour and keep login enabled. However, for new users, we will + // disable login when setting up EasyUnlock. + // After a sufficient number of releases, we should make the default value + // false. + registry->RegisterBooleanPref( + prefs::kProximityAuthIsChromeOSLoginEnabled, true, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); } bool ProximityAuthPrefManager::HasDeviceWithAddress( @@ -136,4 +145,13 @@ return static_cast<ProximityThreshold>(pref_value); } +void ProximityAuthPrefManager::SetIsChromeOSLoginEnabled(bool is_enabled) { + return pref_service_->SetBoolean(prefs::kProximityAuthIsChromeOSLoginEnabled, + is_enabled); +} + +bool ProximityAuthPrefManager::IsChromeOSLoginEnabled() { + return pref_service_->GetBoolean(prefs::kProximityAuthIsChromeOSLoginEnabled); +} + } // namespace proximity_auth
diff --git a/components/proximity_auth/proximity_auth_pref_manager.h b/components/proximity_auth/proximity_auth_pref_manager.h index 9d945e1..9418ad52 100644 --- a/components/proximity_auth/proximity_auth_pref_manager.h +++ b/components/proximity_auth/proximity_auth_pref_manager.h
@@ -84,6 +84,11 @@ virtual void SetProximityThreshold(ProximityThreshold value); virtual ProximityThreshold GetProximityThreshold() const; + // Setting and getter for whether EasyUnlock is enabled for ChromeOS login (in + // addition to screen lock). + virtual void SetIsChromeOSLoginEnabled(bool is_enabled); + virtual bool IsChromeOSLoginEnabled(); + private: const base::DictionaryValue* GetRemoteBleDevices() const;
diff --git a/components/proximity_auth/proximity_auth_pref_manager_unittest.cc b/components/proximity_auth/proximity_auth_pref_manager_unittest.cc index 78856f7..1c250775 100644 --- a/components/proximity_auth/proximity_auth_pref_manager_unittest.cc +++ b/components/proximity_auth/proximity_auth_pref_manager_unittest.cc
@@ -184,4 +184,15 @@ EXPECT_EQ(kProximityThreshold2, pref_manager.GetProximityThreshold()); } +TEST_F(ProximityAuthProximityAuthPrefManagerTest, IsChromeOSLoginEnabled) { + ProximityAuthPrefManager pref_manager(&pref_service_); + EXPECT_TRUE(pref_manager.IsChromeOSLoginEnabled()); + + pref_manager.SetIsChromeOSLoginEnabled(false); + EXPECT_FALSE(pref_manager.IsChromeOSLoginEnabled()); + + pref_manager.SetIsChromeOSLoginEnabled(true); + EXPECT_TRUE(pref_manager.IsChromeOSLoginEnabled()); +} + } // namespace proximity_auth
diff --git a/components/proximity_auth/proximity_auth_pref_names.cc b/components/proximity_auth/proximity_auth_pref_names.cc index 9ef2349..31abf9b0 100644 --- a/components/proximity_auth/proximity_auth_pref_names.cc +++ b/components/proximity_auth/proximity_auth_pref_names.cc
@@ -20,5 +20,10 @@ // Unlock. const char kEasyUnlockProximityThreshold[] = "easy_unlock.proximity_threshold"; +// Whether or not EasyUnlock is enabled on the ChromeOS login screen (in +// addition to the lock screen). +extern const char kProximityAuthIsChromeOSLoginEnabled[] = + "proximity_auth.is_chromeos_login_enabled"; + } // namespace prefs } // namespace proximity_auth
diff --git a/components/proximity_auth/proximity_auth_pref_names.h b/components/proximity_auth/proximity_auth_pref_names.h index de4198e..abc7a57 100644 --- a/components/proximity_auth/proximity_auth_pref_names.h +++ b/components/proximity_auth/proximity_auth_pref_names.h
@@ -11,6 +11,7 @@ extern const char kEasyUnlockProximityThreshold[]; extern const char kProximityAuthLastPasswordEntryTimestampMs[]; extern const char kProximityAuthRemoteBleDevices[]; +extern const char kProximityAuthIsChromeOSLoginEnabled[]; } // namespace prefs } // proximity_auth
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn index 46749156..38d9f84d 100644 --- a/extensions/shell/BUILD.gn +++ b/extensions/shell/BUILD.gn
@@ -188,6 +188,13 @@ ] } + if (is_desktop_linux) { + sources += [ + "browser/api/file_system/shell_file_system_delegate.cc", + "browser/api/file_system/shell_file_system_delegate.h", + ] + } + if (is_chromeos) { sources += [ "browser/api/vpn_provider/vpn_service_factory.cc",
diff --git a/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc b/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc new file mode 100644 index 0000000..58035a35 --- /dev/null +++ b/extensions/shell/browser/api/file_system/shell_file_system_delegate.cc
@@ -0,0 +1,63 @@ +// Copyright 2017 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 "extensions/shell/browser/api/file_system/shell_file_system_delegate.h" + +#include "apps/saved_files_service.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "extensions/browser/api/file_system/saved_files_service_interface.h" + +namespace extensions { + +ShellFileSystemDelegate::ShellFileSystemDelegate() = default; + +ShellFileSystemDelegate::~ShellFileSystemDelegate() {} + +base::FilePath ShellFileSystemDelegate::GetDefaultDirectory() { + NOTIMPLEMENTED(); + return base::FilePath(); +} + +bool ShellFileSystemDelegate::ShowSelectFileDialog( + scoped_refptr<UIThreadExtensionFunction> extension_function, + ui::SelectFileDialog::Type type, + const base::FilePath& default_path, + const ui::SelectFileDialog::FileTypeInfo* file_types, + FileSystemDelegate::FilesSelectedCallback files_selected_callback, + base::OnceClosure file_selection_canceled_callback) { + NOTIMPLEMENTED(); + + // Run the cancel callback by default. + std::move(file_selection_canceled_callback).Run(); + + // Return true since this isn't a disallowed call, just not implemented. + return true; +} + +void ShellFileSystemDelegate::ConfirmSensitiveDirectoryAccess( + bool has_write_permission, + const base::string16& app_name, + content::WebContents* web_contents, + const base::Closure& on_accept, + const base::Closure& on_cancel) { + NOTIMPLEMENTED(); + + // Run the cancel callback by default. + on_cancel.Run(); +} + +int ShellFileSystemDelegate::GetDescriptionIdForAcceptType( + const std::string& accept_type) { + NOTIMPLEMENTED(); + return 0; +} + +SavedFilesServiceInterface* ShellFileSystemDelegate::GetSavedFilesService( + content::BrowserContext* browser_context) { + return apps::SavedFilesService::Get(browser_context); +} + +} // namespace extensions
diff --git a/extensions/shell/browser/api/file_system/shell_file_system_delegate.h b/extensions/shell/browser/api/file_system/shell_file_system_delegate.h new file mode 100644 index 0000000..df41e02 --- /dev/null +++ b/extensions/shell/browser/api/file_system/shell_file_system_delegate.h
@@ -0,0 +1,41 @@ +// Copyright 2017 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 EXTENSIONS_SHELL_BROWSER_API_FILE_SYSTEM_SHELL_FILE_SYSTEM_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_API_FILE_SYSTEM_SHELL_FILE_SYSTEM_DELEGATE_H_ + +#include "extensions/browser/api/file_system/file_system_delegate.h" + +namespace extensions { + +class ShellFileSystemDelegate : public FileSystemDelegate { + public: + ShellFileSystemDelegate(); + ~ShellFileSystemDelegate() override; + + // FileSystemDelegate: + base::FilePath GetDefaultDirectory() override; + bool ShowSelectFileDialog( + scoped_refptr<UIThreadExtensionFunction> extension_function, + ui::SelectFileDialog::Type type, + const base::FilePath& default_path, + const ui::SelectFileDialog::FileTypeInfo* file_types, + FileSystemDelegate::FilesSelectedCallback files_selected_callback, + base::OnceClosure file_selection_canceled_callback) override; + void ConfirmSensitiveDirectoryAccess(bool has_write_permission, + const base::string16& app_name, + content::WebContents* web_contents, + const base::Closure& on_accept, + const base::Closure& on_cancel) override; + int GetDescriptionIdForAcceptType(const std::string& accept_type) override; + SavedFilesServiceInterface* GetSavedFilesService( + content::BrowserContext* browser_context) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellFileSystemDelegate); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_API_FILE_SYSTEM_SHELL_FILE_SYSTEM_DELEGATE_H_
diff --git a/extensions/shell/browser/shell_extensions_api_client.cc b/extensions/shell/browser/shell_extensions_api_client.cc index e290498a..9dfcca2 100644 --- a/extensions/shell/browser/shell_extensions_api_client.cc +++ b/extensions/shell/browser/shell_extensions_api_client.cc
@@ -10,10 +10,15 @@ #include "extensions/shell/browser/shell_extension_web_contents_observer.h" #include "extensions/shell/browser/shell_virtual_keyboard_delegate.h" +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +#include "extensions/shell/browser/api/file_system/shell_file_system_delegate.h" +#endif + namespace extensions { -ShellExtensionsAPIClient::ShellExtensionsAPIClient() { -} +ShellExtensionsAPIClient::ShellExtensionsAPIClient() {} + +ShellExtensionsAPIClient::~ShellExtensionsAPIClient() {} void ShellExtensionsAPIClient::AttachWebContentsHelpers( content::WebContents* web_contents) const { @@ -30,4 +35,12 @@ return base::MakeUnique<ShellVirtualKeyboardDelegate>(); } +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +FileSystemDelegate* ShellExtensionsAPIClient::GetFileSystemDelegate() { + if (!file_system_delegate_) + file_system_delegate_ = base::MakeUnique<ShellFileSystemDelegate>(); + return file_system_delegate_.get(); +} +#endif + } // namespace extensions
diff --git a/extensions/shell/browser/shell_extensions_api_client.h b/extensions/shell/browser/shell_extensions_api_client.h index d42429a..6a26bea 100644 --- a/extensions/shell/browser/shell_extensions_api_client.h +++ b/extensions/shell/browser/shell_extensions_api_client.h
@@ -9,6 +9,8 @@ #include "extensions/browser/api/extensions_api_client.h" +#include "build/build_config.h" + namespace extensions { class VirtualKeyboardDelegate; @@ -16,6 +18,7 @@ class ShellExtensionsAPIClient : public ExtensionsAPIClient { public: ShellExtensionsAPIClient(); + ~ShellExtensionsAPIClient() override; // ExtensionsAPIClient implementation. void AttachWebContentsHelpers(content::WebContents* web_contents) const @@ -23,6 +26,16 @@ AppViewGuestDelegate* CreateAppViewGuestDelegate() const override; std::unique_ptr<VirtualKeyboardDelegate> CreateVirtualKeyboardDelegate() const override; +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + FileSystemDelegate* GetFileSystemDelegate() override; +#endif + + private: +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + std::unique_ptr<FileSystemDelegate> file_system_delegate_; +#endif + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionsAPIClient); }; } // namespace extensions
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc index 83e4041..2b5460b 100644 --- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc +++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
@@ -14,13 +14,54 @@ VideoCaptureDeviceFactoryChromeOS::VideoCaptureDeviceFactoryChromeOS( scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer) : task_runner_for_screen_observer_(task_runner_for_screen_observer), - camera_hal_ipc_thread_("CameraHalIpcThread") {} + camera_hal_ipc_thread_("CameraHalIpcThread"), + initialized_(Init()) {} VideoCaptureDeviceFactoryChromeOS::~VideoCaptureDeviceFactoryChromeOS() { camera_hal_delegate_->Reset(); camera_hal_ipc_thread_.Stop(); } +std::unique_ptr<VideoCaptureDevice> +VideoCaptureDeviceFactoryChromeOS::CreateDevice( + const VideoCaptureDeviceDescriptor& device_descriptor) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!initialized_) { + return std::unique_ptr<VideoCaptureDevice>(); + } + return camera_hal_delegate_->CreateDevice(task_runner_for_screen_observer_, + device_descriptor); +} + +void VideoCaptureDeviceFactoryChromeOS::GetSupportedFormats( + const VideoCaptureDeviceDescriptor& device_descriptor, + VideoCaptureFormats* supported_formats) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!initialized_) { + return; + } + camera_hal_delegate_->GetSupportedFormats(device_descriptor, + supported_formats); +} + +void VideoCaptureDeviceFactoryChromeOS::GetDeviceDescriptors( + VideoCaptureDeviceDescriptors* device_descriptors) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (!initialized_) { + return; + } + camera_hal_delegate_->GetDeviceDescriptors(device_descriptors); +} + +// static +bool VideoCaptureDeviceFactoryChromeOS::ShouldEnable() { + // Checks whether the Chrome OS binary which provides the HAL v3 camera + // service is installed on the device. If the binary exists we assume the + // device is using the new camera HAL v3 stack. + const base::FilePath kArcCamera3Service("/usr/bin/arc_camera3_service"); + return base::PathExists(kArcCamera3Service); +} + bool VideoCaptureDeviceFactoryChromeOS::Init() { if (!camera_hal_ipc_thread_.Start()) { LOG(ERROR) << "Module thread failed to start"; @@ -39,40 +80,6 @@ return true; } -std::unique_ptr<VideoCaptureDevice> -VideoCaptureDeviceFactoryChromeOS::CreateDevice( - const VideoCaptureDeviceDescriptor& device_descriptor) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(camera_hal_delegate_); - return camera_hal_delegate_->CreateDevice(task_runner_for_screen_observer_, - device_descriptor); -} - -void VideoCaptureDeviceFactoryChromeOS::GetSupportedFormats( - const VideoCaptureDeviceDescriptor& device_descriptor, - VideoCaptureFormats* supported_formats) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(camera_hal_delegate_); - camera_hal_delegate_->GetSupportedFormats(device_descriptor, - supported_formats); -} - -void VideoCaptureDeviceFactoryChromeOS::GetDeviceDescriptors( - VideoCaptureDeviceDescriptors* device_descriptors) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(camera_hal_delegate_); - camera_hal_delegate_->GetDeviceDescriptors(device_descriptors); -} - -// static -bool VideoCaptureDeviceFactoryChromeOS::ShouldEnable() { - // Checks whether the Chrome OS binary which provides the HAL v3 camera - // service is installed on the device. If the binary exists we assume the - // device is using the new camera HAL v3 stack. - const base::FilePath kArcCamera3Service("/usr/bin/arc_camera3_service"); - return base::PathExists(kArcCamera3Service); -} - #if defined(OS_CHROMEOS) // static VideoCaptureDeviceFactory* @@ -89,12 +96,8 @@ // some special devices that may never be able to implement a camera HAL // v3. if (VideoCaptureDeviceFactoryChromeOS::ShouldEnable()) { - auto factory = base::MakeUnique<VideoCaptureDeviceFactoryChromeOS>( + return new VideoCaptureDeviceFactoryChromeOS( task_runner_for_screen_observer); - if (!factory->Init()) { - return nullptr; - } - return factory.release(); } else { return new VideoCaptureDeviceFactoryLinux(task_runner_for_screen_observer); }
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h index 49a5c70..0df76be5 100644 --- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h +++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
@@ -31,15 +31,15 @@ void GetDeviceDescriptors( VideoCaptureDeviceDescriptors* device_descriptors) final; - // Initializes the factory. The factory is functional only after this call - // succeeds. - bool Init(); - // A run-time check for whether we should enable // VideoCaptureDeviceFactoryChromeOS on the device. static bool ShouldEnable(); private: + // Initializes the factory. The factory is functional only after this call + // succeeds. + bool Init(); + const scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer_; @@ -53,6 +53,8 @@ // |camera_hal_ipc_thread_|. scoped_refptr<CameraHalDelegate> camera_hal_delegate_; + bool initialized_; + DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryChromeOS); };
diff --git a/media/gpu/vaapi_wrapper.cc b/media/gpu/vaapi_wrapper.cc index 0df3cbb..4206ded 100644 --- a/media/gpu/vaapi_wrapper.cc +++ b/media/gpu/vaapi_wrapper.cc
@@ -27,6 +27,7 @@ #elif defined(USE_OZONE) #include "third_party/libva/va/drm/va_drm.h" #include "third_party/libva/va/va_drmcommon.h" +#include "third_party/libva/va/va_version.h" #include "ui/gfx/buffer_format_util.h" #include "ui/ozone/public/ozone_platform.h" #include "ui/ozone/public/surface_factory_ozone.h" @@ -1200,8 +1201,12 @@ DVLOG(1) << "VAAPI version: " << major_version_ << "." << minor_version_; } - if (VAAPIVersionLessThan(0, 39)) { - LOG(ERROR) << "VAAPI version < 0.39 is not supported."; + if (major_version_ != VA_MAJOR_VERSION || + minor_version_ != VA_MINOR_VERSION) { + LOG(ERROR) << "This build of Chromium requires VA-API version " + << VA_MAJOR_VERSION << "." << VA_MINOR_VERSION + << ", system version: " << major_version_ << "." + << minor_version_; return false; } return true; @@ -1230,9 +1235,4 @@ } #endif // USE_OZONE -bool VaapiWrapper::VADisplayState::VAAPIVersionLessThan(int major, int minor) { - return (major_version_ < major) || - (major_version_ == major && minor_version_ < minor); -} - } // namespace media
diff --git a/media/gpu/vaapi_wrapper.h b/media/gpu/vaapi_wrapper.h index 948f4fb..abb930f8 100644 --- a/media/gpu/vaapi_wrapper.h +++ b/media/gpu/vaapi_wrapper.h
@@ -250,9 +250,6 @@ #endif // USE_OZONE private: - // Returns true if the VAAPI version is less than the specified version. - bool VAAPIVersionLessThan(int major, int minor); - // Protected by |va_lock_|. int refcount_;
diff --git a/net/quic/core/crypto/crypto_framer.cc b/net/quic/core/crypto/crypto_framer.cc index 77d1bfa4..8d2ca6d 100644 --- a/net/quic/core/crypto/crypto_framer.cc +++ b/net/quic/core/crypto/crypto_framer.cc
@@ -64,6 +64,14 @@ return visitor.release(); } +QuicErrorCode CryptoFramer::error() const { + return error_; +} + +const std::string& CryptoFramer::error_detail() const { + return error_detail_; +} + bool CryptoFramer::ProcessInput(QuicStringPiece input, Perspective perspective) { DCHECK_EQ(QUIC_NO_ERROR, error_); @@ -80,6 +88,10 @@ return true; } +size_t CryptoFramer::InputBytesRemaining() const { + return buffer_.length(); +} + // static QuicData* CryptoFramer::ConstructHandshakeMessage( const CryptoHandshakeMessage& message,
diff --git a/net/quic/core/crypto/crypto_framer.h b/net/quic/core/crypto/crypto_framer.h index 0cf0d64..3daf862 100644 --- a/net/quic/core/crypto/crypto_framer.h +++ b/net/quic/core/crypto/crypto_framer.h
@@ -32,13 +32,29 @@ virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0; }; +class QUIC_EXPORT_PRIVATE CryptoMessageParser { + public: + virtual ~CryptoMessageParser() {} + + virtual QuicErrorCode error() const = 0; + virtual const std::string& error_detail() const = 0; + + // Processes input data, which must be delivered in order. Returns + // false if there was an error, and true otherwise. + virtual bool ProcessInput(QuicStringPiece input, Perspective perspective) = 0; + + // Returns the number of bytes of buffered input data remaining to be + // parsed. + virtual size_t InputBytesRemaining() const = 0; +}; + // A class for framing the crypto messages that are exchanged in a QUIC // session. -class QUIC_EXPORT_PRIVATE CryptoFramer { +class QUIC_EXPORT_PRIVATE CryptoFramer : public CryptoMessageParser { public: CryptoFramer(); - virtual ~CryptoFramer(); + ~CryptoFramer() override; // ParseMessage parses exactly one message from the given QuicStringPiece. If // there is an error, the message is truncated, or the message has trailing @@ -55,16 +71,16 @@ visitor_ = visitor; } - QuicErrorCode error() const { return error_; } - const std::string& error_detail() const { return error_detail_; } + QuicErrorCode error() const override; + const std::string& error_detail() const override; // Processes input data, which must be delivered in order. Returns // false if there was an error, and true otherwise. - bool ProcessInput(QuicStringPiece input, Perspective perspective); + bool ProcessInput(QuicStringPiece input, Perspective perspective) override; // Returns the number of bytes of buffered input data remaining to be // parsed. - size_t InputBytesRemaining() const { return buffer_.length(); } + size_t InputBytesRemaining() const override; // Returns a new QuicData owned by the caller that contains a serialized // |message|, or nullptr if there was an error.
diff --git a/net/quic/core/quic_crypto_client_stream.cc b/net/quic/core/quic_crypto_client_stream.cc index 0f4a180..251d1301 100644 --- a/net/quic/core/quic_crypto_client_stream.cc +++ b/net/quic/core/quic_crypto_client_stream.cc
@@ -121,10 +121,8 @@ return handshaker_->crypto_negotiated_params(); } -void QuicCryptoClientStream::OnHandshakeMessage( - const CryptoHandshakeMessage& message) { - QuicCryptoClientStreamBase::OnHandshakeMessage(message); - handshaker_->OnHandshakeMessage(message); +CryptoMessageParser* QuicCryptoClientStream::crypto_message_parser() { + return handshaker_->crypto_message_parser(); } bool QuicCryptoClientStream::WasChannelIDSent() const { @@ -146,7 +144,8 @@ ProofVerifyContext* verify_context, QuicCryptoClientConfig* crypto_config, QuicCryptoClientStream::ProofHandler* proof_handler) - : stream_(stream), + : QuicCryptoHandshaker(stream, session), + stream_(stream), session_(session), next_state_(STATE_IDLE), num_client_hellos_(0), @@ -177,6 +176,7 @@ void QuicCryptoClientHandshaker::OnHandshakeMessage( const CryptoHandshakeMessage& message) { + QuicCryptoHandshaker::OnHandshakeMessage(message); if (message.tag() == kSCUP) { if (!handshake_confirmed()) { stream_->CloseConnectionWithDetails( @@ -242,6 +242,10 @@ return *crypto_negotiated_params_; } +CryptoMessageParser* QuicCryptoClientHandshaker::crypto_message_parser() { + return QuicCryptoHandshaker::crypto_message_parser(); +} + void QuicCryptoClientHandshaker::HandleServerConfigUpdateMessage( const CryptoHandshakeMessage& server_config_update) { DCHECK(server_config_update.tag() == kSCUP); @@ -403,7 +407,7 @@ static_cast<size_t>(max_packet_size - kFramingOverhead)); next_state_ = STATE_RECV_REJ; CryptoUtils::HashHandshakeMessage(out, &chlo_hash_, Perspective::IS_CLIENT); - stream_->SendHandshakeMessage(out); + SendHandshakeMessage(out); return; } @@ -437,7 +441,7 @@ *cached->proof_verify_details()); } next_state_ = STATE_RECV_SHLO; - stream_->SendHandshakeMessage(out); + SendHandshakeMessage(out); // Be prepared to decrypt with the new server write key. session()->connection()->SetAlternativeDecrypter( ENCRYPTION_INITIAL,
diff --git a/net/quic/core/quic_crypto_client_stream.h b/net/quic/core/quic_crypto_client_stream.h index 7707c96..ecb06e0 100644 --- a/net/quic/core/quic_crypto_client_stream.h +++ b/net/quic/core/quic_crypto_client_stream.h
@@ -84,9 +84,6 @@ // to handshake confirmation. virtual int num_scup_messages_received() const = 0; - // TODO(nharper): Move this to QuicCryptoClientHandshaker. - virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0; - // Returns true if a channel ID was sent on this connection. virtual bool WasChannelIDSent() const = 0; @@ -106,6 +103,9 @@ // Returns the parameters negotiated in the crypto handshake. virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const = 0; + + // Used by QuicCryptoStream to parse data received on this stream. + virtual CryptoMessageParser* crypto_message_parser() = 0; }; // ProofHandler is an interface that handles callbacks from the crypto @@ -146,9 +146,7 @@ bool handshake_confirmed() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; - - // CryptoFramerVisitorInterface implementation - void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; + CryptoMessageParser* crypto_message_parser() override; // Returns true if a channel ID was sent on this connection. bool WasChannelIDSent() const; @@ -168,7 +166,8 @@ // An implementation of QuicCryptoClientStream::HandshakerDelegate which uses // QUIC crypto as the crypto handshake protocol. class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker - : public QuicCryptoClientStream::HandshakerDelegate { + : public QuicCryptoClientStream::HandshakerDelegate, + public QuicCryptoHandshaker { public: QuicCryptoClientHandshaker( const QuicServerId& server_id, @@ -184,7 +183,6 @@ bool CryptoConnect() override; int num_sent_client_hellos() const override; int num_scup_messages_received() const override; - void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; bool WasChannelIDSent() const override; bool WasChannelIDSourceCallbackRun() const override; std::string chlo_hash() const override; @@ -192,6 +190,10 @@ bool handshake_confirmed() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; + CryptoMessageParser* crypto_message_parser() override; + + // From QuicCryptoHandshaker + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; private: // ChannelIDSourceCallbackImpl is passed as the callback method to
diff --git a/net/quic/core/quic_crypto_client_stream_test.cc b/net/quic/core/quic_crypto_client_stream_test.cc index 92ca0dd..2453761 100644 --- a/net/quic/core/quic_crypto_client_stream_test.cc +++ b/net/quic/core/quic_crypto_client_stream_test.cc
@@ -60,12 +60,6 @@ stream(), server_options_); } - void ConstructHandshakeMessage(Perspective perspective) { - CryptoFramer framer; - message_data_.reset( - framer.ConstructHandshakeMessage(message_, perspective)); - } - QuicCryptoClientStream* stream() { return session_->GetMutableCryptoStream(); } @@ -77,7 +71,6 @@ std::unique_ptr<TestQuicSpdyClientSession> session_; QuicServerId server_id_; CryptoHandshakeMessage message_; - std::unique_ptr<QuicData> message_data_; QuicCryptoClientConfig crypto_config_; crypto_test_utils::FakeServerOptions server_options_; }; @@ -100,23 +93,19 @@ *connection_, CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _)); message_.set_tag(kCHLO); - ConstructHandshakeMessage(Perspective::IS_CLIENT); - stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false, - /*offset=*/0, - message_data_->AsStringPiece())); + crypto_test_utils::SendHandshakeMessageToStream(stream(), message_, + Perspective::IS_CLIENT); } TEST_F(QuicCryptoClientStreamTest, BadMessageType) { stream()->CryptoConnect(); message_.set_tag(kCHLO); - ConstructHandshakeMessage(Perspective::IS_CLIENT); EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, "Expected REJ", _)); - stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false, - /*offset=*/0, - message_data_->AsStringPiece())); + crypto_test_utils::SendHandshakeMessageToStream(stream(), message_, + Perspective::IS_CLIENT); } TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) { @@ -224,10 +213,8 @@ const uint64_t expiry_seconds = 60 * 60 * 24 * 2; server_config_update.SetValue(kSTTL, expiry_seconds); - std::unique_ptr<QuicData> data(CryptoFramer::ConstructHandshakeMessage( - server_config_update, Perspective::IS_SERVER)); - stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false, - /*offset=*/0, data->AsStringPiece())); + crypto_test_utils::SendHandshakeMessageToStream( + stream(), server_config_update, Perspective::IS_SERVER); // Make sure that the STK and SCFG are cached correctly. EXPECT_EQ("xstk", state->source_address_token()); @@ -286,10 +273,8 @@ EXPECT_TRUE(ok); EXPECT_CALL(*session_, OnProofValid(testing::_)); - std::unique_ptr<QuicData> data(CryptoFramer::ConstructHandshakeMessage( - server_config_update, Perspective::IS_SERVER)); - stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false, - /*offset=*/0, data->AsStringPiece())); + crypto_test_utils::SendHandshakeMessageToStream( + stream(), server_config_update, Perspective::IS_SERVER); // Recreate connection with the new config and verify a 0-RTT attempt. CreateConnection(); @@ -308,10 +293,8 @@ CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE, _, _)); CryptoHandshakeMessage server_config_update; server_config_update.set_tag(kSCUP); - std::unique_ptr<QuicData> data(CryptoFramer::ConstructHandshakeMessage( - server_config_update, Perspective::IS_SERVER)); - stream()->OnStreamFrame(QuicStreamFrame(kCryptoStreamId, /*fin=*/false, - /*offset=*/0, data->AsStringPiece())); + crypto_test_utils::SendHandshakeMessageToStream( + stream(), server_config_update, Perspective::IS_SERVER); } TEST_F(QuicCryptoClientStreamTest, NoChannelID) {
diff --git a/net/quic/core/quic_crypto_server_stream.cc b/net/quic/core/quic_crypto_server_stream.cc index 98c63d5..7119a8e67 100644 --- a/net/quic/core/quic_crypto_server_stream.cc +++ b/net/quic/core/quic_crypto_server_stream.cc
@@ -96,12 +96,6 @@ handshaker()->CancelOutstandingCallbacks(); } -void QuicCryptoServerStream::OnHandshakeMessage( - const CryptoHandshakeMessage& message) { - QuicCryptoServerStreamBase::OnHandshakeMessage(message); - handshaker()->OnHandshakeMessage(message); -} - bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID( string* output) const { return handshaker()->GetBase64SHA256ClientChannelID(output); @@ -169,6 +163,10 @@ return handshaker()->crypto_negotiated_params(); } +CryptoMessageParser* QuicCryptoServerStream::crypto_message_parser() { + return handshaker()->crypto_message_parser(); +} + QuicCryptoServerStream::HandshakerDelegate* QuicCryptoServerStream::handshaker() const { return handshaker_.get(); @@ -181,7 +179,8 @@ bool use_stateless_rejects_if_peer_supported, QuicSession* session, QuicCryptoServerStream::Helper* helper) - : stream_(stream), + : QuicCryptoHandshaker(stream, session), + stream_(stream), session_(session), crypto_config_(crypto_config), compressed_certs_cache_(compressed_certs_cache), @@ -224,6 +223,7 @@ void QuicCryptoServerHandshaker::OnHandshakeMessage( const CryptoHandshakeMessage& message) { + QuicCryptoHandshaker::OnHandshakeMessage(message); ++num_handshake_messages_; chlo_packet_size_ = session()->connection()->GetCurrentPacket().length(); @@ -315,7 +315,7 @@ // retransmitted. session()->connection()->EnableSavingCryptoPackets(); } - stream_->SendHandshakeMessage(*reply); + SendHandshakeMessage(*reply); if (reply->tag() == kSREJ) { DCHECK(use_stateless_rejects_if_peer_supported_); @@ -364,7 +364,7 @@ crypto_negotiated_params_->initial_crypters.decrypter.release()); session()->connection()->SetDiversificationNonce(*diversification_nonce); - stream_->SendHandshakeMessage(*reply); + SendHandshakeMessage(*reply); session()->connection()->SetEncrypter( ENCRYPTION_FORWARD_SECURE, @@ -522,6 +522,10 @@ return *crypto_negotiated_params_; } +CryptoMessageParser* QuicCryptoServerHandshaker::crypto_message_parser() { + return QuicCryptoHandshaker::crypto_message_parser(); +} + void QuicCryptoServerHandshaker::ProcessClientHello( QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result,
diff --git a/net/quic/core/quic_crypto_server_stream.h b/net/quic/core/quic_crypto_server_stream.h index f187991..29271e48 100644 --- a/net/quic/core/quic_crypto_server_stream.h +++ b/net/quic/core/quic_crypto_server_stream.h
@@ -92,9 +92,6 @@ // client hello. virtual void CancelOutstandingCallbacks() = 0; - // TODO(nharper): Move this to QuicCryptoServerHandshaker. - virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0; - // GetBase64SHA256ClientChannelID sets |*output| to the base64 encoded, // SHA-256 hash of the client's ChannelID key and returns true, if the // client presented a ChannelID. Otherwise it returns false. @@ -135,6 +132,9 @@ // Returns the parameters negotiated in the crypto handshake. virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const = 0; + + // Used by QuicCryptoStream to parse data received on this stream. + virtual CryptoMessageParser* crypto_message_parser() = 0; }; class Helper { @@ -167,7 +167,6 @@ // From QuicCryptoServerStreamBase void CancelOutstandingCallbacks() override; - void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; bool GetBase64SHA256ClientChannelID(std::string* output) const override; void SendServerConfigUpdate( const CachedNetworkParameters* cached_network_params) override; @@ -194,6 +193,7 @@ bool handshake_confirmed() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; + CryptoMessageParser* crypto_message_parser() override; protected: // Provided so that subclasses can provide their own handshaker. @@ -206,7 +206,8 @@ }; class QUIC_EXPORT_PRIVATE QuicCryptoServerHandshaker - : public QuicCryptoServerStream::HandshakerDelegate { + : public QuicCryptoServerStream::HandshakerDelegate, + public QuicCryptoHandshaker { public: // |crypto_config| must outlive the stream. // |session| must outlive the stream. @@ -222,7 +223,6 @@ // From HandshakerDelegate void CancelOutstandingCallbacks() override; - void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; bool GetBase64SHA256ClientChannelID(std::string* output) const override; void SendServerConfigUpdate( const CachedNetworkParameters* cached_network_params) override; @@ -239,10 +239,15 @@ CachedNetworkParameters cached_network_params) override; bool ShouldSendExpectCTHeader() const override; + // From QuicCryptoStream bool encryption_established() const override; bool handshake_confirmed() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; + CryptoMessageParser* crypto_message_parser() override; + + // From QuicCryptoHandshaker + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; protected: virtual void ProcessClientHello(
diff --git a/net/quic/core/quic_crypto_server_stream_test.cc b/net/quic/core/quic_crypto_server_stream_test.cc index c91de4f..4166a27 100644 --- a/net/quic/core/quic_crypto_server_stream_test.cc +++ b/net/quic/core/quic_crypto_server_stream_test.cc
@@ -132,12 +132,6 @@ client_session_.reset(client_session); } - void ConstructHandshakeMessage(Perspective perspective) { - CryptoFramer framer; - message_data_.reset( - framer.ConstructHandshakeMessage(message_, perspective)); - } - int CompleteCryptoHandshake() { CHECK(server_connection_); CHECK(server_session_ != nullptr); @@ -183,7 +177,6 @@ std::unique_ptr<TestQuicSpdyClientSession> client_session_; CryptoHandshakeMessage message_; - std::unique_ptr<QuicData> message_data_; crypto_test_utils::FakeClientOptions client_options_; // Which QUIC versions the client and server support. @@ -389,22 +382,18 @@ *server_connection_, CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE, _, _)); message_.set_tag(kCHLO); - ConstructHandshakeMessage(Perspective::IS_CLIENT); - server_stream()->OnStreamFrame( - QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0, - message_data_->AsStringPiece())); + crypto_test_utils::SendHandshakeMessageToStream(server_stream(), message_, + Perspective::IS_CLIENT); } TEST_P(QuicCryptoServerStreamTest, BadMessageType) { Initialize(); message_.set_tag(kSHLO); - ConstructHandshakeMessage(Perspective::IS_SERVER); EXPECT_CALL(*server_connection_, CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, _, _)); - server_stream()->OnStreamFrame( - QuicStreamFrame(kCryptoStreamId, /*fin=*/false, /*offset=*/0, - message_data_->AsStringPiece())); + crypto_test_utils::SendHandshakeMessageToStream(server_stream(), message_, + Perspective::IS_SERVER); } TEST_P(QuicCryptoServerStreamTest, ChannelID) { @@ -472,7 +461,6 @@ TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) { Initialize(); - ConstructHandshakeMessage(Perspective::IS_CLIENT); QuicConfig stateless_reject_config = DefaultQuicConfigStatelessRejects(); stateless_reject_config.ToHandshakeMessage(&message_); EXPECT_TRUE( @@ -570,7 +558,8 @@ // Send in the CHLO, and check that a callback is now pending in the // ProofSource. - server_stream()->OnHandshakeMessage(chlo); + crypto_test_utils::SendHandshakeMessageToStream(server_stream(), chlo, + Perspective::IS_CLIENT); EXPECT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); // Send in a second CHLO while processing of the first is still pending. @@ -581,7 +570,8 @@ *server_connection_, CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO, "Unexpected handshake message while processing CHLO", _)); - server_stream()->OnHandshakeMessage(chlo); + crypto_test_utils::SendHandshakeMessageToStream(server_stream(), chlo, + Perspective::IS_CLIENT); } } // namespace
diff --git a/net/quic/core/quic_crypto_stream.cc b/net/quic/core/quic_crypto_stream.cc index 7534419..3af89889 100644 --- a/net/quic/core/quic_crypto_stream.cc +++ b/net/quic/core/quic_crypto_stream.cc
@@ -25,7 +25,6 @@ QuicCryptoStream::QuicCryptoStream(QuicSession* session) : QuicStream(kCryptoStreamId, session) { - crypto_framer_.set_visitor(this); // The crypto stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); } @@ -42,18 +41,6 @@ /*offset=*/0); } -void QuicCryptoStream::OnError(CryptoFramer* framer) { - QUIC_DLOG(WARNING) << "Error processing crypto data: " - << QuicErrorCodeToString(framer->error()); -} - -void QuicCryptoStream::OnHandshakeMessage( - const CryptoHandshakeMessage& message) { - QUIC_DVLOG(1) << ENDPOINT << "Received " - << message.DebugString(session()->perspective()); - session()->OnCryptoHandshakeMessageReceived(message); -} - void QuicCryptoStream::OnDataAvailable() { struct iovec iov; while (true) { @@ -62,13 +49,15 @@ break; } QuicStringPiece data(static_cast<char*>(iov.iov_base), iov.iov_len); - if (!crypto_framer_.ProcessInput(data, session()->perspective())) { - CloseConnectionWithDetails(crypto_framer_.error(), - crypto_framer_.error_detail()); + if (!crypto_message_parser()->ProcessInput(data, + session()->perspective())) { + CloseConnectionWithDetails(crypto_message_parser()->error(), + crypto_message_parser()->error_detail()); return; } sequencer()->MarkConsumed(iov.iov_len); - if (handshake_confirmed() && crypto_framer_.InputBytesRemaining() == 0 && + if (handshake_confirmed() && + crypto_message_parser()->InputBytesRemaining() == 0 && FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer) { QUIC_FLAG_COUNT(quic_reloadable_flag_quic_release_crypto_stream_buffer); // If the handshake is complete and the current message has been fully @@ -79,17 +68,6 @@ } } -void QuicCryptoStream::SendHandshakeMessage( - const CryptoHandshakeMessage& message) { - QUIC_DVLOG(1) << ENDPOINT << "Sending " - << message.DebugString(session()->perspective()); - session()->connection()->NeuterUnencryptedPackets(); - session()->OnCryptoHandshakeMessageSent(message); - const QuicData& data = message.GetSerialized(session()->perspective()); - WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false, - nullptr); -} - bool QuicCryptoStream::ExportKeyingMaterial(QuicStringPiece label, QuicStringPiece context, size_t result_len, @@ -116,4 +94,39 @@ /* context= */ "", 32, result); } +QuicCryptoHandshaker::QuicCryptoHandshaker(QuicCryptoStream* stream, + QuicSession* session) + : stream_(stream), session_(session) { + crypto_framer_.set_visitor(this); +} + +QuicCryptoHandshaker::~QuicCryptoHandshaker() {} + +void QuicCryptoHandshaker::SendHandshakeMessage( + const CryptoHandshakeMessage& message) { + QUIC_DVLOG(1) << ENDPOINT << "Sending " + << message.DebugString(session()->perspective()); + session()->connection()->NeuterUnencryptedPackets(); + session()->OnCryptoHandshakeMessageSent(message); + const QuicData& data = message.GetSerialized(session()->perspective()); + stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false, + nullptr); +} + +void QuicCryptoHandshaker::OnError(CryptoFramer* framer) { + QUIC_DLOG(WARNING) << "Error processing crypto data: " + << QuicErrorCodeToString(framer->error()); +} + +void QuicCryptoHandshaker::OnHandshakeMessage( + const CryptoHandshakeMessage& message) { + QUIC_DVLOG(1) << ENDPOINT << "Received " + << message.DebugString(session()->perspective()); + session()->OnCryptoHandshakeMessageReceived(message); +} + +CryptoMessageParser* QuicCryptoHandshaker::crypto_message_parser() { + return &crypto_framer_; +} + } // namespace net
diff --git a/net/quic/core/quic_crypto_stream.h b/net/quic/core/quic_crypto_stream.h index 3f4b9b8..fdbf4dc0 100644 --- a/net/quic/core/quic_crypto_stream.h +++ b/net/quic/core/quic_crypto_stream.h
@@ -31,9 +31,7 @@ // // For more details: // https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/edit?usp=sharing -class QUIC_EXPORT_PRIVATE QuicCryptoStream - : public QuicStream, - public CryptoFramerVisitorInterface { +class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { public: explicit QuicCryptoStream(QuicSession* session); @@ -43,17 +41,9 @@ // handshake message for |version|. static QuicByteCount CryptoMessageFramingOverhead(QuicVersion version); - // CryptoFramerVisitorInterface implementation - void OnError(CryptoFramer* framer) override; - void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; - // QuicStream implementation void OnDataAvailable() override; - // Sends |message| to the peer. - // TODO(wtc): return a success/failure status. - void SendHandshakeMessage(const CryptoHandshakeMessage& message); - // Performs key extraction to derive a new secret of |result_len| bytes // dependent on |label|, |context|, and the stream's negotiated subkey secret. // Returns false if the handshake has not been confirmed or the parameters are @@ -83,10 +73,38 @@ virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const = 0; + // Provides the message parser to use when data is received on this stream. + virtual CryptoMessageParser* crypto_message_parser() = 0; + private: + DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream); +}; + +class QUIC_EXPORT_PRIVATE QuicCryptoHandshaker + : public CryptoFramerVisitorInterface { + public: + QuicCryptoHandshaker(QuicCryptoStream* stream, QuicSession* session); + + ~QuicCryptoHandshaker() override; + + // Sends |message| to the peer. + // TODO(wtc): return a success/failure status. + void SendHandshakeMessage(const CryptoHandshakeMessage& message); + + void OnError(CryptoFramer* framer) override; + void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; + + CryptoMessageParser* crypto_message_parser(); + + private: + QuicSession* session() { return session_; } + + QuicCryptoStream* stream_; + QuicSession* session_; + CryptoFramer crypto_framer_; - DISALLOW_COPY_AND_ASSIGN(QuicCryptoStream); + DISALLOW_COPY_AND_ASSIGN(QuicCryptoHandshaker); }; } // namespace net
diff --git a/net/quic/core/quic_crypto_stream_test.cc b/net/quic/core/quic_crypto_stream_test.cc index ca24a4fe..bf29b6c 100644 --- a/net/quic/core/quic_crypto_stream_test.cc +++ b/net/quic/core/quic_crypto_stream_test.cc
@@ -24,10 +24,12 @@ namespace test { namespace { -class MockQuicCryptoStream : public QuicCryptoStream { +class MockQuicCryptoStream : public QuicCryptoStream, + public QuicCryptoHandshaker { public: explicit MockQuicCryptoStream(QuicSession* session) : QuicCryptoStream(session), + QuicCryptoHandshaker(this, session), params_(new QuicCryptoNegotiatedParameters) {} void OnHandshakeMessage(const CryptoHandshakeMessage& message) override { @@ -43,6 +45,9 @@ const override { return *params_; } + CryptoMessageParser* crypto_message_parser() override { + return QuicCryptoHandshaker::crypto_message_parser(); + } private: QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
diff --git a/net/quic/core/quic_server_session_base_test.cc b/net/quic/core/quic_server_session_base_test.cc index b6ac5dbf..8c1eb879 100644 --- a/net/quic/core/quic_server_session_base_test.cc +++ b/net/quic/core/quic_server_session_base_test.cc
@@ -645,7 +645,8 @@ // Feed the CHLO into the crypto stream, which will trigger a call to // ProofSource::GetProof - crypto_stream->OnHandshakeMessage(chlo); + crypto_test_utils::SendHandshakeMessageToStream(crypto_stream, chlo, + Perspective::IS_CLIENT); ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); // Destroy the stream
diff --git a/net/quic/core/quic_session_test.cc b/net/quic/core/quic_session_test.cc index 8bfcb7d..fd1c15ee 100644 --- a/net/quic/core/quic_session_test.cc +++ b/net/quic/core/quic_session_test.cc
@@ -49,10 +49,11 @@ const SpdyPriority kHighestPriority = kV3HighestPriority; -class TestCryptoStream : public QuicCryptoStream { +class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { public: explicit TestCryptoStream(QuicSession* session) : QuicCryptoStream(session), + QuicCryptoHandshaker(this, session), encryption_established_(false), handshake_confirmed_(false), params_(new QuicCryptoNegotiatedParameters) {} @@ -89,10 +90,15 @@ const override { return *params_; } + CryptoMessageParser* crypto_message_parser() override { + return QuicCryptoHandshaker::crypto_message_parser(); + } MOCK_METHOD0(OnCanWrite, void()); private: + using QuicCryptoStream::session; + bool encryption_established_; bool handshake_confirmed_; QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index 3cc2d2c44..70206f2 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -488,6 +488,15 @@ crypto_config->AddDefaultConfig(rand, clock, options)); } +void SendHandshakeMessageToStream(QuicCryptoStream* stream, + const CryptoHandshakeMessage& message, + Perspective perspective) { + const QuicData& data = message.GetSerialized(perspective); + QuicStreamFrame frame(kCryptoStreamId, false, stream->stream_bytes_read(), + data.AsStringPiece()); + stream->OnStreamFrame(frame); +} + void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, QuicCryptoStream* client, PacketSavingConnection* server_conn, @@ -928,7 +937,10 @@ ASSERT_EQ(0u, crypto_framer.InputBytesRemaining()); for (const CryptoHandshakeMessage& message : crypto_visitor.messages()) { - dest_stream->OnHandshakeMessage(message); + SendHandshakeMessageToStream(dest_stream, message, + dest_perspective == Perspective::IS_SERVER + ? Perspective::IS_CLIENT + : Perspective::IS_SERVER); } QuicConnectionPeer::SetCurrentPacket(dest_conn, QuicStringPiece(nullptr, 0)); }
diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h index e961220..1bc2317 100644 --- a/net/quic/test_tools/crypto_test_utils.h +++ b/net/quic/test_tools/crypto_test_utils.h
@@ -139,6 +139,12 @@ QuicCryptoServerConfig* crypto_config, const FakeServerOptions& options); +// Sends the handshake message |message| to stream |stream| with the perspective +// that the message is coming from |perspective|. +void SendHandshakeMessageToStream(QuicCryptoStream* stream, + const CryptoHandshakeMessage& message, + Perspective perspective); + // CommunicateHandshakeMessages moves messages from |client| to |server| and // back until |clients|'s handshake has completed. void CommunicateHandshakeMessages(PacketSavingConnection* client_conn,
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc index c5f19069..ba12953 100644 --- a/net/quic/test_tools/mock_crypto_client_stream.cc +++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -29,6 +29,7 @@ verify_context, crypto_config, session), + QuicCryptoHandshaker(this, session), handshake_mode_(handshake_mode), encryption_established_(false), handshake_confirmed_(false), @@ -126,6 +127,10 @@ return *crypto_negotiated_params_; } +CryptoMessageParser* MockCryptoClientStream::crypto_message_parser() { + return &crypto_framer_; +} + void MockCryptoClientStream::SendOnCryptoHandshakeEvent( QuicSession::CryptoHandshakeEvent event) { encryption_established_ = true;
diff --git a/net/quic/test_tools/mock_crypto_client_stream.h b/net/quic/test_tools/mock_crypto_client_stream.h index 4fb896e..30e1f9b 100644 --- a/net/quic/test_tools/mock_crypto_client_stream.h +++ b/net/quic/test_tools/mock_crypto_client_stream.h
@@ -18,7 +18,8 @@ namespace net { -class MockCryptoClientStream : public QuicCryptoClientStream { +class MockCryptoClientStream : public QuicCryptoClientStream, + public QuicCryptoHandshaker { public: // TODO(zhongyi): might consider move HandshakeMode up to // MockCryptoClientStreamFactory. @@ -59,12 +60,11 @@ // QuicCryptoClientStream implementation. bool CryptoConnect() override; - - // QuicCryptoStream implementation. bool encryption_established() const override; bool handshake_confirmed() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; + CryptoMessageParser* crypto_message_parser() override; // Invokes the sessions's CryptoHandshakeEvent method with the specified // event. @@ -72,6 +72,9 @@ HandshakeMode handshake_mode_; + protected: + using QuicCryptoClientStream::session; + private: void SetConfigNegotiated(); @@ -79,6 +82,7 @@ bool handshake_confirmed_; QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> crypto_negotiated_params_; + CryptoFramer crypto_framer_; const QuicServerId server_id_; const ProofVerifyDetailsChromium* proof_verify_details_;
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 09ff585..0b42b8a 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc
@@ -412,6 +412,10 @@ return *params_; } +CryptoMessageParser* MockQuicCryptoStream::crypto_message_parser() { + return &crypto_framer_; +} + MockQuicSpdySession::MockQuicSpdySession(QuicConnection* connection) : QuicSpdySession(connection, nullptr, DefaultQuicConfig()) { crypto_stream_.reset(new MockQuicCryptoStream(this));
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 414a9c01..500f761 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -537,9 +537,11 @@ bool handshake_confirmed() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const override; + CryptoMessageParser* crypto_message_parser() override; private: QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_; + CryptoFramer crypto_framer_; }; class MockQuicSpdySession : public QuicSpdySession {
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index 87ab095..b45312a 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc
@@ -169,7 +169,8 @@ CryptoHandshakeMessage rej; crypto_test_utils::FillInDummyReject(&rej, /* stateless */ false); EXPECT_TRUE(session_->IsEncryptionEstablished()); - session_->GetMutableCryptoStream()->OnHandshakeMessage(rej); + crypto_test_utils::SendHandshakeMessageToStream( + session_->GetMutableCryptoStream(), rej, Perspective::IS_CLIENT); EXPECT_FALSE(session_->IsEncryptionEstablished()); EXPECT_EQ(ENCRYPTION_NONE, QuicPacketCreatorPeer::GetEncryptionLevel(
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc index 8b9c9f19..b7bbddca 100644 --- a/pdf/out_of_process_instance.cc +++ b/pdf/out_of_process_instance.cc
@@ -528,11 +528,20 @@ dict.Get(pp::Var(kJSPrintPreviewUrl)).is_string() && dict.Get(pp::Var(kJSPrintPreviewGrayscale)).is_bool() && dict.Get(pp::Var(kJSPrintPreviewPageCount)).is_int()) { + int print_preview_page_count = + std::max(dict.Get(pp::Var(kJSPrintPreviewPageCount)).AsInt(), 0); + if (print_preview_page_count <= 0) { + NOTREACHED(); + return; + } + + print_preview_page_count_ = print_preview_page_count; url_ = dict.Get(pp::Var(kJSPrintPreviewUrl)).AsString(); // For security reasons we crash if the URL that is trying to be loaded here // isn't a print preview one. CHECK(IsPrintPreview()); CHECK(IsPrintPreviewUrl(url_)); + preview_pages_info_ = std::queue<PreviewPageInfo>(); preview_document_load_state_ = LOAD_STATE_COMPLETE; document_load_state_ = LOAD_STATE_LOADING; @@ -542,9 +551,6 @@ engine_->SetGrayscale(dict.Get(pp::Var(kJSPrintPreviewGrayscale)).AsBool()); engine_->New(url_.c_str(), nullptr /* empty header */); - print_preview_page_count_ = - std::max(dict.Get(pp::Var(kJSPrintPreviewPageCount)).AsInt(), 0); - paint_manager_.InvalidateRect(pp::Rect(pp::Point(), plugin_size_)); } else if (type == kJSLoadPreviewPageType && dict.Get(pp::Var(kJSPreviewPageUrl)).is_string() && @@ -1387,20 +1393,12 @@ preview_document_load_state_ = LOAD_STATE_COMPLETE; - const std::string& url = preview_pages_info_.front().first; int dest_page_index = preview_pages_info_.front().second; - int src_page_index = ExtractPrintPreviewPageIndex(url); - if (src_page_index > 0 && dest_page_index > -1 && preview_engine_) - engine_->AppendPage(preview_engine_.get(), dest_page_index); + DCHECK_GE(dest_page_index, 0); + DCHECK(preview_engine_); + engine_->AppendPage(preview_engine_.get(), dest_page_index); - preview_pages_info_.pop(); - // |print_preview_page_count_| is not updated yet. Do not load any - // other preview pages until this information is available. - if (print_preview_page_count_ == 0) - return; - - if (!preview_pages_info_.empty()) - LoadAvailablePreviewPage(); + LoadNextPreviewPage(); } void OutOfProcessInstance::DocumentLoadFailed() { @@ -1437,10 +1435,7 @@ } preview_document_load_state_ = LOAD_STATE_FAILED; - preview_pages_info_.pop(); - - if (!preview_pages_info_.empty()) - LoadAvailablePreviewPage(); + LoadNextPreviewPage(); } pp::Instance* OutOfProcessInstance::GetPluginInstance() { @@ -1602,8 +1597,20 @@ int dest_page_index) { DCHECK(IsPrintPreview()); + if (dest_page_index < 0 || dest_page_index >= print_preview_page_count_) { + NOTREACHED(); + return; + } + int src_page_index = ExtractPrintPreviewPageIndex(url); - if (src_page_index < 1) + if (src_page_index < 0) { + NOTREACHED(); + return; + } + + // Print Preview JS will call loadPreviewPage() for every page, including + // page 0. Just ignore it. + if (src_page_index == 0) return; preview_pages_info_.push(std::make_pair(url, dest_page_index)); @@ -1612,22 +1619,24 @@ void OutOfProcessInstance::LoadAvailablePreviewPage() { if (preview_pages_info_.empty() || - document_load_state_ != LOAD_STATE_COMPLETE) { - return; - } - - const std::string& url = preview_pages_info_.front().first; - int dest_page_index = preview_pages_info_.front().second; - int src_page_index = ExtractPrintPreviewPageIndex(url); - if (src_page_index < 1 || dest_page_index >= print_preview_page_count_ || + document_load_state_ != LOAD_STATE_COMPLETE || preview_document_load_state_ == LOAD_STATE_LOADING) { return; } preview_document_load_state_ = LOAD_STATE_LOADING; + const std::string& url = preview_pages_info_.front().first; LoadUrl(url, /*is_print_preview=*/true); } +void OutOfProcessInstance::LoadNextPreviewPage() { + DCHECK(!preview_pages_info_.empty()); + preview_pages_info_.pop(); + + if (!preview_pages_info_.empty()) + LoadAvailablePreviewPage(); +} + void OutOfProcessInstance::UserMetricsRecordAction(const std::string& action) { // TODO(raymes): Move this function to PPB_UMA_Private. pp::PDF::UserMetricsRecordAction(this, pp::Var(action));
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h index ab8a0f0..e4f33b2 100644 --- a/pdf/out_of_process_instance.h +++ b/pdf/out_of_process_instance.h
@@ -208,6 +208,9 @@ // Load the next available preview page into the blank page. void LoadAvailablePreviewPage(); + // Called after a preview page has loaded or failed to load. + void LoadNextPreviewPage(); + // Bound the given scroll offset to the document. pp::FloatPoint BoundScrollOffsetToDocument( const pp::FloatPoint& scroll_offset); @@ -331,9 +334,12 @@ std::vector<int> print_preview_page_numbers_; // Used to manage loaded print preview page information. A |PreviewPageInfo| - // consists of data source url string and the page index in the destination + // consists of data source URL string and the page index in the destination // document. - typedef std::pair<std::string, int> PreviewPageInfo; + // The URL string embeds a page number that can be found with + // ExtractPrintPreviewPageIndex(). This page number is always greater than 0. + // The page index is always in the range of [0, print_preview_page_count_). + using PreviewPageInfo = std::pair<std::string, int>; std::queue<PreviewPageInfo> preview_pages_info_; // Used to signal the browser about focus changes to trigger the OSK.
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index d23fc91..2e8008c 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -10009,11 +10009,8 @@ }, "Fuchsia": { "additional_compile_targets": [ - "d8", "gl_unittests", - "media_unittests", - "skia_unittests", - "ui_base_unittests" + "media_unittests" ], "gtest_tests": [ { @@ -10078,16 +10075,28 @@ "can_use_on_swarming_builders": false }, "test": "net_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": false + }, + "test": "skia_unittests" + }, + { + "args": [ + "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.ui_base_unittests.filter" + ], + "swarming": { + "can_use_on_swarming_builders": false + }, + "test": "ui_base_unittests" } ] }, "Fuchsia (dbg)": { "additional_compile_targets": [ - "d8", "gl_unittests", - "media_unittests", - "skia_unittests", - "ui_base_unittests" + "media_unittests" ], "gtest_tests": [ { @@ -10152,6 +10161,21 @@ "can_use_on_swarming_builders": false }, "test": "net_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": false + }, + "test": "skia_unittests" + }, + { + "args": [ + "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.ui_base_unittests.filter" + ], + "swarming": { + "can_use_on_swarming_builders": false + }, + "test": "ui_base_unittests" } ] },
diff --git a/testing/buildbot/filters/fuchsia.ui_base_unittests.filter b/testing/buildbot/filters/fuchsia.ui_base_unittests.filter new file mode 100644 index 0000000..709b7fb --- /dev/null +++ b/testing/buildbot/filters/fuchsia.ui_base_unittests.filter
@@ -0,0 +1,9 @@ +# TODO(fuchsia): Fix these tests and remove the filter. crbug.com/740608 . + +-*DataPackTest.* +-BytesFormattingTest.FormatBytes +-ResourceBundleImageTest.* +-ResourceBundleTest.DelegateGetNativeImageNamed +-ResourceBundleTest.DelegateGetPathForLocalePack +-ResourceBundleTest.LocaleDataPakExists +-TimeFormatTest.*
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index f5c36f8..fc2fe81 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -403,10 +403,6 @@ "label": "//crypto:crypto_unittests", "type": "console_test_launcher", }, - "d8": { - "label": "//v8:d8", - "type": "additional_compile_target", - }, "dbus_unittests": { "label": "//dbus:dbus_unittests", "type": "windowed_test_launcher",
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 2da2057..46786d2 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -835,7 +835,6 @@ crbug.com/108417 external/wpt/html/rendering/non-replaced-elements/tables/table-border-1.html [ Failure ] crbug.com/490511 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/color.html [ Failure ] crbug.com/490511 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/width.html [ Failure ] -crbug.com/742672 external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/moving-documents.html [ Failure Pass ] crbug.com/692560 external/wpt/html/semantics/document-metadata/styling/LinkStyle.html [ Failure Pass ] crbug.com/627706 external/wpt/html/semantics/embedded-content/the-img-element/invalid-src.html [ Skip ] @@ -3106,3 +3105,7 @@ crbug.com/626703 [ Win7 ] external/wpt/domxpath/xml_xpath_runner.html [ Timeout Pass ] crbug.com/626703 [ Win7 ] external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html [ Failure Pass ] crbug.com/626703 [ Win7 ] external/wpt/html/syntax/parsing/html5lib_tests16.html?run_type=uri [ Timeout Pass ] + +crbug.com/746128 [ Win7 ] media/controls/video-enter-exit-fullscreen-without-hovering-doesnt-show-controls.html [ Failure ] + +crbug.com/626703 [ Win7 ] external/wpt/image-decodes/image-decode-path-changes.html [ Pass Crash ] \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html b/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html index 58524ee..10b9346 100644 --- a/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html +++ b/third_party/WebKit/LayoutTests/accessibility/aom-string-properties.html
@@ -61,6 +61,20 @@ }, "AccessibleNode.current"); </script> +<div role="textbox" id="hasPopUp"></div> + +<script> +test(function(t) { + var node = document.getElementById("hasPopUp"); + var axNode = accessibilityController.accessibleElementById("hasPopUp"); + assert_equals(axNode.hasPopup, false); + node.accessibleNode.hasPopUp = true; + assert_equals(axNode.hasPopup, true); + // TODO(dmazzoni): Test support for ARIA 1.1 values like "dialog", "tree", etc. + // when those are mapped through to platform APIs. +}, "AccessibleNode.hasPopUp"); +</script> + <div role="textbox" id="invalid"></div> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt index 49b5c2f..b85d44f 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/html/dom/reflection-tabular-expected.txt
@@ -32,10 +32,7 @@ PASS colgroup.tabIndex: 24 tests PASS colgroup.span: 11 tests FAIL colgroup.span: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1 -PASS colgroup.span: 49 tests -FAIL colgroup.span: IDL set to 2147483648 assert_equals: getAttribute() expected "1" but got "0" -FAIL colgroup.span: IDL set to 4294967295 assert_equals: getAttribute() expected "1" but got "0" -PASS colgroup.span: 2 tests +PASS colgroup.span: 53 tests PASS colgroup.align: 32 tests PASS colgroup.ch (<colgroup char>): 32 tests PASS colgroup.chOff (<colgroup charoff>): 32 tests @@ -50,10 +47,7 @@ PASS col.tabIndex: 24 tests PASS col.span: 11 tests FAIL col.span: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1 -PASS col.span: 49 tests -FAIL col.span: IDL set to 2147483648 assert_equals: getAttribute() expected "1" but got "0" -FAIL col.span: IDL set to 4294967295 assert_equals: getAttribute() expected "1" but got "0" -PASS col.span: 2 tests +PASS col.span: 53 tests PASS col.align: 32 tests PASS col.ch (<col char>): 32 tests PASS col.chOff (<col charoff>): 32 tests @@ -113,10 +107,7 @@ PASS td.tabIndex: 24 tests PASS td.colSpan: 11 tests FAIL td.colSpan: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1 -PASS td.colSpan: 49 tests -FAIL td.colSpan: IDL set to 2147483648 assert_equals: getAttribute() expected "1" but got "0" -FAIL td.colSpan: IDL set to 4294967295 assert_equals: getAttribute() expected "1" but got "0" -PASS td.colSpan: 2 tests +PASS td.colSpan: 53 tests PASS td.rowSpan: 6 tests FAIL td.rowSpan: setAttribute() to 0 assert_equals: IDL get expected 0 but got 1 PASS td.rowSpan: 4 tests @@ -128,9 +119,7 @@ FAIL td.rowSpan: IDL set to 0 assert_equals: IDL get expected 0 but got 1 PASS td.rowSpan: 3 tests FAIL td.rowSpan: IDL set to "-0" assert_equals: IDL get expected 0 but got 1 -FAIL td.rowSpan: IDL set to 2147483648 assert_equals: getAttribute() expected "1" but got "0" -FAIL td.rowSpan: IDL set to 4294967295 assert_equals: getAttribute() expected "1" but got "0" -PASS td.rowSpan: 2 tests +PASS td.rowSpan: 4 tests PASS td.scope: 72 tests PASS td.abbr: 32 tests PASS td.align: 32 tests @@ -151,10 +140,7 @@ PASS th.tabIndex: 24 tests PASS th.colSpan: 11 tests FAIL th.colSpan: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1 -PASS th.colSpan: 49 tests -FAIL th.colSpan: IDL set to 2147483648 assert_equals: getAttribute() expected "1" but got "0" -FAIL th.colSpan: IDL set to 4294967295 assert_equals: getAttribute() expected "1" but got "0" -PASS th.colSpan: 2 tests +PASS th.colSpan: 53 tests PASS th.rowSpan: 6 tests FAIL th.rowSpan: setAttribute() to 0 assert_equals: IDL get expected 0 but got 1 PASS th.rowSpan: 4 tests @@ -166,9 +152,7 @@ FAIL th.rowSpan: IDL set to 0 assert_equals: IDL get expected 0 but got 1 PASS th.rowSpan: 3 tests FAIL th.rowSpan: IDL set to "-0" assert_equals: IDL get expected 0 but got 1 -FAIL th.rowSpan: IDL set to 2147483648 assert_equals: getAttribute() expected "1" but got "0" -FAIL th.rowSpan: IDL set to 4294967295 assert_equals: getAttribute() expected "1" but got "0" -PASS th.rowSpan: 2 tests +PASS th.rowSpan: 4 tests PASS th.scope: 72 tests PASS th.abbr: 32 tests PASS th.align: 32 tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/moving-documents.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/moving-documents.html deleted file mode 100644 index 241a8e0..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/moving-documents.html +++ /dev/null
@@ -1,51 +0,0 @@ -<!DOCTYPE html> -<meta charset="utf-8"> -<title>When moving between documents, must refresh the original document</title> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<link rel="help" href="https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-refresh"> - -<div id="log"></div> - -<script> -"use strict"; - -const sourceIFrame = document.createElement("iframe"); -const destIFrame = document.createElement("iframe"); -let sourceLoadCount = 0; -let destLoadCount = 0; - -sourceIFrame.onload = () => { - ++sourceLoadCount; - - if (sourceLoadCount === 2) { - assert_equals(sourceIFrame.contentDocument.body.textContent.trim(), "foo"); - done(); - } - - maybeStartTest(); -}; - -destIFrame.onload = () => { - ++destLoadCount; - - if (destLoadCount === 2) { - assert_unreached("The iframe into which the meta was moved must not refresh"); - } - - maybeStartTest(); -}; - -function maybeStartTest() { - if (sourceLoadCount === 1 && destLoadCount === 1) { - const meta = sourceIFrame.contentDocument.querySelector("meta"); - destIFrame.contentDocument.body.appendChild(meta); - } -} - -sourceIFrame.src = "support/refresh.sub.html?input=" + encodeURIComponent("1; url=foo"); -destIFrame.src = "support/ufoo"; - -document.body.appendChild(sourceIFrame); -document.body.appendChild(destIFrame); -</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html index cbfc180..e96251cf 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html
@@ -1,5 +1,6 @@ <!doctype html> <meta charset=utf-8> +<meta name=timeout content=long> <title>Parsing of meta refresh</title> <script src=/resources/testharness.js></script> <script src=/resources/testharnessreport.js></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/remove-from-document.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/remove-from-document.html new file mode 100644 index 0000000..66a067f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/remove-from-document.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>A meta must refresh the original document even if it was removed.</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-refresh"> + +<div id="log"></div> + +<script> +"use strict"; + +const sourceIFrame = document.createElement("iframe"); +let sourceLoadCount = 0; + +sourceIFrame.onload = () => { + ++sourceLoadCount; + + if (sourceLoadCount === 2) { + assert_equals(sourceIFrame.contentDocument.body.textContent.trim(), "foo"); + done(); + } + + maybeStartTest(); +}; + +function maybeStartTest() { + if (sourceLoadCount === 1) { + sourceIFrame.contentDocument.querySelector("meta").remove(); + } +} + +sourceIFrame.src = "support/refresh.sub.html?input=" + encodeURIComponent("1; url=foo"); + +document.body.appendChild(sourceIFrame); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt index 678a90d..ab6f4184 100644 --- a/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/worklet/webexposed/global-interface-listing-paint-worklet-expected.txt
@@ -29,6 +29,8 @@ CONSOLE MESSAGE: line 147: getter x CONSOLE MESSAGE: line 147: getter y CONSOLE MESSAGE: line 147: method constructor +CONSOLE MESSAGE: line 147: setter x +CONSOLE MESSAGE: line 147: setter y CONSOLE MESSAGE: line 147: interface CSSResourceValue : CSSStyleValue CONSOLE MESSAGE: line 147: getter state CONSOLE MESSAGE: line 147: method constructor
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssPositionValue-expected.txt b/third_party/WebKit/LayoutTests/typedcssom/cssPositionValue-expected.txt deleted file mode 100644 index 38423efd..0000000 --- a/third_party/WebKit/LayoutTests/typedcssom/cssPositionValue-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL toString() returns a string with the x and y positions cssStrings separated by a space CSSCalcValue is not defined -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssPositionValue.html b/third_party/WebKit/LayoutTests/typedcssom/cssPositionValue.html index 39298f2a..58df3e1 100644 --- a/third_party/WebKit/LayoutTests/typedcssom/cssPositionValue.html +++ b/third_party/WebKit/LayoutTests/typedcssom/cssPositionValue.html
@@ -4,18 +4,50 @@ <script> -test(function() { - assert_equals(new CSSPositionValue(new CSSUnitValue(50, 'px'), - new CSSCalcValue({px: -10, em: -3.2, pt: 0})).toString(), '50px calc((-3.2em - 10px) + 0pt)'); - assert_equals(new CSSPositionValue(new CSSUnitValue(50, 'px'), - new CSSUnitValue(2, 'em')).toString(), '50px 2em'); - assert_equals(new CSSPositionValue(new CSSCalcValue({px: -10, em: -3.2, pt: 0}), - new CSSCalcValue({px: -10, em: 3.2})).toString(), 'calc((-3.2em - 10px) + 0pt) calc(3.2em - 10px)'); - assert_equals(new CSSPositionValue(new CSSCalcValue({px: -10, em: -3.2, pt: 0}), - new CSSUnitValue(10, 'percent')).toString(), 'calc((-3.2em - 10px) + 0pt) 10%'); -}, "toString() returns a string with the x and y positions cssStrings separated by a space"); +test(() => { + let position = new CSSPositionValue(CSS.percent(1), CSS.percent(2)); + assert_equals(position.x.value, 1); + assert_equals(position.y.value, 2); + assert_equals(position.x.unit, 'percent'); + assert_equals(position.y.unit, 'percent'); +}, "Constructor accepts percentages"); + +test(() => { + assert_throws(new TypeError(), () => { + new CSSPositionValue(CSS.deg(1), CSS.px(1)); + }); + assert_throws(new TypeError(), () => { + new CSSPositionValue(CSS.px(1), CSS.deg(1)); + }); +}, "Constructor throws if a CSSNumericValue that is not a length or " + + "percentage is given"); + +for (let xy of ["x", "y"]) { + test(() => { + let position = new CSSPositionValue(CSS.px(1), CSS.px(2)); + position[xy] = CSS.em(3); + assert_equals(position[xy].value, 3); + assert_equals(position[xy].unit, 'em'); + }, xy + " can be set to a length"); + + test(() => { + let position = new CSSPositionValue(CSS.px(1), CSS.px(2)); + position[xy] = CSS.percent(3); + assert_equals(position[xy].value, 3); + assert_equals(position[xy].unit, 'percent'); + }, xy + " can be set to a percentage"); + + test(() => { + let position = new CSSPositionValue(CSS.px(1), CSS.px(2)); + assert_throws(new TypeError(), () => { + position[xy] = CSS.deg(3); + }); + }, "Setting " + xy + " to something not a length or percentage throws"); +} + +test(() => { + assert_equals( + new CSSPositionValue(CSS.px(50), CSS.em(2)).toString(), '50px 2em'); +}, "toString returns the x and y cssText separated by a space"); </script> - -<body> -</body>
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt index 915b86e..1eb66da24 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -32,6 +32,7 @@ getter errorMessage getter expanded getter flowTo + getter hasPopUp getter hidden getter invalid getter keyShortcuts @@ -79,6 +80,7 @@ setter errorMessage setter expanded setter flowTo + setter hasPopUp setter hidden setter invalid setter keyShortcuts @@ -729,6 +731,8 @@ getter x getter y method constructor + setter x + setter y interface CSSResourceValue : CSSStyleValue attribute @@toStringTag getter state
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 6bc4c458..7bb150cf 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -32,6 +32,7 @@ getter errorMessage getter expanded getter flowTo + getter hasPopUp getter hidden getter invalid getter keyShortcuts @@ -79,6 +80,7 @@ setter errorMessage setter expanded setter flowTo + setter hasPopUp setter hidden setter invalid setter keyShortcuts @@ -729,6 +731,8 @@ getter x getter y method constructor + setter x + setter y interface CSSResourceValue : CSSStyleValue attribute @@toStringTag getter state
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn index 325958b..c120cc0 100644 --- a/third_party/WebKit/Source/core/BUILD.gn +++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -470,6 +470,7 @@ "$blink_core_output_dir/css/properties/CSSPropertyAPIAnimationIterationCount.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIAnimationName.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIAnimationPlayState.h", + "$blink_core_output_dir/css/properties/CSSPropertyAPIAutoOrString.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIBaselineShift.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIBorderColor.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIBorderImageOutset.h", @@ -594,9 +595,12 @@ "$blink_core_output_dir/css/properties/CSSPropertyDescriptor.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIAnimation.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBackgroundPosition.h", + "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderColor.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderImage.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderRadius.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderSpacing.h", + "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderStyle.h", + "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIBorderWidth.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIColumns.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIFlex.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIFont.h", @@ -605,8 +609,11 @@ "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIOutline.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIOverflow.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIOffset.h", + "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIPadding.h", + "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIScrollPadding.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIScrollPaddingBlock.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIScrollPaddingInline.h", + "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIScrollSnapMargin.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIScrollSnapMarginBlock.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPIScrollSnapMarginInline.h", "$blink_core_output_dir/css/properties/CSSShorthandPropertyAPITextDecoration.h",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn index 6798fb1..b6c47555 100644 --- a/third_party/WebKit/Source/core/css/BUILD.gn +++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -380,6 +380,7 @@ "properties/CSSPropertyAPIAnimationIterationCount.cpp", "properties/CSSPropertyAPIAnimationName.cpp", "properties/CSSPropertyAPIAnimationPlayState.cpp", + "properties/CSSPropertyAPIAutoOrString.cpp", "properties/CSSPropertyAPIBaselineShift.cpp", "properties/CSSPropertyAPIBorderColor.cpp", "properties/CSSPropertyAPIBorderImageOutset.cpp", @@ -543,9 +544,12 @@ "properties/CSSPropertyWebkitBorderWidthUtils.h", "properties/CSSShorthandPropertyAPIAnimation.cpp", "properties/CSSShorthandPropertyAPIBackgroundPosition.cpp", + "properties/CSSShorthandPropertyAPIBorderColor.cpp", "properties/CSSShorthandPropertyAPIBorderImage.cpp", "properties/CSSShorthandPropertyAPIBorderRadius.cpp", "properties/CSSShorthandPropertyAPIBorderSpacing.cpp", + "properties/CSSShorthandPropertyAPIBorderStyle.cpp", + "properties/CSSShorthandPropertyAPIBorderWidth.cpp", "properties/CSSShorthandPropertyAPIColumns.cpp", "properties/CSSShorthandPropertyAPIFlex.cpp", "properties/CSSShorthandPropertyAPIFont.cpp", @@ -554,8 +558,11 @@ "properties/CSSShorthandPropertyAPIOffset.cpp", "properties/CSSShorthandPropertyAPIOutline.cpp", "properties/CSSShorthandPropertyAPIOverflow.cpp", + "properties/CSSShorthandPropertyAPIPadding.cpp", + "properties/CSSShorthandPropertyAPIScrollPadding.cpp", "properties/CSSShorthandPropertyAPIScrollPaddingBlock.cpp", "properties/CSSShorthandPropertyAPIScrollPaddingInline.cpp", + "properties/CSSShorthandPropertyAPIScrollSnapMargin.cpp", "properties/CSSShorthandPropertyAPIScrollSnapMarginBlock.cpp", "properties/CSSShorthandPropertyAPIScrollSnapMarginInline.cpp", "properties/CSSShorthandPropertyAPITextDecoration.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSPageRule.cpp b/third_party/WebKit/Source/core/css/CSSPageRule.cpp index 4bcb3cf..fd856c20 100644 --- a/third_party/WebKit/Source/core/css/CSSPageRule.cpp +++ b/third_party/WebKit/Source/core/css/CSSPageRule.cpp
@@ -58,7 +58,7 @@ CSSParserContext* context = CSSParserContext::Create(ParserContext(), nullptr); CSSSelectorList selector_list = CSSParser::ParsePageSelector( - context, parentStyleSheet() ? parentStyleSheet()->Contents() : nullptr, + *context, parentStyleSheet() ? parentStyleSheet()->Contents() : nullptr, selector_text); if (!selector_list.IsValid()) return;
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5 index d6a1634e..8ca3dd5d 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.json5 +++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -559,6 +559,8 @@ }, { name: "-webkit-locale", + api_class: "CSSPropertyAPIAutoOrString", + api_methods: ["parseSingleValue"], custom_value: true, font: true, inherited: true, @@ -2552,7 +2554,6 @@ name: "text-decoration-line", api_class: "CSSPropertyAPITextDecorationLine", api_methods: ["parseSingleValue"], - api_class: "CSSPropertyAPITextDecorationLine", converter: "ConvertFlags<TextDecoration>", name_for_methods: "TextDecoration", runtime_flag: "CSS3TextDecorations", @@ -3053,6 +3054,8 @@ }, { name: "-webkit-hyphenate-character", + api_class: "CSSPropertyAPIAutoOrString", + api_methods: ["parseSingleValue"], converter: "ConvertString<CSSValueAuto>", inherited: true, name_for_methods: "HyphenationString", @@ -3630,7 +3633,6 @@ name: "-webkit-text-decorations-in-effect", api_class: "CSSPropertyAPITextDecorationLine", api_methods: ["parseSingleValue"], - api_class: "CSSPropertyAPITextDecorationLine", builder_skip: true, inherited: true, }, @@ -3707,6 +3709,8 @@ { name: "border-color", longhands: ["border-top-color", "border-right-color", "border-bottom-color", "border-left-color"], + api_class: true, + api_methods: ["parseShorthand"], }, { name: "border-image", @@ -3737,6 +3741,8 @@ { name: "border-style", longhands: ["border-top-style", "border-right-style", "border-bottom-style", "border-left-style"], + api_class: true, + api_methods: ["parseShorthand"], keywords: ["none"], typedom_types: ["Image"], }, @@ -3747,6 +3753,8 @@ { name: "border-width", longhands: ["border-top-width", "border-right-width", "border-bottom-width", "border-left-width"], + api_class: true, + api_methods: ["parseShorthand"], }, { name: "flex", @@ -3856,6 +3864,8 @@ { name: "padding", longhands: ["padding-top", "padding-right", "padding-bottom", "padding-left"], + api_class: true, + api_methods: ["parseShorthand"], }, { name: "page-break-after", @@ -3872,6 +3882,8 @@ { name: "scroll-padding", longhands: ["scroll-padding-top", "scroll-padding-right", "scroll-padding-bottom", "scroll-padding-left"], + api_class: true, + api_methods: ["parseShorthand"], runtime_flag: "CSSScrollSnapPoints", }, { @@ -3891,6 +3903,8 @@ { name: "scroll-snap-margin", longhands: ["scroll-snap-margin-top", "scroll-snap-margin-right", "scroll-snap-margin-bottom", "scroll-snap-margin-left"], + api_class: true, + api_methods: ["parseShorthand"], runtime_flag: "CSSScrollSnapPoints", }, {
diff --git a/third_party/WebKit/Source/core/css/CSSSelector.cpp b/third_party/WebKit/Source/core/css/CSSSelector.cpp index bf28303..3ed4ad2 100644 --- a/third_party/WebKit/Source/core/css/CSSSelector.cpp +++ b/third_party/WebKit/Source/core/css/CSSSelector.cpp
@@ -31,6 +31,7 @@ #include "core/HTMLNames.h" #include "core/css/CSSMarkup.h" #include "core/css/CSSSelectorList.h" +#include "core/css/parser/CSSParserContext.h" #include "platform/wtf/Assertions.h" #include "platform/wtf/HashMap.h" #include "platform/wtf/StdLibExtras.h" @@ -495,6 +496,7 @@ } void CSSSelector::UpdatePseudoType(const AtomicString& value, + const CSSParserContext& context, bool has_arguments, CSSParserMode mode) { DCHECK(match_ == kPseudoClass || match_ == kPseudoElement); @@ -525,11 +527,14 @@ case kPseudoSelection: case kPseudoWebKitCustomElement: case kPseudoContent: - case kPseudoShadow: case kPseudoSlotted: if (match_ != kPseudoElement) pseudo_type_ = kPseudoUnknown; break; + case kPseudoShadow: + if (match_ != kPseudoElement || context.IsDynamicProfile()) + pseudo_type_ = kPseudoUnknown; + break; case kPseudoBlinkInternalElement: if (match_ != kPseudoElement || mode != kUASheetMode) pseudo_type_ = kPseudoUnknown; @@ -796,6 +801,7 @@ result = " > " + builder.ToString() + result; break; case kShadowDeep: + case kShadowDeepAsDescendant: result = " /deep/ " + builder.ToString() + result; break; case kShadowPiercingDescendant:
diff --git a/third_party/WebKit/Source/core/css/CSSSelector.h b/third_party/WebKit/Source/core/css/CSSSelector.h index 319b859..f959904 100644 --- a/third_party/WebKit/Source/core/css/CSSSelector.h +++ b/third_party/WebKit/Source/core/css/CSSSelector.h
@@ -25,6 +25,7 @@ #include <memory> #include "core/CoreExport.h" +#include "core/css/parser/CSSParserContext.h" #include "core/css/parser/CSSParserMode.h" #include "core/dom/QualifiedName.h" #include "core/style/ComputedStyleConstants.h" @@ -133,6 +134,7 @@ // Special cases for shadow DOM related selectors. kShadowPiercingDescendant, // >>> combinator kShadowDeep, // /deep/ combinator + kShadowDeepAsDescendant, // /deep/ as an alias for descendant kShadowPseudo, // ::shadow pseudo element kShadowSlot // ::slotted() pseudo element }; @@ -239,7 +241,11 @@ PseudoType GetPseudoType() const { return static_cast<PseudoType>(pseudo_type_); } - void UpdatePseudoType(const AtomicString&, bool has_arguments, CSSParserMode); + + void UpdatePseudoType(const AtomicString&, + const CSSParserContext&, + bool has_arguments, + CSSParserMode); void UpdatePseudoPage(const AtomicString&); static PseudoType ParsePseudoType(const AtomicString&, bool has_arguments);
diff --git a/third_party/WebKit/Source/core/css/SelectorChecker.cpp b/third_party/WebKit/Source/core/css/SelectorChecker.cpp index f036cbf..1fcc5f1 100644 --- a/third_party/WebKit/Source/core/css/SelectorChecker.cpp +++ b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
@@ -339,6 +339,10 @@ next_context.pseudo_id = kPseudoIdNone; switch (relation) { + case CSSSelector::kShadowDeepAsDescendant: + Deprecation::CountDeprecation(context.element->GetDocument(), + WebFeature::kCSSDeepCombinator); + // fall through case CSSSelector::kDescendant: if (context.selector->RelationIsAffectedByPseudoContent()) { for (Element* element = context.element; element; @@ -416,11 +420,6 @@ return kSelectorFailsAllSiblings; case CSSSelector::kShadowPseudo: { - if (!is_ua_rule_ && mode_ != kQueryingRules && - context.selector->GetPseudoType() == CSSSelector::kPseudoShadow) { - Deprecation::CountDeprecation(context.element->GetDocument(), - WebFeature::kCSSSelectorPseudoShadow); - } // If we're in the same tree-scope as the scoping element, then following // a shadow descendant combinator would escape that and thus the scope. if (context.scope && context.scope->OwnerShadowHost() &&
diff --git a/third_party/WebKit/Source/core/css/SelectorFilter.cpp b/third_party/WebKit/Source/core/css/SelectorFilter.cpp index 4b50414..2f3acfa3 100644 --- a/third_party/WebKit/Source/core/css/SelectorFilter.cpp +++ b/third_party/WebKit/Source/core/css/SelectorFilter.cpp
@@ -177,6 +177,7 @@ *identifier_hashes = 0; return; case CSSSelector::kDescendant: + case CSSSelector::kShadowDeepAsDescendant: case CSSSelector::kChild: // Fall through. case CSSSelector::kShadowPseudo:
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.cpp b/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.cpp index 0967d36..ca273c0 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.cpp +++ b/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.cpp
@@ -4,11 +4,52 @@ #include "core/css/cssom/CSSPositionValue.h" +#include "bindings/core/v8/ExceptionState.h" #include "core/css/CSSValuePair.h" #include "core/css/cssom/CSSNumericValue.h" namespace blink { +CSSPositionValue* CSSPositionValue::Create(CSSNumericValue* x, + CSSNumericValue* y, + ExceptionState& exception_state) { + if (x->GetType() != CSSStyleValue::StyleValueType::kLengthType && + x->GetType() != CSSStyleValue::StyleValueType::kPercentType) { + exception_state.ThrowTypeError( + "Must pass length or percentage to x in CSSPositionValue"); + return nullptr; + } + if (y->GetType() != CSSStyleValue::StyleValueType::kLengthType && + y->GetType() != CSSStyleValue::StyleValueType::kPercentType) { + exception_state.ThrowTypeError( + "Must pass length or percentage to y in CSSPositionValue"); + return nullptr; + } + return new CSSPositionValue(x, y); +} + +void CSSPositionValue::setX(CSSNumericValue* x, + ExceptionState& exception_state) { + if (x->GetType() != CSSStyleValue::StyleValueType::kLengthType && + x->GetType() != CSSStyleValue::StyleValueType::kPercentType) { + exception_state.ThrowTypeError( + "Must pass length or percentage to x in CSSPositionValue"); + return; + } + x_ = x; +} + +void CSSPositionValue::setY(CSSNumericValue* y, + ExceptionState& exception_state) { + if (y->GetType() != CSSStyleValue::StyleValueType::kLengthType && + y->GetType() != CSSStyleValue::StyleValueType::kPercentType) { + exception_state.ThrowTypeError( + "Must pass length or percentage to y in CSSPositionValue"); + return; + } + y_ = y; +} + CSSValue* CSSPositionValue::ToCSSValue() const { return CSSValuePair::Create(x_->ToCSSValue(), y_->ToCSSValue(), CSSValuePair::kKeepIdenticalValues);
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.h b/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.h index 693dd53..59c12d83 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.h +++ b/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.h
@@ -12,24 +12,28 @@ namespace blink { class CSSNumericValue; +class ExceptionState; class CORE_EXPORT CSSPositionValue final : public CSSStyleValue { WTF_MAKE_NONCOPYABLE(CSSPositionValue); DEFINE_WRAPPERTYPEINFO(); public: - static CSSPositionValue* Create(const CSSNumericValue* x, - const CSSNumericValue* y) { - return new CSSPositionValue(x, y); - } + // Constructor defined in the IDL. + static CSSPositionValue* Create(CSSNumericValue* x, + CSSNumericValue* y, + ExceptionState&); - // Bindings require a non const return value. - CSSNumericValue* x() const { return const_cast<CSSNumericValue*>(x_.Get()); } - CSSNumericValue* y() const { return const_cast<CSSNumericValue*>(y_.Get()); } + // Getters and setters defined in the IDL. + CSSNumericValue* x() { return x_.Get(); } + CSSNumericValue* y() { return y_.Get(); } + void setX(CSSNumericValue* x, ExceptionState&); + void setY(CSSNumericValue* x, ExceptionState&); - StyleValueType GetType() const override { return kPositionType; } + // Internal methods - from CSSStyleValue. + StyleValueType GetType() const final { return kPositionType; } - CSSValue* ToCSSValue() const override; + CSSValue* ToCSSValue() const final; DEFINE_INLINE_VIRTUAL_TRACE() { visitor->Trace(x_); @@ -38,11 +42,10 @@ } protected: - CSSPositionValue(const CSSNumericValue* x, const CSSNumericValue* y) - : x_(x), y_(y) {} + CSSPositionValue(CSSNumericValue* x, CSSNumericValue* y) : x_(x), y_(y) {} - Member<const CSSNumericValue> x_; - Member<const CSSNumericValue> y_; + Member<CSSNumericValue> x_; + Member<CSSNumericValue> y_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.idl b/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.idl index 405f8ed..d0cac56 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.idl +++ b/third_party/WebKit/Source/core/css/cssom/CSSPositionValue.idl
@@ -6,9 +6,10 @@ // background-position. // Spec: https://drafts.css-houdini.org/css-typed-om/#positionvalue-objects [ - Constructor(CSSNumericValue x, CSSNumericValue y), - Exposed(Window CSSTypedOM, PaintWorklet CSSPaintAPI) + Constructor(CSSNumericValue x, CSSNumericValue y), + Exposed(Window CSSTypedOM, PaintWorklet CSSPaintAPI), + RaisesException=Constructor ] interface CSSPositionValue : CSSStyleValue { - readonly attribute CSSNumericValue x; - readonly attribute CSSNumericValue y; + [RaisesException=Setter] attribute CSSNumericValue x; + [RaisesException=Setter] attribute CSSNumericValue y; };
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSParser.cpp index b6fcb75..0e15635 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParser.cpp
@@ -4,6 +4,7 @@ #include "core/css/parser/CSSParser.h" +#include <memory> #include "core/css/CSSColorValue.h" #include "core/css/CSSKeyframeRule.h" #include "core/css/StyleColor.h" @@ -17,7 +18,6 @@ #include "core/css/parser/CSSTokenizer.h" #include "core/css/parser/CSSVariableParser.h" #include "core/layout/LayoutTheme.h" -#include <memory> namespace blink { @@ -48,11 +48,11 @@ } CSSSelectorList CSSParser::ParsePageSelector( - const CSSParserContext* context, + const CSSParserContext& context, StyleSheetContents* style_sheet_contents, const String& selector) { CSSTokenizer tokenizer(selector); - return CSSParserImpl::ParsePageSelector(tokenizer.TokenRange(), + return CSSParserImpl::ParsePageSelector(context, tokenizer.TokenRange(), style_sheet_contents); }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParser.h b/third_party/WebKit/Source/core/css/parser/CSSParser.h index 0111aacf..19444258 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParser.h +++ b/third_party/WebKit/Source/core/css/parser/CSSParser.h
@@ -5,11 +5,11 @@ #ifndef CSSParser_h #define CSSParser_h +#include <memory> #include "core/CSSPropertyNames.h" #include "core/CoreExport.h" #include "core/css/StylePropertySet.h" #include "core/css/parser/CSSParserContext.h" -#include <memory> namespace blink { @@ -40,7 +40,7 @@ static CSSSelectorList ParseSelector(const CSSParserContext*, StyleSheetContents*, const String&); - static CSSSelectorList ParsePageSelector(const CSSParserContext*, + static CSSSelectorList ParsePageSelector(const CSSParserContext&, StyleSheetContents*, const String&); static bool ParseDeclarationList(const CSSParserContext*,
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp index 73ac4128..94249e4 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
@@ -254,6 +254,7 @@ } CSSSelectorList CSSParserImpl::ParsePageSelector( + const CSSParserContext& context, CSSParserTokenRange range, StyleSheetContents* style_sheet) { // We only support a small subset of the css-page spec. @@ -734,7 +735,8 @@ StyleRulePage* CSSParserImpl::ConsumePageRule(CSSParserTokenRange prelude, CSSParserTokenRange block) { - CSSSelectorList selector_list = ParsePageSelector(prelude, style_sheet_); + CSSSelectorList selector_list = + ParsePageSelector(*context_, prelude, style_sheet_); if (!selector_list.IsValid()) return nullptr; // Parse error, invalid @page selector
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h index df169ad..ca11f336 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h +++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
@@ -84,7 +84,8 @@ const CSSParserContext*, StyleSheetContents*, bool defer_property_parsing = false); - static CSSSelectorList ParsePageSelector(CSSParserTokenRange, + static CSSSelectorList ParsePageSelector(const CSSParserContext&, + CSSParserTokenRange, StyleSheetContents*); static ImmutableStylePropertySet* ParseCustomPropertySet(CSSParserTokenRange);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h index 9aab817..976cc47 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h +++ b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h
@@ -29,6 +29,8 @@ namespace blink { +class CSSParserContext; + class CORE_EXPORT CSSParserSelector { WTF_MAKE_NONCOPYABLE(CSSParserSelector); USING_FAST_MALLOC(CSSParserSelector); @@ -74,9 +76,10 @@ } void UpdatePseudoType(const AtomicString& value, + const CSSParserContext& context, bool has_arguments, CSSParserMode mode) const { - selector_->UpdatePseudoType(value, has_arguments, mode); + selector_->UpdatePseudoType(value, context, has_arguments, mode); } void UpdatePseudoPage(const AtomicString& value) { selector_->UpdatePseudoPage(value);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index b83c452..f214cfa 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -304,12 +304,6 @@ return nullptr; } -static CSSValue* ConsumeLocale(CSSParserTokenRange& range) { - if (range.Peek().Id() == CSSValueAuto) - return ConsumeIdent(range); - return ConsumeString(range); -} - static CSSFunctionValue* ConsumeFilterFunction( CSSParserTokenRange& range, const CSSParserContext* context) { @@ -1003,9 +997,6 @@ case CSSPropertyWebkitLogicalWidth: case CSSPropertyWebkitLogicalHeight: return CSSPropertyLengthUtils::ConsumeWidthOrHeight(range_, *context_); - case CSSPropertyWebkitHyphenateCharacter: - case CSSPropertyWebkitLocale: - return ConsumeLocale(range_); case CSSPropertyAnimationDelay: case CSSPropertyTransitionDelay: return ConsumeCommaSeparatedList(ConsumeTime, range_, kValueRangeAll); @@ -1447,38 +1438,6 @@ return range_.AtEnd(); } -bool CSSPropertyParser::Consume4Values(const StylePropertyShorthand& shorthand, - bool important) { - DCHECK_EQ(shorthand.length(), 4u); - const CSSPropertyID* longhands = shorthand.properties(); - const CSSValue* top = ParseSingleValue(longhands[0], shorthand.id()); - if (!top) - return false; - - const CSSValue* right = ParseSingleValue(longhands[1], shorthand.id()); - const CSSValue* bottom = nullptr; - const CSSValue* left = nullptr; - if (right) { - bottom = ParseSingleValue(longhands[2], shorthand.id()); - if (bottom) - left = ParseSingleValue(longhands[3], shorthand.id()); - } - - if (!right) - right = top; - if (!bottom) - bottom = top; - if (!left) - left = right; - - AddParsedProperty(longhands[0], shorthand.id(), *top, important); - AddParsedProperty(longhands[1], shorthand.id(), *right, important); - AddParsedProperty(longhands[2], shorthand.id(), *bottom, important); - AddParsedProperty(longhands[3], shorthand.id(), *left, important); - - return range_.AtEnd(); -} - static inline CSSValueID MapFromPageBreakBetween(CSSValueID value) { if (value == CSSValueAlways) return CSSValuePage; @@ -2111,8 +2070,6 @@ case CSSPropertyTextDecoration: DCHECK(RuntimeEnabledFeatures::CSS3TextDecorationsEnabled()); return ConsumeShorthandGreedily(textDecorationShorthand(), important); - case CSSPropertyPadding: - return Consume4Values(paddingShorthand(), important); case CSSPropertyMarker: { const CSSValue* marker = ParseSingleValue(CSSPropertyMarkerStart); if (!marker || !range_.AtEnd()) @@ -2131,12 +2088,6 @@ return ConsumeShorthandGreedily(columnRuleShorthand(), important); case CSSPropertyListStyle: return ConsumeShorthandGreedily(listStyleShorthand(), important); - case CSSPropertyBorderColor: - return Consume4Values(borderColorShorthand(), important); - case CSSPropertyBorderStyle: - return Consume4Values(borderStyleShorthand(), important); - case CSSPropertyBorderWidth: - return Consume4Values(borderWidthShorthand(), important); case CSSPropertyBorderTop: return ConsumeShorthandGreedily(borderTopShorthand(), important); case CSSPropertyBorderRight: @@ -2208,10 +2159,6 @@ return ConsumePlaceItemsShorthand(important); case CSSPropertyPlaceSelf: return ConsumePlaceSelfShorthand(important); - case CSSPropertyScrollPadding: - return Consume4Values(scrollPaddingShorthand(), important); - case CSSPropertyScrollSnapMargin: - return Consume4Values(scrollSnapMarginShorthand(), important); case CSSPropertyScrollBoundaryBehavior: return Consume2Values(scrollBoundaryBehaviorShorthand(), important); default:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h index 6c96729f..6f3ef0a 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -86,7 +86,6 @@ bool ParseShorthand(CSSPropertyID, bool important); bool ConsumeShorthandGreedily(const StylePropertyShorthand&, bool important); bool Consume2Values(const StylePropertyShorthand&, bool important); - bool Consume4Values(const StylePropertyShorthand&, bool important); bool ConsumeBackgroundShorthand(const StylePropertyShorthand&, bool important);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h index 5e0b998..040ccc2b 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParserHelpers.h
@@ -131,14 +131,13 @@ CSSParserTokenRange&, bool& needs_legacy_parsing); -// ConsumeShorthandVia2LonghandAPIs, ConsumeShorthandVia4LonghandAPIs and -// ConsumeShorthandGreedilyViaLonghandAPIs are based on CSSPropertyParsers' -// Consume2Values, Consume4Values and ConsumeShorthandGreedily. +// ConsumeShorthandVia2LonghandAPIs and ConsumeShorthandGreedilyViaLonghandAPIs +// are based on CSSPropertyParsers' Consume2Values and ConsumeShorthandGreedily. // They all delegate parsing of a shorthand property to its respective longhand // components. The difference is the functions in this Helpers file expect // component longhands to have API implementations already because each // shorthand will call its component longhand APIs' parseShorthand method. -// Consume4Values and ConsumeShorthandGreedily will be removed soon, when +// Consume2Values and ConsumeShorthandGreedily will be removed soon, when // shorthand properties are ribbonised (i.e. have their own APIs). Until then, // there is a slight code duplication between the two versions for the following // reasons:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp index 19174f62..b96b3eda 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
@@ -442,7 +442,7 @@ AtomicString value = token.Value().ToAtomicString().LowerASCII(); bool has_arguments = token.GetType() == kFunctionToken; - selector->UpdatePseudoType(value, has_arguments, context_->Mode()); + selector->UpdatePseudoType(value, *context_, has_arguments, context_->Mode()); if (!RuntimeEnabledFeatures::CSSSelectorsFocusWithinEnabled() && selector->GetPseudoType() == CSSSelector::kPseudoFocusWithin) @@ -582,7 +582,8 @@ const CSSParserToken& slash = range.ConsumeIncludingWhitespace(); if (slash.GetType() != kDelimiterToken || slash.Delimiter() != '/') failed_parsing_ = true; - return CSSSelector::kShadowDeep; + return context_->IsDynamicProfile() ? CSSSelector::kShadowDeepAsDescendant + : CSSSelector::kShadowDeep; } default:
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAutoOrString.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAutoOrString.cpp new file mode 100644 index 0000000..9480544 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAutoOrString.cpp
@@ -0,0 +1,22 @@ +// Copyright 2017 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 "core/css/properties/CSSPropertyAPIAutoOrString.h" + +#include "core/css/CSSStringValue.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { +class CSSParserLocalContext; + +const CSSValue* CSSPropertyAPIAutoOrString::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext&, + const CSSParserLocalContext&) { + if (range.Peek().Id() == CSSValueAuto) + return CSSPropertyParserHelpers::ConsumeIdent(range); + return CSSPropertyParserHelpers::ConsumeString(range); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderColor.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderColor.cpp new file mode 100644 index 0000000..d8dc28b --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderColor.cpp
@@ -0,0 +1,22 @@ +// Copyright 2017 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 "core/css/properties/CSSShorthandPropertyAPIBorderColor.h" + +#include "core/StylePropertyShorthand.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +bool CSSShorthandPropertyAPIBorderColor::parseShorthand( + bool important, + CSSParserTokenRange& range, + const CSSParserContext& context, + bool, + HeapVector<CSSProperty, 256>& properties) { + return CSSPropertyParserHelpers::ConsumeShorthandVia4LonghandAPIs( + borderColorShorthand(), important, context, range, properties); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderStyle.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderStyle.cpp new file mode 100644 index 0000000..cce2e6f --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderStyle.cpp
@@ -0,0 +1,22 @@ +// Copyright 2017 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 "core/css/properties/CSSShorthandPropertyAPIBorderStyle.h" + +#include "core/StylePropertyShorthand.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +bool CSSShorthandPropertyAPIBorderStyle::parseShorthand( + bool important, + CSSParserTokenRange& range, + const CSSParserContext& context, + bool, + HeapVector<CSSProperty, 256>& properties) { + return CSSPropertyParserHelpers::ConsumeShorthandVia4LonghandAPIs( + borderStyleShorthand(), important, context, range, properties); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderWidth.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderWidth.cpp new file mode 100644 index 0000000..7a5e594 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIBorderWidth.cpp
@@ -0,0 +1,22 @@ +// Copyright 2017 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 "core/css/properties/CSSShorthandPropertyAPIBorderWidth.h" + +#include "core/StylePropertyShorthand.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +bool CSSShorthandPropertyAPIBorderWidth::parseShorthand( + bool important, + CSSParserTokenRange& range, + const CSSParserContext& context, + bool, + HeapVector<CSSProperty, 256>& properties) { + return CSSPropertyParserHelpers::ConsumeShorthandVia4LonghandAPIs( + borderWidthShorthand(), important, context, range, properties); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIPadding.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIPadding.cpp new file mode 100644 index 0000000..3d85209 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIPadding.cpp
@@ -0,0 +1,22 @@ +// Copyright 2017 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 "core/css/properties/CSSShorthandPropertyAPIPadding.h" + +#include "core/StylePropertyShorthand.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +bool CSSShorthandPropertyAPIPadding::parseShorthand( + bool important, + CSSParserTokenRange& range, + const CSSParserContext& context, + bool, + HeapVector<CSSProperty, 256>& properties) { + return CSSPropertyParserHelpers::ConsumeShorthandVia4LonghandAPIs( + paddingShorthand(), important, context, range, properties); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollPadding.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollPadding.cpp new file mode 100644 index 0000000..8a67d5e --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollPadding.cpp
@@ -0,0 +1,22 @@ +// Copyright 2017 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 "core/css/properties/CSSShorthandPropertyAPIScrollPadding.h" + +#include "core/StylePropertyShorthand.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +bool CSSShorthandPropertyAPIScrollPadding::parseShorthand( + bool important, + CSSParserTokenRange& range, + const CSSParserContext& context, + bool, + HeapVector<CSSProperty, 256>& properties) { + return CSSPropertyParserHelpers::ConsumeShorthandVia4LonghandAPIs( + scrollPaddingShorthand(), important, context, range, properties); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollSnapMargin.cpp b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollSnapMargin.cpp new file mode 100644 index 0000000..7af9637 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSShorthandPropertyAPIScrollSnapMargin.cpp
@@ -0,0 +1,22 @@ +// Copyright 2017 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 "core/css/properties/CSSShorthandPropertyAPIScrollSnapMargin.h" + +#include "core/StylePropertyShorthand.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +bool CSSShorthandPropertyAPIScrollSnapMargin::parseShorthand( + bool important, + CSSParserTokenRange& range, + const CSSParserContext& context, + bool, + HeapVector<CSSProperty, 256>& properties) { + return CSSPropertyParserHelpers::ConsumeShorthandVia4LonghandAPIs( + scrollSnapMarginShorthand(), important, context, range, properties); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp index 18a4673..9823ee43 100644 --- a/third_party/WebKit/Source/core/dom/AccessibleNode.cpp +++ b/third_party/WebKit/Source/core/dom/AccessibleNode.cpp
@@ -24,6 +24,8 @@ return aria_checkedAttr; case AOMStringProperty::kCurrent: return aria_currentAttr; + case AOMStringProperty::kHasPopUp: + return aria_haspopupAttr; case AOMStringProperty::kInvalid: return aria_invalidAttr; case AOMStringProperty::kKeyShortcuts: @@ -685,6 +687,15 @@ NotifyAttributeChanged(aria_flowtoAttr); } +AtomicString AccessibleNode::hasPopUp() const { + return GetProperty(element_, AOMStringProperty::kHasPopUp); +} + +void AccessibleNode::setHasPopUp(const AtomicString& has_popup) { + SetStringProperty(AOMStringProperty::kHasPopUp, has_popup); + NotifyAttributeChanged(aria_haspopupAttr); +} + bool AccessibleNode::hidden(bool& is_null) const { return GetProperty(element_, AOMBooleanProperty::kHidden, is_null); }
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.h b/third_party/WebKit/Source/core/dom/AccessibleNode.h index d7362df..4dce32f 100644 --- a/third_party/WebKit/Source/core/dom/AccessibleNode.h +++ b/third_party/WebKit/Source/core/dom/AccessibleNode.h
@@ -25,6 +25,7 @@ kAutocomplete, kChecked, kCurrent, + kHasPopUp, kInvalid, kKeyShortcuts, kLabel, @@ -228,6 +229,9 @@ AccessibleNodeList* flowTo() const; void setFlowTo(AccessibleNodeList*); + AtomicString hasPopUp() const; + void setHasPopUp(const AtomicString&); + bool hidden(bool& is_null) const; void setHidden(bool, bool is_null);
diff --git a/third_party/WebKit/Source/core/dom/AccessibleNode.idl b/third_party/WebKit/Source/core/dom/AccessibleNode.idl index 0c8356c..e9909ab 100644 --- a/third_party/WebKit/Source/core/dom/AccessibleNode.idl +++ b/third_party/WebKit/Source/core/dom/AccessibleNode.idl
@@ -24,6 +24,7 @@ attribute AccessibleNode? errorMessage; attribute boolean? expanded; attribute AccessibleNodeList? flowTo; + attribute DOMString? hasPopUp; attribute boolean? hidden; attribute DOMString? invalid; attribute DOMString? keyShortcuts;
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index a75f292..6b4d879 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -3621,12 +3621,13 @@ } void Element::SetUnsignedIntegralAttribute(const QualifiedName& attribute_name, - unsigned value) { + unsigned value, + unsigned default_value) { // Range restrictions are enforced for unsigned IDL attributes that // reflect content attributes, // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes if (value > 0x7fffffffu) - value = 0; + value = default_value; setAttribute(attribute_name, AtomicString::Number(value)); }
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h index 1395bda..1cdeaf8d 100644 --- a/third_party/WebKit/Source/core/dom/Element.h +++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -156,7 +156,8 @@ int GetIntegralAttribute(const QualifiedName& attribute_name) const; void SetIntegralAttribute(const QualifiedName& attribute_name, int value); void SetUnsignedIntegralAttribute(const QualifiedName& attribute_name, - unsigned value); + unsigned value, + unsigned default_value = 0); double GetFloatingPointAttribute( const QualifiedName& attribute_name, double fallback_value = std::numeric_limits<double>::quiet_NaN()) const;
diff --git a/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp b/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp index da00b16..b44d24aa 100644 --- a/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp +++ b/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp
@@ -364,12 +364,6 @@ EXPECT_EQ(ScheduleInvalidationsForRules( *shadow_root, ".a ::content span { background: green}"), kRuleSetInvalidationFullRecalc); - EXPECT_EQ(ScheduleInvalidationsForRules( - *shadow_root, ".a /deep/ span { background: green}"), - kRuleSetInvalidationFullRecalc); - EXPECT_EQ(ScheduleInvalidationsForRules( - *shadow_root, ".a::shadow span { background: green}"), - kRuleSetInvalidationFullRecalc); } TEST_F(StyleEngineTest, HasViewportDependentMediaQueries) {
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp index dbd7f98..8ac57001 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -34,6 +34,7 @@ #include "core/dom/Text.h" #include "core/editing/EditingUtilities.h" #include "core/editing/Editor.h" +#include "core/editing/FrameSelection.h" #include "core/editing/commands/TypingCommand.h" #include "core/editing/markers/DocumentMarkerController.h" #include "core/editing/state_machines/BackwardCodePointStateMachine.h" @@ -344,11 +345,24 @@ SelectionInDOMTree::Builder().SetBaseAndExtent(range).Build(), 0); } +bool IsCompositionTooLong(const Element& element) { + if (isHTMLInputElement(element)) + return toHTMLInputElement(element).TooLong(); + if (isHTMLTextAreaElement(element)) + return toHTMLTextAreaElement(element).TooLong(); + return false; +} + bool InputMethodController::FinishComposingText( ConfirmCompositionBehavior confirm_behavior) { if (!HasComposition()) return false; + // If text is longer than maxlength, give input/textarea's handler a chance to + // clamp the text by replacing the composition with the same value. + const bool is_too_long = + IsCompositionTooLong(*GetDocument().FocusedElement()); + const String& composing = ComposingText(); if (confirm_behavior == kKeepSelection) { @@ -359,8 +373,12 @@ const PlainTextRange& old_offsets = GetSelectionOffsets(); Editor::RevealSelectionScope reveal_selection_scope(&GetEditor()); - Clear(); - DispatchCompositionEndEvent(GetFrame(), composing); + if (is_too_long) { + ReplaceComposition(ComposingText()); + } else { + Clear(); + DispatchCompositionEndEvent(GetFrame(), composing); + } // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. see http://crbug.com/590369 for more details. @@ -392,7 +410,11 @@ if (composition_range.IsNull()) return false; - Clear(); + if (is_too_long) { + ReplaceComposition(ComposingText()); + } else { + Clear(); + } if (!MoveCaret(composition_range.End())) return false; @@ -688,7 +710,7 @@ GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets(); // We shouldn't close typing in the middle of setComposition. - SetEditableSelectionOffsets(selected_range, kNotUserTriggered); + SetEditableSelectionOffsets(selected_range, TypingContinuation::kContinue); if (underlines.IsEmpty()) { GetDocument().Markers().AddCompositionMarker( @@ -799,23 +821,37 @@ } bool InputMethodController::SetSelectionOffsets( + const PlainTextRange& selection_offsets) { + return SetSelectionOffsets(selection_offsets, TypingContinuation::kEnd); +} + +bool InputMethodController::SetSelectionOffsets( const PlainTextRange& selection_offsets, - FrameSelection::SetSelectionOptions options) { + TypingContinuation Typing_continuation) { const EphemeralRange range = EphemeralRangeForOffsets(selection_offsets); if (range.IsNull()) return false; GetFrame().Selection().SetSelection( - SelectionInDOMTree::Builder().SetBaseAndExtent(range).Build(), options); + SelectionInDOMTree::Builder().SetBaseAndExtent(range).Build(), + Typing_continuation == TypingContinuation::kEnd + ? FrameSelection::kCloseTyping + : 0); return true; } bool InputMethodController::SetEditableSelectionOffsets( + const PlainTextRange& selection_offsets) { + return SetEditableSelectionOffsets(selection_offsets, + TypingContinuation::kEnd); +} + +bool InputMethodController::SetEditableSelectionOffsets( const PlainTextRange& selection_offsets, - FrameSelection::SetSelectionOptions options) { + TypingContinuation typing_continuation) { if (!GetEditor().CanEdit()) return false; - return SetSelectionOffsets(selection_offsets, options); + return SetSelectionOffsets(selection_offsets, typing_continuation); } PlainTextRange InputMethodController::CreateRangeForSelection(
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.h b/third_party/WebKit/Source/core/editing/InputMethodController.h index ebb1fab1..65c7e0b 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.h +++ b/third_party/WebKit/Source/core/editing/InputMethodController.h
@@ -30,7 +30,6 @@ #include "core/dom/SynchronousMutationObserver.h" #include "core/editing/CompositionUnderline.h" #include "core/editing/EphemeralRange.h" -#include "core/editing/FrameSelection.h" #include "core/editing/PlainTextRange.h" #include "platform/heap/Handle.h" #include "platform/wtf/Vector.h" @@ -42,6 +41,7 @@ class Editor; class LocalFrame; class Range; +enum class TypingContinuation; class CORE_EXPORT InputMethodController final : public GarbageCollectedFinalized<InputMethodController>, @@ -92,9 +92,7 @@ PlainTextRange GetSelectionOffsets() const; // Returns true if setting selection to specified offsets, otherwise false. - bool SetEditableSelectionOffsets( - const PlainTextRange&, - FrameSelection::SetSelectionOptions = FrameSelection::kCloseTyping); + bool SetEditableSelectionOffsets(const PlainTextRange&); void ExtendSelectionAndDelete(int before, int after); PlainTextRange CreateRangeForSelection(int start, int end, @@ -129,9 +127,7 @@ EphemeralRange EphemeralRangeForOffsets(const PlainTextRange&) const; // Returns true if selection offsets were successfully set. - bool SetSelectionOffsets( - const PlainTextRange&, - FrameSelection::SetSelectionOptions = FrameSelection::kCloseTyping); + bool SetSelectionOffsets(const PlainTextRange&); void AddCompositionUnderlines(const Vector<CompositionUnderline>& underlines, ContainerNode* base_element, @@ -164,6 +160,12 @@ // Implements |SynchronousMutationObserver|. void ContextDestroyed(Document*) final; + + // Returns true if setting selection to specified offsets, otherwise false. + bool SetEditableSelectionOffsets(const PlainTextRange&, TypingContinuation); + + // Returns true if selection offsets were successfully set. + bool SetSelectionOffsets(const PlainTextRange&, TypingContinuation); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp index c1b0175..4a08e3a2 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -2287,4 +2287,18 @@ EXPECT_EQ(kWebTextInputTypeContentEditable, Controller().TextInputType()); } +// http://crbug.com/721666 +TEST_F(InputMethodControllerTest, MaxLength) { + HTMLInputElement* input = toHTMLInputElement( + InsertHTMLElement("<input id='a' maxlength='4'/>", "a")); + + EXPECT_EQ(kWebTextInputTypeText, Controller().TextInputType()); + + Controller().SetComposition("abcde", Vector<CompositionUnderline>(), 4, 4); + EXPECT_STREQ("abcde", input->value().Utf8().data()); + + Controller().FinishComposingText(InputMethodController::kKeepSelection); + EXPECT_STREQ("abcd", input->value().Utf8().data()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp b/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp index 3c85a2da..9d4d022b 100644 --- a/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp +++ b/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp
@@ -151,62 +151,58 @@ return Position(); } -} // namespace - -void SelectionAdjuster::AdjustSelectionToAvoidCrossingShadowBoundaries( - VisibleSelection* selection) { - // Note: |m_selectionType| isn't computed yet. - DCHECK(selection->Base().IsNotNull()); - DCHECK(selection->Extent().IsNotNull()); - DCHECK(selection->Start().IsNotNull()); - DCHECK(selection->End().IsNotNull()); - - // TODO(hajimehoshi): Checking treeScope is wrong when a node is - // distributed, but we leave it as it is for backward compatibility. - if (selection->Start().AnchorNode()->GetTreeScope() == - selection->End().AnchorNode()->GetTreeScope()) - return; - - if (selection->IsBaseFirst()) { - const Position& new_end = AdjustPositionForEnd( - selection->End(), selection->Start().ComputeContainerNode()); - selection->extent_ = new_end; - selection->end_ = new_end; - return; - } - - const Position& new_start = AdjustPositionForStart( - selection->Start(), selection->End().ComputeContainerNode()); - selection->extent_ = new_start; - selection->start_ = new_start; +// TODO(hajimehoshi): Checking treeScope is wrong when a node is +// distributed, but we leave it as it is for backward compatibility. +bool IsCrossingShadowBoundaries(const EphemeralRange& range) { + DCHECK(range.IsNotNull()); + return range.StartPosition().AnchorNode()->GetTreeScope() != + range.EndPosition().AnchorNode()->GetTreeScope(); } -// This function is called twice. The first is called when |m_start| and |m_end| -// or |m_extent| are same, and the second when |m_start| and |m_end| are changed -// after downstream/upstream. -void SelectionAdjuster::AdjustSelectionToAvoidCrossingShadowBoundaries( - VisibleSelectionInFlatTree* selection) { - Node* const shadow_host_start = - EnclosingShadowHostForStart(selection->Start()); - Node* const shadow_host_end = EnclosingShadowHostForEnd(selection->End()); - if (shadow_host_start == shadow_host_end) - return; +} // namespace - if (selection->IsBaseFirst()) { - Node* const shadow_host = - shadow_host_start ? shadow_host_start : shadow_host_end; - const PositionInFlatTree& new_end = - AdjustPositionInFlatTreeForEnd(selection->End(), shadow_host); - selection->extent_ = new_end; - selection->end_ = new_end; - return; - } +Position SelectionAdjuster::AdjustSelectionStartToAvoidCrossingShadowBoundaries( + const EphemeralRange& range) { + DCHECK(range.IsNotNull()); + if (!IsCrossingShadowBoundaries(range)) + return range.StartPosition(); + return AdjustPositionForStart(range.StartPosition(), + range.EndPosition().ComputeContainerNode()); +} + +Position SelectionAdjuster::AdjustSelectionEndToAvoidCrossingShadowBoundaries( + const EphemeralRange& range) { + DCHECK(range.IsNotNull()); + if (!IsCrossingShadowBoundaries(range)) + return range.EndPosition(); + return AdjustPositionForEnd(range.EndPosition(), + range.StartPosition().ComputeContainerNode()); +} + +PositionInFlatTree +SelectionAdjuster::AdjustSelectionStartToAvoidCrossingShadowBoundaries( + const EphemeralRangeInFlatTree& range) { + Node* const shadow_host_start = + EnclosingShadowHostForStart(range.StartPosition()); + Node* const shadow_host_end = EnclosingShadowHostForEnd(range.EndPosition()); + if (shadow_host_start == shadow_host_end) + return range.StartPosition(); Node* const shadow_host = shadow_host_end ? shadow_host_end : shadow_host_start; - const PositionInFlatTree& new_start = - AdjustPositionInFlatTreeForStart(selection->Start(), shadow_host); - selection->extent_ = new_start; - selection->start_ = new_start; + return AdjustPositionInFlatTreeForStart(range.StartPosition(), shadow_host); +} + +PositionInFlatTree +SelectionAdjuster::AdjustSelectionEndToAvoidCrossingShadowBoundaries( + const EphemeralRangeInFlatTree& range) { + Node* const shadow_host_start = + EnclosingShadowHostForStart(range.StartPosition()); + Node* const shadow_host_end = EnclosingShadowHostForEnd(range.EndPosition()); + if (shadow_host_start == shadow_host_end) + return range.EndPosition(); + Node* const shadow_host = + shadow_host_start ? shadow_host_start : shadow_host_end; + return AdjustPositionInFlatTreeForEnd(range.EndPosition(), shadow_host); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/SelectionAdjuster.h b/third_party/WebKit/Source/core/editing/SelectionAdjuster.h index f7c1047..836b83c 100644 --- a/third_party/WebKit/Source/core/editing/SelectionAdjuster.h +++ b/third_party/WebKit/Source/core/editing/SelectionAdjuster.h
@@ -17,9 +17,14 @@ STATIC_ONLY(SelectionAdjuster); public: - static void AdjustSelectionToAvoidCrossingShadowBoundaries(VisibleSelection*); - static void AdjustSelectionToAvoidCrossingShadowBoundaries( - VisibleSelectionInFlatTree*); + static Position AdjustSelectionStartToAvoidCrossingShadowBoundaries( + const EphemeralRange&); + static Position AdjustSelectionEndToAvoidCrossingShadowBoundaries( + const EphemeralRange&); + static PositionInFlatTree AdjustSelectionStartToAvoidCrossingShadowBoundaries( + const EphemeralRangeInFlatTree&); + static PositionInFlatTree AdjustSelectionEndToAvoidCrossingShadowBoundaries( + const EphemeralRangeInFlatTree&); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp index 88cfd71..a55d7d2 100644 --- a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
@@ -483,7 +483,15 @@ granularity); end_ = new_end.IsNotNull() ? new_end : end; - AdjustSelectionToAvoidCrossingShadowBoundaries(); + if (base_is_first_) { + end_ = SelectionAdjuster::AdjustSelectionEndToAvoidCrossingShadowBoundaries( + EphemeralRangeTemplate<Strategy>(start_, end_)); + } else { + start_ = + SelectionAdjuster::AdjustSelectionStartToAvoidCrossingShadowBoundaries( + EphemeralRangeTemplate<Strategy>(start_, end_)); + } + AdjustSelectionToAvoidCrossingEditingBoundaries(); UpdateSelectionType(); @@ -554,14 +562,6 @@ return visible_selection; } -template <typename Strategy> -void VisibleSelectionTemplate< - Strategy>::AdjustSelectionToAvoidCrossingShadowBoundaries() { - if (base_.IsNull() || start_.IsNull() || base_.IsNull()) - return; - SelectionAdjuster::AdjustSelectionToAvoidCrossingShadowBoundaries(this); -} - static Element* LowestEditableAncestor(Node* node) { while (node) { if (HasEditableStyle(*node))
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.h b/third_party/WebKit/Source/core/editing/VisibleSelection.h index 3e6210b3..4bfda490 100644 --- a/third_party/WebKit/Source/core/editing/VisibleSelection.h +++ b/third_party/WebKit/Source/core/editing/VisibleSelection.h
@@ -155,7 +155,6 @@ void Validate(const SelectionTemplate<Strategy>&, TextGranularity); // Support methods for Validate() - void AdjustSelectionToAvoidCrossingShadowBoundaries(); void AdjustSelectionToAvoidCrossingEditingBoundaries(); void UpdateSelectionType();
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp index 2509e4f..682a212 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -897,95 +897,91 @@ frame->GetSpellChecker().UpdateMarkersForWordsAffectedByEditing(false); - switch (EndingSelection().GetSelectionType()) { - case kRangeSelection: - ForwardDeleteKeyPressedInternal(EndingSelection(), EndingSelection(), - kill_ring, editing_state); - return; - case kCaretSelection: { - smart_delete_ = false; - GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets(); - - // Handle delete at beginning-of-block case. - // Do nothing in the case that the caret is at the start of a - // root editable element or at the start of a document. - SelectionModifier selection_modifier(*frame, EndingSelection()); - selection_modifier.Modify(FrameSelection::kAlterationExtend, - kDirectionForward, granularity); - if (kill_ring && selection_modifier.Selection().IsCaret() && - granularity != TextGranularity::kCharacter) { - selection_modifier.Modify(FrameSelection::kAlterationExtend, - kDirectionForward, - TextGranularity::kCharacter); - } - - Position downstream_end = - MostForwardCaretPosition(EndingSelection().End()); - VisiblePosition visible_end = EndingSelection().VisibleEnd(); - Node* enclosing_table_cell = - EnclosingNodeOfType(visible_end.DeepEquivalent(), &IsTableCell); - if (enclosing_table_cell && - visible_end.DeepEquivalent() == - VisiblePosition::LastPositionInNode(*enclosing_table_cell) - .DeepEquivalent()) - return; - if (visible_end.DeepEquivalent() == - EndOfParagraph(visible_end).DeepEquivalent()) - downstream_end = MostForwardCaretPosition( - NextPositionOf(visible_end, kCannotCrossEditingBoundary) - .DeepEquivalent()); - // When deleting tables: Select the table first, then perform the deletion - if (IsDisplayInsideTable(downstream_end.ComputeContainerNode()) && - downstream_end.ComputeOffsetInContainerNode() <= - CaretMinOffset(downstream_end.ComputeContainerNode())) { - SetEndingSelection( - SelectionInDOMTree::Builder() - .SetBaseAndExtentDeprecated( - EndingSelection().End(), - Position::AfterNode(*downstream_end.ComputeContainerNode())) - .SetIsDirectional(EndingSelection().IsDirectional()) - .Build()); - TypingAddedToOpenCommand(kForwardDeleteKey); - return; - } - - // deleting to end of paragraph when at end of paragraph needs to merge - // the next paragraph (if any) - if (granularity == TextGranularity::kParagraphBoundary && - selection_modifier.Selection().IsCaret() && - IsEndOfParagraph(selection_modifier.Selection().VisibleEnd())) { - selection_modifier.Modify(FrameSelection::kAlterationExtend, - kDirectionForward, - TextGranularity::kCharacter); - } - - const VisibleSelection& selection_to_delete = - selection_modifier.Selection(); - if (!StartingSelection().IsRange() || - MostBackwardCaretPosition(selection_to_delete.Base()) != - StartingSelection().Start()) { - ForwardDeleteKeyPressedInternal( - selection_to_delete, selection_to_delete, kill_ring, editing_state); - return; - } - // It's a little tricky to compute what the starting selection would - // have been in the original document. We can't let the VisibleSelection - // class's validation kick in or it'll adjust for us based on the - // current state of the document and we'll get the wrong result. - const VisibleSelection& selection_after_undo = - VisibleSelection::CreateWithoutValidationDeprecated( - StartingSelection().Start(), - ComputeExtentForForwardDeleteUndo(selection_to_delete, - StartingSelection().End()), - TextAffinity::kDownstream); - ForwardDeleteKeyPressedInternal(selection_to_delete, selection_after_undo, - kill_ring, editing_state); - return; - } - case kNoSelection: - NOTREACHED(); - break; + if (EndingSelection().IsRange()) { + ForwardDeleteKeyPressedInternal(EndingSelection(), EndingSelection(), + kill_ring, editing_state); + return; } + + if (!EndingSelection().IsCaret()) { + NOTREACHED(); + return; + } + + smart_delete_ = false; + GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets(); + + // Handle delete at beginning-of-block case. + // Do nothing in the case that the caret is at the start of a + // root editable element or at the start of a document. + SelectionModifier selection_modifier(*frame, EndingSelection()); + selection_modifier.Modify(FrameSelection::kAlterationExtend, + kDirectionForward, granularity); + if (kill_ring && selection_modifier.Selection().IsCaret() && + granularity != TextGranularity::kCharacter) { + selection_modifier.Modify(FrameSelection::kAlterationExtend, + kDirectionForward, TextGranularity::kCharacter); + } + + Position downstream_end = MostForwardCaretPosition(EndingSelection().End()); + VisiblePosition visible_end = EndingSelection().VisibleEnd(); + Node* enclosing_table_cell = + EnclosingNodeOfType(visible_end.DeepEquivalent(), &IsTableCell); + if (enclosing_table_cell && + visible_end.DeepEquivalent() == + VisiblePosition::LastPositionInNode(*enclosing_table_cell) + .DeepEquivalent()) + return; + if (visible_end.DeepEquivalent() == + EndOfParagraph(visible_end).DeepEquivalent()) { + downstream_end = MostForwardCaretPosition( + NextPositionOf(visible_end, kCannotCrossEditingBoundary) + .DeepEquivalent()); + } + // When deleting tables: Select the table first, then perform the deletion + if (IsDisplayInsideTable(downstream_end.ComputeContainerNode()) && + downstream_end.ComputeOffsetInContainerNode() <= + CaretMinOffset(downstream_end.ComputeContainerNode())) { + SetEndingSelection( + SelectionInDOMTree::Builder() + .SetBaseAndExtentDeprecated( + EndingSelection().End(), + Position::AfterNode(*downstream_end.ComputeContainerNode())) + .SetIsDirectional(EndingSelection().IsDirectional()) + .Build()); + TypingAddedToOpenCommand(kForwardDeleteKey); + return; + } + + // deleting to end of paragraph when at end of paragraph needs to merge + // the next paragraph (if any) + if (granularity == TextGranularity::kParagraphBoundary && + selection_modifier.Selection().IsCaret() && + IsEndOfParagraph(selection_modifier.Selection().VisibleEnd())) { + selection_modifier.Modify(FrameSelection::kAlterationExtend, + kDirectionForward, TextGranularity::kCharacter); + } + + const VisibleSelection& selection_to_delete = selection_modifier.Selection(); + if (!StartingSelection().IsRange() || + MostBackwardCaretPosition(selection_to_delete.Base()) != + StartingSelection().Start()) { + ForwardDeleteKeyPressedInternal(selection_to_delete, selection_to_delete, + kill_ring, editing_state); + return; + } + // It's a little tricky to compute what the starting selection would + // have been in the original document. We can't let the VisibleSelection + // class's validation kick in or it'll adjust for us based on the + // current state of the document and we'll get the wrong result. + const VisibleSelection& selection_after_undo = + VisibleSelection::CreateWithoutValidationDeprecated( + StartingSelection().Start(), + ComputeExtentForForwardDeleteUndo(selection_to_delete, + StartingSelection().End()), + TextAffinity::kDownstream); + ForwardDeleteKeyPressedInternal(selection_to_delete, selection_after_undo, + kill_ring, editing_state); } void TypingCommand::ForwardDeleteKeyPressedInternal(
diff --git a/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp b/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp index 1de7d39..f7fda5a 100644 --- a/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLTableCellElement.cpp
@@ -38,6 +38,11 @@ using namespace HTMLNames; +namespace { +const unsigned kDefaultColSpan = 1; +const unsigned kDefaultRowSpan = 1; +} // namespace + inline HTMLTableCellElement::HTMLTableCellElement(const QualifiedName& tag_name, Document& document) : HTMLTablePartElement(tag_name, document) {} @@ -49,7 +54,7 @@ unsigned value = 0; if (col_span_value.IsEmpty() || !ParseHTMLNonNegativeInteger(col_span_value, value)) - return 1; + return kDefaultColSpan; // Counting for https://github.com/whatwg/html/issues/1198 UseCounter::Count(GetDocument(), WebFeature::kHTMLTableCellElementColspan); if (value > 8190) { @@ -67,7 +72,7 @@ unsigned value = 0; if (row_span_value.IsEmpty() || !ParseHTMLNonNegativeInteger(row_span_value, value)) - return 1; + return kDefaultRowSpan; return std::max(1u, std::min(value, MaxRowSpan())); } @@ -160,7 +165,7 @@ } void HTMLTableCellElement::setColSpan(unsigned n) { - SetUnsignedIntegralAttribute(colspanAttr, n); + SetUnsignedIntegralAttribute(colspanAttr, n, kDefaultColSpan); } const AtomicString& HTMLTableCellElement::Headers() const { @@ -168,7 +173,7 @@ } void HTMLTableCellElement::setRowSpan(unsigned n) { - SetUnsignedIntegralAttribute(rowspanAttr, n); + SetUnsignedIntegralAttribute(rowspanAttr, n, kDefaultRowSpan); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLTableColElement.cpp b/third_party/WebKit/Source/core/html/HTMLTableColElement.cpp index aa6274d..67d28fcb 100644 --- a/third_party/WebKit/Source/core/html/HTMLTableColElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLTableColElement.cpp
@@ -36,6 +36,10 @@ using namespace HTMLNames; +namespace { +const unsigned kDefaultSpan = 1; +} // namespace + inline HTMLTableColElement::HTMLTableColElement(const QualifiedName& tag_name, Document& document) : HTMLTablePartElement(tag_name, document), span_(1) {} @@ -69,7 +73,7 @@ new_span < 1) { // If the value of span is not a valid non-negative integer greater than // zero, set it to 1. - new_span = 1; + new_span = kDefaultSpan; } new_span = std::min(new_span, HTMLTableCellElement::MaxColSpan()); span_ = new_span; @@ -100,7 +104,7 @@ } void HTMLTableColElement::setSpan(unsigned n) { - SetUnsignedIntegralAttribute(spanAttr, n); + SetUnsignedIntegralAttribute(spanAttr, n, kDefaultSpan); } const AtomicString& HTMLTableColElement::Width() const {
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp index 537645b6..9fb1a4e 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -136,27 +136,16 @@ { MutexLocker lock(thread_state_mutex_); - if (requested_to_terminate_) return; requested_to_terminate_ = true; - - if (ShouldScheduleToTerminateExecution(lock)) { - // Schedule a task to forcibly terminate the script execution in case that - // the shutdown sequence does not start on the worker thread in a certain - // time period. - DCHECK(!forcible_termination_task_handle_.IsActive()); - forcible_termination_task_handle_ = - parent_frame_task_runners_->Get(TaskType::kUnspecedTimer) - ->PostDelayedCancellableTask( - BLINK_FROM_HERE, - WTF::Bind(&WorkerThread::EnsureScriptExecutionTerminates, - WTF::Unretained(this), - ExitCode::kAsyncForciblyTerminated), - forcible_termination_delay_); - } } + // Schedule a task to forcibly terminate the script execution in case that the + // shutdown sequence does not start on the worker thread in a certain time + // period. + ScheduleToTerminateScriptExecution(); + worker_thread_lifecycle_context_->NotifyContextDestroyed(); inspector_task_runner_->Kill(); @@ -346,7 +335,19 @@ ConvertToBaseCallback(WTF::Bind(&ForwardInterfaceRequest))); } -bool WorkerThread::ShouldScheduleToTerminateExecution(const MutexLocker& lock) { +void WorkerThread::ScheduleToTerminateScriptExecution() { + DCHECK(!forcible_termination_task_handle_.IsActive()); + forcible_termination_task_handle_ = + parent_frame_task_runners_->Get(TaskType::kUnspecedTimer) + ->PostDelayedCancellableTask( + BLINK_FROM_HERE, + WTF::Bind(&WorkerThread::EnsureScriptExecutionTerminates, + WTF::Unretained(this), + ExitCode::kAsyncForciblyTerminated), + forcible_termination_delay_); +} + +bool WorkerThread::ShouldTerminateScriptExecution(const MutexLocker& lock) { DCHECK(IsMainThread()); DCHECK(IsThreadStateMutexLocked(lock)); @@ -372,7 +373,7 @@ void WorkerThread::EnsureScriptExecutionTerminates(ExitCode exit_code) { DCHECK(IsMainThread()); MutexLocker lock(thread_state_mutex_); - if (!ShouldScheduleToTerminateExecution(lock)) + if (!ShouldTerminateScriptExecution(lock)) return; DCHECK(exit_code == ExitCode::kSyncForciblyTerminated ||
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.h b/third_party/WebKit/Source/core/workers/WorkerThread.h index 831b3beb..4437bc7 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThread.h +++ b/third_party/WebKit/Source/core/workers/WorkerThread.h
@@ -202,8 +202,7 @@ private: friend class WorkerThreadTest; - FRIEND_TEST_ALL_PREFIXES(WorkerThreadTest, - ShouldScheduleToTerminateExecution); + FRIEND_TEST_ALL_PREFIXES(WorkerThreadTest, ShouldTerminateScriptExecution); FRIEND_TEST_ALL_PREFIXES( WorkerThreadTest, Terminate_WhileDebuggerTaskIsRunningOnInitialization); @@ -221,11 +220,14 @@ kReadyToShutdown, }; - // Returns true if we should synchronously terminate or schedule to - // terminate the worker execution so that a shutdown task can be handled by - // the thread event loop. This must be called with |m_threadStateMutex| - // acquired. - bool ShouldScheduleToTerminateExecution(const MutexLocker&); + // Posts a delayed task to forcibly terminate script execution in case the + // normal shutdown sequence does not start within a certain time period. + void ScheduleToTerminateScriptExecution(); + + // Returns true if we should synchronously terminate the script execution so + // that a shutdown task can be handled by the thread event loop. This must be + // called with |m_threadStateMutex| acquired. + bool ShouldTerminateScriptExecution(const MutexLocker&); // Terminates worker script execution if the worker thread is running and not // already shutting down. Does not terminate if a debugger task is running,
diff --git a/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp b/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp index 9d06019d..a559965 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp
@@ -144,22 +144,22 @@ Persistent<MockWorkerThreadLifecycleObserver> lifecycle_observer_; }; -TEST_F(WorkerThreadTest, ShouldScheduleToTerminateExecution) { +TEST_F(WorkerThreadTest, ShouldTerminateScriptExecution) { using ThreadState = WorkerThread::ThreadState; MutexLocker dummy_lock(worker_thread_->thread_state_mutex_); EXPECT_EQ(ThreadState::kNotStarted, worker_thread_->thread_state_); - EXPECT_FALSE(worker_thread_->ShouldScheduleToTerminateExecution(dummy_lock)); + EXPECT_FALSE(worker_thread_->ShouldTerminateScriptExecution(dummy_lock)); worker_thread_->SetThreadState(dummy_lock, ThreadState::kRunning); EXPECT_FALSE(worker_thread_->running_debugger_task_); - EXPECT_TRUE(worker_thread_->ShouldScheduleToTerminateExecution(dummy_lock)); + EXPECT_TRUE(worker_thread_->ShouldTerminateScriptExecution(dummy_lock)); worker_thread_->running_debugger_task_ = true; - EXPECT_FALSE(worker_thread_->ShouldScheduleToTerminateExecution(dummy_lock)); + EXPECT_FALSE(worker_thread_->ShouldTerminateScriptExecution(dummy_lock)); worker_thread_->SetThreadState(dummy_lock, ThreadState::kReadyToShutdown); - EXPECT_FALSE(worker_thread_->ShouldScheduleToTerminateExecution(dummy_lock)); + EXPECT_FALSE(worker_thread_->ShouldTerminateScriptExecution(dummy_lock)); // This is necessary to satisfy DCHECK in the dtor of WorkerThread. worker_thread_->SetExitCode(dummy_lock, ExitCode::kGracefullyTerminated); @@ -215,14 +215,11 @@ // There are two possible cases depending on timing: // (1) If the thread hasn't been initialized on the worker thread yet, - // terminateAndWait() should wait for initialization and shut down the - // thread immediately after that. + // TerminateAllWorkersForTesting() should wait for initialization and shut + // down the thread immediately after that. // (2) If the thread has already been initialized on the worker thread, - // terminateAndWait() should synchronously forcibly terminates the worker - // execution. - // TODO(nhiroki): Make this test deterministically pass through the case 1), - // that is, terminateAndWait() is called before initializeOnWorkerThread(). - // Then, rename this test to SyncTerminate_BeforeInitialization. + // TerminateAllWorkersForTesting() should synchronously forcibly terminates + // the worker execution. WorkerThread::TerminateAllWorkersForTesting(); ExitCode exit_code = GetExitCode(); EXPECT_TRUE(ExitCode::kGracefullyTerminated == exit_code || @@ -237,17 +234,17 @@ StartWithSourceCodeNotToFinish(); reporting_proxy_->WaitUntilScriptEvaluation(); - // terminate() schedules a force termination task. + // Terminate() schedules a forcible termination task. worker_thread_->Terminate(); EXPECT_TRUE(IsForcibleTerminationTaskScheduled()); EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); - // Multiple terminate() calls should not take effect. + // Multiple Terminate() calls should not take effect. worker_thread_->Terminate(); worker_thread_->Terminate(); EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); - // Wait until the force termination task runs. + // Wait until the forcible termination task runs. testing::RunDelayedTasks(kDelay); worker_thread_->WaitForShutdownForTesting(); EXPECT_EQ(ExitCode::kAsyncForciblyTerminated, GetExitCode()); @@ -258,7 +255,8 @@ StartWithSourceCodeNotToFinish(); reporting_proxy_->WaitUntilScriptEvaluation(); - // terminateAndWait() synchronously terminates the worker execution. + // TerminateAllWorkersForTesting() synchronously terminates the worker + // execution. WorkerThread::TerminateAllWorkersForTesting(); EXPECT_EQ(ExitCode::kSyncForciblyTerminated, GetExitCode()); } @@ -271,18 +269,22 @@ StartWithSourceCodeNotToFinish(); reporting_proxy_->WaitUntilScriptEvaluation(); - // terminate() schedules a force termination task. + // Terminate() schedules a forcible termination task. worker_thread_->Terminate(); EXPECT_TRUE(IsForcibleTerminationTaskScheduled()); EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); - // terminateAndWait() should overtake the scheduled force termination task. + // TerminateAllWorkersForTesting() should overtake the scheduled forcible + // termination task. WorkerThread::TerminateAllWorkersForTesting(); EXPECT_FALSE(IsForcibleTerminationTaskScheduled()); EXPECT_EQ(ExitCode::kSyncForciblyTerminated, GetExitCode()); } TEST_F(WorkerThreadTest, Terminate_WhileDebuggerTaskIsRunningOnInitialization) { + constexpr TimeDelta kDelay = TimeDelta::FromMilliseconds(10); + SetForcibleTerminationDelay(kDelay); + EXPECT_CALL(*reporting_proxy_, DidCreateWorkerGlobalScope(_)).Times(1); EXPECT_CALL(*reporting_proxy_, DidInitializeWorkerContext()).Times(1); EXPECT_CALL(*reporting_proxy_, WillDestroyWorkerGlobalScope()).Times(1); @@ -320,20 +322,19 @@ testing::EnterRunLoop(); EXPECT_TRUE(worker_thread_->running_debugger_task_); - // terminate() should not schedule a force termination task because there is - // a running debugger task. + // Terminate() schedules a forcible termination task. worker_thread_->Terminate(); + EXPECT_TRUE(IsForcibleTerminationTaskScheduled()); + EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); + + // Wait until the task runs. It shouldn't terminate the script execution + // because of the running debugger task. + testing::RunDelayedTasks(kDelay); EXPECT_FALSE(IsForcibleTerminationTaskScheduled()); EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); - // Multiple terminate() calls should not take effect. - worker_thread_->Terminate(); - worker_thread_->Terminate(); - EXPECT_FALSE(IsForcibleTerminationTaskScheduled()); - EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); - - // Focible script termination request should also respect the running debugger - // task. + // Forcible script termination request should also respect the running + // debugger task. worker_thread_->EnsureScriptExecutionTerminates( ExitCode::kSyncForciblyTerminated); EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); @@ -345,6 +346,9 @@ } TEST_F(WorkerThreadTest, Terminate_WhileDebuggerTaskIsRunning) { + constexpr TimeDelta kDelay = TimeDelta::FromMilliseconds(10); + SetForcibleTerminationDelay(kDelay); + ExpectReportingCalls(); Start(); worker_thread_->WaitForInit(); @@ -360,20 +364,19 @@ testing::EnterRunLoop(); EXPECT_TRUE(worker_thread_->running_debugger_task_); - // terminate() should not schedule a force termination task because there is - // a running debugger task. + // Terminate() schedules a forcible termination task. worker_thread_->Terminate(); + EXPECT_TRUE(IsForcibleTerminationTaskScheduled()); + EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); + + // Wait until the task runs. It shouldn't terminate the script execution + // because of the running debugger task. + testing::RunDelayedTasks(kDelay); EXPECT_FALSE(IsForcibleTerminationTaskScheduled()); EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); - // Multiple terminate() calls should not take effect. - worker_thread_->Terminate(); - worker_thread_->Terminate(); - EXPECT_FALSE(IsForcibleTerminationTaskScheduled()); - EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); - - // Focible script termination request should also respect the running debugger - // task. + // Forcible script termination request should also respect the running + // debugger task. worker_thread_->EnsureScriptExecutionTerminates( ExitCode::kSyncForciblyTerminated); EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode());
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp index a0d2f7a..3868b61 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -1279,7 +1279,11 @@ } bool AXLayoutObject::AriaHasPopup() const { - return ElementAttributeValue(aria_haspopupAttr); + const AtomicString& has_popup = + GetAOMPropertyOrARIAAttribute(AOMStringProperty::kHasPopUp); + + return !has_popup.IsNull() && !has_popup.IsEmpty() && + !EqualIgnoringASCIICase(has_popup, "false"); } bool AXLayoutObject::AriaRoleHasPresentationalChildren() const {
diff --git a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp index 6ec4a83..fa0c1f7 100644 --- a/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp +++ b/third_party/WebKit/Source/modules/accessibility/InspectorAccessibilityAgent.cpp
@@ -165,8 +165,8 @@ CreateProperty(AXWidgetAttributesEnum::Autocomplete, CreateValue(autocomplete, AXValueTypeEnum::Token))); - if (ax_object.HasAttribute(HTMLNames::aria_haspopupAttr)) { - bool has_popup = ax_object.AriaHasPopup(); + bool has_popup = ax_object.AriaHasPopup(); + if (has_popup || ax_object.HasAttribute(HTMLNames::aria_haspopupAttr)) { properties.addItem(CreateProperty(AXWidgetAttributesEnum::Haspopup, CreateBooleanValue(has_popup))); }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index c904b1d0..0e249e8 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -15406,8 +15406,11 @@ <summary>The start result of download attempts.</summary> </histogram> -<histogram name="Download.Service.StartUpStatus" +<histogram base="true" name="Download.Service.StartUpStatus" enum="Download.Service.StartUpResult"> +<!-- Name completed by histogram_suffixes + name="Download.Service.StartUpStep" --> + <owner>xingliu@chromium.org</owner> <summary>The start up result of the download service.</summary> </histogram> @@ -69043,6 +69046,16 @@ </summary> </histogram> +<histogram name="Search.ContextualSearchTapOnWordMiddleSeen" + enum="ContextualSearchResultsSeen"> + <owner>donnd@chromium.org</owner> + <owner>twellington@chromium.org</owner> + <summary> + Whether results were seen for a Tap that was on the middle part of a word. + Recorded when the UX is hidden. Implemented for Android. + </summary> +</histogram> + <histogram name="Search.ContextualSearchTapShortDurationSeen" enum="ContextualSearchResultsSeen"> <owner>donnd@chromium.org</owner> @@ -91226,6 +91239,12 @@ <affected-histogram name="Download.Service.Db.Records"/> </histogram_suffixes> +<histogram_suffixes name="Download.Service.StartUpStep" separator="."> + <suffix name="Initialization" label="The initialization start up step."/> + <suffix name="Recovery" label="The recovery start up step."/> + <affected-histogram name="Download.Service.StartUpStatus"/> +</histogram_suffixes> + <histogram_suffixes name="Download.Service.TaskType" separator="."> <suffix name="DownloadTask" label="Download task."/> <suffix name="CleanUpTask" label="Clean up task."/>
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc index 8bbca86..c7b25e51 100644 --- a/ui/app_list/views/app_list_view_unittest.cc +++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -9,16 +9,13 @@ #include <string> #include <vector> -#include "base/command_line.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/app_list/app_list_constants.h" -#include "ui/app_list/app_list_switches.h" #include "ui/app_list/pagination_model.h" #include "ui/app_list/search_box_model.h" #include "ui/app_list/test/app_list_test_model.h" @@ -38,16 +35,16 @@ #include "ui/app_list/views/tile_item_view.h" #include "ui/events/event_utils.h" #include "ui/views/controls/textfield/textfield.h" -#include "ui/views/test/test_views_delegate.h" #include "ui/views/test/views_test_base.h" -#include "ui/views/views_delegate.h" -#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" namespace app_list { namespace test { namespace { +// Choose a set that is 3 regular app list pages and 2 landscape app list pages. +constexpr int kInitialItems = 34; + template <class T> size_t GetVisibleViews(const std::vector<T*>& tiles) { size_t count = 0; @@ -58,6 +55,15 @@ return count; } +// A standard set of checks on a view, e.g., ensuring it is drawn and visible. +void CheckView(views::View* subview) { + ASSERT_TRUE(subview); + EXPECT_TRUE(subview->parent()); + EXPECT_TRUE(subview->visible()); + EXPECT_TRUE(subview->IsDrawn()); + EXPECT_FALSE(subview->bounds().IsEmpty()); +} + void SimulateClick(views::View* view) { gfx::Point center = view->GetLocalBounds().CenterPoint(); view->OnMousePressed(ui::MouseEvent( @@ -68,9 +74,6 @@ ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); } -// Choose a set that is 3 regular app list pages and 2 landscape app list pages. -const int kInitialItems = 34; - class TestStartPageSearchResult : public TestSearchResult { public: TestStartPageSearchResult() { set_display_type(DISPLAY_RECOMMENDATION); } @@ -80,174 +83,98 @@ DISALLOW_COPY_AND_ASSIGN(TestStartPageSearchResult); }; -// Allows the same tests to run with different contexts: either an Ash-style -// root window or a desktop window tree host. -class AppListViewTestContext { +class AppListViewTest : public views::ViewsTestBase { public: - explicit AppListViewTestContext(gfx::NativeView parent); - ~AppListViewTestContext(); + AppListViewTest() = default; + ~AppListViewTest() override = default; - // Test displaying the app list and performs a standard set of checks on its - // top level views. Then closes the window. - void RunDisplayTest(); + // testing::Test overrides: + void SetUp() override { + views::ViewsTestBase::SetUp(); - // Hides and reshows the app list with a folder open, expecting the main grid - // view to be shown. - void RunReshowWithOpenFolderTest(); + gfx::NativeView parent = GetContext(); + delegate_.reset(new AppListTestViewDelegate); + view_ = new AppListView(delegate_.get()); - // Tests that pressing the search box's back button navigates correctly. - void RunBackTest(); - - // Tests displaying of the app list and shows the start page. - void RunStartPageTest(); - - // Tests switching rapidly between multiple pages of the launcher. - void RunPageSwitchingAnimationTest(); - - // Tests displaying of the search results. - void RunSearchResultsTest(); - - // Tests displaying the app list overlay. - void RunAppListOverlayTest(); - - // A standard set of checks on a view, e.g., ensuring it is drawn and visible. - static void CheckView(views::View* subview); - - // Invoked when the Widget is closing, and the view it contains is about to - // be torn down. This only occurs in a run loop and will be used as a signal - // to quit. - void NativeWidgetClosing() { - view_ = NULL; - run_loop_->Quit(); + view_->Initialize(parent, 0, false, false); + // Initialize around a point that ensures the window is wholly shown. + gfx::Size size = view_->bounds().size(); + view_->MaybeSetAnchorPoint(gfx::Point(size.width() / 2, size.height() / 2)); } - private: + // testing::Test overrides: + void TearDown() override { + view_->GetWidget()->Close(); + views::ViewsTestBase::TearDown(); + } + + protected: // Switches the launcher to |state| and lays out to ensure all launcher pages // are in the correct position. Checks that the state is where it should be // and returns false on failure. - bool SetAppListState(AppListModel::State state); + bool SetAppListState(AppListModel::State state) { + ContentsView* contents_view = view_->app_list_main_view()->contents_view(); + contents_view->SetActiveState(state); + contents_view->Layout(); + return IsStateShown(state); + } // Returns true if all of the pages are in their correct position for |state|. - bool IsStateShown(AppListModel::State state); + bool IsStateShown(AppListModel::State state) { + ContentsView* contents_view = view_->app_list_main_view()->contents_view(); + bool success = true; + for (int i = 0; i < contents_view->NumLauncherPages(); ++i) { + success = success && + (contents_view->GetPageView(i)->GetPageBoundsForState(state) == + contents_view->GetPageView(i)->bounds()); + } + return success && state == delegate_->GetTestModel()->state(); + } // Shows the app list and waits until a paint occurs. - void Show(); + void Show() { + view_->GetWidget()->Show(); + base::RunLoop run_loop; + AppListViewTestApi test_api(view_); + test_api.SetNextPaintCallback(run_loop.QuitClosure()); + run_loop.Run(); - // Closes the app list. This sets |view_| to NULL. - void Close(); + EXPECT_TRUE(view_->GetWidget()->IsVisible()); + } // Checks the search box widget is at |expected| in the contents view's // coordinate space. - bool CheckSearchBoxWidget(const gfx::Rect& expected); + bool CheckSearchBoxWidget(const gfx::Rect& expected) { + ContentsView* contents_view = view_->app_list_main_view()->contents_view(); + // Adjust for the search box view's shadow. + gfx::Rect expected_with_shadow = + view_->app_list_main_view() + ->search_box_view() + ->GetViewBoundsForSearchBoxContentsBounds(expected); + gfx::Point point = expected_with_shadow.origin(); + views::View::ConvertPointToScreen(contents_view, &point); + + return gfx::Rect(point, expected_with_shadow.size()) == + view_->search_box_widget()->GetWindowBoundsInScreen(); + } // Gets the PaginationModel owned by |view_|. - PaginationModel* GetPaginationModel(); + PaginationModel* GetPaginationModel() const { + return view_->GetAppsPaginationModel(); + } - std::unique_ptr<base::RunLoop> run_loop_; - app_list::AppListView* view_; // Owned by native widget. - std::unique_ptr<app_list::test::AppListTestViewDelegate> delegate_; - - DISALLOW_COPY_AND_ASSIGN(AppListViewTestContext); -}; - -// Extend the regular AppListTestViewDelegate to communicate back to the test -// context. Note the test context doesn't simply inherit this, because the -// delegate is owned by the view. -class UnitTestViewDelegate : public app_list::test::AppListTestViewDelegate { - public: - explicit UnitTestViewDelegate(AppListViewTestContext* parent) - : parent_(parent) {} - - // Overridden from app_list::test::AppListTestViewDelegate: - void ViewClosing() override { parent_->NativeWidgetClosing(); } + AppListView* view_ = nullptr; // Owned by native widget. + std::unique_ptr<AppListTestViewDelegate> delegate_; private: - AppListViewTestContext* parent_; - - DISALLOW_COPY_AND_ASSIGN(UnitTestViewDelegate); + DISALLOW_COPY_AND_ASSIGN(AppListViewTest); }; -AppListViewTestContext::AppListViewTestContext(gfx::NativeView parent) { - delegate_.reset(new UnitTestViewDelegate(this)); - view_ = new app_list::AppListView(delegate_.get()); +} // namespace - // Initialize centered around a point that ensures the window is wholly shown. - view_->Initialize(parent, 0, false, false); - view_->MaybeSetAnchorPoint(gfx::Point(300, 300)); -} - -AppListViewTestContext::~AppListViewTestContext() { - // The view observes the PaginationModel which is about to get destroyed, so - // if the view is not already deleted by the time this destructor is called, - // there will be problems. - EXPECT_FALSE(view_); -} - -// static -void AppListViewTestContext::CheckView(views::View* subview) { - ASSERT_TRUE(subview); - EXPECT_TRUE(subview->parent()); - EXPECT_TRUE(subview->visible()); - EXPECT_TRUE(subview->IsDrawn()); - EXPECT_FALSE(subview->bounds().IsEmpty()); -} - -bool AppListViewTestContext::SetAppListState(AppListModel::State state) { - ContentsView* contents_view = view_->app_list_main_view()->contents_view(); - contents_view->SetActiveState(state); - contents_view->Layout(); - return IsStateShown(state); -} - -bool AppListViewTestContext::IsStateShown(AppListModel::State state) { - ContentsView* contents_view = view_->app_list_main_view()->contents_view(); - bool success = true; - for (int i = 0; i < contents_view->NumLauncherPages(); ++i) { - success = success && - (contents_view->GetPageView(i)->GetPageBoundsForState(state) == - contents_view->GetPageView(i)->bounds()); - } - return success && state == delegate_->GetTestModel()->state(); -} - -void AppListViewTestContext::Show() { - view_->GetWidget()->Show(); - run_loop_.reset(new base::RunLoop); - AppListViewTestApi test_api(view_); - test_api.SetNextPaintCallback(run_loop_->QuitClosure()); - run_loop_->Run(); - - EXPECT_TRUE(view_->GetWidget()->IsVisible()); -} - -void AppListViewTestContext::Close() { - view_->GetWidget()->Close(); - run_loop_.reset(new base::RunLoop); - run_loop_->Run(); - - // |view_| should have been deleted and set to NULL via ViewClosing(). - EXPECT_FALSE(view_); -} - -bool AppListViewTestContext::CheckSearchBoxWidget(const gfx::Rect& expected) { - ContentsView* contents_view = view_->app_list_main_view()->contents_view(); - // Adjust for the search box view's shadow. - gfx::Rect expected_with_shadow = - view_->app_list_main_view() - ->search_box_view() - ->GetViewBoundsForSearchBoxContentsBounds(expected); - gfx::Point point = expected_with_shadow.origin(); - views::View::ConvertPointToScreen(contents_view, &point); - - return gfx::Rect(point, expected_with_shadow.size()) == - view_->search_box_widget()->GetWindowBoundsInScreen(); -} - -PaginationModel* AppListViewTestContext::GetPaginationModel() { - return view_->GetAppsPaginationModel(); -} - -void AppListViewTestContext::RunDisplayTest() { +// Tests displaying the app list and performs a standard set of checks on its +// top level views. Then closes the window. +TEST_F(AppListViewTest, DisplayTest) { EXPECT_FALSE(view_->GetWidget()->IsVisible()); EXPECT_EQ(-1, GetPaginationModel()->total_pages()); delegate_->GetTestModel()->PopulateApps(kInitialItems); @@ -270,11 +197,11 @@ AppListModel::State expected = AppListModel::STATE_START; EXPECT_TRUE(main_view->contents_view()->IsStateActive(expected)); EXPECT_EQ(expected, delegate_->GetTestModel()->state()); - - Close(); } -void AppListViewTestContext::RunReshowWithOpenFolderTest() { +// Tests that the main grid view is shown after hiding and reshowing the app +// list with a folder view open. This is a regression test for crbug.com/357058. +TEST_F(AppListViewTest, ReshowWithOpenFolderTest) { EXPECT_FALSE(view_->GetWidget()->IsVisible()); EXPECT_EQ(-1, GetPaginationModel()->total_pages()); @@ -314,63 +241,10 @@ EXPECT_NO_FATAL_FAILURE(CheckView(main_view)); EXPECT_NO_FATAL_FAILURE(CheckView(container_view->apps_grid_view())); EXPECT_FALSE(container_view->app_list_folder_view()->visible()); - - Close(); } -void AppListViewTestContext::RunBackTest() { - EXPECT_FALSE(view_->GetWidget()->IsVisible()); - EXPECT_EQ(-1, GetPaginationModel()->total_pages()); - - Show(); - - AppListMainView* main_view = view_->app_list_main_view(); - ContentsView* contents_view = main_view->contents_view(); - SearchBoxView* search_box_view = main_view->search_box_view(); - - // Show the apps grid. - SetAppListState(AppListModel::STATE_APPS); - EXPECT_NO_FATAL_FAILURE(CheckView(search_box_view->back_button())); - - // The back button should return to the start page. - EXPECT_TRUE(contents_view->Back()); - contents_view->Layout(); - EXPECT_TRUE(IsStateShown(AppListModel::STATE_START)); - EXPECT_FALSE(search_box_view->back_button()->visible()); - - // Show the apps grid again. - SetAppListState(AppListModel::STATE_APPS); - EXPECT_NO_FATAL_FAILURE(CheckView(search_box_view->back_button())); - - // Pressing ESC should return to the start page. - view_->AcceleratorPressed(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); - contents_view->Layout(); - EXPECT_TRUE(IsStateShown(AppListModel::STATE_START)); - EXPECT_FALSE(search_box_view->back_button()->visible()); - - // Pressing ESC from the start page should close the app list. - EXPECT_EQ(0, delegate_->dismiss_count()); - view_->AcceleratorPressed(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); - EXPECT_EQ(1, delegate_->dismiss_count()); - - // Show the search results. - base::string16 new_search_text = base::UTF8ToUTF16("apple"); - search_box_view->search_box()->SetText(base::string16()); - search_box_view->search_box()->InsertText(new_search_text); - contents_view->Layout(); - EXPECT_TRUE(IsStateShown(AppListModel::STATE_SEARCH_RESULTS)); - EXPECT_NO_FATAL_FAILURE(CheckView(search_box_view->back_button())); - - // The back button should return to the start page. - EXPECT_TRUE(contents_view->Back()); - contents_view->Layout(); - EXPECT_TRUE(IsStateShown(AppListModel::STATE_START)); - EXPECT_FALSE(search_box_view->back_button()->visible()); - - Close(); -} - -void AppListViewTestContext::RunStartPageTest() { +// Tests that the start page view operates correctly. +TEST_F(AppListViewTest, StartPageTest) { EXPECT_FALSE(view_->GetWidget()->IsVisible()); EXPECT_EQ(-1, GetPaginationModel()->total_pages()); AppListTestModel* model = delegate_->GetTestModel(); @@ -423,13 +297,10 @@ EXPECT_EQ(0u, GetVisibleViews(start_page_view->tile_views())); EXPECT_TRUE(SetAppListState(AppListModel::STATE_START)); EXPECT_EQ(1u, GetVisibleViews(start_page_view->tile_views())); - - Close(); } -void AppListViewTestContext::RunPageSwitchingAnimationTest() { - Show(); - +// Tests switching rapidly between multiple pages of the launcher. +TEST_F(AppListViewTest, PageSwitchingAnimationTest) { AppListMainView* main_view = view_->app_list_main_view(); // Checks on the main view. EXPECT_NO_FATAL_FAILURE(CheckView(main_view)); @@ -454,11 +325,10 @@ // Call Layout(). Should jump to the third page. contents_view->Layout(); IsStateShown(AppListModel::STATE_APPS); - - Close(); } -void AppListViewTestContext::RunSearchResultsTest() { +// Tests that the correct views are displayed for showing search results. +TEST_F(AppListViewTest, SearchResultsTest) { EXPECT_FALSE(view_->GetWidget()->IsVisible()); EXPECT_EQ(-1, GetPaginationModel()->total_pages()); AppListTestModel* model = delegate_->GetTestModel(); @@ -515,11 +385,61 @@ contents_view->Layout(); EXPECT_TRUE(IsStateShown(AppListModel::STATE_SEARCH_RESULTS)); EXPECT_TRUE(CheckSearchBoxWidget(contents_view->GetDefaultSearchBoxBounds())); - - Close(); } -void AppListViewTestContext::RunAppListOverlayTest() { +// Tests that the back button navigates through the app list correctly. +TEST_F(AppListViewTest, BackTest) { + EXPECT_FALSE(view_->GetWidget()->IsVisible()); + EXPECT_EQ(-1, GetPaginationModel()->total_pages()); + + Show(); + + AppListMainView* main_view = view_->app_list_main_view(); + ContentsView* contents_view = main_view->contents_view(); + SearchBoxView* search_box_view = main_view->search_box_view(); + + // Show the apps grid. + SetAppListState(AppListModel::STATE_APPS); + EXPECT_NO_FATAL_FAILURE(CheckView(search_box_view->back_button())); + + // The back button should return to the start page. + EXPECT_TRUE(contents_view->Back()); + contents_view->Layout(); + EXPECT_TRUE(IsStateShown(AppListModel::STATE_START)); + EXPECT_FALSE(search_box_view->back_button()->visible()); + + // Show the apps grid again. + SetAppListState(AppListModel::STATE_APPS); + EXPECT_NO_FATAL_FAILURE(CheckView(search_box_view->back_button())); + + // Pressing ESC should return to the start page. + view_->AcceleratorPressed(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); + contents_view->Layout(); + EXPECT_TRUE(IsStateShown(AppListModel::STATE_START)); + EXPECT_FALSE(search_box_view->back_button()->visible()); + + // Pressing ESC from the start page should close the app list. + EXPECT_EQ(0, delegate_->dismiss_count()); + view_->AcceleratorPressed(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); + EXPECT_EQ(1, delegate_->dismiss_count()); + + // Show the search results. + base::string16 new_search_text = base::UTF8ToUTF16("apple"); + search_box_view->search_box()->SetText(base::string16()); + search_box_view->search_box()->InsertText(new_search_text); + contents_view->Layout(); + EXPECT_TRUE(IsStateShown(AppListModel::STATE_SEARCH_RESULTS)); + EXPECT_NO_FATAL_FAILURE(CheckView(search_box_view->back_button())); + + // The back button should return to the start page. + EXPECT_TRUE(contents_view->Back()); + contents_view->Layout(); + EXPECT_TRUE(IsStateShown(AppListModel::STATE_START)); + EXPECT_FALSE(search_box_view->back_button()->visible()); +} + +// Tests that the correct views are displayed for showing search results. +TEST_F(AppListViewTest, AppListOverlayTest) { Show(); AppListMainView* main_view = view_->app_list_main_view(); @@ -534,159 +454,6 @@ EXPECT_TRUE(search_box_view->enabled()); EXPECT_EQ(search_box_view->search_box(), view_->GetWidget()->GetFocusManager()->GetFocusedView()); - - Close(); -} - -class AppListViewTestAura : public views::ViewsTestBase { - public: - AppListViewTestAura() {} - ~AppListViewTestAura() override {} - - // testing::Test overrides: - void SetUp() override { - views::ViewsTestBase::SetUp(); - - // On Ash (only) the app list is placed into an aura::Window "container", - // which is also used to determine the context. In tests, use the ash root - // window as the parent. This only works on aura where the root window is a - // NativeView as well as a NativeWindow. - gfx::NativeView container = NULL; - container = GetContext(); - test_context_.reset(new AppListViewTestContext(container)); - } - - void TearDown() override { - test_context_.reset(); - views::ViewsTestBase::TearDown(); - } - - protected: - std::unique_ptr<AppListViewTestContext> test_context_; - - private: - DISALLOW_COPY_AND_ASSIGN(AppListViewTestAura); -}; - -class AppListViewTestDesktop : public views::ViewsTestBase { - public: - AppListViewTestDesktop() {} - ~AppListViewTestDesktop() override {} - - // testing::Test overrides: - void SetUp() override { - set_views_delegate(base::MakeUnique<AppListViewTestViewsDelegate>(this)); - views::ViewsTestBase::SetUp(); - test_context_.reset(new AppListViewTestContext(NULL)); - } - - void TearDown() override { - test_context_.reset(); - views::ViewsTestBase::TearDown(); - } - - protected: - std::unique_ptr<AppListViewTestContext> test_context_; - - private: - class AppListViewTestViewsDelegate : public views::TestViewsDelegate { - public: - explicit AppListViewTestViewsDelegate(AppListViewTestDesktop* parent) - : parent_(parent) - { - } - - // Overridden from views::ViewsDelegate: - void OnBeforeWidgetInit( - views::Widget::InitParams* params, - views::internal::NativeWidgetDelegate* delegate) override; - - private: - AppListViewTestDesktop* parent_; - - DISALLOW_COPY_AND_ASSIGN(AppListViewTestViewsDelegate); - }; - - DISALLOW_COPY_AND_ASSIGN(AppListViewTestDesktop); -}; - -void AppListViewTestDesktop::AppListViewTestViewsDelegate::OnBeforeWidgetInit( - views::Widget::InitParams* params, - views::internal::NativeWidgetDelegate* delegate) { -// Mimic the logic in ChromeViewsDelegate::OnBeforeWidgetInit(). Except, for -// ChromeOS, use the root window from the AuraTestHelper rather than depending -// on ash::Shell:GetPrimaryRootWindow(). Also assume non-ChromeOS is never the -// Ash desktop, as that is covered by AppListViewTestAura. - if (!params->parent && !params->context) - params->context = parent_->GetContext(); -} - -} // namespace - -// Tests showing the app list with basic test model in an ash-style root window. -TEST_F(AppListViewTestAura, Display) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunDisplayTest()); -} - -// Tests showing the app list on the desktop. Note on ChromeOS, this will still -// use the regular root window. -TEST_F(AppListViewTestDesktop, Display) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunDisplayTest()); -} - -// Tests that the main grid view is shown after hiding and reshowing the app -// list with a folder view open. This is a regression test for crbug.com/357058. -TEST_F(AppListViewTestAura, ReshowWithOpenFolder) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunReshowWithOpenFolderTest()); -} - -TEST_F(AppListViewTestDesktop, ReshowWithOpenFolder) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunReshowWithOpenFolderTest()); -} - -// Tests that the start page view operates correctly. -TEST_F(AppListViewTestAura, StartPageTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunStartPageTest()); -} - -TEST_F(AppListViewTestDesktop, StartPageTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunStartPageTest()); -} - -// Tests that the start page view operates correctly. -TEST_F(AppListViewTestAura, PageSwitchingAnimationTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunPageSwitchingAnimationTest()); -} - -TEST_F(AppListViewTestDesktop, PageSwitchingAnimationTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunPageSwitchingAnimationTest()); -} - -// Tests that the correct views are displayed for showing search results. -TEST_F(AppListViewTestAura, SearchResultsTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunSearchResultsTest()); -} - -TEST_F(AppListViewTestDesktop, SearchResultsTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunSearchResultsTest()); -} - -// Tests that the back button navigates through the app list correctly. -TEST_F(AppListViewTestAura, BackTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunBackTest()); -} - -TEST_F(AppListViewTestDesktop, BackTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunBackTest()); -} - -// Tests that the correct views are displayed for showing search results. -TEST_F(AppListViewTestAura, AppListOverlayTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunAppListOverlayTest()); -} - -TEST_F(AppListViewTestDesktop, AppListOverlayTest) { - EXPECT_NO_FATAL_FAILURE(test_context_->RunAppListOverlayTest()); } } // namespace test
diff --git a/ui/base/ime/input_method_chromeos.cc b/ui/base/ime/input_method_chromeos.cc index 695e23ed..de201a30 100644 --- a/ui/base/ime/input_method_chromeos.cc +++ b/ui/base/ime/input_method_chromeos.cc
@@ -59,7 +59,7 @@ ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEvent( ui::KeyEvent* event, - std::unique_ptr<AckCallback> ack_callback) { + AckCallback ack_callback) { DCHECK(event->IsKeyEvent()); DCHECK(!(event->flags() & ui::EF_IS_SYNTHESIZED)); @@ -80,7 +80,7 @@ // generates some IME event, dispatch_details = ProcessKeyEventPostIME(event, true); if (ack_callback) - ack_callback->Run(true); + std::move(ack_callback).Run(true); return dispatch_details; } dispatch_details = ProcessUnfilteredKeyPressEvent(event); @@ -88,7 +88,7 @@ dispatch_details = DispatchKeyEventPostIME(event); } if (ack_callback) - ack_callback->Run(false); + std::move(ack_callback).Run(false); return dispatch_details; } @@ -112,17 +112,16 @@ return false; } -void InputMethodChromeOS::KeyEventDoneCallback( - ui::KeyEvent* event, - std::unique_ptr<AckCallback> ack_callback, - bool is_handled) { +void InputMethodChromeOS::KeyEventDoneCallback(ui::KeyEvent* event, + AckCallback ack_callback, + bool is_handled) { ignore_result( ProcessKeyEventDone(event, std::move(ack_callback), is_handled)); } ui::EventDispatchDetails InputMethodChromeOS::ProcessKeyEventDone( ui::KeyEvent* event, - std::unique_ptr<AckCallback> ack_callback, + AckCallback ack_callback, bool is_handled) { DCHECK(event); if (event->type() == ET_KEY_PRESSED) { @@ -138,7 +137,7 @@ } if (ack_callback) - ack_callback->Run(is_handled); + std::move(ack_callback).Run(is_handled); ui::EventDispatchDetails details; if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED) @@ -150,7 +149,7 @@ ui::EventDispatchDetails InputMethodChromeOS::DispatchKeyEvent( ui::KeyEvent* event) { - return DispatchKeyEvent(event, nullptr); + return DispatchKeyEvent(event, AckCallback()); } void InputMethodChromeOS::OnTextInputTypeChanged(
diff --git a/ui/base/ime/input_method_chromeos.h b/ui/base/ime/input_method_chromeos.h index 3dc5a3b..8c375a6 100644 --- a/ui/base/ime/input_method_chromeos.h +++ b/ui/base/ime/input_method_chromeos.h
@@ -28,10 +28,9 @@ explicit InputMethodChromeOS(internal::InputMethodDelegate* delegate); ~InputMethodChromeOS() override; - using AckCallback = base::Callback<void(bool)>; - ui::EventDispatchDetails DispatchKeyEvent( - ui::KeyEvent* event, - std::unique_ptr<AckCallback> ack_callback); + using AckCallback = base::OnceCallback<void(bool)>; + ui::EventDispatchDetails DispatchKeyEvent(ui::KeyEvent* event, + AckCallback ack_callback); // Overridden from InputMethod: bool OnUntranslatedIMEMessage(const base::NativeEvent& event, @@ -110,12 +109,12 @@ // Callback function for IMEEngineHandlerInterface::ProcessKeyEvent. void KeyEventDoneCallback(ui::KeyEvent* event, - std::unique_ptr<AckCallback> ack_callback, + AckCallback ack_callback, bool is_handled); - ui::EventDispatchDetails ProcessKeyEventDone( - ui::KeyEvent* event, - std::unique_ptr<AckCallback> ack_callback, - bool is_handled) WARN_UNUSED_RESULT; + ui::EventDispatchDetails ProcessKeyEventDone(ui::KeyEvent* event, + AckCallback ack_callback, + bool is_handled) + WARN_UNUSED_RESULT; // Returns whether an non-password input field is focused. bool IsNonPasswordInputFieldFocused();
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css index 46259a7..91b20ea 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -363,18 +363,6 @@ url(../images/files/ui/2x/share.png) 2x); } -#share-button > .icon { - background-image: -webkit-image-set( - url(../images/files/ui/person_add_white.png) 1x, - url(../images/files/ui/2x/person_add_white.png) 2x); -} - -body.check-select #share-button > .icon { - background-image: -webkit-image-set( - url(../images/files/ui/person_add.png) 1x, - url(../images/files/ui/2x/person_add.png) 2x); -} - #delete-button > .icon { background-image: -webkit-image-set( url(../images/files/ui/delete_white.png) 1x, @@ -1655,6 +1643,12 @@ padding-left: 32px; } +#share-menu cr-menu-item[command='#share'] { + background-image: -webkit-image-set( + url(../images/files/ui/person_add.png) 1x, + url(../images/files/ui/2x/person_add.png) 2x); +} + .detail-name > * { align-items: center; display: flex;
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/2x/person_add_white.png b/ui/file_manager/file_manager/foreground/images/files/ui/2x/person_add_white.png deleted file mode 100644 index 0f2a111..0000000 --- a/ui/file_manager/file_manager/foreground/images/files/ui/2x/person_add_white.png +++ /dev/null Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/files/ui/person_add_white.png b/ui/file_manager/file_manager/foreground/images/files/ui/person_add_white.png deleted file mode 100644 index 152e94b..0000000 --- a/ui/file_manager/file_manager/foreground/images/files/ui/person_add_white.png +++ /dev/null Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js index 05c41f8c..8e0fc74 100644 --- a/ui/file_manager/file_manager/foreground/js/file_tasks.js +++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -743,11 +743,29 @@ * @param {!Array<!Object>} tasks */ FileTasks.prototype.updateShareMenuButton_ = function(shareMenuButton, tasks) { - shareMenuButton.hidden = tasks.length == 0; - if (tasks.length == 0) - return; + var driveShareCommand = + shareMenuButton.menu.querySelector('cr-menu-item[command="#share"]'); + var driveShareCommandSeparator = + shareMenuButton.menu.querySelector('#drive-share-separator'); - shareMenuButton.menu.clear(); + shareMenuButton.hidden = driveShareCommand.disabled && tasks.length == 0; + + // Show the separator if Drive share command is enabled and there is at least + // one other share actions. + driveShareCommandSeparator.hidden = + driveShareCommand.disabled || tasks.length == 0; + + // Clear menu items except for drive share menu and a separator for it. + // As querySelectorAll() returns live NodeList, we need to copy elements to + // Array object to modify DOM in the for loop. + var itemsToRemove = [].slice.call( + shareMenuButton.menu.querySelectorAll('cr-menu-item[command~="share"]')); + for (var i = 0; i < itemsToRemove.length; i++) { + var item = itemsToRemove[i]; + item.parentNode.removeChild(item); + } + + // Add menu items for the new tasks. var items = this.createItems_(tasks); for (var i = 0; i < items.length; i++) { var menuitem = shareMenuButton.menu.addMenuItem(items[i]);
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js index ff34eb6..b6862c0 100644 --- a/ui/file_manager/file_manager/foreground/js/task_controller.js +++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -148,6 +148,11 @@ * @private */ TaskController.prototype.onTaskItemClicked_ = function(event) { + // If the clicked target has an associated command, the click event should not + // be handled here since it is handled as a command. + if (event.target && event.target.command) + return; + // 'select' event from ComboButton has the item as event.item. // 'activate' event from cr.ui.MenuButton has the item as event.target.data. var item = event.item || event.target.data;
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html index 0075dea..54dd735 100644 --- a/ui/file_manager/file_manager/main.html +++ b/ui/file_manager/file_manager/main.html
@@ -263,6 +263,8 @@ <cr-menu id="share-menu" class="chrome-menu files-menu" menu-item-selector="cr-menu-item, hr"> + <cr-menu-item command="#share"></cr-menu-item> + <hr id="drive-share-separator"> </cr-menu> <cr-menu id="add-new-services-menu" @@ -301,14 +303,6 @@ <files-toggle-ripple></files-toggle-ripple> <div class="icon"></div> </button> - <button id="share-button" class="icon-button" command="#share" - tabindex="11" hidden - i18n-values="aria-label:SHARE_BUTTON_LABEL" - visibleif="full-page" - has-tooltip> - <files-ripple></files-ripple> - <div class="icon"></div> - </button> <button id="delete-button" class="icon-button" tabindex="12" hidden i18n-values="aria-label:DELETE_BUTTON_LABEL" visibleif="full-page"
diff --git a/ui/file_manager/integration_tests/file_manager/share_dialog.js b/ui/file_manager/integration_tests/file_manager/share_dialog.js index 0ac284a..44d1249a 100644 --- a/ui/file_manager/integration_tests/file_manager/share_dialog.js +++ b/ui/file_manager/integration_tests/file_manager/share_dialog.js
@@ -24,15 +24,29 @@ // Wait for the share button. function(result) { chrome.test.assertTrue(result); - remoteCall.waitForElement(appId, '#share-button:not([disabled])'). - then(this.next); + remoteCall.waitForElement(appId, '#share-menu-button:not([disabled])') + .then(this.next); + }, + // Open share options menu + function(result) { + chrome.test.assertTrue(!!result); + remoteCall.callRemoteTestUtil( + 'fakeMouseClick', appId, ['#share-menu-button'], this.next); + }, + // Wait until the "Share with others" item is shown. + function(result) { + chrome.test.assertTrue(result); + remoteCall + .waitForElement( + appId, 'cr-menu-item[command="#share"]:not([disabled]') + .then(this.next); }, // Invoke the share dialog. function(result) { - remoteCall.callRemoteTestUtil('fakeMouseClick', - appId, - ['#share-button'], - this.next); + chrome.test.assertTrue(!!result); + remoteCall.callRemoteTestUtil( + 'fakeMouseClick', appId, ['cr-menu-item[command="#share"]'], + this.next); }, // Wait until the share dialog's contents are shown. function(result) {
diff --git a/ui/file_manager/integration_tests/file_manager/tab_index.js b/ui/file_manager/integration_tests/file_manager/tab_index.js index 04e14800..f32f5fc 100644 --- a/ui/file_manager/integration_tests/file_manager/tab_index.js +++ b/ui/file_manager/integration_tests/file_manager/tab_index.js
@@ -164,47 +164,61 @@ }, function(elements) { remoteCall.callRemoteTestUtil('getActiveElement', appId, [], this.next); - }, function(element) { + }, + function(element) { chrome.test.assertEq('list', element.attributes['class']); // Select the directory named 'photos'. remoteCall.callRemoteTestUtil( 'selectFile', appId, ['photos']).then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); - Promise.all([ - remoteCall.waitForElement( - appId, ['#share-button:not([hidden]):not([disabled])']), - remoteCall.waitForElement( - appId, ['#delete-button:not([hidden]):not([disabled])']), - ]).then(this.next); - // Press the Tab key. - }, function(elements) { - remoteCall.checkNextTabFocus(appId, 'share-button').then(this.next); - }, function(result) { + Promise + .all([ + remoteCall.waitForElement( + appId, ['#share-menu-button:not([hidden]):not([disabled])']), + remoteCall.waitForElement( + appId, ['#delete-button:not([hidden]):not([disabled])']), + ]) + .then(this.next); + // Press the Tab key. + }, + function(elements) { + remoteCall.checkNextTabFocus(appId, 'share-menu-button').then(this.next); + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'delete-button').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'search-button').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'view-button').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'sort-button').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'gear-button').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'directory-tree').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'drive-welcome-link').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); remoteCall.checkNextTabFocus(appId, 'file-list').then(this.next); - }, function(result) { + }, + function(result) { chrome.test.assertTrue(result); checkIfNoErrorsOccured(this.next); }