diff --git a/DEPS b/DEPS index 9076ffa..30c001f 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': '626575112bf0129d6cdf4ea5c843a2231a84fbbb', + 'v8_revision': '4b8a39354acd5949f3a389581fe6bda679a4e6d2', # 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. @@ -228,7 +228,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'ee5b9eaa30f9734c14c2d35130518b48da7eace6', # commit position 16098 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '3e52797e71d77b2d61bb31bf035314c030d0cfcc', # commit position 16104 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/chrome/VERSION b/chrome/VERSION index e6e5fc0..c04a571f 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=57 MINOR=0 -BUILD=2984 +BUILD=2985 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 792c49c..9fea3db 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -959,6 +959,8 @@ }; mMainTab = null; + // mHasCreatedTabEarly == true => mMainTab != null in the rest of the code. + mHasCreatedTabEarly = false; tab.detachAndStartReparenting(intent, startActivityOptions, finalizeCallback); } else { // Temporarily allowing disk access while fixing. TODO: http://crbug.com/581860
diff --git a/chrome/browser/browsing_data/browsing_data_remover.h b/chrome/browser/browsing_data/browsing_data_remover.h index aea1b61..79d79a2 100644 --- a/chrome/browser/browsing_data/browsing_data_remover.h +++ b/chrome/browser/browsing_data/browsing_data_remover.h
@@ -10,7 +10,6 @@ #include "base/time/time.h" #include "build/build_config.h" #include "chrome/browser/browsing_data/browsing_data_remover_delegate.h" -#include "chrome/common/features.h" //////////////////////////////////////////////////////////////////////////////// // BrowsingDataRemover is responsible for removing data related to browsing:
diff --git a/chrome/browser/browsing_data/browsing_data_remover_impl.cc b/chrome/browser/browsing_data/browsing_data_remover_impl.cc index 927a3e9..58c7550 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_impl.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_impl.cc
@@ -32,8 +32,6 @@ #include "content/public/browser/plugin_data_remover.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/user_metrics.h" -#include "extensions/features/features.h" -#include "media/media_features.h" #include "net/base/net_errors.h" #include "net/cookies/cookie_store.h" #include "net/http/http_network_session.h"
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc index 74b8913e..86af547 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
@@ -61,6 +61,7 @@ constexpr char kUnmanagedAuthToken[] = "unmanaged-auth-token"; constexpr char kWellKnownConsumerName[] = "test@gmail.com"; constexpr char kFakeUserName[] = "test@example.com"; +constexpr char kFakeGaiaId[] = "1234567890"; } // namespace @@ -183,7 +184,7 @@ profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); const AccountId account_id( - AccountId::FromUserEmailGaiaId(kFakeUserName, "1234567890")); + AccountId::FromUserEmailGaiaId(kFakeUserName, kFakeGaiaId)); GetFakeUserManager()->AddUser(account_id); GetFakeUserManager()->LoginUser(account_id); @@ -192,6 +193,13 @@ } void TearDownOnMainThread() override { + // Explicitly removing the user is required; otherwise ProfileHelper keeps + // a dangling pointer to the User. + // TODO(nya): Consider removing all users from ProfileHelper in the + // destructor of FakeChromeUserManager. + const AccountId account_id( + AccountId::FromUserEmailGaiaId(kFakeUserName, kFakeGaiaId)); + GetFakeUserManager()->RemoveUserFromList(account_id); ArcSessionManager::Get()->Shutdown(); ArcServiceManager::Get()->Shutdown(); profile_.reset();
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc index 261516ff..999c676a 100644 --- a/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc +++ b/chrome/browser/chromeos/arc/fileapi/arc_media_view_util.cc
@@ -13,7 +13,7 @@ } // namespace const base::Feature kMediaViewFeature{"ArcMediaView", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const char kMediaDocumentsProviderAuthority[] = "com.android.providers.media.documents";
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc index 00eadabc..219a2405c 100644 --- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc +++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -1218,7 +1218,12 @@ popup_model->result().default_match()->destination_url.spec()); } -IN_PROC_BROWSER_TEST_F(OmniboxViewTest, DeleteItem) { +#if defined(OS_WIN) +#define MAYBE_DeleteItem DISABLED_DeleteItem +#else +#define MAYBE_DeleteItem DeleteItem +#endif +IN_PROC_BROWSER_TEST_F(OmniboxViewTest, MAYBE_DeleteItem) { // Disable the search provider, to make sure the popup contains only history // items. TemplateURLService* model =
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index ed51898..c6c0c1bf 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -9189.0.0 \ No newline at end of file +9191.0.0 \ No newline at end of file
diff --git a/components/ntp_snippets/category_rankers/click_based_category_ranker.cc b/components/ntp_snippets/category_rankers/click_based_category_ranker.cc index 3fe59a8..8b78279 100644 --- a/components/ntp_snippets/category_rankers/click_based_category_ranker.cc +++ b/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
@@ -9,9 +9,11 @@ #include "base/memory/ptr_util.h" #include "base/values.h" #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" +#include "components/ntp_snippets/features.h" #include "components/ntp_snippets/pref_names.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "components/variations/variations_associated_data.h" namespace ntp_snippets { @@ -56,11 +58,19 @@ const int kDecayFactorDenominator = 100; // pow(0.91, 7) = 0.517 // Number of positions by which a dismissed category is downgraded. -const int kDismissedCategoryPenalty = 1; +const int kDefaultDismissedCategoryPenalty = 1; +const char* kDismissedCategoryPenaltyParamName = + "click_based_category_ranker-dismissed_category_penalty"; const char kCategoryIdKey[] = "category"; const char kClicksKey[] = "clicks"; +int GetDismissedCategoryPenaltyVariationValue() { + return variations::GetVariationParamByFeatureAsInt( + kCategoryRanker, kDismissedCategoryPenaltyParamName, + kDefaultDismissedCategoryPenalty); +} + } // namespace ClickBasedCategoryRanker::ClickBasedCategoryRanker( @@ -188,8 +198,14 @@ return; } + const int penalty = GetDismissedCategoryPenaltyVariationValue(); + if (penalty == 0) { + // The dismissed category penalty is turned off, the call is ignored. + return; + } + std::vector<RankedCategory>::iterator current = FindCategory(category); - for (int downgrade = 0; downgrade < kDismissedCategoryPenalty; ++downgrade) { + for (int downgrade = 0; downgrade < penalty; ++downgrade) { std::vector<RankedCategory>::iterator next = current + 1; if (next == ordered_categories_.end()) { break; @@ -232,7 +248,7 @@ // static int ClickBasedCategoryRanker::GetDismissedCategoryPenalty() { - return kDismissedCategoryPenalty; + return GetDismissedCategoryPenaltyVariationValue(); } ClickBasedCategoryRanker::RankedCategory::RankedCategory(Category category,
diff --git a/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc b/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc index 1956fea..7c19013 100644 --- a/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc +++ b/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
@@ -5,12 +5,16 @@ #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h" #include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" #include "base/test/simple_test_clock.h" #include "base/time/default_clock.h" #include "base/time/time.h" #include "components/ntp_snippets/category.h" #include "components/ntp_snippets/category_rankers/constant_category_ranker.h" +#include "components/ntp_snippets/features.h" +#include "components/ntp_snippets/ntp_snippets_constants.h" #include "components/prefs/testing_pref_service.h" +#include "components/variations/variations_params_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -65,12 +69,21 @@ ranker()->OnCategoryDismissed(category); } + void SetDismissedCategoryPenaltyVariationParam(int value) { + variation_params_manager_.SetVariationParamsWithFeatureAssociations( + ntp_snippets::kStudyName, + {{"click_based_category_ranker-dismissed_category_penalty", + base::IntToString(value)}}, + {kCategoryRanker.name}); + } + ClickBasedCategoryRanker* ranker() { return ranker_.get(); } private: std::unique_ptr<TestingPrefServiceSimple> pref_service_; int unused_remote_category_id_; std::unique_ptr<ClickBasedCategoryRanker> ranker_; + variations::testing::VariationParamsManager variation_params_manager_; DISALLOW_COPY_AND_ASSIGN(ClickBasedCategoryRankerTest); }; @@ -324,6 +337,8 @@ } TEST_F(ClickBasedCategoryRankerTest, ShouldMoveCategoryDownWhenDismissed) { + SetDismissedCategoryPenaltyVariationParam(2); + // Take top categories. std::vector<KnownCategories> default_order = ConstantCategoryRanker::GetKnownCategoriesDefaultOrder(); @@ -337,6 +352,8 @@ TEST_F(ClickBasedCategoryRankerTest, ShouldMoveSecondToLastCategoryDownWhenDismissed) { + SetDismissedCategoryPenaltyVariationParam(2); + // Add categories to the bottom. Category first = AddUnusedRemoteCategory(); Category second = AddUnusedRemoteCategory(); @@ -348,6 +365,8 @@ TEST_F(ClickBasedCategoryRankerTest, ShouldNotMoveCategoryTooMuchDownWhenDismissed) { + SetDismissedCategoryPenaltyVariationParam(2); + // Add enough categories to the end. std::vector<Category> categories; const int penalty = ClickBasedCategoryRanker::GetDismissedCategoryPenalty(); @@ -377,6 +396,8 @@ TEST_F(ClickBasedCategoryRankerTest, ShouldNotChangeOrderOfOtherCategoriesWhenDismissed) { + SetDismissedCategoryPenaltyVariationParam(2); + // Add enough categories to the end. std::vector<Category> categories; const int penalty = ClickBasedCategoryRanker::GetDismissedCategoryPenalty(); @@ -399,6 +420,8 @@ } TEST_F(ClickBasedCategoryRankerTest, ShouldNotMoveLastCategoryWhenDismissed) { + SetDismissedCategoryPenaltyVariationParam(2); + Category first = AddUnusedRemoteCategory(); Category second = AddUnusedRemoteCategory(); @@ -409,6 +432,8 @@ TEST_F(ClickBasedCategoryRankerTest, ShouldReduceLastCategoryClicksWhenDismissed) { + SetDismissedCategoryPenaltyVariationParam(2); + Category first = AddUnusedRemoteCategory(); Category second = AddUnusedRemoteCategory(); @@ -432,6 +457,46 @@ EXPECT_FALSE(CompareCategories(first, second)); } +TEST_F(ClickBasedCategoryRankerTest, + ShouldTakeVariationValueForDismissedCategoryPenalty) { + const int penalty = 10203; + SetDismissedCategoryPenaltyVariationParam(penalty); + EXPECT_EQ(penalty, ClickBasedCategoryRanker::GetDismissedCategoryPenalty()); +} + +TEST_F(ClickBasedCategoryRankerTest, + ShouldDoNothingWhenCategoryDismissedIfPenaltyIsZero) { + SetDismissedCategoryPenaltyVariationParam(0); + + // Add dummy remote categories to ensure that the following categories are not + // in the top anymore. + AddUnusedRemoteCategories( + ClickBasedCategoryRanker::GetNumTopCategoriesWithExtraMargin()); + + Category first = AddUnusedRemoteCategory(); + Category second = AddUnusedRemoteCategory(); + Category third = AddUnusedRemoteCategory(); + + NotifyOnSuggestionOpened( + /*times=*/1, second); + + // This should be ignored, because the penalty is set to 0. + NotifyOnCategoryDismissed(second); + + // The second category should stay where it was. + EXPECT_TRUE(CompareCategories(first, second)); + EXPECT_TRUE(CompareCategories(second, third)); + + // Try to move the second category up assuming that the previous click is + // still there. + NotifyOnSuggestionOpened( + /*times=*/ClickBasedCategoryRanker::GetPassingMargin() - 1, second); + + // It should overtake the first category, because the dismissal should be + // ignored and the click should remain. + EXPECT_FALSE(CompareCategories(first, second)); +} + TEST_F(ClickBasedCategoryRankerTest, ShouldRestoreDefaultOrderOnClearHistory) { std::vector<KnownCategories> default_order = ConstantCategoryRanker::GetKnownCategoriesDefaultOrder();
diff --git a/content/browser/service_worker/service_worker_context_request_handler.cc b/content/browser/service_worker/service_worker_context_request_handler.cc index ed72f5f..520e5b61 100644 --- a/content/browser/service_worker/service_worker_context_request_handler.cc +++ b/content/browser/service_worker/service_worker_context_request_handler.cc
@@ -65,18 +65,16 @@ switch (status) { case CreateJobStatus::UNINITIALIZED: return "UNINITIALIZED"; - case CreateJobStatus::WRITE_JOB_FOR_REGISTER: - return "WRITE_JOB_FOR_REGISTER"; - case CreateJobStatus::WRITE_JOB_FOR_UPDATE: - return "WRITE_JOB_FOR_UPDATE"; + case CreateJobStatus::WRITE_JOB: + return "WRITE_JOB"; + case CreateJobStatus::WRITE_JOB_WITH_INCUMBENT: + return "WRITE_JOB_WITH_INCUMBENT"; case CreateJobStatus::READ_JOB: return "READ_JOB"; case CreateJobStatus::READ_JOB_FOR_DUPLICATE_SCRIPT_IMPORT: return "READ_JOB_FOR_DUPLICATE_SCRIPT_IMPORT"; case CreateJobStatus::ERROR_NO_PROVIDER: return "ERROR_NO_PROVIDER"; - case CreateJobStatus::ERROR_NO_VERSION: - return "ERROR_NO_VERSION"; case CreateJobStatus::ERROR_REDUNDANT_VERSION: return "ERROR_REDUNDANT_VERSION"; case CreateJobStatus::ERROR_NO_CONTEXT: @@ -113,7 +111,8 @@ net::URLRequestJob* job = MaybeCreateJobImpl(request, network_delegate, &status); const bool is_main_script = resource_type_ == RESOURCE_TYPE_SERVICE_WORKER; - // TODO(falken): Add UMA for CreateJobStatus. + ServiceWorkerMetrics::RecordContextRequestHandlerStatus( + status, IsInstalled(version_.get()), is_main_script); if (is_main_script) version_->NotifyMainScriptJobCreated(status); if (job) @@ -146,18 +145,15 @@ net::URLRequest* request, net::NetworkDelegate* network_delegate, CreateJobStatus* out_status) { - if (!provider_host_) { - *out_status = CreateJobStatus::ERROR_NO_PROVIDER; - return nullptr; - } if (!context_) { *out_status = CreateJobStatus::ERROR_NO_CONTEXT; return nullptr; } - if (!version_) { - *out_status = CreateJobStatus::ERROR_NO_VERSION; + if (!provider_host_) { + *out_status = CreateJobStatus::ERROR_NO_PROVIDER; return nullptr; } + // This could happen if browser-side has set the status to redundant but the // worker has not yet stopped. The worker is already doomed so just reject the // request. Handle it specially here because otherwise it'd be unclear whether @@ -227,15 +223,16 @@ ? registration->waiting_version() : registration->active_version(); int64_t incumbent_resource_id = kInvalidServiceWorkerResourceId; - if (stored_version && stored_version->script_url() == request->url()) { - incumbent_resource_id = - stored_version->script_cache_map()->LookupResourceId(request->url()); - } - if (is_main_script) + if (is_main_script) { + if (stored_version && stored_version->script_url() == request->url()) { + incumbent_resource_id = + stored_version->script_cache_map()->LookupResourceId(request->url()); + } version_->embedded_worker()->OnURLJobCreatedForMainScript(); + } *out_status = incumbent_resource_id == kInvalidServiceWorkerResourceId - ? CreateJobStatus::WRITE_JOB_FOR_REGISTER - : CreateJobStatus::WRITE_JOB_FOR_UPDATE; + ? CreateJobStatus::WRITE_JOB + : CreateJobStatus::WRITE_JOB_WITH_INCUMBENT; return new ServiceWorkerWriteToCacheJob( request, network_delegate, resource_type_, context_, version_.get(), extra_load_flags, resource_id, incumbent_resource_id);
diff --git a/content/browser/service_worker/service_worker_context_request_handler.h b/content/browser/service_worker/service_worker_context_request_handler.h index 1f00dabf..26bf3869 100644 --- a/content/browser/service_worker/service_worker_context_request_handler.h +++ b/content/browser/service_worker/service_worker_context_request_handler.h
@@ -19,22 +19,38 @@ class CONTENT_EXPORT ServiceWorkerContextRequestHandler : public ServiceWorkerRequestHandler { public: + // The result status for MaybeCreateJob. Used in histograms. Append-only. enum class CreateJobStatus { + // Unitialized status. UNINITIALIZED, - WRITE_JOB_FOR_REGISTER, - WRITE_JOB_FOR_UPDATE, + // A ServiceWorkerWriteToCacheJob was created. + WRITE_JOB, + // A ServiceWorkerWriteToCacheJob was created with an incumbent script to + // compare against. + WRITE_JOB_WITH_INCUMBENT, + // A ServiceWorkerReadFromCacheJob was created. READ_JOB, - // When a new worker imports a script that was already imported. + // A ServiceWorkerReadFromCacheJob was created for a new worker that is + // importing a script that was already imported. READ_JOB_FOR_DUPLICATE_SCRIPT_IMPORT, + // A job could not be created because there is no live + // ServiceWorkerProviderHost. ERROR_NO_PROVIDER, - ERROR_NO_VERSION, + // A job could not be created because the ServiceWorkerVersion is in status + // REDUNDANT. ERROR_REDUNDANT_VERSION, + // A job could not be created because there is no live + // ServiceWorkerContextCore. ERROR_NO_CONTEXT, + // A job could not be created because a redirect occurred. ERROR_REDIRECT, - // When an installed worker imports a script that was not stored at - // installation time. + // A job was not created because an installed worker is importing a script + // that was not stored at installation time. ERROR_UNINSTALLED_SCRIPT_IMPORT, + // A job could not be created because there are no resource ids available. ERROR_OUT_OF_RESOURCE_IDS, + // Add new types here. + NUM_TYPES };
diff --git a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc index 96486459f..c6ed19f 100644 --- a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc +++ b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -9,6 +9,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/logging.h" #include "base/run_loop.h" +#include "base/test/histogram_tester.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/fileapi/mock_url_request_delegate.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" @@ -30,12 +31,6 @@ namespace content { -namespace { - -void EmptyCallback() {} - -} // namespace - class MockHttpProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { public: @@ -62,29 +57,19 @@ void SetUp() override { helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath())); + context()->storage()->LazyInitialize(base::Bind(&base::DoNothing)); + base::RunLoop().RunUntilIdle(); // A new unstored registration/version. scope_ = GURL("https://host/scope/"); script_url_ = GURL("https://host/script.js"); + import_script_url_ = GURL("https://host/import.js"); registration_ = new ServiceWorkerRegistration( scope_, 1L, context()->AsWeakPtr()); - version_ = new ServiceWorkerVersion( - registration_.get(), script_url_, 1L, context()->AsWeakPtr()); - - // A provider host for the version. - std::unique_ptr<ServiceWorkerProviderHost> host( - new ServiceWorkerProviderHost( - helper_->mock_render_process_id(), - MSG_ROUTING_NONE /* render_frame_id */, 1 /* provider_id */, - SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, - ServiceWorkerProviderHost::FrameSecurityLevel::SECURE, - context()->AsWeakPtr(), nullptr)); - provider_host_ = host->AsWeakPtr(); - context()->AddProviderHost(std::move(host)); - provider_host_->running_hosted_version_ = version_; - - context()->storage()->LazyInitialize(base::Bind(&EmptyCallback)); - base::RunLoop().RunUntilIdle(); + version_ = new ServiceWorkerVersion(registration_.get(), script_url_, + context()->storage()->NewVersionId(), + context()->AsWeakPtr()); + SetUpProvider(); std::unique_ptr<MockHttpProtocolHandler> handler( new MockHttpProtocolHandler( @@ -101,11 +86,43 @@ ServiceWorkerContextCore* context() const { return helper_->context(); } - EmbeddedWorkerTestHelper* helper() { return helper_.get(); } - ServiceWorkerVersion* version() { return version_.get(); } - ServiceWorkerProviderHost* provider_host() { return provider_host_.get(); } - storage::BlobStorageContext* blob_storage_context() { - return &blob_storage_context_; + void SetUpProvider() { + std::unique_ptr<ServiceWorkerProviderHost> host( + new ServiceWorkerProviderHost( + helper_->mock_render_process_id(), + MSG_ROUTING_NONE /* render_frame_id */, 1 /* provider_id */, + SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, + ServiceWorkerProviderHost::FrameSecurityLevel::SECURE, + context()->AsWeakPtr(), nullptr)); + provider_host_ = host->AsWeakPtr(); + context()->AddProviderHost(std::move(host)); + provider_host_->running_hosted_version_ = version_; + } + + std::unique_ptr<net::URLRequest> CreateRequest(const GURL& url) { + return url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, + &url_request_delegate_); + } + + // Creates a ServiceWorkerContextHandler directly. + std::unique_ptr<ServiceWorkerContextRequestHandler> CreateHandler( + ResourceType resource_type) { + return base::MakeUnique<ServiceWorkerContextRequestHandler>( + context()->AsWeakPtr(), provider_host_, + base::WeakPtr<storage::BlobStorageContext>(), resource_type); + } + + // Associates a ServiceWorkerRequestHandler with a request. Use this instead + // of CreateHandler if you want to actually start the request to test what the + // job created by the handler does. + void InitializeHandler(net::URLRequest* request) { + ServiceWorkerRequestHandler::InitializeHandler( + request, helper_->context_wrapper(), &blob_storage_context_, + helper_->mock_render_process_id(), provider_host_->provider_id(), + false /* skip_service_worker */, FETCH_REQUEST_MODE_NO_CORS, + FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE, + RESOURCE_TYPE_SERVICE_WORKER, REQUEST_CONTEXT_TYPE_SERVICE_WORKER, + REQUEST_CONTEXT_FRAME_TYPE_NONE, nullptr); } protected: @@ -119,6 +136,7 @@ net::URLRequestJobFactoryImpl url_request_job_factory_; GURL scope_; GURL script_url_; + GURL import_script_url_; storage::BlobStorageContext blob_storage_context_; }; @@ -129,19 +147,20 @@ version_->SetStatus(ServiceWorkerVersion::NEW); // Conduct a resource fetch for the main script. - const GURL kScriptUrl("https://host/script.js"); - std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest( - kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_); + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); std::unique_ptr<ServiceWorkerContextRequestHandler> handler( - new ServiceWorkerContextRequestHandler( - context()->AsWeakPtr(), provider_host_, - base::WeakPtr<storage::BlobStorageContext>(), - RESOURCE_TYPE_SERVICE_WORKER)); + CreateHandler(RESOURCE_TYPE_SERVICE_WORKER)); std::unique_ptr<net::URLRequestJob> job( handler->MaybeCreateJob(request.get(), nullptr, nullptr)); ASSERT_TRUE(job.get()); ServiceWorkerWriteToCacheJob* sw_job = static_cast<ServiceWorkerWriteToCacheJob*>(job.get()); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::WRITE_JOB), + 1); // Verify the net request is not initialized to bypass the browser cache. EXPECT_FALSE(sw_job->net_request_->load_flags() & net::LOAD_BYPASS_CACHE); @@ -155,19 +174,20 @@ version_->SetStatus(ServiceWorkerVersion::NEW); // Conduct a resource fetch for the main script. - const GURL kScriptUrl("https://host/script.js"); - std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest( - kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_); + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); std::unique_ptr<ServiceWorkerContextRequestHandler> handler( - new ServiceWorkerContextRequestHandler( - context()->AsWeakPtr(), provider_host_, - base::WeakPtr<storage::BlobStorageContext>(), - RESOURCE_TYPE_SERVICE_WORKER)); + CreateHandler(RESOURCE_TYPE_SERVICE_WORKER)); std::unique_ptr<net::URLRequestJob> job( handler->MaybeCreateJob(request.get(), nullptr, nullptr)); ASSERT_TRUE(job.get()); ServiceWorkerWriteToCacheJob* sw_job = static_cast<ServiceWorkerWriteToCacheJob*>(job.get()); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::WRITE_JOB), + 1); // Verify the net request is initialized to bypass the browser cache. EXPECT_TRUE(sw_job->net_request_->load_flags() & net::LOAD_BYPASS_CACHE); @@ -181,14 +201,9 @@ version_->set_force_bypass_cache_for_scripts(true); // Conduct a resource fetch for the main script. - const GURL kScriptUrl("https://host/script.js"); - std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest( - kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_); + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); std::unique_ptr<ServiceWorkerContextRequestHandler> handler( - new ServiceWorkerContextRequestHandler( - context()->AsWeakPtr(), provider_host_, - base::WeakPtr<storage::BlobStorageContext>(), - RESOURCE_TYPE_SERVICE_WORKER)); + CreateHandler(RESOURCE_TYPE_SERVICE_WORKER)); std::unique_ptr<net::URLRequestJob> job( handler->MaybeCreateJob(request.get(), nullptr, nullptr)); ASSERT_TRUE(job.get()); @@ -204,20 +219,21 @@ version_->SetStatus(ServiceWorkerVersion::NEW); // Conduct a resource fetch for the main script. - const GURL kScriptUrl("https://host/script.js"); - std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest( - kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_); + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); std::unique_ptr<ServiceWorkerContextRequestHandler> handler( - new ServiceWorkerContextRequestHandler( - context()->AsWeakPtr(), provider_host_, - base::WeakPtr<storage::BlobStorageContext>(), - RESOURCE_TYPE_SERVICE_WORKER)); + CreateHandler(RESOURCE_TYPE_SERVICE_WORKER)); std::unique_ptr<net::URLRequestJob> job( handler->MaybeCreateJob(request.get(), nullptr, nullptr)); ASSERT_TRUE(job.get()); ServiceWorkerWriteToCacheJob* sw_job = static_cast<ServiceWorkerWriteToCacheJob*>(job.get()); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::WRITE_JOB), + 1); // Verify that the request is properly annotated as originating from a // Service Worker. EXPECT_TRUE(ResourceRequestInfo::OriginatedFromServiceWorker( @@ -230,9 +246,7 @@ SkipServiceWorkerForServiceWorkerRequest) { // Conduct a resource fetch for the main script. version_->SetStatus(ServiceWorkerVersion::NEW); - const GURL kScriptUrl("https://host/script.js"); - std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest( - kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_); + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); ServiceWorkerRequestHandler::InitializeHandler( request.get(), helper_->context_wrapper(), &blob_storage_context_, helper_->mock_render_process_id(), provider_host_->provider_id(), @@ -246,25 +260,182 @@ EXPECT_TRUE(handler); } -TEST_F(ServiceWorkerContextRequestHandlerTest, RedundantVersion) { - // Create a redundant version. - version_->SetStatus(ServiceWorkerVersion::REDUNDANT); +TEST_F(ServiceWorkerContextRequestHandlerTest, NewWorker) { + // Conduct a resource fetch for the main script. + { + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); + std::unique_ptr<ServiceWorkerContextRequestHandler> handler( + CreateHandler(RESOURCE_TYPE_SERVICE_WORKER)); + std::unique_ptr<net::URLRequestJob> job( + handler->MaybeCreateJob(request.get(), nullptr, nullptr)); + EXPECT_TRUE(job); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::WRITE_JOB), + 1); + } + + // Conduct a resource fetch for an imported script. + { + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(import_script_url_)); + std::unique_ptr<ServiceWorkerContextRequestHandler> handler( + CreateHandler(RESOURCE_TYPE_SCRIPT)); + std::unique_ptr<net::URLRequestJob> job( + handler->MaybeCreateJob(request.get(), nullptr, nullptr)); + EXPECT_TRUE(job); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.ImportedScript", + static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::WRITE_JOB), + 1); + } +} + +TEST_F(ServiceWorkerContextRequestHandlerTest, InstalledWorker) { + using Resource = ServiceWorkerDatabase::ResourceRecord; + std::vector<Resource> resources = { + Resource(context()->storage()->NewResourceId(), script_url_, 100), + Resource(context()->storage()->NewResourceId(), import_script_url_, 100)}; + version_->script_cache_map()->SetResources(resources); + version_->set_fetch_handler_existence( + ServiceWorkerVersion::FetchHandlerExistence::EXISTS); + version_->SetStatus(ServiceWorkerVersion::ACTIVATED); + registration_->SetActiveVersion(version_); // Conduct a resource fetch for the main script. - std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest( - version_->script_url(), net::DEFAULT_PRIORITY, &url_request_delegate_); - ServiceWorkerRequestHandler::InitializeHandler( - request.get(), helper()->context_wrapper(), blob_storage_context(), - helper()->mock_render_process_id(), provider_host()->provider_id(), - true /* skip_service_worker */, FETCH_REQUEST_MODE_NO_CORS, - FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE, - RESOURCE_TYPE_SERVICE_WORKER, REQUEST_CONTEXT_TYPE_SERVICE_WORKER, - REQUEST_CONTEXT_FRAME_TYPE_NONE, nullptr); + { + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); + std::unique_ptr<ServiceWorkerContextRequestHandler> handler( + CreateHandler(RESOURCE_TYPE_SERVICE_WORKER)); + std::unique_ptr<net::URLRequestJob> job( + handler->MaybeCreateJob(request.get(), nullptr, nullptr)); + EXPECT_TRUE(job); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.InstalledWorker.MainScript", + static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::READ_JOB), + 1); + } - // Verify that the request fails. - request->Start(); - base::RunLoop().Run(); - EXPECT_EQ(net::ERR_FAILED, url_request_delegate_.request_status()); + // Conduct a resource fetch for an imported script. + { + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(import_script_url_)); + std::unique_ptr<ServiceWorkerContextRequestHandler> handler( + CreateHandler(RESOURCE_TYPE_SCRIPT)); + std::unique_ptr<net::URLRequestJob> job( + handler->MaybeCreateJob(request.get(), nullptr, nullptr)); + EXPECT_TRUE(job); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.InstalledWorker." + "ImportedScript", + static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::READ_JOB), + 1); + } +} + +TEST_F(ServiceWorkerContextRequestHandlerTest, Incumbent) { + // Make an incumbent version. + scoped_refptr<ServiceWorkerVersion> incumbent = new ServiceWorkerVersion( + registration_.get(), script_url_, context()->storage()->NewVersionId(), + context()->AsWeakPtr()); + incumbent->set_fetch_handler_existence( + ServiceWorkerVersion::FetchHandlerExistence::EXISTS); + std::vector<ServiceWorkerDatabase::ResourceRecord> resources = { + ServiceWorkerDatabase::ResourceRecord( + context()->storage()->NewResourceId(), script_url_, 100)}; + incumbent->script_cache_map()->SetResources(resources); + incumbent->SetStatus(ServiceWorkerVersion::ACTIVATED); + registration_->SetActiveVersion(incumbent); + + // Make a new version. + version_->SetStatus(ServiceWorkerVersion::NEW); + + // Conduct a resource fetch for the main script. + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); + std::unique_ptr<ServiceWorkerContextRequestHandler> handler( + CreateHandler(RESOURCE_TYPE_SERVICE_WORKER)); + std::unique_ptr<net::URLRequestJob> job( + handler->MaybeCreateJob(request.get(), nullptr, nullptr)); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>(ServiceWorkerContextRequestHandler::CreateJobStatus:: + WRITE_JOB_WITH_INCUMBENT), + 1); +} + +TEST_F(ServiceWorkerContextRequestHandlerTest, ErrorCases) { + { + // Set up a request. + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); + InitializeHandler(request.get()); + + // Make the version redundant. + version_->SetStatus(ServiceWorkerVersion::REDUNDANT); + + // Verify that the request fails. + request->Start(); + base::RunLoop().Run(); + EXPECT_EQ(net::ERR_FAILED, url_request_delegate_.request_status()); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>(ServiceWorkerContextRequestHandler::CreateJobStatus:: + ERROR_REDUNDANT_VERSION), + 1); + } + // Return the version to normal. + version_->SetStatus(ServiceWorkerVersion::NEW); + + { + // Set up a request. + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); + InitializeHandler(request.get()); + + // Remove the host. + context()->RemoveProviderHost(helper_->mock_render_process_id(), + provider_host_->provider_id()); + + // Verify that the request fails. + request->Start(); + base::RunLoop().Run(); + EXPECT_EQ(net::ERR_FAILED, url_request_delegate_.request_status()); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>(ServiceWorkerContextRequestHandler::CreateJobStatus:: + ERROR_NO_PROVIDER), + 1); + } + // Recreate the host. + SetUpProvider(); + + { + // Set up a request. + base::HistogramTester histograms; + std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_)); + InitializeHandler(request.get()); + + // Destroy the context. + helper_->ShutdownContext(); + base::RunLoop().RunUntilIdle(); + + // Verify that the request fails. + request->Start(); + base::RunLoop().Run(); + EXPECT_EQ(net::ERR_FAILED, url_request_delegate_.request_status()); + histograms.ExpectUniqueSample( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + static_cast<int>(ServiceWorkerContextRequestHandler::CreateJobStatus:: + ERROR_NO_CONTEXT), + 1); + } } } // namespace content
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc index d7c7533b..af9dcb1 100644 --- a/content/browser/service_worker/service_worker_metrics.cc +++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -767,4 +767,37 @@ size); } +void ServiceWorkerMetrics::RecordContextRequestHandlerStatus( + ServiceWorkerContextRequestHandler::CreateJobStatus status, + bool is_installed, + bool is_main_script) { + const int value = static_cast<int>(status); + const int max = static_cast<int>( + ServiceWorkerContextRequestHandler::CreateJobStatus::NUM_TYPES); + if (is_installed) { + if (is_main_script) { + UMA_HISTOGRAM_ENUMERATION( + "ServiceWorker.ContextRequestHandlerStatus.InstalledWorker." + "MainScript", + value, max); + } else { + UMA_HISTOGRAM_ENUMERATION( + "ServiceWorker.ContextRequestHandlerStatus.InstalledWorker." + "ImportedScript", + value, max); + } + } else { + if (is_main_script) { + UMA_HISTOGRAM_ENUMERATION( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript", + value, max); + } else { + UMA_HISTOGRAM_ENUMERATION( + "ServiceWorker.ContextRequestHandlerStatus.NewWorker." + "ImportedScript", + value, max); + } + } +} + } // namespace content
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h index 9b75bd3f..40b340d 100644 --- a/content/browser/service_worker/service_worker_metrics.h +++ b/content/browser/service_worker/service_worker_metrics.h
@@ -290,6 +290,13 @@ // navigation preload request is to be sent. static void RecordNavigationPreloadRequestHeaderSize(size_t size); + // Records the result of trying to handle a request for a service worker + // script. + static void RecordContextRequestHandlerStatus( + ServiceWorkerContextRequestHandler::CreateJobStatus status, + bool is_installed, + bool is_main_script); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceWorkerMetrics); };
diff --git a/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm b/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm index 8b919655..f151874 100644 --- a/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm +++ b/ios/chrome/browser/reading_list/reading_list_web_state_observer.mm
@@ -282,18 +282,39 @@ DCHECK(entry->DistilledState() == ReadingListEntry::PROCESSED); GURL url = reading_list::DistilledURLForPath(entry->DistilledPath(), entry->URL()); - web::NavigationManager* manager = web_state()->GetNavigationManager(); - web::NavigationItem* item = manager->GetPendingItem(); - if (item) { + web::NavigationManager* navigationManager = + web_state()->GetNavigationManager(); + web::NavigationItem* item = navigationManager->GetPendingItem(); + if (!item) { + // Either the loading finished on error and the item is already committed, + // or the page is being reloaded and due to crbug.com/676129. there is no + // pending item. Either way, the correct item to reuse is the last committed + // item. + // TODO(crbug.com/676129): this case can be removed. + item = navigationManager->GetLastCommittedItem(); + item->SetURL(url); + item->SetVirtualURL(pending_url_); + navigationManager->Reload(false); + } else if (navigationManager->GetPendingItemIndex() != -1 && + navigationManager->GetItemAtIndex( + navigationManager->GetPendingItemIndex()) == item) { + // The navigation corresponds to a back/forward. The item on the stack can + // be reused for the offline navigation. + // TODO(crbug.com/665189): GetPendingItemIndex() will return currentEntry() + // if navigating to a new URL. Test the addresses to verify that + // GetPendingItemIndex() actually returns the pending item index. Remove + // this extra test on item addresses once bug 665189 is fixed. + item->SetURL(url); + item->SetVirtualURL(pending_url_); + navigationManager->GoToIndex(navigationManager->GetPendingItemIndex()); + } else { + // The pending item corresponds to a new navigation and will be discarded + // on next navigation. + // Trigger a new navigation on the offline URL. web::WebState::OpenURLParams params(url, item->GetReferrer(), WindowOpenDisposition::CURRENT_TAB, item->GetTransitionType(), NO); web_state()->OpenURL(params); - } else { - item = manager->GetLastCommittedItem(); - item->SetURL(url); - item->SetVirtualURL(pending_url_); - web_state()->GetNavigationManager()->Reload(false); } reading_list_model_->SetReadStatus(entry->URL(), true); UMA_HISTOGRAM_BOOLEAN("ReadingList.OfflineVersionDisplayed", true);
diff --git a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm index 4f30e28..43d8f04f 100644 --- a/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm +++ b/ios/chrome/browser/reading_list/reading_list_web_state_observer_unittest.mm
@@ -120,13 +120,18 @@ GURL distilled_url = reading_list::DistilledURLForPath(entry->DistilledPath(), entry->URL()); - test_navigation_manager_->GetPendingItem()->SetURL(url); + // Test on commited entry, there must be no pending item. + test_navigation_manager_->SetPendingItem(nullptr); + test_navigation_manager_->GetLastCommittedItem()->SetURL(url); test_web_state_.SetLoading(true); test_web_state_.OnPageLoaded(web::PageLoadCompletionStatus::FAILURE); test_web_state_.SetLoading(false); - EXPECT_FALSE(test_navigation_manager_->ReloadCalled()); - EXPECT_EQ(test_web_state_.LastOpenedUrl(), distilled_url); + EXPECT_TRUE(test_navigation_manager_->ReloadCalled()); + EXPECT_EQ(test_navigation_manager_->GetLastCommittedItem()->GetVirtualURL(), + url); + EXPECT_EQ(test_navigation_manager_->GetLastCommittedItem()->GetURL(), + distilled_url); EXPECT_TRUE(entry->IsRead()); }
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index b768c1e4..6749fc2 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -2455,20 +2455,6 @@ if (web::UrlHasWebScheme(link)) { web::Referrer referrer([_model currentTab].url, params.referrer_policy); - if (reading_list::switches::IsReadingListEnabled()) { - NSString* innerText = params.link_text; - if ([innerText length] > 0) { - // Add to reading list. - title = l10n_util::GetNSStringWithFixup( - IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST); - action = ^{ - Record(ACTION_READ_LATER, isImage, isLink); - [weakSelf addToReadingListURL:link title:innerText]; - }; - [_contextMenuCoordinator addItemWithTitle:title action:action]; - } - } - // Open in New Tab. title = l10n_util::GetNSStringWithFixup( IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB); @@ -2496,6 +2482,20 @@ }; [_contextMenuCoordinator addItemWithTitle:title action:action]; } + + if (reading_list::switches::IsReadingListEnabled()) { + NSString* innerText = params.link_text; + if ([innerText length] > 0) { + // Add to reading list. + title = l10n_util::GetNSStringWithFixup( + IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST); + action = ^{ + Record(ACTION_READ_LATER, isImage, isLink); + [weakSelf addToReadingListURL:link title:innerText]; + }; + [_contextMenuCoordinator addItemWithTitle:title action:action]; + } + } } // Copy Link. title = l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_COPY);
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm index 6d78d91..42ebcf2 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
@@ -151,12 +151,16 @@ - (void)initializeActionSheet; // Exits the editing mode and update the toolbar state with animation. - (void)exitEditingModeAnimated:(BOOL)animated; -// Applies |action| to every cell in the section |identifier|. +// Applies |updater| to the URL of every cell in the section |identifier|. The +// updates are done in reverse order of the cells in the section to keep the +// order. The monitoring of the model updates are suspended during this time. - (void)updateItemsInSectionIdentifier:(SectionIdentifier)identifier usingEntryUpdater:(EntryUpdater)updater; -// Applies |action| to every selected element of collection view. The monitoring -// of the model updates is stopped during this time. -- (void)updateSelectedItemsWithEntryUpdater:(EntryUpdater)updater; +// Applies |updater| to the URL of every element in |indexPaths|. The updates +// are done in reverse order |indexPaths| to keep the order. The monitoring of +// the model updates are suspended during this time. +- (void)updateIndexPaths:(NSArray<NSIndexPath*>*)indexPaths + usingEntryUpdater:(EntryUpdater)updater; // Logs the deletions histograms for the entry with |url|. - (void)logDeletionHistogramsForEntry:(const GURL&)url; // Move all the items from |sourceSectionIdentifier| to @@ -810,24 +814,26 @@ - (void)markItemsRead { base::RecordAction(base::UserMetricsAction("MobileReadingListMarkRead")); - [self updateSelectedItemsWithEntryUpdater:^(const GURL& url) { - [self readingListModel]->SetReadStatus(url, true); - }]; - NSArray* sortedIndexPaths = [self.collectionView.indexPathsForSelectedItems sortedArrayUsingSelector:@selector(compare:)]; + [self updateIndexPaths:sortedIndexPaths + usingEntryUpdater:^(const GURL& url) { + [self readingListModel]->SetReadStatus(url, true); + }]; + [self exitEditingModeAnimated:YES]; [self moveSelectedItems:sortedIndexPaths toSection:SectionIdentifierRead]; } - (void)markItemsUnread { base::RecordAction(base::UserMetricsAction("MobileReadingListMarkUnread")); - [self updateSelectedItemsWithEntryUpdater:^(const GURL& url) { - [self readingListModel]->SetReadStatus(url, false); - }]; - NSArray* sortedIndexPaths = [self.collectionView.indexPathsForSelectedItems sortedArrayUsingSelector:@selector(compare:)]; + [self updateIndexPaths:sortedIndexPaths + usingEntryUpdater:^(const GURL& url) { + [self readingListModel]->SetReadStatus(url, false); + }]; + [self exitEditingModeAnimated:YES]; [self moveSelectedItems:sortedIndexPaths toSection:SectionIdentifierUnread]; } @@ -864,12 +870,13 @@ } - (void)deleteSelectedItems { - [self updateSelectedItemsWithEntryUpdater:^(const GURL& url) { - [self logDeletionHistogramsForEntry:url]; - [self readingListModel]->RemoveEntryByURL(url); - }]; - NSArray* indexPaths = [self.collectionView.indexPathsForSelectedItems copy]; + [self updateIndexPaths:indexPaths + usingEntryUpdater:^(const GURL& url) { + [self logDeletionHistogramsForEntry:url]; + [self readingListModel]->RemoveEntryByURL(url); + }]; + [self exitEditingModeAnimated:YES]; [self.collectionView performBatchUpdates:^{ @@ -889,21 +896,27 @@ - (void)updateItemsInSectionIdentifier:(SectionIdentifier)identifier usingEntryUpdater:(EntryUpdater)updater { + _shouldMonitorModel = NO; auto token = self.readingListModel->BeginBatchUpdates(); NSArray* readItems = [self.collectionViewModel itemsInSectionWithIdentifier:identifier]; - for (id item in readItems) { + // Read the objects in reverse order to keep the order (last modified first). + for (id item in [readItems reverseObjectEnumerator]) { ReadingListCollectionViewItem* readingListItem = base::mac::ObjCCastStrict<ReadingListCollectionViewItem>(item); if (updater) updater(readingListItem.url); } + token.reset(); + _shouldMonitorModel = YES; } -- (void)updateSelectedItemsWithEntryUpdater:(EntryUpdater)updater { +- (void)updateIndexPaths:(NSArray<NSIndexPath*>*)indexPaths + usingEntryUpdater:(EntryUpdater)updater { _shouldMonitorModel = NO; auto token = self.readingListModel->BeginBatchUpdates(); - for (NSIndexPath* index in self.collectionView.indexPathsForSelectedItems) { + // Read the objects in reverse order to keep the order (last modified first). + for (NSIndexPath* index in [indexPaths reverseObjectEnumerator]) { CollectionViewItem* cell = [self.collectionViewModel itemAtIndexPath:index]; ReadingListCollectionViewItem* readingListItem = base::mac::ObjCCastStrict<ReadingListCollectionViewItem>(cell); @@ -988,9 +1001,7 @@ sectionForSectionIdentifier:sectionIdentifier]; NSInteger newItemIndex = 0; - // In order to make sure the we do not end modifying the wrong item, we have - // to take the items in the reverse order of the indexPaths. - for (NSIndexPath* index in [sortedIndexPaths reverseObjectEnumerator]) { + for (NSIndexPath* index in sortedIndexPaths) { // The |sortedIndexPaths| is a copy of the index paths before the // destination section has been added if necessary. The section part of // the index potentially needs to be updated. @@ -1005,13 +1016,16 @@ NSIndexPath* updatedIndex = [NSIndexPath indexPathForItem:index.item inSection:updatedSection]; + NSIndexPath* indexForModel = + [NSIndexPath indexPathForItem:index.item - newItemIndex + inSection:updatedSection]; // Index of the item in the new section. The newItemIndex is the index of // this item in the targeted section. NSIndexPath* newIndexPath = [NSIndexPath indexPathForItem:newItemIndex++ inSection:section]; [self collectionView:self.collectionView - willMoveItemAtIndexPath:updatedIndex + willMoveItemAtIndexPath:indexForModel toIndexPath:newIndexPath]; [self.collectionView moveItemAtIndexPath:updatedIndex toIndexPath:newIndexPath];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h index 7dbd0cf..ca03cc62 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h +++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h
@@ -44,6 +44,7 @@ @property(nonatomic, readonly) UIView* topBar; // Sets the cell's appearance using information in |tab|. +// The delegate needs to be set before calling this method. - (void)setAppearanceForTab:(Tab*)tab cellSize:(CGSize)cellSize; // Sets the cell's appearance depending on |type|. - (void)setSessionType:(TabSwitcherSessionType)type;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm index 1bd0b375..bad9ca2 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
@@ -230,6 +230,8 @@ CGSize snapshotSize = cellSize; snapshotSize.height -= tabSwitcherLocalSessionCellTopBarHeight(); base::WeakNSObject<TabSwitcherLocalSessionCell> weakCell(self); + DCHECK(self.delegate); + DCHECK([self cache]); _currentPendingSnapshotRequest = [[self cache] requestSnapshotForTab:tab withSize:snapshotSize
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm index aac14c8..da2519be 100644 --- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm +++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_controller.mm
@@ -237,6 +237,7 @@ [panelCell setTitle:SysUTF16ToNSString(tab->title)]; [panelCell setSessionGURL:tab->virtual_url withBrowserState:[_model browserState]]; + [panelCell setDelegate:self]; } else { NSString* identifier = [TabSwitcherLocalSessionCell identifier]; TabSwitcherLocalSessionCell* panelCell = @@ -247,10 +248,10 @@ Tab* tab = _localSession->tabs()[tabIndex]; [panelCell setSessionType:_sessionType]; + [panelCell setDelegate:self]; [panelCell setAppearanceForTab:tab cellSize:[_panelView cellSize]]; } DCHECK(cell); - cell.delegate = self; return cell; }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 5d3b758..30a468b 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1217,24 +1217,6 @@ ] } ], - "NewAudioRenderingMixingStrategy": [ - { - "platforms": [ - "android", - "linux", - "mac", - "win" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "NewAudioRenderingMixingStrategy" - ] - } - ] - } - ], "NewProfileManagement": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations index ac42e3d2..49c6e30 100644 --- a/third_party/WebKit/LayoutTests/W3CImportExpectations +++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -236,8 +236,7 @@ # imported/wpt/domxpath [ Pass ] imported/wpt/dpub-aam [ Skip ] imported/wpt/dpub-aria [ Skip ] -## Owners: dom-dev@chromium.org -# imported/wpt/editing [ Pass ] +imported/wpt/editing [ Skip ] ## Owners: jsbell@chromium.org # imported/wpt/encoding [ Pass ] ## Owners: jrummell@chromium.org @@ -309,8 +308,7 @@ imported/wpt/resources/webidl2/test [ Skip ] imported/wpt/screen-orientation [ Skip ] imported/wpt/secure-contexts [ Skip ] -## Owners: dom-dev@chromium.org -# imported/wpt/selection [ Pass ] +imported/wpt/selection [ Skip ] imported/wpt/selectors [ Skip ] imported/wpt/selectors-api [ Skip ] imported/wpt/serve [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fast/forms/radio/radio-input-keyboard-navigation.html b/third_party/WebKit/LayoutTests/fast/forms/radio/radio-input-keyboard-navigation.html new file mode 100644 index 0000000..40b9786 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/forms/radio/radio-input-keyboard-navigation.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<style> + #test1 { + max-height: 65px; + overflow: auto; + width: 100px; + height: 65px; + } + input[type="radio"] { + display: block; + } +</style> +</head> +<body> +<div id="test1"> + <input type="radio" name="foo" checked> + <input type="radio" name="foo"> + <input type="radio" name="foo"> + <input type="radio" name="foo"> + <input type="radio" name="foo"> + <input type="radio" name="foo"> +</div> +<script> + test(function() { + document.querySelector("input").focus(); + assert_exists(window, "eventSender"); + for (var i = 0; i < 5; i++) { + window.eventSender.keyDown("ArrowDown"); + } + assert_greater_than(document.getElementById("test1").scrollTop, 0); + }, "Parent container should be scrolled while navigating through radio inputs"); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/span/empty-block-between-spanners.html b/third_party/WebKit/LayoutTests/fast/multicol/span/empty-block-between-spanners.html new file mode 100644 index 0000000..475ad27 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/multicol/span/empty-block-between-spanners.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<p>PASS if no crash or assertion failure.</p> +<div style="columns:2; line-height:20px;"> + <div style="margin-bottom:1px;"> + <br> + <div style="column-span:all;"></div> + <div></div> + <div style="column-span:all;"></div> + </div> + <br> +</div> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script> + test(function() { }, "No crash!"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/span/empty-block-with-bottom-margin-between-spanners.html b/third_party/WebKit/LayoutTests/fast/multicol/span/empty-block-with-bottom-margin-between-spanners.html new file mode 100644 index 0000000..7a3daddd --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/multicol/span/empty-block-with-bottom-margin-between-spanners.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<p>PASS if no crash or assertion failure.</p> +<div style="columns:2; line-height:20px;"> + <br> + <div style="column-span:all;"></div> + <div style="margin-bottom:1px;"> + <div style="column-span:all;"></div> + </div> + <br> +</div> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script> + test(function() { }, "No crash!"); +</script>
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn index 7000b35e..ec0777d 100644 --- a/third_party/WebKit/Source/core/css/BUILD.gn +++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -354,6 +354,7 @@ "properties/CSSPropertyAPIOutlineOffset.cpp", "properties/CSSPropertyAPIPage.cpp", "properties/CSSPropertyAPIPaintOrder.cpp", + "properties/CSSPropertyAPIQuotes.cpp", "properties/CSSPropertyAPIRotate.cpp", "properties/CSSPropertyAPIScrollSnapCoordinate.cpp", "properties/CSSPropertyAPIShapeMargin.cpp", @@ -370,6 +371,7 @@ "properties/CSSPropertyAPIWebkitHighlight.cpp", "properties/CSSPropertyAPIWebkitLineClamp.cpp", "properties/CSSPropertyAPIWebkitPadding.cpp", + "properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp", "properties/CSSPropertyAPIWebkitTransformOriginZ.cpp", "properties/CSSPropertyAPIWillChange.cpp", "properties/CSSPropertyAPIZIndex.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in index 27001cd..9e7133c 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.in +++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -342,7 +342,7 @@ perspective-origin interpolable, converter=convertPosition pointer-events inherited, independent, keyword_only, keywords=[none|auto|stroke|fill|painted|visible|visibleStroke|visibleFill|visiblePainted|bounding-box|all], initial_keyword=auto position custom_inherit -quotes inherited, converter=convertQuotes +quotes inherited, converter=convertQuotes, api_class resize custom_value right typedom_types=[Length], keywords=[auto], supports_percentage, interpolable, initial=initialOffset, converter=convertLengthOrAuto r interpolable, svg, converter=convertLength @@ -459,7 +459,7 @@ -webkit-text-combine inherited, type_name=TextCombine, name_for_methods=TextCombine -webkit-text-emphasis-color inherited, custom_all -webkit-text-emphasis-position inherited, type_name=TextEmphasisPosition --webkit-text-emphasis-style inherited, custom_all +-webkit-text-emphasis-style inherited, custom_all, api_class -webkit-text-fill-color inherited, custom_all -webkit-text-security inherited -webkit-text-stroke-color interpolable, inherited, custom_all
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index 86ad465..1989f2025 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -329,19 +329,10 @@ return settings; } -static CSSValue* consumeQuotes(CSSParserTokenRange& range) { +static CSSValue* consumeWebkitHighlight(CSSParserTokenRange& range) { if (range.peek().id() == CSSValueNone) return consumeIdent(range); - CSSValueList* values = CSSValueList::createSpaceSeparated(); - while (!range.atEnd()) { - CSSStringValue* parsedValue = consumeString(range); - if (!parsedValue) - return nullptr; - values->append(*parsedValue); - } - if (values->length() && values->length() % 2 == 0) - return values; - return nullptr; + return consumeString(range); } class FontVariantLigaturesParser { @@ -1349,33 +1340,6 @@ return true; } -static CSSValue* consumeTextEmphasisStyle(CSSParserTokenRange& range) { - CSSValueID id = range.peek().id(); - if (id == CSSValueNone) - return consumeIdent(range); - - if (CSSValue* textEmphasisStyle = consumeString(range)) - return textEmphasisStyle; - - CSSIdentifierValue* fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range); - CSSIdentifierValue* shape = - consumeIdent<CSSValueDot, CSSValueCircle, CSSValueDoubleCircle, - CSSValueTriangle, CSSValueSesame>(range); - if (!fill) - fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range); - if (fill && shape) { - CSSValueList* parsedValues = CSSValueList::createSpaceSeparated(); - parsedValues->append(*fill); - parsedValues->append(*shape); - return parsedValues; - } - if (fill) - return fill; - if (shape) - return shape; - return nullptr; -} - static CSSValue* consumeOutlineColor(CSSParserTokenRange& range, CSSParserMode cssParserMode) { // Allow the special focus color even in HTML Standard parsing mode. @@ -3020,8 +2984,8 @@ return cssPropertyDesc.parseSingleValue(m_range, m_context); switch (property) { - case CSSPropertyQuotes: - return consumeQuotes(m_range); + case CSSPropertyWebkitHighlight: + return consumeWebkitHighlight(m_range); case CSSPropertyFontVariantCaps: return consumeFontVariantCaps(m_range); case CSSPropertyFontVariantLigatures: @@ -3213,8 +3177,6 @@ case CSSPropertyOffsetRotate: case CSSPropertyOffsetRotation: return consumeOffsetRotate(m_range); - case CSSPropertyWebkitTextEmphasisStyle: - return consumeTextEmphasisStyle(m_range); case CSSPropertyOutlineColor: return consumeOutlineColor(m_range, m_context->mode()); case CSSPropertyOutlineWidth:
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIQuotes.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIQuotes.cpp new file mode 100644 index 0000000..d8fdc55 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIQuotes.cpp
@@ -0,0 +1,32 @@ +// 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/CSSPropertyAPIQuotes.h" + +#include "core/css/CSSStringValue.h" +#include "core/css/CSSValueList.h" +#include "core/css/parser/CSSParserContext.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIQuotes::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + if (range.peek().id() == CSSValueNone) + return CSSPropertyParserHelpers::consumeIdent(range); + CSSValueList* values = CSSValueList::createSpaceSeparated(); + while (!range.atEnd()) { + CSSStringValue* parsedValue = + CSSPropertyParserHelpers::consumeString(range); + if (!parsedValue) + return nullptr; + values->append(*parsedValue); + } + if (values->length() && values->length() % 2 == 0) + return values; + return nullptr; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp new file mode 100644 index 0000000..8366577a --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp
@@ -0,0 +1,49 @@ +// 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/CSSPropertyAPIWebkitTextEmphasisStyle.h" + +#include "core/css/CSSStringValue.h" +#include "core/css/CSSValueList.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIWebkitTextEmphasisStyle::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext* context) { + CSSValueID id = range.peek().id(); + if (id == CSSValueNone) + return CSSPropertyParserHelpers::consumeIdent(range); + + if (CSSValue* textEmphasisStyle = + CSSPropertyParserHelpers::consumeString(range)) + return textEmphasisStyle; + + CSSIdentifierValue* fill = + CSSPropertyParserHelpers::consumeIdent<CSSValueFilled, CSSValueOpen>( + range); + CSSIdentifierValue* shape = + CSSPropertyParserHelpers::consumeIdent<CSSValueDot, CSSValueCircle, + CSSValueDoubleCircle, + CSSValueTriangle, CSSValueSesame>( + range); + if (!fill) { + fill = CSSPropertyParserHelpers::consumeIdent<CSSValueFilled, CSSValueOpen>( + range); + } + if (fill && shape) { + CSSValueList* parsedValues = CSSValueList::createSpaceSeparated(); + parsedValues->append(*fill); + parsedValues->append(*shape); + return parsedValues; + } + if (fill) + return fill; + if (shape) + return shape; + return nullptr; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp index 9d67471..246dcc0 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -927,6 +927,7 @@ else initial = true; } + DCHECK(initial ^ inherit); state.style()->removeVariable(name, isInheritedProperty); if (initial) {
diff --git a/third_party/WebKit/Source/core/editing/CaretBase.cpp b/third_party/WebKit/Source/core/editing/CaretBase.cpp index 16e0f02e..144b86c 100644 --- a/third_party/WebKit/Source/core/editing/CaretBase.cpp +++ b/third_party/WebKit/Source/core/editing/CaretBase.cpp
@@ -146,15 +146,6 @@ node->layoutObject()->invalidatePaintRectangle(inflatedRect, this); } -bool CaretBase::shouldRepaintCaret(Node& node) { - // If PositionAnchorType::BeforeAnchor or PositionAnchorType::AfterAnchor, - // carets need to be repainted not only when the node is contentEditable but - // also when its parentNode() is contentEditable. - node.document().updateStyleAndLayoutTree(); - return hasEditableStyle(node) || - (node.parentNode() && hasEditableStyle(*node.parentNode())); -} - void CaretBase::invalidateCaretRect(Node* node, const LayoutRect& caretLocalRect) { node->document().updateStyleAndLayoutTree();
diff --git a/third_party/WebKit/Source/core/editing/CaretBase.h b/third_party/WebKit/Source/core/editing/CaretBase.h index 993371d..3984329 100644 --- a/third_party/WebKit/Source/core/editing/CaretBase.h +++ b/third_party/WebKit/Source/core/editing/CaretBase.h
@@ -52,10 +52,6 @@ static LayoutRect computeCaretRect(const PositionWithAffinity& caretPosition); static IntRect absoluteBoundsForLocalRect(Node*, const LayoutRect&); - // TODO(yosin): We should move |shouldRepaintCaret()| to "FrameCaret.cpp" as - // static file local function. - static bool shouldRepaintCaret(Node&); - void paintCaret(Node*, GraphicsContext&, const LayoutRect& caretLocalRect,
diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.cpp b/third_party/WebKit/Source/core/editing/FrameCaret.cpp index 5e5eee8..e00c0a8 100644 --- a/third_party/WebKit/Source/core/editing/FrameCaret.cpp +++ b/third_party/WebKit/Source/core/editing/FrameCaret.cpp
@@ -166,6 +166,15 @@ return caretPosition().document() == document && !caretPosition().isOrphan(); } +static bool shouldRepaintCaret(Node& node) { + // If PositionAnchorType::BeforeAnchor or PositionAnchorType::AfterAnchor, + // carets need to be repainted not only when the node is contentEditable but + // also when its parentNode() is contentEditable. + node.document().updateStyleAndLayoutTree(); + return hasEditableStyle(node) || + (node.parentNode() && hasEditableStyle(*node.parentNode())); +} + void FrameCaret::invalidateCaretRect(bool forceInvalidation) { if (!m_caretRectDirty) return; @@ -202,11 +211,11 @@ return; if (m_previousCaretAnchorNode && - CaretBase::shouldRepaintCaret(*m_previousCaretAnchorNode)) { + shouldRepaintCaret(*m_previousCaretAnchorNode)) { m_caretBase->invalidateLocalCaretRect(m_previousCaretAnchorNode.get(), m_previousCaretRect); } - if (newAnchorNode && CaretBase::shouldRepaintCaret(*newAnchorNode)) + if (newAnchorNode && shouldRepaintCaret(*newAnchorNode)) m_caretBase->invalidateLocalCaretRect(newAnchorNode, newRect); m_previousCaretNode = newNode; m_previousCaretAnchorNode = newAnchorNode;
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp index b56c9bb..0c4a452a 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp +++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -1042,6 +1042,11 @@ return m_pendingSelection->commit(layoutView); } +void FrameSelection::didLayout() { + setCaretRectNeedsUpdate(); + updateAppearance(); +} + void FrameSelection::updateAppearance() { m_frameCaret->updateAppearance();
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h index d5caa17..72a86920 100644 --- a/third_party/WebKit/Source/core/editing/FrameSelection.h +++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -215,9 +215,9 @@ void didMergeTextNodes(const Text& oldNode, unsigned offset); void didSplitTextNode(const Text& oldNode); + void didLayout(); bool isAppearanceDirty() const; void commitAppearanceIfNeeded(LayoutView&); - void updateAppearance(); void setCaretVisible(bool caretIsVisible); bool isCaretBoundsDirty() const; void setCaretRectNeedsUpdate(); @@ -269,6 +269,7 @@ RevealExtentOption = DoNotRevealExtent); void setSelectionFromNone(); + void updateAppearance(); bool shouldShowBlockCursor() const; void setShouldShowBlockCursor(bool);
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 9d35318..8dca0e8f 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -2425,8 +2425,7 @@ m_postLayoutTasksTimer.stop(); - m_frame->selection().setCaretRectNeedsUpdate(); - m_frame->selection().updateAppearance(); + m_frame->selection().didLayout(); ASSERT(m_frame->document());
diff --git a/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp b/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp index 92e36eb..ed9afd7b 100644 --- a/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp
@@ -126,9 +126,9 @@ } } if (inputElement) { - document.setFocusedElement( - inputElement, - FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr)); + document.setFocusedElement(inputElement, + FocusParams(SelectionBehaviorOnFocus::Restore, + WebFocusTypeNone, nullptr)); inputElement->dispatchSimulatedClick(event, SendNoEvents); event->setDefaultHandled(); return;
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp index eaa90b37..84663769 100644 --- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
@@ -463,17 +463,19 @@ DCHECK(!m_columnSetsInvalidated); if (m_multiColumnSetList.isEmpty()) return nullptr; - if (offset < LayoutUnit()) - return m_multiColumnSetList.first(); + if (offset < LayoutUnit()) { + columnSet = m_multiColumnSetList.first(); + } else { + MultiColumnSetSearchAdapter adapter(offset); + m_multiColumnSetIntervalTree + .allOverlapsWithAdapter<MultiColumnSetSearchAdapter>(adapter); - MultiColumnSetSearchAdapter adapter(offset); - m_multiColumnSetIntervalTree - .allOverlapsWithAdapter<MultiColumnSetSearchAdapter>(adapter); - - // If no set was found, the offset is in the flow thread overflow. - if (!adapter.result() && !m_multiColumnSetList.isEmpty()) - return m_multiColumnSetList.last(); - columnSet = adapter.result(); + // If no set was found, the offset is in the flow thread overflow. + if (!adapter.result() && !m_multiColumnSetList.isEmpty()) + columnSet = m_multiColumnSetList.last(); + else + columnSet = adapter.result(); + } } if (pageBoundaryRule == AssociateWithFormerPage && columnSet && offset == columnSet->logicalTopInFlowThread()) { @@ -483,7 +485,19 @@ // previous column set. if (LayoutMultiColumnSet* previousSet = columnSet->previousSiblingMultiColumnSet()) - return previousSet; + columnSet = previousSet; + } + // Avoid returning zero-height column sets, if possible. We found a column set + // based on a flow thread coordinate. If multiple column sets share that + // coordinate (because we have zero-height column sets between column + // spanners, for instance), look for one that has a height. + for (LayoutMultiColumnSet* walker = columnSet; walker; + walker = walker->nextSiblingMultiColumnSet()) { + if (!walker->isPageLogicalHeightKnown()) + continue; + if (walker->logicalTopInFlowThread() == offset) + return walker; + break; } return columnSet; }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index 41a435f..6a3d4fd 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1122,7 +1122,6 @@ "mhtml/MHTMLParser.h", "mojo/BluetoothStructTraits.cpp", "mojo/CommonCustomTypesStructTraits.cpp", - "mojo/GeometryStructTraits.cpp", "mojo/MojoHelper.h", "network/ContentSecurityPolicyParsers.cpp", "network/ContentSecurityPolicyParsers.h", @@ -1513,14 +1512,6 @@ "/wd4334", # Result of 32-bit shift implicitly converted to 64 bits. "/wd4724", # Modulo by 0. ] - - # crbug.com/654776: Suppress symbol import warnings. - if (is_component_build) { - ldflags = [ - "/ignore:4217", - "/ignore:4049", - ] - } } else { sources -= [ "clipboard/ClipboardUtilitiesWin.cpp", @@ -1698,6 +1689,7 @@ "blob/BlobDataTest.cpp", "clipboard/ClipboardUtilitiesTest.cpp", "exported/FilePathConversionTest.cpp", + "exported/WebStringTest.cpp", "feature_policy/FeaturePolicyTest.cpp", "fonts/AcceptLanguagesResolverTest.cpp", "fonts/FontCacheTest.cpp", @@ -1776,7 +1768,6 @@ "network/LinkHeaderTest.cpp", "network/NetworkUtilsTest.cpp", "network/ResourceRequestTest.cpp", - "network/ResourceResponseTest.cpp", "network/mime/MIMETypeRegistryTest.cpp", "scheduler/base/intrusive_heap_unittest.cc", "scheduler/base/queueing_time_estimator_unittest.cc", @@ -2089,6 +2080,7 @@ "graphics/test/FakeGLES2Interface.h", "graphics/test/FakeWebGraphicsContext3DProvider.h", "graphics/test/MockImageDecoder.h", + "network/ResourceResponseTest.cpp", ] configs += [
diff --git a/third_party/WebKit/Source/platform/exported/WebString.cpp b/third_party/WebKit/Source/platform/exported/WebString.cpp index 5ff32e9..a41e1b0 100644 --- a/third_party/WebKit/Source/platform/exported/WebString.cpp +++ b/third_party/WebKit/Source/platform/exported/WebString.cpp
@@ -38,6 +38,18 @@ #include "wtf/text/StringView.h" #include "wtf/text/WTFString.h" +#define STATIC_ASSERT_ENUM(a, b) \ + static_assert(static_cast<int>(a) == static_cast<int>(b), \ + "mismatching enums: " #a) + +STATIC_ASSERT_ENUM(WTF::LenientUTF8Conversion, + blink::WebString::UTF8ConversionMode::kLenient); +STATIC_ASSERT_ENUM(WTF::StrictUTF8Conversion, + blink::WebString::UTF8ConversionMode::kStrict); +STATIC_ASSERT_ENUM( + WTF::StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD, + blink::WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD); + namespace blink { void WebString::reset() { @@ -68,8 +80,9 @@ return !m_private.isNull() && !is8Bit() ? m_private->characters16() : 0; } -std::string WebString::utf8() const { - StringUTF8Adaptor utf8(m_private.get()); +std::string WebString::utf8(UTF8ConversionMode mode) const { + StringUTF8Adaptor utf8(m_private.get(), + static_cast<WTF::UTF8ConversionMode>(mode)); return std::string(utf8.data(), utf8.length()); }
diff --git a/third_party/WebKit/Source/platform/exported/WebStringTest.cpp b/third_party/WebKit/Source/platform/exported/WebStringTest.cpp new file mode 100644 index 0000000..c5199c4 --- /dev/null +++ b/third_party/WebKit/Source/platform/exported/WebStringTest.cpp
@@ -0,0 +1,50 @@ +// 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 "public/platform/WebString.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "wtf/text/WTFString.h" + +namespace blink { + +TEST(WebStringTest, UTF8ConversionRoundTrip) { + // Valid characters. + for (UChar uchar = 0; uchar <= 0xD7FF; ++uchar) { + WebString utf16String(&uchar, 1); + std::string utf8String(utf16String.utf8()); + WebString utf16NewString = + WebString::fromUTF8(utf8String.data(), utf8String.length()); + EXPECT_FALSE(utf16NewString.isNull()); + EXPECT_TRUE(utf16String == utf16NewString); + } + + // Unpaired surrogates. + for (UChar uchar = 0xD800; uchar <= 0xDFFF; ++uchar) { + WebString utf16String(&uchar, 1); + + // Conversion with Strict mode results in an empty string. + std::string utf8String( + utf16String.utf8(WebString::UTF8ConversionMode::kStrict)); + EXPECT_TRUE(utf8String.empty()); + + // Unpaired surrogates can't be converted back in Lenient mode. + utf8String = utf16String.utf8(WebString::UTF8ConversionMode::kLenient); + EXPECT_FALSE(utf8String.empty()); + WebString utf16NewString = + WebString::fromUTF8(utf8String.data(), utf8String.length()); + EXPECT_TRUE(utf16NewString.isNull()); + + // Round-trip works with StrictReplacingErrorsWithFFFD mode. + utf8String = utf16String.utf8( + WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD); + EXPECT_FALSE(utf8String.empty()); + utf16NewString = + WebString::fromUTF8(utf8String.data(), utf8String.length()); + EXPECT_FALSE(utf16NewString.isNull()); + EXPECT_FALSE(utf16String == utf16NewString); + } +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/mojo/BUILD.gn b/third_party/WebKit/Source/platform/mojo/BUILD.gn new file mode 100644 index 0000000..b47dfa9 --- /dev/null +++ b/third_party/WebKit/Source/platform/mojo/BUILD.gn
@@ -0,0 +1,15 @@ +# 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. + +source_set("geometry_struct_traits") { + sources = [ + "GeometryStructTraits.cpp", + "GeometryStructTraits.h", + ] + public_deps = [ + "//third_party/WebKit/public:blink_headers", + "//ui/gfx/geometry", + "//ui/gfx/geometry/mojo:mojo_shared_cpp_sources", + ] +}
diff --git a/third_party/WebKit/Source/platform/mojo/Geometry.typemap b/third_party/WebKit/Source/platform/mojo/Geometry.typemap index 75c3545..a97b6f491d 100644 --- a/third_party/WebKit/Source/platform/mojo/Geometry.typemap +++ b/third_party/WebKit/Source/platform/mojo/Geometry.typemap
@@ -10,6 +10,7 @@ # Note: consumers of this typemap must themselves depend on platform. deps = [ "//mojo/public/cpp/bindings", + "//third_party/WebKit/Source/platform/mojo:geometry_struct_traits", ] # TODO(zqzhang): ideally, gfx.mojom.Size should be mapped into ::blink::IntSize.
diff --git a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp index 21de7c1..4ec1c2a 100644 --- a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp +++ b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.cpp
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "platform/mojo/GeometryStructTraits.h" +#include "third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h" namespace mojo { // static -bool StructTraits<gfx::mojom::blink::Size::DataView, ::blink::WebSize>::Read( - gfx::mojom::blink::Size::DataView data, +bool StructTraits<gfx::mojom::SizeDataView, ::blink::WebSize>::Read( + gfx::mojom::SizeDataView data, ::blink::WebSize* out) { if (data.width() < 0 || data.height() < 0) return false;
diff --git a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h index 42afd66..b88c3b2 100644 --- a/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h +++ b/third_party/WebKit/Source/platform/mojo/GeometryStructTraits.h
@@ -5,17 +5,16 @@ #ifndef GeometryStructTraits_h #define GeometryStructTraits_h -#include "platform/PlatformExport.h" -#include "ui/gfx/geometry/mojo/geometry.mojom-blink.h" +#include "third_party/WebKit/public/platform/WebSize.h" +#include "ui/gfx/geometry/mojo/geometry.mojom-shared.h" namespace mojo { template <> -struct PLATFORM_EXPORT - StructTraits<gfx::mojom::blink::Size::DataView, ::blink::WebSize> { +struct StructTraits<gfx::mojom::SizeDataView, ::blink::WebSize> { static int width(const ::blink::WebSize& size) { return size.width; } static int height(const ::blink::WebSize& size) { return size.height; } - static bool Read(gfx::mojom::blink::Size::DataView, ::blink::WebSize* out); + static bool Read(gfx::mojom::SizeDataView, ::blink::WebSize* out); }; } // namespace mojo
diff --git a/third_party/WebKit/Source/platform/network/HTTPParsers.cpp b/third_party/WebKit/Source/platform/network/HTTPParsers.cpp index 456db9c..3ca4b69 100644 --- a/third_party/WebKit/Source/platform/network/HTTPParsers.cpp +++ b/third_party/WebKit/Source/platform/network/HTTPParsers.cpp
@@ -703,13 +703,11 @@ cacheControlHeader.staleWhileRevalidate = std::numeric_limits<double>::quiet_NaN(); - DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache")); - DEFINE_STATIC_LOCAL(const AtomicString, noStoreDirective, ("no-store")); - DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, - ("must-revalidate")); - DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age")); - DEFINE_STATIC_LOCAL(const AtomicString, staleWhileRevalidateDirective, - ("stale-while-revalidate")); + static const char noCacheDirective[] = "no-cache"; + static const char noStoreDirective[] = "no-store"; + static const char mustRevalidateDirective[] = "must-revalidate"; + static const char maxAgeDirective[] = "max-age"; + static const char staleWhileRevalidateDirective[] = "stale-while-revalidate"; if (!cacheControlValue.isEmpty()) { Vector<std::pair<String, String>> directives;
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp index 9f58f33..810420cd 100644 --- a/third_party/WebKit/Source/platform/network/ResourceResponse.cpp +++ b/third_party/WebKit/Source/platform/network/ResourceResponse.cpp
@@ -45,6 +45,9 @@ return result; } +static const char cacheControlHeader[] = "cache-control"; +static const char pragmaHeader[] = "pragma"; + } // namespace ResourceResponse::SignedCertificateTimestamp::SignedCertificateTimestamp( @@ -357,28 +360,16 @@ return m_httpHeaderFields.get(name); } -static const AtomicString& cacheControlHeaderString() { - DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, - ("cache-control")); - return cacheControlHeader; -} - -static const AtomicString& pragmaHeaderString() { - DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma")); - return pragmaHeader; -} - void ResourceResponse::updateHeaderParsedState(const AtomicString& name) { - DEFINE_STATIC_LOCAL(const AtomicString, ageHeader, ("age")); - DEFINE_STATIC_LOCAL(const AtomicString, dateHeader, ("date")); - DEFINE_STATIC_LOCAL(const AtomicString, expiresHeader, ("expires")); - DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, - ("last-modified")); + static const char ageHeader[] = "age"; + static const char dateHeader[] = "date"; + static const char expiresHeader[] = "expires"; + static const char lastModifiedHeader[] = "last-modified"; if (equalIgnoringCase(name, ageHeader)) m_haveParsedAgeHeader = false; - else if (equalIgnoringCase(name, cacheControlHeaderString()) || - equalIgnoringCase(name, pragmaHeaderString())) + else if (equalIgnoringCase(name, cacheControlHeader) || + equalIgnoringCase(name, pragmaHeader)) m_cacheControlHeader = CacheControlHeader(); else if (equalIgnoringCase(name, dateHeader)) m_haveParsedDateHeader = false; @@ -440,50 +431,54 @@ } bool ResourceResponse::cacheControlContainsNoCache() const { - if (!m_cacheControlHeader.parsed) - m_cacheControlHeader = parseCacheControlDirectives( - m_httpHeaderFields.get(cacheControlHeaderString()), - m_httpHeaderFields.get(pragmaHeaderString())); + if (!m_cacheControlHeader.parsed) { + m_cacheControlHeader = + parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeader), + m_httpHeaderFields.get(pragmaHeader)); + } return m_cacheControlHeader.containsNoCache; } bool ResourceResponse::cacheControlContainsNoStore() const { - if (!m_cacheControlHeader.parsed) - m_cacheControlHeader = parseCacheControlDirectives( - m_httpHeaderFields.get(cacheControlHeaderString()), - m_httpHeaderFields.get(pragmaHeaderString())); + if (!m_cacheControlHeader.parsed) { + m_cacheControlHeader = + parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeader), + m_httpHeaderFields.get(pragmaHeader)); + } return m_cacheControlHeader.containsNoStore; } bool ResourceResponse::cacheControlContainsMustRevalidate() const { - if (!m_cacheControlHeader.parsed) - m_cacheControlHeader = parseCacheControlDirectives( - m_httpHeaderFields.get(cacheControlHeaderString()), - m_httpHeaderFields.get(pragmaHeaderString())); + if (!m_cacheControlHeader.parsed) { + m_cacheControlHeader = + parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeader), + m_httpHeaderFields.get(pragmaHeader)); + } return m_cacheControlHeader.containsMustRevalidate; } bool ResourceResponse::hasCacheValidatorFields() const { - DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, - ("last-modified")); - DEFINE_STATIC_LOCAL(const AtomicString, eTagHeader, ("etag")); + static const char lastModifiedHeader[] = "last-modified"; + static const char eTagHeader[] = "etag"; return !m_httpHeaderFields.get(lastModifiedHeader).isEmpty() || !m_httpHeaderFields.get(eTagHeader).isEmpty(); } double ResourceResponse::cacheControlMaxAge() const { - if (!m_cacheControlHeader.parsed) - m_cacheControlHeader = parseCacheControlDirectives( - m_httpHeaderFields.get(cacheControlHeaderString()), - m_httpHeaderFields.get(pragmaHeaderString())); + if (!m_cacheControlHeader.parsed) { + m_cacheControlHeader = + parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeader), + m_httpHeaderFields.get(pragmaHeader)); + } return m_cacheControlHeader.maxAge; } double ResourceResponse::cacheControlStaleWhileRevalidate() const { - if (!m_cacheControlHeader.parsed) - m_cacheControlHeader = parseCacheControlDirectives( - m_httpHeaderFields.get(cacheControlHeaderString()), - m_httpHeaderFields.get(pragmaHeaderString())); + if (!m_cacheControlHeader.parsed) { + m_cacheControlHeader = + parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeader), + m_httpHeaderFields.get(pragmaHeader)); + } return m_cacheControlHeader.staleWhileRevalidate; } @@ -504,7 +499,7 @@ double ResourceResponse::date() const { if (!m_haveParsedDateHeader) { - DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("date")); + static const char headerName[] = "date"; m_date = parseDateValueInHeader(m_httpHeaderFields, headerName); m_haveParsedDateHeader = true; } @@ -513,7 +508,7 @@ double ResourceResponse::age() const { if (!m_haveParsedAgeHeader) { - DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("age")); + static const char headerName[] = "age"; const AtomicString& headerValue = m_httpHeaderFields.get(headerName); bool ok; m_age = headerValue.toDouble(&ok); @@ -526,7 +521,7 @@ double ResourceResponse::expires() const { if (!m_haveParsedExpiresHeader) { - DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("expires")); + static const char headerName[] = "expires"; m_expires = parseDateValueInHeader(m_httpHeaderFields, headerName); m_haveParsedExpiresHeader = true; } @@ -535,7 +530,7 @@ double ResourceResponse::lastModified() const { if (!m_haveParsedLastModifiedHeader) { - DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("last-modified")); + static const char headerName[] = "last-modified"; m_lastModified = parseDateValueInHeader(m_httpHeaderFields, headerName); m_haveParsedLastModifiedHeader = true; } @@ -543,13 +538,13 @@ } bool ResourceResponse::isAttachment() const { - DEFINE_STATIC_LOCAL(const AtomicString, headerName, ("content-disposition")); + static const char headerName[] = "content-disposition"; + static const char attachmentString[] = "attachment"; String value = m_httpHeaderFields.get(headerName); size_t loc = value.find(';'); if (loc != kNotFound) value = value.left(loc); value = value.stripWhiteSpace(); - DEFINE_STATIC_LOCAL(const AtomicString, attachmentString, ("attachment")); return equalIgnoringCase(value, attachmentString); }
diff --git a/third_party/WebKit/Source/platform/network/ResourceResponseTest.cpp b/third_party/WebKit/Source/platform/network/ResourceResponseTest.cpp index 4a6b6e57..573b827 100644 --- a/third_party/WebKit/Source/platform/network/ResourceResponseTest.cpp +++ b/third_party/WebKit/Source/platform/network/ResourceResponseTest.cpp
@@ -4,10 +4,45 @@ #include "platform/network/ResourceResponse.h" +#include "platform/CrossThreadFunctional.h" +#include "platform/WebTaskRunner.h" +#include "public/platform/Platform.h" +#include "public/platform/WebThread.h" #include "testing/gtest/include/gtest/gtest.h" namespace blink { +namespace { + +ResourceResponse createTestResponse() { + ResourceResponse response; + response.addHTTPHeaderField("age", "0"); + response.addHTTPHeaderField("cache-control", "no-cache"); + response.addHTTPHeaderField("date", "Tue, 17 Jan 2017 04:01:00 GMT"); + response.addHTTPHeaderField("expires", "Tue, 17 Jan 2017 04:11:00 GMT"); + response.addHTTPHeaderField("last-modified", "Tue, 17 Jan 2017 04:00:00 GMT"); + response.addHTTPHeaderField("pragma", "public"); + response.addHTTPHeaderField("etag", "abc"); + response.addHTTPHeaderField("content-disposition", + "attachment; filename=a.txt"); + return response; +} + +void runHeaderRelatedTest(const ResourceResponse& response) { + EXPECT_EQ(0, response.age()); + EXPECT_NE(0, response.date()); + EXPECT_NE(0, response.expires()); + EXPECT_NE(0, response.lastModified()); + EXPECT_EQ(true, response.cacheControlContainsNoCache()); +} + +void runInThread() { + ResourceResponse response(createTestResponse()); + runHeaderRelatedTest(response); +} + +} // namespace + TEST(ResourceResponseTest, SignedCertificateTimestampIsolatedCopy) { ResourceResponse::SignedCertificateTimestamp src( "status", "origin", "logDescription", "logId", 7, "hashAlgorithm", @@ -32,4 +67,16 @@ EXPECT_NE(src.m_signatureData.impl(), dest.m_signatureData.impl()); } +TEST(ResourceResponseTest, CrossThreadAtomicStrings) { + // This test checks that AtomicStrings in ResourceResponse doesn't cause the + // failure of ThreadRestrictionVerifier check. + ResourceResponse response(createTestResponse()); + runHeaderRelatedTest(response); + std::unique_ptr<WebThread> thread = + WTF::wrapUnique(Platform::current()->createThread("WorkerThread")); + thread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, + crossThreadBind(&runInThread)); + thread.reset(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index ebd1431..0ab358f 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1458,6 +1458,7 @@ WebFrameClient* client, WebRemoteFrame* oldWebFrame, WebSandboxFlags flags) { + DCHECK(client); WebLocalFrameImpl* webFrame = new WebLocalFrameImpl(oldWebFrame, client); Frame* oldFrame = oldWebFrame->toImplBase()->frame(); webFrame->setParent(oldWebFrame->parent()); @@ -1471,8 +1472,7 @@ // reuse it here. LocalFrame* frame = LocalFrame::create( webFrame->m_frameLoaderClientImpl.get(), oldFrame->host(), tempOwner, - client ? client->interfaceProvider() : nullptr, - client ? client->interfaceRegistry() : nullptr); + client->interfaceProvider(), client->interfaceRegistry()); // Set the name and unique name directly, bypassing any of the normal logic // to calculate unique name. frame->tree().setPrecalculatedName(
diff --git a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h index 9eeb3ba..1aa0897 100644 --- a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h +++ b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
@@ -46,7 +46,9 @@ DISALLOW_NEW(); public: - explicit StringUTF8Adaptor(const String& string) : m_data(0), m_length(0) { + StringUTF8Adaptor(const String& string, + UTF8ConversionMode mode = LenientUTF8Conversion) + : m_data(0), m_length(0) { if (string.isEmpty()) return; // Unfortunately, 8 bit WTFStrings are encoded in Latin-1 and GURL uses @@ -57,7 +59,7 @@ m_data = reinterpret_cast<const char*>(string.characters8()); m_length = string.length(); } else { - m_utf8Buffer = string.utf8(); + m_utf8Buffer = string.utf8(mode); m_data = m_utf8Buffer.data(); m_length = m_utf8Buffer.length(); }
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn index 08739cb..c9a387a 100644 --- a/third_party/WebKit/public/BUILD.gn +++ b/third_party/WebKit/public/BUILD.gn
@@ -673,7 +673,6 @@ "//device/bluetooth/public/interfaces", "//mojo/common:common_custom_types", "//ui/gfx/geometry/mojo", - "//ui/gfx/geometry/mojo:mojo", "//url/mojo:url_mojom_gurl", "//url/mojo:url_mojom_origin", ]
diff --git a/third_party/WebKit/public/platform/WebString.h b/third_party/WebKit/public/platform/WebString.h index 5c1c540..b5e4a896c 100644 --- a/third_party/WebKit/public/platform/WebString.h +++ b/third_party/WebKit/public/platform/WebString.h
@@ -66,6 +66,11 @@ // * webstring.utf16() // * WebString::toNullableString16(webstring) // +// Note that if you need to convert the UTF8 string converted from WebString +// back to WebString with fromUTF8() you may want to specify Strict +// UTF8ConversionMode when you call utf8(), as fromUTF8 rejects strings +// with invalid UTF8 characters. +// // Some types like GURL and base::FilePath can directly take either utf-8 or // utf-16 strings. Use following methods to convert WebString to/from GURL or // FilePath rather than going through intermediate string types: @@ -79,6 +84,16 @@ // class WebString { public: + enum class UTF8ConversionMode { + // Ignores errors for invalid characters. + kLenient, + // Errors out on invalid characters, returns null string. + kStrict, + // Replace invalid characters with 0xFFFD. + // (This is the same conversion mode as base::UTF16ToUTF8) + kStrictReplacingErrorsWithFFFD, + }; + ~WebString() { reset(); } WebString() {} @@ -104,7 +119,8 @@ bool isEmpty() const { return !length(); } bool isNull() const { return m_private.isNull(); } - BLINK_COMMON_EXPORT std::string utf8() const; + BLINK_COMMON_EXPORT std::string utf8( + UTF8ConversionMode = UTF8ConversionMode::kLenient) const; BLINK_COMMON_EXPORT static WebString fromUTF8(const char* data, size_t length);
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 7d4422f1..11f243c 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -59433,6 +59433,16 @@ </summary> </histogram> +<histogram name="ServiceWorker.ContextRequestHandlerStatus" + enum="ServiceWorkerContextRequestHandlerStatus"> + <owner>falken@chromium.org</owner> + <summary> + The result of ServiceWorkerContextRequestHandler handling a request for a + service worker script. The histogram is suffixed to distinguish new vs + installed workers and main vs imported scripts. + </summary> +</histogram> + <histogram name="ServiceWorker.Database.DestroyDatabaseResult" enum="ServiceWorkerDatabaseStatus"> <owner>nhiroki@chromium.org</owner> @@ -103745,6 +103755,25 @@ <int value="5" label="OpaqueRedirect"/> </enum> +<enum name="ServiceWorkerContextRequestHandlerStatus" type="int"> + <summary> + The result of ServiceWorkerContextHandler handling a request for a service + worker script. From ServiceWorkerContextHandler::CreateJobStatus. + </summary> + <int value="0" label="Uninitialized"/> + <int value="1" label="Created a write job"/> + <int value="2" label="Created a write job with an incumbent"/> + <int value="3" label="Created a read job"/> + <int value="4" label="Created a read job for a duplicate script import"/> + <int value="5" label="Error: no provider"/> + <int value="6" label="Error: redundant version"/> + <int value="7" label="Error: no context"/> + <int value="8" label="Error: redirect"/> + <int value="9" + label="Error: fell back to network for an uninstalled script import"/> + <int value="10" label="Error: out of resource ids"/> +</enum> + <enum name="ServiceWorkerDatabaseStatus" type="int"> <int value="0" label="OK"/> <int value="1" label="Not Found Error"/> @@ -116137,6 +116166,18 @@ <affected-histogram name="interstitial.interaction"/> </histogram_suffixes> +<histogram_suffixes name="ServiceWorker.ContextRequestType" separator="."> + <suffix name="InstalledWorker.MainScript" + label="Main script for an installed worker"/> + <suffix name="InstalledWorker.ImportedScript" + label="Imported script for an installed worker"/> + <suffix name="NewWorker.MainScript" + label="Main script for a new (not installed) worker"/> + <suffix name="NewWorker.ImportedScript" + label="Imported script for new (not installed) worker"/> + <affected-histogram name="ServiceWorker.ContextRequestHandlerStatus"/> +</histogram_suffixes> + <histogram_suffixes name="ServiceWorker.EventType"> <suffix name="ACTIVATE" label="ACTIVATE"/> <suffix name="INSTALL" label="INSTALL"/>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html index c0c6bfd..8cff994d 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
@@ -21,7 +21,7 @@ <paper-toolbar id="toolbar"> <div>[[filePath]]</div> <div id="buttons"> - <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[isUnsupported_(type, browsable)]]" i18n-values="aria-label:QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL" tabindex="0" has-tooltip> + <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[!hasTask]]" i18n-values="aria-label:QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL" tabindex="0" has-tooltip> <iron-icon icon="files:open-in-new"></iron-icon> </paper-button> <files-icon-button toggles id="metadata-button" on-tap="onMetadataButtonTap_" active="{{metadataBoxActive}}" i18n-values="aria-label:QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL" tabindex="0" has-tooltip>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js index c551cd52..a3096bb 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js
@@ -9,6 +9,8 @@ // File media type, e.g. image, video. type: String, filePath: String, + // If there is a task to open the file. + hasTask: Boolean, // URLs should be accessible from webview since contets are rendered inside // it. Hint: use URL.createObjectURL. contentUrl: String, @@ -41,6 +43,7 @@ clear: function() { this.type = ''; this.filePath = ''; + this.hasTask = false; this.contentUrl = ''; this.videoPoster = ''; this.audioArtwork = '';
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js index 86a1376..667e70aa 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -548,7 +548,7 @@ assert(this.metadataModel_), assert(this.selectionHandler_), assert(this.ui_.listContainer), assert(this.quickViewModel_), assert(this.taskController_), fileListSelectionModel, - assert(this.quickViewUma_), metadataBoxController); + assert(this.quickViewUma_), metadataBoxController, this.dialogType); if (this.dialogType === DialogType.FULL_PAGE) { importer.importEnabled().then(
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js index 7435dc6..f659b30 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -14,13 +14,14 @@ * @param {!cr.ui.ListSelectionModel} fileListSelectionModel * @param {!QuickViewUma} quickViewUma * @param {!MetadataBoxController} metadataBoxController + * @param {DialogType} dialogType * * @constructor */ function QuickViewController( metadataModel, selectionHandler, listContainer, quickViewModel, taskController, fileListSelectionModel, quickViewUma, - metadataBoxController) { + metadataBoxController, dialogType) { /** * @type {FilesQuickView} * @private @@ -76,6 +77,12 @@ this.metadataBoxController_ = metadataBoxController; /** + * @type {DialogType} + * @private + */ + this.dialogType_ = dialogType; + + /** * Current selection of selectionHandler. * * @type {!Array<!FileEntry>} @@ -218,6 +225,17 @@ }; /** + * @param {!FileEntry} entry + * @return {!Promise<!Array<!FileTask>>} + * @private + */ +QuickViewController.prototype.getAvailableTasks_ = function(entry) { + return this.taskController_.getFileTasks().then(function(tasks) { + return tasks.getTaskItems(); + }); +}; + +/** * Update quick view using current entries. * * @return {!Promise} Promise fulfilled after quick view is updated. @@ -238,27 +256,40 @@ (/** @type {!FileEntry} */ (this.quickViewModel_.getSelectedEntry())); assert(entry); this.quickViewUma_.onEntryChanged(entry); - return this.metadataModel_.get([entry], ['thumbnailUrl', 'externalFileUrl']) - .then(this.onMetadataLoaded_.bind(this, entry)); + return Promise + .all([ + this.metadataModel_.get([entry], ['thumbnailUrl', 'externalFileUrl']), + this.getAvailableTasks_(entry) + ]) + .then(function(values) { + var items = (/**@type{Array<MetadataItem>}*/ (values[0])); + var tasks = (/**@type{!Array<!FileTask>}*/ (values[1])); + return this.onMetadataLoaded_(entry, items, tasks); + }.bind(this)) + .catch(console.error); }; /** - * Update quick view using file entry and loaded metadata. + * Update quick view using file entry and loaded metadata and tasks. * * @param {!FileEntry} entry * @param {Array<MetadataItem>} items + * @param {!Array<!FileTask>} tasks * @private */ -QuickViewController.prototype.onMetadataLoaded_ = function(entry, items) { - return this.getQuickViewParameters_(entry, items).then(function(params) { - this.quickView_.type = params.type || ''; - this.quickView_.filePath = params.filePath || ''; - this.quickView_.contentUrl = params.contentUrl || ''; - this.quickView_.videoPoster = params.videoPoster || ''; - this.quickView_.audioArtwork = params.audioArtwork || ''; - this.quickView_.autoplay = params.autoplay || false; - this.quickView_.browsable = params.browsable || false; - }.bind(this)); +QuickViewController.prototype.onMetadataLoaded_ = function( + entry, items, tasks) { + return this.getQuickViewParameters_(entry, items, tasks) + .then(function(params) { + this.quickView_.type = params.type || ''; + this.quickView_.filePath = params.filePath || ''; + this.quickView_.hasTask = params.hasTask || false; + this.quickView_.contentUrl = params.contentUrl || ''; + this.quickView_.videoPoster = params.videoPoster || ''; + this.quickView_.audioArtwork = params.audioArtwork || ''; + this.quickView_.autoplay = params.autoplay || false; + this.quickView_.browsable = params.browsable || false; + }.bind(this)); }; /** @@ -277,11 +308,13 @@ /** * @param {!FileEntry} entry * @param {Array<MetadataItem>} items + * @param {!Array<!FileTask>} tasks * @return !Promise<!QuickViewParams> * * @private */ -QuickViewController.prototype.getQuickViewParameters_ = function(entry, items) { +QuickViewController.prototype.getQuickViewParameters_ = function( + entry, items, tasks) { var item = items[0]; var type = FileType.getType(entry).type; @@ -289,97 +322,77 @@ var params = { type: type, filePath: entry.name, + hasTask: tasks.length > 0, }; - /** - * @type function(!FileEntry): !Promise<!File> - */ - var getFile = function(entry) { - return new Promise(function(resolve, reject) { - entry.file(resolve, reject); - }); - }; - - if (type === 'image') { - if (item.externalFileUrl) { - if (item.thumbnailUrl) { - return this.loadThumbnailFromDrive_(item.thumbnailUrl) - .then(function(result) { - if (result.status === 'success') - params.contentUrl = result.data; - return params; - }.bind(this)); - } - } else { - return getFile(entry).then(function(file) { - params.contentUrl = URL.createObjectURL(file); - return params; - }); + if (item.externalFileUrl) { + switch (type) { + case 'image': + if (item.thumbnailUrl) { + return this.loadThumbnailFromDrive_(item.thumbnailUrl) + .then(function(result) { + if (result.status === 'success') + params.contentUrl = result.data; + return params; + }.bind(this)); + } + break; + case 'video': + if (item.thumbnailUrl) { + return this.loadThumbnailFromDrive_(item.thumbnailUrl) + .then(function(result) { + if (result.status === 'success') { + params.videoPoster = result.data; + } + return params; + }); + } + break; } - } else if (type === 'video') { - if (item.externalFileUrl) { - if (item.thumbnailUrl) { - return this.loadThumbnailFromDrive_(item.thumbnailUrl) - .then(function(result) { - if (result.status === 'success') { - params.videoPoster = result.data; - } - return params; - }); - } - } else { - params.autoplay = true; - if (item.thumbnailUrl) { - params.videoPoster = item.thumbnailUrl; - } - return getFile(entry).then(function(file) { - params.contentUrl = URL.createObjectURL(file); - return params; - }); - } - } else if (type === 'audio') { - if (item.externalFileUrl) { - // If the file is in Drive, we ask user to open it with external app. - } else { - params.autoplay = true; - return Promise - .all([ - this.metadataModel_.get([entry], ['contentThumbnailUrl']), - getFile(entry) - ]) - .then(function(values) { - /** @type {!Array<!MetadataItem>} */ - var items = values[0]; - /** @type {!File} */ - var file = values[1]; - var item = items[0]; - if (item.contentThumbnailUrl) { - params.audioArtwork = item.contentThumbnailUrl; - } - params.contentUrl = URL.createObjectURL(file); - return params; - }); - } - } - if (item.externalFileUrl || type === '.folder') { + // If the file is in Drive, we ask user to open it with external app. return Promise.resolve(params); } - return Promise - .all([ - getFile(entry), - new Promise(function(resolve) { - chrome.fileManagerPrivate.getFileTasks([entry], resolve); - }) - ]) - .then(function(values) { - var file = values[0]; - var tasks = values[1]; + + if (type === '.folder') { + return Promise.resolve(params); + } + return new Promise(function(resolve, reject) { + entry.file(resolve, reject); + }) + .then(function(file) { + switch (type) { + case 'image': + params.contentUrl = URL.createObjectURL(file); + return params; + case 'video': + params.contentUrl = URL.createObjectURL(file); + params.autoplay = true; + if (item.thumbnailUrl) { + params.videoPoster = item.thumbnailUrl; + } + return params; + case 'audio': + params.contentUrl = URL.createObjectURL(file); + params.autoplay = true; + return this.metadataModel_.get([entry], ['contentThumbnailUrl']) + .then(function(items) { + var item = items[0]; + if (item.contentThumbnailUrl) { + params.audioArtwork = item.contentThumbnailUrl; + } + return params; + }); + } var browsable = tasks.some(function(task) { return ['view-in-browser', 'view-pdf'].includes( task.taskId.split('|')[2]); }); params.browsable = browsable; - params.contentUrl = browsable && URL.createObjectURL(file); + params.contentUrl = browsable ? URL.createObjectURL(file) : ''; + return params; + }.bind(this)) + .catch(function(e) { + console.error(e); return params; }); };
diff --git a/ui/file_manager/gallery/js/gallery_data_model.js b/ui/file_manager/gallery/js/gallery_data_model.js index 0db7823..ad2b4e5 100644 --- a/ui/file_manager/gallery/js/gallery_data_model.js +++ b/ui/file_manager/gallery/js/gallery_data_model.js
@@ -42,14 +42,6 @@ */ GalleryDataModel.MAX_FULL_IMAGE_CACHE_ = 3; -/** - * Maximum number of screen size image cache. - * @type {number} - * @const - * @private - */ -GalleryDataModel.MAX_SCREEN_IMAGE_CACHE_ = 5; - GalleryDataModel.prototype = { __proto__: cr.ui.ArrayDataModel.prototype };