diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn index cffe6c2..4015196 100644 --- a/base/allocator/BUILD.gn +++ b/base/allocator/BUILD.gn
@@ -216,18 +216,17 @@ "$tcmalloc_dir/src", ] - configs -= [ - "//build/config/compiler:chromium_code", - - # Thumb mode disabled due to bug in clang integrated assembler - # TODO(https://llvm.org/bugs/show_bug.cgi?id=31058) - "//build/config/compiler:compiler_arm_thumb", - ] + configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code", ":tcmalloc_flags", ] + # Thumb mode disabled due to bug in clang integrated assembler + # TODO(https://llvm.org/bugs/show_bug.cgi?id=31058) + configs -= [ "//build/config/compiler:compiler_arm_thumb" ] + configs += [ "//build/config/compiler:compiler_arm" ] + # TODO(crbug.com/633719) Make tcmalloc work with AFDO if possible. configs -= [ "//build/config/compiler:afdo" ]
diff --git a/base/run_loop.cc b/base/run_loop.cc index a2322f8..6faaeee 100644 --- a/base/run_loop.cc +++ b/base/run_loop.cc
@@ -25,6 +25,7 @@ } void RunLoop::Run() { + DCHECK(thread_checker_.CalledOnValidThread()); if (!BeforeRun()) return; @@ -44,6 +45,7 @@ } void RunLoop::Quit() { + DCHECK(thread_checker_.CalledOnValidThread()); quit_called_ = true; if (running_ && loop_->run_loop_ == this) { // This is the inner-most RunLoop, so quit now. @@ -52,6 +54,7 @@ } void RunLoop::QuitWhenIdle() { + DCHECK(thread_checker_.CalledOnValidThread()); quit_when_idle_received_ = true; }
diff --git a/base/run_loop.h b/base/run_loop.h index 635018f43..077d097b 100644 --- a/base/run_loop.h +++ b/base/run_loop.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" +#include "base/threading/thread_checker.h" #include "build/build_config.h" namespace base { @@ -105,6 +106,8 @@ // that we should quit Run once it becomes idle. bool quit_when_idle_received_; + base::ThreadChecker thread_checker_; + // WeakPtrFactory for QuitClosure safety. base::WeakPtrFactory<RunLoop> weak_factory_;
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 661245af..3c6470ae 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -779,6 +779,14 @@ } } +config("compiler_arm") { + if (current_cpu == "arm" && is_chromeos) { + # arm is normally the default mode for clang, but on chromeos a wrapper + # is used to pass -mthumb, and therefor change the default. + cflags = [ "-marm" ] + } +} + # runtime_library ------------------------------------------------------------- # # Sets the runtime library and associated options.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index e135107..02da47b 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- ChromeOS-specific strings (included from generated_resources.grd). +<!-- Chrome OS-specific strings (included from generated_resources.grd). Everything in this file is wrapped in <if expr="chromeos">. --> <grit-part> <message name="IDS_EMPTY_STRING" desc="Empty string, exist only to make code generic. No translation required."> @@ -6171,6 +6171,9 @@ <message name="IDS_ENTERPRISE_ENROLLMENT_STATUS_NO_MACHINE_IDENTIFICATION" desc="Error message shown on the enrollment screen when the system failed to determine the device model or serial number."> Oops! The system failed to determine device model or serial number. </message> + <message name="IDS_ENTERPRISE_ENROLLMENT_ERROR_ACTIVE_DIRECTORY_POLICY_FETCH" desc="Error message shown on the enrollment screen when the system failed to fetch device policy from Active Directory."> + Oops! The system failed to fetch policy from Microsoft® Active Directory®. + </message> <message name="IDS_ENTERPRISE_ENROLLMENT_SCREEN_TITLE" desc="The title on the enterprise enrollment dialog."> Enterprise enrollment </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 6aae3e3d..66c921d 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -4278,6 +4278,8 @@ sources += [ "chromeos/app_mode/fake_cws.cc", "chromeos/app_mode/fake_cws.h", + "chromeos/arc/extensions/fake_arc_support.cc", + "chromeos/arc/extensions/fake_arc_support.h", "chromeos/file_manager/fake_disk_mount_manager.cc", "chromeos/file_manager/fake_disk_mount_manager.h", "chromeos/input_method/mock_candidate_window_controller.cc",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 19f18b12..ade3609 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -252,6 +252,8 @@ "arc/optin/arc_optin_preference_handler.cc", "arc/optin/arc_optin_preference_handler.h", "arc/optin/arc_optin_preference_handler_delegate.h", + "arc/optin/arc_terms_of_service_negotiator.cc", + "arc/optin/arc_terms_of_service_negotiator.h", "arc/policy/arc_android_management_checker.cc", "arc/policy/arc_android_management_checker.h", "arc/policy/arc_android_management_checker_delegate.h", @@ -1408,6 +1410,7 @@ "arc/fileapi/arc_content_file_system_url_util_unittest.cc", "arc/intent_helper/arc_external_protocol_dialog_unittest.cc", "arc/intent_helper/arc_navigation_throttle_unittest.cc", + "arc/optin/arc_terms_of_service_negotiator_unittest.cc", "arc/policy/arc_policy_bridge_unittest.cc", "attestation/attestation_ca_client_unittest.cc", "attestation/attestation_policy_observer_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc index 21effca8..2be4bdc2 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -19,7 +19,7 @@ #include "chrome/browser/chromeos/arc/arc_optin_uma.h" #include "chrome/browser/chromeos/arc/arc_support_host.h" #include "chrome/browser/chromeos/arc/auth/arc_robot_auth.h" -#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.h" +#include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h" #include "chrome/browser/chromeos/arc/policy/arc_android_management_checker.h" #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" @@ -377,11 +377,6 @@ DCHECK(!support_host_); support_host_ = base::MakeUnique<ArcSupportHost>(profile_); support_host_->AddObserver(this); - - preference_handler_ = base::MakeUnique<arc::ArcOptInPreferenceHandler>( - this, profile_->GetPrefs()); - // This automatically updates all preferences. - preference_handler_->Start(); } DCHECK_EQ(State::NOT_INITIALIZED, state_); @@ -493,49 +488,65 @@ if (support_host_) support_host_->SetArcManaged(IsArcManaged()); - // In case UI is disabled we assume that ARC is opted-in. For ARC Kiosk we - // skip ToS because it is very likely that near the device there will be - // no one who is eligible to accept them. We skip if Android management check - // because there are no managed human users for Kiosk exist. - if (IsOptInVerificationDisabled() || IsArcKioskMode()) { - // Automatically accept terms in kiosk mode. This is not required for - // IsOptInVerificationDisabled mode because in last case it may cause - // a privacy issue on next run without this flag set. - if (IsArcKioskMode()) - profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); - StartArc(); - return; - } + // For ARC Kiosk we skip ToS because it is very likely that near the device + // there will be no one who is eligible to accept them. + // TODO(poromov): Move to more Kiosk dedicated set-up phase. + if (IsArcKioskMode()) + profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); - if (!profile_->GetPrefs()->GetBoolean(prefs::kArcSignedIn)) { - if (profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) { - StartArc(); - } else { - // Need pre-fetch auth code and show OptIn UI if needed. - StartUI(); - } - } else { - // Ready to start Arc, but check Android management in parallel. + // If it is marked that sign in has been successfully done, then directly + // start ARC. + // For testing, and for Kisok mode, we also skip ToS negotiation procedure. + // For backward compatibility, this check needs to be prior to the + // kArcTermsAccepted check below. + if (profile_->GetPrefs()->GetBoolean(prefs::kArcSignedIn) || + IsOptInVerificationDisabled() || IsArcKioskMode()) { StartArc(); + + // Skip Android management check for testing. + // We also skip if Android management check for Kiosk mode, + // because there are no managed human users for Kiosk exist. + if (IsOptInVerificationDisabled() || IsArcKioskMode() || + (g_disable_ui_for_testing && + !g_enable_check_android_management_for_testing)) { + return; + } + + // Check Android management in parallel. // Note: Because the callback may be called in synchronous way (i.e. called // on the same stack), StartCheck() needs to be called *after* StartArc(). // Otherwise, DisableArc() which may be called in // OnBackgroundAndroidManagementChecked() could be ignored. - if (!g_disable_ui_for_testing || - g_enable_check_android_management_for_testing) { - android_management_checker_.reset(new ArcAndroidManagementChecker( - profile_, context_->token_service(), context_->account_id(), - true /* retry_on_error */)); - android_management_checker_->StartCheck( - base::Bind(&ArcSessionManager::OnBackgroundAndroidManagementChecked, - weak_ptr_factory_.GetWeakPtr())); - } + android_management_checker_ = base::MakeUnique<ArcAndroidManagementChecker>( + profile_, context_->token_service(), context_->account_id(), + true /* retry_on_error */); + android_management_checker_->StartCheck( + base::Bind(&ArcSessionManager::OnBackgroundAndroidManagementChecked, + weak_ptr_factory_.GetWeakPtr())); + return; } + + // If it is marked that the Terms of service is accepted already, + // just skip the negotiation with user, and start Android management + // check directly. + // This happens, e.g., when; + // 1) User accepted the Terms of service on OOBE flow. + // 2) User accepted the Terms of service on Opt-in flow, but logged out + // before ARC sign in procedure was done. Then, logs in again. + if (profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) { + support_host_->ShowArcLoading(); + StartArcAndroidManagementCheck(); + return; + } + + // Need user's explicit Terms Of Service agreement. + StartTermsOfServiceNegotiation(); } void ArcSessionManager::ShutdownBridge() { arc_sign_in_timer_.Stop(); playstore_launcher_.reset(); + terms_of_service_negotiator_.reset(); android_management_checker_.reset(); arc_bridge_service()->RequestStop(); if (state_ != State::NOT_INITIALIZED) @@ -648,8 +659,9 @@ UpdateEnabledStateUMA(IsArcEnabled()); } -void ArcSessionManager::StartUI() { +void ArcSessionManager::StartTermsOfServiceNegotiation() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(!terms_of_service_negotiator_); if (!arc_bridge_service()->stopped()) { // If the user attempts to re-enable ARC while the bridge is still running @@ -662,8 +674,32 @@ } SetState(State::SHOWING_TERMS_OF_SERVICE); - if (support_host_) - support_host_->ShowTermsOfService(); + if (support_host_) { + terms_of_service_negotiator_ = + base::MakeUnique<ArcTermsOfServiceNegotiator>(profile_->GetPrefs(), + support_host_.get()); + terms_of_service_negotiator_->StartNegotiation( + base::Bind(&ArcSessionManager::OnTermsOfServiceNegotiated, + weak_ptr_factory_.GetWeakPtr())); + } +} + +void ArcSessionManager::OnTermsOfServiceNegotiated(bool accepted) { + DCHECK(terms_of_service_negotiator_); + terms_of_service_negotiator_.reset(); + + if (!accepted) { + // To cancel, user needs to close the window. Note that clicking "Cancel" + // button effectively just closes the window. + CancelAuthCode(); + return; + } + + // Terms were accepted. + profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); + + support_host_->ShowArcLoading(); + StartArcAndroidManagementCheck(); } void ArcSessionManager::StartArcAndroidManagementCheck() { @@ -734,6 +770,11 @@ void ArcSessionManager::OnWindowClosed() { DCHECK(support_host_); + if (terms_of_service_negotiator_) { + // In this case, ArcTermsOfServiceNegotiator should handle the case. + // Do nothing. + return; + } CancelAuthCode(); } @@ -741,19 +782,8 @@ bool is_backup_and_restore_enabled, bool is_location_service_enabled) { DCHECK(support_host_); - - // Terms were accepted - profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); - - // Since this is ARC support's UI event callback, preference_handler_ - // should be always created (see OnPrimaryUserProfilePrepared()). - // TODO(hidehiko): Simplify the logic with the code restructuring. - DCHECK(preference_handler_); - preference_handler_->EnableMetrics(is_metrics_enabled); - preference_handler_->EnableBackupRestore(is_backup_and_restore_enabled); - preference_handler_->EnableLocationService(is_location_service_enabled); - support_host_->ShowArcLoading(); - StartArcAndroidManagementCheck(); + DCHECK(terms_of_service_negotiator_); + // This should be handled in ArcTermsOfServiceNegotiator. Do nothing here. } void ArcSessionManager::OnRetryClicked() { @@ -762,9 +792,11 @@ UpdateOptInActionUMA(OptInActionType::RETRY); // TODO(hidehiko): Simplify the retry logic. - if (!profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) { - // If the user has not yet agreed on Terms of Service, then show it. - support_host_->ShowTermsOfService(); + if (terms_of_service_negotiator_) { + // Currently Terms of service is shown. ArcTermsOfServiceNegotiator should + // handle this. + } else if (!profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) { + StartTermsOfServiceNegotiation(); } else if (support_host_->ui_page() == ArcSupportHost::UIPage::ERROR && !arc_bridge_service()->stopped()) { // ERROR_WITH_FEEDBACK is set in OnSignInFailed(). In the case, stopping @@ -791,26 +823,6 @@ chrome::OpenFeedbackDialog(nullptr); } -void ArcSessionManager::OnMetricsModeChanged(bool enabled, bool managed) { - if (!support_host_) - return; - support_host_->SetMetricsPreferenceCheckbox(enabled, managed); -} - -void ArcSessionManager::OnBackupAndRestoreModeChanged(bool enabled, - bool managed) { - if (!support_host_) - return; - support_host_->SetBackupAndRestorePreferenceCheckbox(enabled, managed); -} - -void ArcSessionManager::OnLocationServicesModeChanged(bool enabled, - bool managed) { - if (!support_host_) - return; - support_host_->SetLocationServicesPreferenceCheckbox(enabled, managed); -} - std::ostream& operator<<(std::ostream& os, const ArcSessionManager::State& state) { switch (state) {
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h index a4e6bbc4..8c14697 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager.h +++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -14,7 +14,6 @@ #include "base/observer_list.h" #include "base/timer/timer.h" #include "chrome/browser/chromeos/arc/arc_support_host.h" -#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler_observer.h" #include "chrome/browser/chromeos/policy/android_management_client.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_service.h" @@ -39,7 +38,7 @@ class ArcAndroidManagementChecker; class ArcAuthCodeFetcher; class ArcAuthContext; -class ArcOptInPreferenceHandler; +class ArcTermsOfServiceNegotiator; enum class ProvisioningResult : int; // This class proxies the request from the client to fetch an auth code from @@ -47,7 +46,6 @@ class ArcSessionManager : public ArcService, public ArcBridgeService::Observer, public ArcSupportHost::Observer, - public ArcOptInPreferenceHandlerObserver, public sync_preferences::PrefServiceSyncableObserver, public sync_preferences::SyncedPrefObserver { public: @@ -181,11 +179,6 @@ void OnRetryClicked() override; void OnSendFeedbackClicked() override; - // ArcOptInPreferenceHandlerObserver: - void OnMetricsModeChanged(bool enabled, bool managed) override; - void OnBackupAndRestoreModeChanged(bool enabled, bool managed) override; - void OnLocationServicesModeChanged(bool enabled, bool managed) override; - // Stops ARC without changing ArcEnabled preference. void StopArc(); @@ -209,11 +202,13 @@ void OnProvisioningFinished(ProvisioningResult result); private: - // TODO(hidehiko): move UI methods/fields to ArcSupportHost. + // Negotiates the terms of service to user. + void StartTermsOfServiceNegotiation(); + void OnTermsOfServiceNegotiated(bool accepted); + void SetState(State state); void ShutdownBridge(); void OnOptInPreferenceChanged(); - void StartUI(); void OnAndroidManagementPassed(); void OnArcDataRemoved(bool success); void OnArcSignInTimeout(); @@ -245,12 +240,9 @@ bool reenable_arc_ = false; base::OneShotTimer arc_sign_in_timer_; - // Temporarily keeps the ArcSupportHost instance. - // This should be moved to ArcSessionManager when the refactoring is - // done. std::unique_ptr<ArcSupportHost> support_host_; - // Handles preferences and metrics mode. - std::unique_ptr<ArcOptInPreferenceHandler> preference_handler_; + + std::unique_ptr<ArcTermsOfServiceNegotiator> terms_of_service_negotiator_; std::unique_ptr<ArcAuthContext> context_; std::unique_ptr<ArcAndroidManagementChecker> android_management_checker_;
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc index e8f90f1..6b6db154 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
@@ -153,6 +153,7 @@ token_service_->UpdateCredentials("", kRefreshToken); profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true); + profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); const AccountId account_id( AccountId::FromUserEmailGaiaId(kFakeUserName, "1234567890"));
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc index 574acaa..7403af09 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
@@ -288,6 +288,8 @@ arc_session_manager()->OnPrimaryUserProfilePrepared(profile()); EXPECT_EQ(ArcSessionManager::State::SHOWING_TERMS_OF_SERVICE, arc_session_manager()->state()); + // Emulate to accept the terms of service. + prefs->SetBoolean(prefs::kArcTermsAccepted, true); arc_session_manager()->StartArc(); EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); EXPECT_TRUE(bridge_service()->ready());
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc index 5e072ad..3941d5d 100644 --- a/chrome/browser/chromeos/arc/arc_support_host.cc +++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -8,6 +8,7 @@ #include <utility> #include "ash/common/system/chromeos/devicetype_utils.h" +#include "base/bind.h" #include "base/i18n/timezone.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" @@ -86,6 +87,18 @@ // "onSendFeedbackClicked" is fired when a user clicks "Send Feedback" button. constexpr char kEventOnSendFeedbackClicked[] = "onSendFeedbackClicked"; +void RequestOpenApp(Profile* profile) { + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension( + ArcSupportHost::kHostAppId); + DCHECK(extension); + DCHECK( + extensions::util::IsAppLaunchable(ArcSupportHost::kHostAppId, profile)); + OpenApplication(CreateAppLaunchParamsUserContainer( + profile, extension, WindowOpenDisposition::NEW_WINDOW, + extensions::SOURCE_CHROME_INTERNAL)); +} + std::ostream& operator<<(std::ostream& os, ArcSupportHost::UIPage ui_page) { switch (ui_page) { case ArcSupportHost::UIPage::NO_PAGE: @@ -140,7 +153,11 @@ // static const char ArcSupportHost::kStorageId[] = "arc_support"; -ArcSupportHost::ArcSupportHost(Profile* profile) : profile_(profile) {} +ArcSupportHost::ArcSupportHost(Profile* profile) + : profile_(profile), + request_open_app_callback_(base::Bind(&RequestOpenApp)) { + DCHECK(profile_); +} ArcSupportHost::~ArcSupportHost() { if (message_host_) @@ -317,7 +334,9 @@ DisconnectMessageHost(); message_host_ = message_host; message_host_->SetObserver(this); - display::Screen::GetScreen()->AddObserver(this); + display::Screen* screen = display::Screen::GetScreen(); + if (screen) + screen->AddObserver(this); if (!Initialize()) { Close(); @@ -352,7 +371,9 @@ void ArcSupportHost::DisconnectMessageHost() { DCHECK(message_host_); - display::Screen::GetScreen()->RemoveObserver(this); + display::Screen* screen = display::Screen::GetScreen(); + if (screen) + screen->RemoveObserver(this); message_host_->SetObserver(nullptr); message_host_ = nullptr; } @@ -362,14 +383,15 @@ DCHECK(!app_start_pending_); app_start_pending_ = true; - const extensions::Extension* extension = - extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension( - kHostAppId); - DCHECK(extension); - DCHECK(extensions::util::IsAppLaunchable(kHostAppId, profile_)); - OpenApplication(CreateAppLaunchParamsUserContainer( - profile_, extension, WindowOpenDisposition::NEW_WINDOW, - extensions::SOURCE_CHROME_INTERNAL)); + request_open_app_callback_.Run(profile_); +} + +void ArcSupportHost::SetRequestOpenAppCallbackForTesting( + const RequestOpenAppCallback& callback) { + DCHECK(!message_host_); + DCHECK(!app_start_pending_); + DCHECK(!callback.is_null()); + request_open_app_callback_ = callback; } bool ArcSupportHost::Initialize() { @@ -463,7 +485,6 @@ const std::string device_id = user_manager::known_user::GetDeviceId( multi_user_util::GetAccountIdFromProfile(profile_)); - DCHECK(!device_id.empty()); message.SetString(kDeviceId, device_id); message_host_->SendMessage(message);
diff --git a/chrome/browser/chromeos/arc/arc_support_host.h b/chrome/browser/chromeos/arc/arc_support_host.h index 1712611a..9a33c41 100644 --- a/chrome/browser/chromeos/arc/arc_support_host.h +++ b/chrome/browser/chromeos/arc/arc_support_host.h
@@ -8,6 +8,7 @@ #include <memory> #include <string> +#include "base/callback.h" #include "base/macros.h" #include "base/observer_list.h" #include "chrome/browser/chromeos/arc/extensions/arc_support_message_host.h" @@ -51,8 +52,6 @@ virtual void OnWindowClosed() {} // Called when the user press AGREE button on ToS page. - // TODO(hidehiko): Currently, due to implementation reason, - // this is also called when RETRY on error page is clicked. Fix this. virtual void OnTermsAgreed(bool is_metrics_enabled, bool is_backup_and_restore_enabled, bool is_location_service_enabled) {} @@ -70,6 +69,8 @@ static const char kHostAppId[]; static const char kStorageId[]; + using RequestOpenAppCallback = base::Callback<void(Profile* profile)>; + explicit ArcSupportHost(Profile* profile); ~ArcSupportHost() override; @@ -124,6 +125,9 @@ // TODO(hidehiko): Remove this exposure. UIPage ui_page() const { return ui_page_; } + void SetRequestOpenAppCallbackForTesting( + const RequestOpenAppCallback& callback); + private: struct PreferenceCheckboxData { PreferenceCheckboxData() : PreferenceCheckboxData(false, false) {} @@ -155,6 +159,7 @@ void DisconnectMessageHost(); Profile* const profile_; + RequestOpenAppCallback request_open_app_callback_; base::ObserverList<Observer> observer_list_;
diff --git a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc new file mode 100644 index 0000000..2b2063a --- /dev/null +++ b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
@@ -0,0 +1,127 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/arc/extensions/fake_arc_support.h" + +#include <string> + +#include "base/bind.h" +#include "base/json/json_reader.h" +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/values.h" +#include "chrome/browser/chromeos/arc/extensions/arc_support_message_host.h" + +namespace arc { + +FakeArcSupport::FakeArcSupport(ArcSupportHost* support_host) + : support_host_(support_host), weak_ptr_factory_(this) { + DCHECK(support_host_); + support_host_->SetRequestOpenAppCallbackForTesting( + base::Bind(&FakeArcSupport::Open, weak_ptr_factory_.GetWeakPtr())); +} + +FakeArcSupport::~FakeArcSupport() { + // Ensure that message host is disconnected. + if (native_message_host_) + Close(); +} + +void FakeArcSupport::Open(Profile* profile) { + DCHECK(!native_message_host_); + native_message_host_ = ArcSupportMessageHost::Create(); + native_message_host_->Start(this); + support_host_->SetMessageHost( + static_cast<ArcSupportMessageHost*>(native_message_host_.get())); +} + +void FakeArcSupport::Close() { + DCHECK(native_message_host_); + native_message_host_->OnMessage("{\"event\": \"onWindowClosed\"}"); + support_host_->UnsetMessageHost( + static_cast<ArcSupportMessageHost*>(native_message_host_.get())); + native_message_host_.reset(); +} + +void FakeArcSupport::ClickAgreeButton() { + DCHECK(native_message_host_); + DCHECK_EQ(ui_page_, ArcSupportHost::UIPage::TERMS); + + base::DictionaryValue message; + message.SetString("event", "onAgreed"); + message.SetBoolean("isMetricsEnabled", metrics_mode_); + message.SetBoolean("isBackupRestoreEnabled", backup_and_restore_mode_); + message.SetBoolean("isLocationServiceEnabled", location_service_mode_); + + std::string message_string; + if (!base::JSONWriter::Write(message, &message_string)) { + NOTREACHED(); + return; + } + native_message_host_->OnMessage(message_string); +} + +void FakeArcSupport::ClickRetryButton() { + DCHECK(native_message_host_); + DCHECK_EQ(ui_page_, ArcSupportHost::UIPage::ERROR); + native_message_host_->OnMessage("{\"event\": \"onRetryClicked\"}"); +} + +void FakeArcSupport::PostMessageFromNativeHost( + const std::string& message_string) { + std::unique_ptr<base::DictionaryValue> message = + base::DictionaryValue::From(base::JSONReader::Read(message_string)); + DCHECK(message); + + std::string action; + if (!message->GetString("action", &action)) { + NOTREACHED() << message_string; + return; + } + + if (action == "initialize") { + // Do nothing as emulation. + } else if (action == "showPage") { + std::string page; + if (!message->GetString("page", &page)) { + NOTREACHED() << message_string; + return; + } + if (page == "terms") { + ui_page_ = ArcSupportHost::UIPage::TERMS; + } else if (page == "lso-loading") { + ui_page_ = ArcSupportHost::UIPage::LSO; + } else if (page == "arc-loading") { + ui_page_ = ArcSupportHost::UIPage::ARC_LOADING; + } else { + NOTREACHED() << message_string; + } + } else if (action == "showErrorPage") { + ui_page_ = ArcSupportHost::UIPage::ERROR; + } else if (action == "setMetricsMode") { + if (!message->GetBoolean("enabled", &metrics_mode_)) { + NOTREACHED() << message_string; + return; + } + } else if (action == "setBackupAndRestoreMode") { + if (!message->GetBoolean("enabled", &backup_and_restore_mode_)) { + NOTREACHED() << message_string; + return; + } + } else if (action == "setLocationServiceMode") { + if (!message->GetBoolean("enabled", &location_service_mode_)) { + NOTREACHED() << message_string; + return; + } + } else { + // Unknown or unsupported action. + NOTREACHED() << message_string; + } +} + +void FakeArcSupport::CloseChannel(const std::string& error_message) { + NOTREACHED(); +} + +} // namespace arc
diff --git a/chrome/browser/chromeos/arc/extensions/fake_arc_support.h b/chrome/browser/chromeos/arc/extensions/fake_arc_support.h new file mode 100644 index 0000000..a0af1b5 --- /dev/null +++ b/chrome/browser/chromeos/arc/extensions/fake_arc_support.h
@@ -0,0 +1,68 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_ARC_EXTENSIONS_FAKE_ARC_SUPPORT_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_EXTENSIONS_FAKE_ARC_SUPPORT_H_ + +#include <memory> +#include <string> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/arc/arc_support_host.h" +#include "extensions/browser/api/messaging/native_message_host.h" + +namespace arc { + +// Fake implementation of ARC support Chrome App for testing. +class FakeArcSupport : public extensions::NativeMessageHost::Client { + public: + explicit FakeArcSupport(ArcSupportHost* support_host); + ~FakeArcSupport() override; + + // Emulates to open ARC support Chrome app, and connect message host to + // ARC support host. + void Open(Profile* profile); + + // Emulates clicking Close button. + void Close(); + + // Terms of service page emulation. + // Emulates clicking Agree button. + void ClickAgreeButton(); + + // Emulates checking preference box. + void set_metrics_mode(bool mode) { metrics_mode_ = mode; } + void set_backup_and_restore_mode(bool mode) { + backup_and_restore_mode_ = mode; + } + void set_location_service_mode(bool mode) { location_service_mode_ = mode; } + + // Error page emulation. + void ClickRetryButton(); + + // Returns the current page. + ArcSupportHost::UIPage ui_page() const { return ui_page_; } + + private: + // extensions::NativeMessageHost::Client: + void PostMessageFromNativeHost(const std::string& message) override; + void CloseChannel(const std::string& error_message) override; + + ArcSupportHost* const support_host_; + + std::unique_ptr<extensions::NativeMessageHost> native_message_host_; + ArcSupportHost::UIPage ui_page_ = ArcSupportHost::UIPage::NO_PAGE; + bool metrics_mode_ = false; + bool backup_and_restore_mode_ = false; + bool location_service_mode_ = false; + + base::WeakPtrFactory<FakeArcSupport> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(FakeArcSupport); +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_EXTENSIONS_FAKE_ARC_SUPPORT_H_
diff --git a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc index 4eac145e..11972d6 100644 --- a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc +++ b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
@@ -24,12 +24,13 @@ } void ArcOptInPreferenceHandler::Start() { - DCHECK(g_browser_process->local_state()); - pref_local_change_registrar_.Init(g_browser_process->local_state()); - pref_local_change_registrar_.Add( - metrics::prefs::kMetricsReportingEnabled, - base::Bind(&ArcOptInPreferenceHandler::OnMetricsPreferenceChanged, - base::Unretained(this))); + if (g_browser_process->local_state()) { + pref_local_change_registrar_.Init(g_browser_process->local_state()); + pref_local_change_registrar_.Add( + metrics::prefs::kMetricsReportingEnabled, + base::Bind(&ArcOptInPreferenceHandler::OnMetricsPreferenceChanged, + base::Unretained(this))); + } pref_change_registrar_.Init(pref_service_); pref_change_registrar_.Add( @@ -63,9 +64,11 @@ } void ArcOptInPreferenceHandler::SendMetricsMode() { - observer_->OnMetricsModeChanged( - ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(), - IsMetricsReportingPolicyManaged()); + if (g_browser_process->local_state()) { + observer_->OnMetricsModeChanged( + ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(), + IsMetricsReportingPolicyManaged()); + } } void ArcOptInPreferenceHandler::SendBackupAndRestoreMode() { @@ -81,7 +84,8 @@ } void ArcOptInPreferenceHandler::EnableMetrics(bool is_enabled) { - ChangeMetricsReportingState(is_enabled); + if (g_browser_process->local_state()) + ChangeMetricsReportingState(is_enabled); } void ArcOptInPreferenceHandler::EnableBackupRestore(bool is_enabled) {
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.cc new file mode 100644 index 0000000..8214aa5a --- /dev/null +++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.cc
@@ -0,0 +1,98 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h" + +#include <string> + +#include "base/callback_helpers.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.h" + +namespace arc { + +ArcTermsOfServiceNegotiator::ArcTermsOfServiceNegotiator( + PrefService* pref_service, + ArcSupportHost* support_host) + : pref_service_(pref_service), support_host_(support_host) { + DCHECK(pref_service_); + DCHECK(support_host_); +} + +ArcTermsOfServiceNegotiator::~ArcTermsOfServiceNegotiator() { + support_host_->RemoveObserver(this); +} + +void ArcTermsOfServiceNegotiator::StartNegotiation( + const NegotiationCallback& callback) { + DCHECK(pending_callback_.is_null()); + DCHECK(!preference_handler_); + pending_callback_ = callback; + preference_handler_ = + base::MakeUnique<ArcOptInPreferenceHandler>(this, pref_service_); + // This automatically updates all preferences. + preference_handler_->Start(); + + support_host_->AddObserver(this); + support_host_->ShowTermsOfService(); +} + +void ArcTermsOfServiceNegotiator::OnWindowClosed() { + DCHECK(!pending_callback_.is_null()); + DCHECK(preference_handler_); + support_host_->RemoveObserver(this); + preference_handler_.reset(); + + // User cancels terms-of-service agreement UI by clicking "Cancel" button + // or closing the window directly. + base::ResetAndReturn(&pending_callback_).Run(false); +} + +void ArcTermsOfServiceNegotiator::OnTermsAgreed( + bool is_metrics_enabled, + bool is_backup_and_restore_enabled, + bool is_location_service_enabled) { + DCHECK(!pending_callback_.is_null()); + DCHECK(preference_handler_); + support_host_->RemoveObserver(this); + + // Update the preferences with the value passed from UI. + preference_handler_->EnableMetrics(is_metrics_enabled); + preference_handler_->EnableBackupRestore(is_backup_and_restore_enabled); + preference_handler_->EnableLocationService(is_location_service_enabled); + preference_handler_.reset(); + + base::ResetAndReturn(&pending_callback_).Run(true); +} + +void ArcTermsOfServiceNegotiator::OnAuthSucceeded( + const std::string& auth_code) { + NOTREACHED(); +} + +void ArcTermsOfServiceNegotiator::OnRetryClicked() { + support_host_->ShowTermsOfService(); +} + +void ArcTermsOfServiceNegotiator::OnSendFeedbackClicked() { + NOTREACHED(); +} + +void ArcTermsOfServiceNegotiator::OnMetricsModeChanged(bool enabled, + bool managed) { + support_host_->SetMetricsPreferenceCheckbox(enabled, managed); +} + +void ArcTermsOfServiceNegotiator::OnBackupAndRestoreModeChanged(bool enabled, + bool managed) { + support_host_->SetBackupAndRestorePreferenceCheckbox(enabled, managed); +} + +void ArcTermsOfServiceNegotiator::OnLocationServicesModeChanged(bool enabled, + bool managed) { + support_host_->SetLocationServicesPreferenceCheckbox(enabled, managed); +} + +} // namespace arc
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h new file mode 100644 index 0000000..41871dde --- /dev/null +++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h
@@ -0,0 +1,66 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_ARC_OPTIN_ARC_TERMS_OF_SERVICE_NEGOTIATOR_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_OPTIN_ARC_TERMS_OF_SERVICE_NEGOTIATOR_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "chrome/browser/chromeos/arc/arc_support_host.h" +#include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler_observer.h" + +class PrefService; + +namespace arc { + +class ArcOptInPreferenceHandler; + +// Handles the Terms-of-service agreement user action. +class ArcTermsOfServiceNegotiator : public ArcSupportHost::Observer, + public ArcOptInPreferenceHandlerObserver { + public: + ArcTermsOfServiceNegotiator(PrefService* pref_service, + ArcSupportHost* support_host); + ~ArcTermsOfServiceNegotiator() override; + + // Shows "Terms of service" page on ARC support Chrome App. Invokes the + // |callback| asynchronously with "|agreed| = true" if user agrees it. + // Otherwise (e.g., user clicks "Cancel" or closes the window), invokes + // |callback| with |agreed| = false. + // Deleting this instance cancels the operation, so |callback| will never + // be invoked then. + using NegotiationCallback = base::Callback<void(bool accepted)>; + void StartNegotiation(const NegotiationCallback& callback); + + private: + // ArcSupportHost::Observer: + void OnWindowClosed() override; + void OnTermsAgreed(bool is_metrics_enabled, + bool is_backup_and_restore_enabled, + bool is_location_service_enabled) override; + void OnAuthSucceeded(const std::string& auth_code) override; + void OnRetryClicked() override; + void OnSendFeedbackClicked() override; + + // ArcOptInPreferenceHandlerObserver: + void OnMetricsModeChanged(bool enabled, bool managed) override; + void OnBackupAndRestoreModeChanged(bool enabled, bool managed) override; + void OnLocationServicesModeChanged(bool enabled, bool managed) override; + + PrefService* const pref_service_; + // Owned by ArcSessionManager. + ArcSupportHost* const support_host_; + + NegotiationCallback pending_callback_; + std::unique_ptr<ArcOptInPreferenceHandler> preference_handler_; + + DISALLOW_COPY_AND_ASSIGN(ArcTermsOfServiceNegotiator); +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_OPTIN_ARC_TERMS_OF_SERVICE_NEGOTIATOR_H_
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator_unittest.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator_unittest.cc new file mode 100644 index 0000000..4feb871 --- /dev/null +++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator_unittest.cc
@@ -0,0 +1,193 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <ostream> + +#include "base/bind.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "chrome/browser/chromeos/arc/arc_support_host.h" +#include "chrome/browser/chromeos/arc/extensions/fake_arc_support.h" +#include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h" +#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" +#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "components/prefs/pref_service.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace arc { + +class ArcTermsOfServiceNegotiatorTest : public testing::Test { + public: + ArcTermsOfServiceNegotiatorTest() = default; + ~ArcTermsOfServiceNegotiatorTest() override = default; + + void SetUp() override { + user_manager_enabler_ = + base::MakeUnique<chromeos::ScopedUserManagerEnabler>( + new chromeos::FakeChromeUserManager()); + + profile_ = base::MakeUnique<TestingProfile>(); + profile_->GetPrefs()->SetBoolean(prefs::kArcBackupRestoreEnabled, false); + profile_->GetPrefs()->SetBoolean(prefs::kArcLocationServiceEnabled, false); + + support_host_ = base::MakeUnique<ArcSupportHost>(profile_.get()); + fake_arc_support_ = base::MakeUnique<FakeArcSupport>(support_host_.get()); + negotiator_ = base::MakeUnique<ArcTermsOfServiceNegotiator>( + profile_->GetPrefs(), support_host()); + } + + void TearDown() override { + negotiator_.reset(); + fake_arc_support_.reset(); + support_host_.reset(); + profile_.reset(); + user_manager_enabler_.reset(); + } + + Profile* profile() { return profile_.get(); } + ArcSupportHost* support_host() { return support_host_.get(); } + FakeArcSupport* fake_arc_support() { return fake_arc_support_.get(); } + ArcTermsOfServiceNegotiator* negotiator() { return negotiator_.get(); } + + private: + // Fake as if the current testing thread is UI thread. + content::TestBrowserThreadBundle bundle_; + + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_; + std::unique_ptr<ArcSupportHost> support_host_; + std::unique_ptr<FakeArcSupport> fake_arc_support_; + std::unique_ptr<ArcTermsOfServiceNegotiator> negotiator_; + + DISALLOW_COPY_AND_ASSIGN(ArcTermsOfServiceNegotiatorTest); +}; + +namespace { + +enum class Status { + PENDING, + ACCEPTED, + CANCELLED, +}; + +// For better logging. +std::ostream& operator<<(std::ostream& os, Status status) { + switch (status) { + case Status::PENDING: + return os << "PENDING"; + case Status::ACCEPTED: + return os << "ACCEPTED"; + case Status::CANCELLED: + return os << "CANCELLED"; + } + + NOTREACHED(); + return os; +} + +ArcTermsOfServiceNegotiator::NegotiationCallback UpdateStatusCallback( + Status* status) { + return base::Bind( + [](Status* status, bool accepted) { + *status = accepted ? Status::ACCEPTED : Status::CANCELLED; + }, + status); +} + +} // namespace + +TEST_F(ArcTermsOfServiceNegotiatorTest, Accept) { + // Show Terms of service page. + Status status = Status::PENDING; + negotiator()->StartNegotiation(UpdateStatusCallback(&status)); + + // TERMS page should be shown. + EXPECT_EQ(status, Status::PENDING); + EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS); + + // Check the preference related checkbox. + fake_arc_support()->set_metrics_mode(true); + fake_arc_support()->set_backup_and_restore_mode(true); + fake_arc_support()->set_location_service_mode(true); + + // Make sure preference values are not yet updated. + EXPECT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled)); + EXPECT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled)); + + // Click the "AGREE" button so that the callback should be invoked + // with |agreed| = true. + fake_arc_support()->ClickAgreeButton(); + EXPECT_EQ(status, Status::ACCEPTED); + + // Make sure preference values are now updated. + EXPECT_TRUE( + profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled)); + EXPECT_TRUE( + profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled)); +} + +TEST_F(ArcTermsOfServiceNegotiatorTest, Cancel) { + // Show Terms of service page. + Status status = Status::PENDING; + negotiator()->StartNegotiation(UpdateStatusCallback(&status)); + + // TERMS page should be shown. + EXPECT_EQ(status, Status::PENDING); + EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS); + + // Check the preference related checkbox. + fake_arc_support()->set_metrics_mode(true); + fake_arc_support()->set_backup_and_restore_mode(true); + fake_arc_support()->set_location_service_mode(true); + + // Make sure preference values are not yet updated. + EXPECT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled)); + EXPECT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled)); + + // Clicking "CANCEL" button closes the window. + fake_arc_support()->Close(); + EXPECT_EQ(status, Status::CANCELLED); + + // Make sure preference checkbox values are discarded. + EXPECT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcBackupRestoreEnabled)); + EXPECT_FALSE( + profile()->GetPrefs()->GetBoolean(prefs::kArcLocationServiceEnabled)); +} + +TEST_F(ArcTermsOfServiceNegotiatorTest, Retry) { + // Show Terms of service page. + Status status = Status::PENDING; + negotiator()->StartNegotiation(UpdateStatusCallback(&status)); + + // TERMS page should be shown. + EXPECT_EQ(status, Status::PENDING); + EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS); + + // Switch to error page. + support_host()->ShowError(ArcSupportHost::Error::SIGN_IN_NETWORK_ERROR, + false); + + // The callback should not be called yet. + EXPECT_EQ(status, Status::PENDING); + EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::ERROR); + + // Click RETRY button on the page, then Terms of service page should be + // re-shown. + fake_arc_support()->ClickRetryButton(); + EXPECT_EQ(status, Status::PENDING); + EXPECT_EQ(fake_arc_support()->ui_page(), ArcSupportHost::UIPage::TERMS); +} + +} // namespace arc
diff --git a/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc b/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc index ab2fecf..29c46fad 100644 --- a/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/zip_file_creator_browsertest.cc
@@ -54,11 +54,10 @@ std::vector<base::FilePath> paths; paths.push_back(base::FilePath(FILE_PATH_LITERAL("not.exist"))); (new ZipFileCreator( - base::Bind( - &TestCallback, &success, content::GetQuitTaskForRunLoop(&run_loop)), - zip_base_dir(), - paths, - zip_archive_path()))->Start(); + base::Bind(&TestCallback, &success, + content::GetDeferredQuitTaskForRunLoop(&run_loop)), + zip_base_dir(), paths, zip_archive_path())) + ->Start(); content::RunThisRunLoop(&run_loop); EXPECT_FALSE(success); @@ -84,11 +83,10 @@ paths.push_back(kFile1); paths.push_back(kFile2); (new ZipFileCreator( - base::Bind( - &TestCallback, &success, content::GetQuitTaskForRunLoop(&run_loop)), - zip_base_dir(), - paths, - zip_archive_path()))->Start(); + base::Bind(&TestCallback, &success, + content::GetDeferredQuitTaskForRunLoop(&run_loop)), + zip_base_dir(), paths, zip_archive_path())) + ->Start(); content::RunThisRunLoop(&run_loop); EXPECT_TRUE(success);
diff --git a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc index 051ec92..4d12d48 100644 --- a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc +++ b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
@@ -421,6 +421,9 @@ case policy::EnrollmentStatus::STATUS_NO_MACHINE_IDENTIFICATION: UMA(policy::kMetricEnrollmentNoDeviceIdentification); break; + case policy::EnrollmentStatus::STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED: + UMA(policy::kMetricEnrollmentActiveDirectoryPolicyFetchFailed); + break; } }
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc index 3338b0d..02c3c067 100644 --- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc +++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -25,6 +25,8 @@ #include "chrome/browser/profiles/profile.h" #include "chromeos/attestation/attestation_flow.h" #include "chromeos/chromeos_switches.h" +#include "chromeos/dbus/auth_policy_client.h" +#include "chromeos/dbus/dbus_thread_manager.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_urls.h" #include "net/http/http_status_code.h" @@ -250,6 +252,7 @@ // enterprise-managed. return; } + LOG(ERROR) << "Error in device policy store."; ReportResult(EnrollmentStatus::ForStoreError(store_->status(), store_->validation_status())); } @@ -488,14 +491,38 @@ return; } + SetStep(STEP_STORE_POLICY); if (device_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD) { - ReportResult(EnrollmentStatus::ForStatus(EnrollmentStatus::STATUS_SUCCESS)); + CHECK(install_attributes_->IsActiveDirectoryManaged()); + // Update device settings so that in case of Active Directory unsigned + // policy is accepted. + chromeos::DeviceSettingsService::Get()->SetDeviceMode( + install_attributes_->GetMode()); + chromeos::DBusThreadManager::Get() + ->GetAuthPolicyClient() + ->RefreshDevicePolicy(base::Bind( + &EnrollmentHandlerChromeOS::HandleActiveDirectoryPolicyRefreshed, + weak_ptr_factory_.GetWeakPtr())); } else { - SetStep(STEP_STORE_POLICY); store_->InstallInitialPolicy(*policy_); } } +void EnrollmentHandlerChromeOS::HandleActiveDirectoryPolicyRefreshed( + bool success) { + DCHECK_EQ(STEP_STORE_POLICY, enrollment_step_); + + if (!success) { + LOG(ERROR) << "Failed to load Active Directory policy."; + ReportResult(EnrollmentStatus::ForStatus( + EnrollmentStatus::STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED)); + return; + } + + // After that, the enrollment flow continues in one of the OnStore* observers. + store_->Load(); +} + void EnrollmentHandlerChromeOS::Stop() { if (client_.get()) client_->RemoveObserver(this);
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h index 7d61578..7d63d22 100644 --- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h +++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
@@ -113,7 +113,8 @@ STEP_LOCK_DEVICE = 8, // Writing installation-time attributes. STEP_STORE_TOKEN_AND_ID = 9, // Storing DM token and virtual device ID. STEP_STORE_ROBOT_AUTH = 10, // Encrypting & writing robot refresh token. - STEP_STORE_POLICY = 11, // Storing policy and API refresh token. + STEP_STORE_POLICY = 11, // Storing policy and API refresh token. For + // AD, includes policy fetch via authpolicyd. STEP_FINISHED = 12, // Enrollment process done, no further action. }; @@ -154,6 +155,9 @@ // Handles completion of the robot token store operation. void HandleStoreRobotAuthTokenResult(bool result); + // Handles result from device policy refresh via authpolicyd. + void HandleActiveDirectoryPolicyRefreshed(bool success); + // Drops any ongoing actions. void Stop();
diff --git a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h index b437347..4930f38 100644 --- a/chrome/browser/chromeos/policy/enrollment_status_chromeos.h +++ b/chrome/browser/chromeos/policy/enrollment_status_chromeos.h
@@ -43,6 +43,9 @@ STATUS_REGISTRATION_CERTIFICATE_FETCH_FAILED = 15, // Cannot obtain // registration cert. STATUS_NO_MACHINE_IDENTIFICATION = 16, // Machine model or serial missing. + STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED = 17, // Failed to fetch Active + // Directory policy via + // authpolicyd. }; // Helpers for constructing errors for relevant cases.
diff --git a/chrome/browser/chromeos/settings/device_settings_service.cc b/chrome/browser/chromeos/settings/device_settings_service.cc index d96df94..73cd756 100644 --- a/chrome/browser/chromeos/settings/device_settings_service.cc +++ b/chrome/browser/chromeos/settings/device_settings_service.cc
@@ -132,6 +132,8 @@ void DeviceSettingsService::Store( std::unique_ptr<em::PolicyFetchResponse> policy, const base::Closure& callback) { + // On Active Directory managed devices policy is written only by authpolicyd. + CHECK(device_mode_ != policy::DEVICE_MODE_ENTERPRISE_AD); Enqueue(linked_ptr<SessionManagerOperation>(new StoreSettingsOperation( base::Bind(&DeviceSettingsService::HandleCompletedOperation, weak_factory_.GetWeakPtr(), callback), @@ -256,9 +258,6 @@ const base::Closure& callback, SessionManagerOperation* operation, Status status) { - // Exactly one must be true: Active Directory management or existence of key. - DCHECK((device_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD) != - (operation->public_key() != nullptr)); DCHECK_EQ(operation, pending_operations_.front().get()); store_status_ = status;
diff --git a/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm b/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm index 3e6b7f2d..1f69ccd 100644 --- a/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm +++ b/chrome/browser/global_keyboard_shortcuts_mac_browsertest.mm
@@ -18,6 +18,20 @@ using GlobalKeyboardShortcutsTest = ExtensionBrowserTest; +namespace { + +void ActivateAccelerator(NSWindow* window, NSEvent* ns_event) { + if ([window performKeyEquivalent:ns_event]) + return; + + // This is consistent with the way AppKit dispatches events when + // -performKeyEquivalent: returns NO. See "The Path of Key Events" in the + // Cocoa Event Architecture documentation. + [window sendEvent:ns_event]; +} + +} // namespace + // Test that global keyboard shortcuts are handled by the native window. IN_PROC_BROWSER_TEST_F(GlobalKeyboardShortcutsTest, SwitchTabsMac) { NSWindow* ns_window = browser()->window()->GetNativeWindow(); @@ -29,17 +43,19 @@ EXPECT_TRUE(tab_strip->IsTabSelected(1)); // Ctrl+Tab goes to the next tab, which loops back to the first tab. - [ns_window performKeyEquivalent:SynthesizeKeyEvent( - ns_window, true, ui::VKEY_TAB, NSControlKeyMask)]; + ActivateAccelerator( + ns_window, + SynthesizeKeyEvent(ns_window, true, ui::VKEY_TAB, NSControlKeyMask)); EXPECT_TRUE(tab_strip->IsTabSelected(0)); // Cmd+2 goes to the second tab. - [ns_window performKeyEquivalent:SynthesizeKeyEvent( - ns_window, true, ui::VKEY_2, NSCommandKeyMask)]; + ActivateAccelerator(ns_window, SynthesizeKeyEvent(ns_window, true, ui::VKEY_2, + NSCommandKeyMask)); EXPECT_TRUE(tab_strip->IsTabSelected(1)); // Cmd+{ goes to the previous tab. - [ns_window performKeyEquivalent:SynthesizeKeyEvent( - ns_window, true, ui::VKEY_OEM_4, NSShiftKeyMask | NSCommandKeyMask)]; + ActivateAccelerator(ns_window, + SynthesizeKeyEvent(ns_window, true, ui::VKEY_OEM_4, + NSShiftKeyMask | NSCommandKeyMask)); EXPECT_TRUE(tab_strip->IsTabSelected(0)); }
diff --git a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc index 18547fa..ac58ac3f 100644 --- a/chrome/browser/media/webrtc/webrtc_text_log_handler.cc +++ b/chrome/browser/media/webrtc/webrtc_text_log_handler.cc
@@ -24,6 +24,7 @@ #include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/render_process_host.h" #include "gpu/config/gpu_info.h" +#include "media/audio/audio_manager.h" #include "net/base/ip_address.h" #include "net/base/network_change_notifier.h" #include "net/base/network_interfaces.h" @@ -474,6 +475,13 @@ ", gl-renderer=" + gpu_info.gl_renderer + ", gl-version=" + gpu_info.gl_version); + // Audio manager + // On some platforms, this can vary depending on build flags and failure + // fallbacks. On Linux for example, we fallback on ALSA if PulseAudio fails to + // initialize. + LogToCircularBuffer(base::StringPrintf( + "Audio manager: %s", media::AudioManager::Get()->GetName())); + // Network interfaces LogToCircularBuffer("Discovered " + base::SizeTToString(network_list.size()) + " network interfaces:");
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index 2ceb570..d89f788 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc
@@ -3956,6 +3956,8 @@ arc::ArcSessionManager::DisableUIForTesting(); browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true); + browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, + true); } void TearDownTest() { arc::ArcSessionManager::Get()->Shutdown(); }
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html index 0fe8c28..9aa5ecf 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html +++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -23,8 +23,17 @@ width: 0; } + /* The following non-flex directives allow eliding long originUrls from + * the left. Forcing rtl should not cause an issue for right-to-left + * languages in this case, since valid URL characters are restricted to + * ASCII. */ .website-column { + direction: rtl; flex: 3; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; } .username-column {
diff --git a/chrome/browser/sync/test/integration/dictionary_helper.cc b/chrome/browser/sync/test/integration/dictionary_helper.cc index 30f92967..e6fd2914 100644 --- a/chrome/browser/sync/test/integration/dictionary_helper.cc +++ b/chrome/browser/sync/test/integration/dictionary_helper.cc
@@ -56,7 +56,8 @@ if (dictionary->IsLoaded()) return; base::RunLoop run_loop; - DictionaryLoadObserver observer(content::GetQuitTaskForRunLoop(&run_loop)); + DictionaryLoadObserver observer( + content::GetDeferredQuitTaskForRunLoop(&run_loop)); dictionary->AddObserver(&observer); dictionary->Load(); content::RunThisRunLoop(&run_loop);
diff --git a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc index c4d0035..8475219 100644 --- a/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc +++ b/chrome/browser/sync_file_system/sync_file_system_service_unittest.cc
@@ -73,12 +73,11 @@ run_loop->Quit(); } -// This is called on IO thread. -void VerifyFileError(base::RunLoop* run_loop, +// This is called on IO thread. Posts |callback| to be called on UI thread. +void VerifyFileError(base::Closure callback, base::File::Error error) { - DCHECK(run_loop); EXPECT_EQ(base::File::FILE_OK, error); - run_loop->Quit(); + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); } } // namespace @@ -430,7 +429,7 @@ base::Bind(&CannedSyncableFileSystem::DoCreateFile, base::Unretained(file_system_.get()), kFile, base::Bind(&VerifyFileError, - &verify_file_error_run_loop))); + verify_file_error_run_loop.QuitClosure()))); run_loop.Run();
diff --git a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc b/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc index 820ab2c..069af32 100644 --- a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc +++ b/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
@@ -213,7 +213,7 @@ private: void RunUntilTabActive(Browser* browser, int target) { base::RunLoop run_loop; - quit_closure_ = content::GetQuitTaskForRunLoop(&run_loop); + quit_closure_ = content::GetDeferredQuitTaskForRunLoop(&run_loop); browser->tab_strip_model()->AddObserver(this); target_index_ = target; content::RunThisRunLoop(&run_loop);
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc index 4f2bcd5e..6741c32c 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -382,6 +382,10 @@ ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_NO_MACHINE_IDENTIFICATION, false); return; + case policy::EnrollmentStatus::STATUS_ACTIVE_DIRECTORY_POLICY_FETCH_FAILED: + ShowError(IDS_ENTERPRISE_ENROLLMENT_ERROR_ACTIVE_DIRECTORY_POLICY_FETCH, + false); + return; } NOTREACHED(); }
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index f2c32ae..d175997 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -651,7 +651,7 @@ return; base::RunLoop run_loop; HistoryIndexRestoreObserver observer( - content::GetQuitTaskForRunLoop(&run_loop)); + content::GetDeferredQuitTaskForRunLoop(&run_loop)); index->set_restore_cache_observer(&observer); run_loop.Run(); index->set_restore_cache_observer(NULL);
diff --git a/chromecast/media/audio/cast_audio_manager.cc b/chromecast/media/audio/cast_audio_manager.cc index 230a1f9..fbad984 100644 --- a/chromecast/media/audio/cast_audio_manager.cc +++ b/chromecast/media/audio/cast_audio_manager.cc
@@ -83,6 +83,10 @@ ::media::CHANNEL_LAYOUT_STEREO, 48000, 16, 1024); } +const char* CastAudioManager::GetName() { + return "Cast"; +} + std::unique_ptr<MediaPipelineBackend> CastAudioManager::CreateMediaPipelineBackend( const MediaPipelineDeviceParams& params) {
diff --git a/chromecast/media/audio/cast_audio_manager.h b/chromecast/media/audio/cast_audio_manager.h index f9a733e..677954ea 100644 --- a/chromecast/media/audio/cast_audio_manager.h +++ b/chromecast/media/audio/cast_audio_manager.h
@@ -39,6 +39,7 @@ ::media::AudioDeviceNames* device_names) override; ::media::AudioParameters GetInputStreamParameters( const std::string& device_id) override; + const char* GetName() override; // AudioManagerBase implementation void ReleaseOutputStream(::media::AudioOutputStream* stream) override;
diff --git a/components/policy/core/common/cloud/enterprise_metrics.h b/components/policy/core/common/cloud/enterprise_metrics.h index 7d84783..7f8427be 100644 --- a/components/policy/core/common/cloud/enterprise_metrics.h +++ b/components/policy/core/common/cloud/enterprise_metrics.h
@@ -226,6 +226,8 @@ kMetricEnrollmentRegisterCannotSignRequest = 53, // Device model or serial number missing from VPD. kMetricEnrollmentNoDeviceIdentification = 54, + // Active Directory policy fetch failed. + kMetricEnrollmentActiveDirectoryPolicyFetchFailed = 55, }; // Events related to policy refresh.
diff --git a/components/policy/core/common/schema_map.cc b/components/policy/core/common/schema_map.cc index 90d62c56..dd2a329 100644 --- a/components/policy/core/common/schema_map.cc +++ b/components/policy/core/common/schema_map.cc
@@ -70,10 +70,10 @@ SCHEMA_STRICT, &error_path, &error)) { - LOG(ERROR) << "Dropping policy " << policy_name << " for " - << it->first.component_id - << " because it's not valid: " << error - << " at " << error_path; + LOG(ERROR) << "Dropping policy " << policy_name << " of component " + << it->first.component_id << " due to error at " + << (error_path.empty() ? "root" : error_path) << ": " + << error; map->Erase(policy_name); } }
diff --git a/content/browser/loader/async_revalidation_manager_browsertest.cc b/content/browser/loader/async_revalidation_manager_browsertest.cc index 2646222..2a9b8c33 100644 --- a/content/browser/loader/async_revalidation_manager_browsertest.cc +++ b/content/browser/loader/async_revalidation_manager_browsertest.cc
@@ -90,8 +90,10 @@ // The second time this handler is run is the async revalidation. Tests can // use this for synchronisation. - if (version == 2) - run_loop_.Quit(); + if (version == 2) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + run_loop_.QuitClosure()); + } return std::move(http_response); }
diff --git a/content/public/test/test_launcher.h b/content/public/test/test_launcher.h index 522c5fd..b58f9b75d 100644 --- a/content/public/test/test_launcher.h +++ b/content/public/test/test_launcher.h
@@ -14,7 +14,6 @@ namespace base { class CommandLine; class FilePath; -class RunLoop; } namespace content { @@ -47,8 +46,6 @@ virtual bool AdjustChildProcessCommandLine( base::CommandLine* command_line, const base::FilePath& temp_data_dir) = 0; - virtual void PreRunMessageLoop(base::RunLoop* run_loop) {} - virtual void PostRunMessageLoop() {} virtual ContentMainDelegate* CreateContentMainDelegate() = 0; // Called prior to running each test. The delegate may alter the CommandLine
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc index a19a31d..4c6449d 100644 --- a/content/public/test/test_utils.cc +++ b/content/public/test/test_utils.cc
@@ -120,23 +120,14 @@ void RunThisRunLoop(base::RunLoop* run_loop) { base::MessageLoop::ScopedNestableTaskAllower allow( base::MessageLoop::current()); - - // If we're running inside a browser test, we might need to allow the test - // launcher to do extra work before/after running a nested message loop. - TestLauncherDelegate* delegate = NULL; - delegate = GetCurrentTestLauncherDelegate(); - if (delegate) - delegate->PreRunMessageLoop(run_loop); run_loop->Run(); - if (delegate) - delegate->PostRunMessageLoop(); } void RunAllPendingInMessageLoop() { DCHECK_CURRENTLY_ON(BrowserThread::UI); base::RunLoop run_loop; base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, GetQuitTaskForRunLoop(&run_loop)); + FROM_HERE, GetDeferredQuitTaskForRunLoop(&run_loop)); RunThisRunLoop(&run_loop); } @@ -175,7 +166,7 @@ } } -base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop) { +base::Closure GetDeferredQuitTaskForRunLoop(base::RunLoop* run_loop) { return base::Bind(&DeferredQuitRunLoop, run_loop->QuitClosure(), kNumQuitDeferrals); } @@ -240,7 +231,7 @@ if (loop_running_) { switch (quit_mode_) { case QuitMode::DEFERRED: - GetQuitTaskForRunLoop(&run_loop_).Run(); + GetDeferredQuitTaskForRunLoop(&run_loop_).Run(); break; case QuitMode::IMMEDIATE: run_loop_.Quit();
diff --git a/content/public/test/test_utils.h b/content/public/test/test_utils.h index e6bbc562..6e46fd2 100644 --- a/content/public/test/test_utils.h +++ b/content/public/test/test_utils.h
@@ -62,7 +62,7 @@ // Get task to quit the given RunLoop. It allows a few generations of pending // tasks to run as opposed to run_loop->QuitClosure(). -base::Closure GetQuitTaskForRunLoop(base::RunLoop* run_loop); +base::Closure GetDeferredQuitTaskForRunLoop(base::RunLoop* run_loop); // Executes the specified JavaScript in the specified frame, and runs a nested // MessageLoop. When the result is available, it is returned. @@ -91,6 +91,12 @@ // has returned is safe and has no effect. // Note that by default Quit does not quit immediately. If that is not what you // really need, pass QuitMode::IMMEDIATE in the constructor. +// +// DEPRECATED. Consider using base::RunLoop, in most cases MessageLoopRunner is +// not needed. If you need to defer quitting the loop, use +// GetDeferredQuitTaskForRunLoop directly. +// If you found a case where base::RunLoop is inconvenient or can not be used at +// all, please post details in a comment on https://crbug.com/668707. class MessageLoopRunner : public base::RefCounted<MessageLoopRunner> { public: enum class QuitMode {
diff --git a/content/renderer/media/gpu/rtc_video_decoder.cc b/content/renderer/media/gpu/rtc_video_decoder.cc index 34100350..929ab57 100644 --- a/content/renderer/media/gpu/rtc_video_decoder.cc +++ b/content/renderer/media/gpu/rtc_video_decoder.cc
@@ -210,10 +210,10 @@ #endif bool need_to_reset_for_midstream_resize = false; - if (inputImage._frameType == webrtc::kVideoFrameKey) { - const gfx::Size new_frame_size(inputImage._encodedWidth, - inputImage._encodedHeight); - DVLOG(2) << "Got key frame. size=" << new_frame_size.ToString(); + const gfx::Size new_frame_size(inputImage._encodedWidth, + inputImage._encodedHeight); + if (!new_frame_size.IsEmpty() && new_frame_size != frame_size_) { + DVLOG(2) << "Got new size=" << new_frame_size.ToString(); if (new_frame_size.width() > max_resolution_.width() || new_frame_size.width() < min_resolution_.width() || @@ -237,7 +237,7 @@ // If we're are in an error condition, increase the counter. vda_error_counter_ += vda_error_counter_ ? 1 : 0; - DVLOG(1) << "The first frame should be a key frame. Drop this."; + DVLOG(1) << "The first frame should have resolution. Drop this."; return WEBRTC_VIDEO_CODEC_ERROR; }
diff --git a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc index 877d457..7fdbb91 100644 --- a/content/renderer/media/gpu/rtc_video_decoder_unittest.cc +++ b/content/renderer/media/gpu/rtc_video_decoder_unittest.cc
@@ -291,8 +291,8 @@ webrtc::EncodedImage input_image; input_image._completeFrame = true; - input_image._encodedWidth = kMinResolutionWidth; - input_image._encodedHeight = kMaxResolutionHeight; + input_image._encodedWidth = 0; + input_image._encodedHeight = 0; input_image._frameType = webrtc::kVideoFrameDelta; input_image._length = kMinResolutionWidth * kMaxResolutionHeight; EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, @@ -310,8 +310,8 @@ rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting()); - // Decoder expects a keyframe after reset, so drops any other frames. However, - // we should still increment the error counter. + // Decoder expects a frame with size after reset, so drops any other frames. + // However, we should still increment the error counter. EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); EXPECT_EQ(2, rtc_decoder_->GetVDAErrorCounterForTesting());
diff --git a/extensions/test/result_catcher.cc b/extensions/test/result_catcher.cc index 53c569ff..f2e9801 100644 --- a/extensions/test/result_catcher.cc +++ b/extensions/test/result_catcher.cc
@@ -30,7 +30,7 @@ // empty. if (results_.empty()) { base::RunLoop run_loop; - quit_closure_ = content::GetQuitTaskForRunLoop(&run_loop); + quit_closure_ = content::GetDeferredQuitTaskForRunLoop(&run_loop); content::RunThisRunLoop(&run_loop); quit_closure_ = base::Closure(); }
diff --git a/ios/chrome/browser/favicon/BUILD.gn b/ios/chrome/browser/favicon/BUILD.gn index 162387ab..01b0c56 100644 --- a/ios/chrome/browser/favicon/BUILD.gn +++ b/ios/chrome/browser/favicon/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("favicon") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "favicon_attributes.h", "favicon_attributes.mm",
diff --git a/ios/chrome/browser/favicon/favicon_attributes.mm b/ios/chrome/browser/favicon/favicon_attributes.mm index b0b0050f..3659175 100644 --- a/ios/chrome/browser/favicon/favicon_attributes.mm +++ b/ios/chrome/browser/favicon/favicon_attributes.mm
@@ -5,11 +5,12 @@ #import "ios/chrome/browser/favicon/favicon_attributes.h" #include "base/logging.h" -#include "base/mac/objc_property_releaser.h" -@implementation FaviconAttributes { - base::mac::ObjCPropertyReleaser _propertyReleaser_FaviconAttributes; -} +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation FaviconAttributes @synthesize faviconImage = _faviconImage; @synthesize monogramString = _monogramString; @synthesize textColor = _textColor; @@ -22,11 +23,10 @@ DCHECK(image || (monogram && textColor && backgroundColor)); self = [super init]; if (self) { - _propertyReleaser_FaviconAttributes.Init(self, [FaviconAttributes class]); - _faviconImage = [image retain]; + _faviconImage = image; _monogramString = [monogram copy]; - _textColor = [textColor retain]; - _backgroundColor = [backgroundColor retain]; + _textColor = textColor; + _backgroundColor = backgroundColor; } return self; @@ -49,15 +49,15 @@ } + (instancetype)attributesWithImage:(UIImage*)image { - return [[[self alloc] initWithImage:image] autorelease]; + return [[self alloc] initWithImage:image]; } + (instancetype)attributesWithMonogram:(NSString*)monogram textColor:(UIColor*)textColor backgroundColor:(UIColor*)backgroundColor { - return [[[self alloc] initWithMonogram:monogram - textColor:textColor - backgroundColor:backgroundColor] autorelease]; + return [[self alloc] initWithMonogram:monogram + textColor:textColor + backgroundColor:backgroundColor]; } @end
diff --git a/ios/chrome/browser/favicon/favicon_attributes_provider.mm b/ios/chrome/browser/favicon/favicon_attributes_provider.mm index a417397..9e852cb6 100644 --- a/ios/chrome/browser/favicon/favicon_attributes_provider.mm +++ b/ios/chrome/browser/favicon/favicon_attributes_provider.mm
@@ -16,6 +16,10 @@ #include "skia/ext/skia_utils_ios.h" #include "url/gurl.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + @interface FaviconAttributesProvider () { // Used to cancel tasks for the LargeIconService. base::CancelableTaskTracker _faviconTaskTracker; @@ -76,7 +80,7 @@ CGFloat faviconSize = [UIScreen mainScreen].scale * self.faviconSize; CGFloat minFaviconSize = [UIScreen mainScreen].scale * self.minSize; self.largeIconService->GetLargeIconOrFallbackStyle( - URL, minFaviconSize, faviconSize, base::BindBlock(faviconBlock), + URL, minFaviconSize, faviconSize, base::BindBlockArc(faviconBlock), &_faviconTaskTracker); } @end
diff --git a/ios/chrome/browser/favicon/favicon_client_impl.mm b/ios/chrome/browser/favicon/favicon_client_impl.mm index a35e4b27..860e4894 100644 --- a/ios/chrome/browser/favicon/favicon_client_impl.mm +++ b/ios/chrome/browser/favicon/favicon_client_impl.mm
@@ -11,6 +11,10 @@ #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #include "url/gurl.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace { void RunFaviconCallbackIfNotCanceled(
diff --git a/ios/chrome/browser/favicon/favicon_loader.h b/ios/chrome/browser/favicon/favicon_loader.h index 60f8ccc..ee8a9ba6 100644 --- a/ios/chrome/browser/favicon/favicon_loader.h +++ b/ios/chrome/browser/favicon/favicon_loader.h
@@ -8,7 +8,6 @@ #include <memory> #include <vector> -#import "base/mac/scoped_nsobject.h" #include "base/macros.h" #include "base/task/cancelable_task_tracker.h" #include "base/threading/thread_checker.h" @@ -69,7 +68,7 @@ // Holds cached favicons. This dictionary is populated as favicons are // retrieved from the FaviconService. This will be emptied during low-memory // conditions. Keyed by NSString of URL spec. - base::scoped_nsobject<NSMutableDictionary> favicon_cache_; + NSMutableDictionary* favicon_cache_; DISALLOW_COPY_AND_ASSIGN(FaviconLoader); };
diff --git a/ios/chrome/browser/favicon/favicon_loader.mm b/ios/chrome/browser/favicon/favicon_loader.mm index eb947b1..ccde02f8 100644 --- a/ios/chrome/browser/favicon/favicon_loader.mm +++ b/ios/chrome/browser/favicon/favicon_loader.mm
@@ -14,20 +14,23 @@ #include "ui/gfx/favicon_size.h" #include "url/gurl.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + struct FaviconLoader::RequestData { RequestData() {} RequestData(NSString* key, FaviconLoader::ImageCompletionBlock block) - : key([key copy]), block(block, base::scoped_policy::RETAIN) {} + : key([key copy]), block(block) {} ~RequestData() {} - base::scoped_nsobject<NSString> key; + NSString* key; base::mac::ScopedBlock<FaviconLoader::ImageCompletionBlock> block; }; FaviconLoader::FaviconLoader(favicon::FaviconService* favicon_service) : favicon_service_(favicon_service), - favicon_cache_([[NSMutableDictionary dictionaryWithCapacity:10] retain]) { -} + favicon_cache_([NSMutableDictionary dictionaryWithCapacity:10]) {} FaviconLoader::~FaviconLoader() {} @@ -67,8 +70,7 @@ void FaviconLoader::PurgeCache() { DCHECK(thread_checker_.CalledOnValidThread()); cancelable_task_tracker_.TryCancelAll(); - favicon_cache_.reset( - [[NSMutableDictionary dictionaryWithCapacity:10] retain]); + favicon_cache_ = [NSMutableDictionary dictionaryWithCapacity:10]; } void FaviconLoader::OnFaviconAvailable(
diff --git a/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm b/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm index 5b99726..c839d07a 100644 --- a/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm +++ b/ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.mm
@@ -13,6 +13,10 @@ #import "ios/chrome/browser/favicon/favicon_loader.h" #include "ios/chrome/browser/favicon/favicon_service_factory.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + FaviconLoader* IOSChromeFaviconLoaderFactory::GetForBrowserState( ios::ChromeBrowserState* browser_state) { return static_cast<FaviconLoader*>(
diff --git a/ios/chrome/browser/reading_list/BUILD.gn b/ios/chrome/browser/reading_list/BUILD.gn index 6a07d576..7c7148b 100644 --- a/ios/chrome/browser/reading_list/BUILD.gn +++ b/ios/chrome/browser/reading_list/BUILD.gn
@@ -10,6 +10,8 @@ "reading_list_download_service.h", "reading_list_download_service_factory.cc", "reading_list_download_service_factory.h", + "reading_list_entry_loading_util.h", + "reading_list_entry_loading_util.mm", "reading_list_model_factory.cc", "reading_list_model_factory.h", "reading_list_web_state_observer.h", @@ -41,6 +43,7 @@ testonly = true sources = [ "offline_url_utils_unittest.cc", + "reading_list_entry_loading_util_unittest.mm", "url_downloader_unittest.mm", ] deps = [ @@ -50,7 +53,9 @@ "//components/reading_list/ios", "//ios/chrome/browser", "//ios/chrome/browser/dom_distiller", + "//ios/web", "//ios/web:test_support", + "//net", "//testing/gtest", "//url", ]
diff --git a/ios/chrome/browser/reading_list/offline_url_utils.cc b/ios/chrome/browser/reading_list/offline_url_utils.cc index f8b3086..b3d3037 100644 --- a/ios/chrome/browser/reading_list/offline_url_utils.cc +++ b/ios/chrome/browser/reading_list/offline_url_utils.cc
@@ -8,14 +8,40 @@ #include "base/strings/stringprintf.h" #include "components/reading_list/ios/offline_url_utils.h" #include "ios/chrome/browser/chrome_url_constants.h" +#include "net/base/url_util.h" + +namespace { +const char kVirtualURLQueryParam[] = "virtualURL"; +} namespace reading_list { -GURL DistilledURLForPath(const base::FilePath& distilled_path) { +GURL DistilledURLForPath(const base::FilePath& distilled_path, + const GURL& virtual_url) { if (distilled_path.empty()) { return GURL(); } - return GURL(kChromeUIOfflineURL + distilled_path.value()); + GURL page_url(kChromeUIOfflineURL); + GURL::Replacements replacements; + replacements.SetPathStr(distilled_path.value()); + page_url = page_url.ReplaceComponents(replacements); + if (virtual_url.is_valid()) { + page_url = net::AppendQueryParameter(page_url, kVirtualURLQueryParam, + virtual_url.spec()); + } + return page_url; +} + +GURL VirtualURLForDistilledURL(const GURL& distilled_url) { + std::string virtual_url_string; + if (net::GetValueForKeyInQuery(distilled_url, kVirtualURLQueryParam, + &virtual_url_string)) { + GURL virtual_url = GURL(virtual_url_string); + if (virtual_url.is_valid()) { + return virtual_url; + } + } + return distilled_url; } GURL FileURLForDistilledURL(const GURL& distilled_url,
diff --git a/ios/chrome/browser/reading_list/offline_url_utils.h b/ios/chrome/browser/reading_list/offline_url_utils.h index c0997c7..bee8586 100644 --- a/ios/chrome/browser/reading_list/offline_url_utils.h +++ b/ios/chrome/browser/reading_list/offline_url_utils.h
@@ -13,7 +13,11 @@ namespace reading_list { // The distilled URL chrome://offline/... that will load the file at |path|. -GURL DistilledURLForPath(const base::FilePath& path); +GURL DistilledURLForPath(const base::FilePath& path, const GURL& virtual_url); + +// If |distilled_url| has a query "virtualURL" query params that is a URL, +// returns it. If not, return |distilled_url| +GURL VirtualURLForDistilledURL(const GURL& distilled_url); // The file URL pointing to the local file to load to display |distilled_url|. // If |resources_root_url| is not nullptr, it is set to a file URL to the
diff --git a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc index 9f68501..7beea10 100644 --- a/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc +++ b/ios/chrome/browser/reading_list/offline_url_utils_unittest.cc
@@ -13,10 +13,36 @@ // Checks the distilled URL for the page is chrome://offline/MD5/page.html; TEST(OfflineURLUtilsTest, DistilledURLForPathTest) { base::FilePath page_path("MD5/page.html"); - GURL distilled_url = reading_list::DistilledURLForPath(page_path); + GURL distilled_url = reading_list::DistilledURLForPath(page_path, GURL()); EXPECT_EQ("chrome://offline/MD5/page.html", distilled_url.spec()); } +// Checks the distilled URL for the page with an onlineURL is +// chrome://offline/MD5/page.html?virtualURL=encorded%20URL; +TEST(OfflineURLUtilsTest, DistilledURLForPathWithVirtualURLTest) { + base::FilePath page_path("MD5/page.html"); + GURL online_url = GURL("http://foo.bar"); + GURL distilled_url = reading_list::DistilledURLForPath(page_path, online_url); + EXPECT_EQ("chrome://offline/MD5/page.html?virtualURL=http%3A%2F%2Ffoo.bar%2F", + distilled_url.spec()); +} + +// Checks the distilled URL for the page is chrome://offline/MD5/page.html; +TEST(OfflineURLUtilsTest, VirtualURLForDistilledURLTest) { + GURL distilled_url("chrome://offline/MD5/page.html"); + GURL virtual_url = reading_list::VirtualURLForDistilledURL(distilled_url); + EXPECT_EQ("chrome://offline/MD5/page.html", virtual_url.spec()); +} + +// Checks the distilled URL for the page with an onlineURL is +// chrome://offline/MD5/page.html?virtualURL=encorded%20URL; +TEST(OfflineURLUtilsTest, VirtualURLForDistilledURLWithVirtualURLTest) { + GURL distilled_url( + "chrome://offline/MD5/page.html?virtualURL=http%3A%2F%2Ffoo.bar%2F"); + GURL virtual_url = reading_list::VirtualURLForDistilledURL(distilled_url); + EXPECT_EQ("http://foo.bar/", virtual_url.spec()); +} + // Checks the file path for chrome://offline/MD5/page.html is // file://profile_path/Offline/MD5/page.html. // Checks the resource root for chrome://offline/MD5/page.html is
diff --git a/ios/chrome/browser/reading_list/reading_list_entry_loading_util.h b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.h new file mode 100644 index 0000000..0218cda --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_LOADING_UTIL_H_ +#define IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_LOADING_UTIL_H_ + +class ReadingListEntry; +class ReadingListModel; + +namespace web { +class WebState; +}; + +namespace reading_list { + +// Loads the URL of the |entry| into the |web_state|. If the entry is +// successfully loaded, marks the entry as read. +void LoadReadingListEntry(ReadingListEntry const& entry, + ReadingListModel* model, + web::WebState* web_state); + +// Loads the distilled URL of the |entry| into the |web_state|, and marks +// |entry| as read. |entry->DistilledState()| must be |PROCESSED|. +void LoadReadingListDistilled(ReadingListEntry const& entry, + ReadingListModel* model, + web::WebState* web_state); +}; + +#endif // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_ENTRY_LOADING_UTIL_H_
diff --git a/ios/chrome/browser/reading_list/reading_list_entry_loading_util.mm b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.mm new file mode 100644 index 0000000..741c4141 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_entry_loading_util.mm
@@ -0,0 +1,52 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_entry_loading_util.h" + +#include "components/reading_list/ios/reading_list_entry.h" +#include "components/reading_list/ios/reading_list_model.h" +#include "ios/chrome/browser/reading_list/offline_url_utils.h" +#include "ios/chrome/browser/reading_list/reading_list_web_state_observer.h" +#import "ios/web/public/navigation_manager.h" +#import "ios/web/public/web_state/web_state.h" +#include "net/base/network_change_notifier.h" + +namespace reading_list { + +void LoadReadingListEntry(ReadingListEntry const& entry, + ReadingListModel* model, + web::WebState* web_state) { + // TODO(crbug.com/625617): Evaluate whether NetworkChangeNotifier + // correctly detects when users are offline. + bool open_distilled_entry = + net::NetworkChangeNotifier::IsOffline() && + entry.DistilledState() == ReadingListEntry::PROCESSED; + if (open_distilled_entry) { + return LoadReadingListDistilled(entry, model, web_state); + } + + DCHECK(entry.URL().is_valid()); + web::NavigationManager::WebLoadParams params(entry.URL()); + params.transition_type = ui::PageTransition::PAGE_TRANSITION_AUTO_BOOKMARK; + web_state->GetNavigationManager()->LoadURLWithParams(params); + ReadingListWebStateObserver* web_state_observer = + ReadingListWebStateObserver::FromWebState(web_state, model); + web_state_observer->StartCheckingProgress(); + model->SetReadStatus(entry.URL(), true); +} + +void LoadReadingListDistilled(ReadingListEntry const& entry, + ReadingListModel* model, + web::WebState* web_state) { + DCHECK(entry.DistilledState() == ReadingListEntry::PROCESSED); + GURL url = + reading_list::DistilledURLForPath(entry.DistilledPath(), entry.URL()); + DCHECK(url.is_valid()); + web::NavigationManager::WebLoadParams params(url); + params.transition_type = ui::PageTransition::PAGE_TRANSITION_AUTO_BOOKMARK; + web_state->GetNavigationManager()->LoadURLWithParams(params); + model->SetReadStatus(entry.URL(), true); +} + +} // namespace reading_list
diff --git a/ios/chrome/browser/reading_list/reading_list_entry_loading_util_unittest.mm b/ios/chrome/browser/reading_list/reading_list_entry_loading_util_unittest.mm new file mode 100644 index 0000000..754413088 --- /dev/null +++ b/ios/chrome/browser/reading_list/reading_list_entry_loading_util_unittest.mm
@@ -0,0 +1,138 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/chrome/browser/reading_list/reading_list_entry_loading_util.h" + +#include "base/memory/ptr_util.h" +#include "components/reading_list/ios/reading_list_model_impl.h" +#include "ios/chrome/browser/reading_list/offline_url_utils.h" +#import "ios/web/public/navigation_item.h" +#import "ios/web/public/navigation_manager.h" +#include "ios/web/public/test/web_test_with_web_state.h" +#import "ios/web/public/web_state/web_state.h" +#include "net/base/network_change_notifier.h" +#include "testing/gtest/include/gtest/gtest.h" + +// A mock NetworkChangeNotifier that will report the network state passed in the +// constructor. +class MockNetworkChangeNotifier : public net::NetworkChangeNotifier { + public: + MockNetworkChangeNotifier(ConnectionType connection) + : NetworkChangeNotifier() { + connection_ = connection; + } + + ~MockNetworkChangeNotifier() override {} + + ConnectionType GetCurrentConnectionType() const override { + return connection_; + }; + + private: + ConnectionType connection_; +}; + +// Test fixture to test loading of Reading list entries. +typedef web::WebTestWithWebState ReadingListEntryLoadingUtilTest; + +// Tests that loading a not distilled entry with network will load online +// version. +TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOnlineWODistilled) { + MockNetworkChangeNotifier network_enabler( + net::NetworkChangeNotifier::CONNECTION_WIFI); + GURL url("http://foo.bar"); + auto reading_list_model = + base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr); + reading_list_model->AddEntry(url, "title"); + const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url); + reading_list::LoadReadingListEntry(*entry, reading_list_model.get(), + web_state()); + web::NavigationManager* navigation_manager = + web_state()->GetNavigationManager(); + EXPECT_EQ(navigation_manager->GetPendingItem()->GetURL(), url); + EXPECT_TRUE(entry->IsRead()); +} + +// Tests that loading a distilled entry with network will load online version. +TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOnlineWithistilled) { + MockNetworkChangeNotifier network_enabler( + net::NetworkChangeNotifier::CONNECTION_WIFI); + GURL url("http://foo.bar"); + std::string distilled_path = "distilled/page.html"; + auto reading_list_model = + base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr); + reading_list_model->AddEntry(url, "title"); + reading_list_model->SetEntryDistilledPath(url, + base::FilePath(distilled_path)); + const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url); + reading_list::LoadReadingListEntry(*entry, reading_list_model.get(), + web_state()); + web::NavigationManager* navigation_manager = + web_state()->GetNavigationManager(); + EXPECT_EQ(navigation_manager->GetPendingItem()->GetURL(), url); + EXPECT_TRUE(entry->IsRead()); +} + +// Tests that loading a not distilled entry without network will load online +// version. +TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOfflineWODistilled) { + MockNetworkChangeNotifier network_disabler( + net::NetworkChangeNotifier::CONNECTION_NONE); + GURL url("http://foo.bar"); + auto reading_list_model = + base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr); + reading_list_model->AddEntry(url, "title"); + const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url); + reading_list::LoadReadingListEntry(*entry, reading_list_model.get(), + web_state()); + web::NavigationManager* navigation_manager = + web_state()->GetNavigationManager(); + EXPECT_EQ(navigation_manager->GetPendingItem()->GetURL(), url); + EXPECT_TRUE(entry->IsRead()); +} + +// Tests that loading a distilled entry without network will load offline +// version. +TEST_F(ReadingListEntryLoadingUtilTest, TestLoadEntryOfflineWithDistilled) { + MockNetworkChangeNotifier network_disabler( + net::NetworkChangeNotifier::CONNECTION_NONE); + GURL url("http://foo.bar"); + std::string distilled_path = "distilled/page.html"; + auto reading_list_model = + base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr); + reading_list_model->AddEntry(url, "title"); + reading_list_model->SetEntryDistilledPath(url, + base::FilePath(distilled_path)); + const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url); + reading_list::LoadReadingListEntry(*entry, reading_list_model.get(), + web_state()); + web::NavigationManager* navigation_manager = + web_state()->GetNavigationManager(); + EXPECT_NE(navigation_manager->GetPendingItem()->GetURL(), url); + EXPECT_EQ( + navigation_manager->GetPendingItem()->GetURL(), + reading_list::DistilledURLForPath(entry->DistilledPath(), entry->URL())); + EXPECT_TRUE(entry->IsRead()); +} + +// Tests that loading a distilled version of an entry. +TEST_F(ReadingListEntryLoadingUtilTest, TestLoadReadingListDistilled) { + GURL url("http://foo.bar"); + std::string distilled_path = "distilled/page.html"; + auto reading_list_model = + base::MakeUnique<ReadingListModelImpl>(nullptr, nullptr); + reading_list_model->AddEntry(url, "title"); + reading_list_model->SetEntryDistilledPath(url, + base::FilePath(distilled_path)); + const ReadingListEntry* entry = reading_list_model->GetEntryByURL(url); + reading_list::LoadReadingListDistilled(*entry, reading_list_model.get(), + web_state()); + web::NavigationManager* navigation_manager = + web_state()->GetNavigationManager(); + EXPECT_NE(navigation_manager->GetPendingItem()->GetURL(), url); + EXPECT_EQ( + navigation_manager->GetPendingItem()->GetURL(), + reading_list::DistilledURLForPath(entry->DistilledPath(), entry->URL())); + EXPECT_TRUE(entry->IsRead()); +}
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 d7aab6f..c97630ad 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
@@ -9,7 +9,7 @@ #include "base/memory/ptr_util.h" #include "components/reading_list/ios/reading_list_model.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/reading_list/offline_url_utils.h" +#include "ios/chrome/browser/reading_list/reading_list_entry_loading_util.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" #include "ios/web/public/navigation_item.h" #include "ios/web/public/navigation_manager.h" @@ -118,11 +118,7 @@ const ReadingListEntry* entry = reading_list_model_->GetEntryByURL(url); if (!entry) return; - // TODO(crbug.com/664124) Actually load offline pages. - GURL distilled_url = - reading_list::DistilledURLForPath(entry->DistilledPath()); - web::NavigationManager::WebLoadParams params(distilled_url); - params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK; - navigation_manager->LoadURLWithParams(params); + reading_list::LoadReadingListDistilled(*entry, reading_list_model_, + web_state()); } }
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index 6a6ba6fe..f2abbbc 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -409,6 +409,10 @@ "public/test/scoped_testing_web_client.mm", "public/test/test_browser_state.cc", "public/test/test_browser_state.h", + "public/test/test_native_content.h", + "public/test/test_native_content.mm", + "public/test/test_native_content_provider.h", + "public/test/test_native_content_provider.mm", "public/test/test_redirect_observer.h", "public/test/test_redirect_observer.mm", "public/test/test_web_client.h",
diff --git a/ios/web/public/test/test_native_content.h b/ios/web/public/test/test_native_content.h new file mode 100644 index 0000000..cd487dfa --- /dev/null +++ b/ios/web/public/test/test_native_content.h
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_H_ +#define IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_H_ + +#import "ios/web/public/web_state/ui/crw_native_content.h" + +// A test class that implement CRWNativeContent. +@interface TestNativeContent : NSObject<CRWNativeContent> +// Inits the CRWNativeContent. +// |URL| will be returned by the |url| method of the object. +// If |virtualURL| is valid, it will be returned by the |virtualURL| method. +// If not, the object will pretend it does not implement |virtualURL|. +- (instancetype)initWithURL:(const GURL&)URL + virtualURL:(const GURL&)virtualURL NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; +@end + +#endif // IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_H_
diff --git a/ios/web/public/test/test_native_content.mm b/ios/web/public/test/test_native_content.mm new file mode 100644 index 0000000..3b1c5ea4 --- /dev/null +++ b/ios/web/public/test/test_native_content.mm
@@ -0,0 +1,56 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/web/public/test/test_native_content.h" + +#include "base/mac/scoped_nsobject.h" + +@implementation TestNativeContent { + GURL _URL; + GURL _virtualURL; + base::scoped_nsobject<UIView> _view; +} +- (instancetype)initWithURL:(const GURL&)URL + virtualURL:(const GURL&)virtualURL { + self = [super init]; + if (self) { + _URL = URL; + _virtualURL = virtualURL; + } + return self; +} + +- (BOOL)respondsToSelector:(SEL)selector { + if (selector == @selector(virtualURL)) { + return _virtualURL.is_valid(); + } + return [super respondsToSelector:selector]; +} + +- (NSString*)title { + return @"Test Title"; +} + +- (const GURL&)url { + return _URL; +} + +- (GURL)virtualURL { + return _virtualURL; +} + +- (UIView*)view { + return nil; +} + +- (void)handleLowMemory { +} + +- (BOOL)isViewAlive { + return YES; +} + +- (void)reload { +} +@end
diff --git a/ios/web/public/test/test_native_content_provider.h b/ios/web/public/test/test_native_content_provider.h new file mode 100644 index 0000000..135a252b --- /dev/null +++ b/ios/web/public/test/test_native_content_provider.h
@@ -0,0 +1,20 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_PROVIDER_H_ +#define IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_PROVIDER_H_ + +#import "ios/web/public/web_state/ui/crw_native_content_provider.h" + +@protocol CRWNativeContent; + +// A test class that will return CRWNativeContent for specified URLs. +@interface TestNativeContentProvider : NSObject<CRWNativeContentProvider> + +// Add a |CRWNativeContent| for |URL|. +- (void)setController:(id<CRWNativeContent>)controller forURL:(const GURL&)URL; + +@end + +#endif // IOS_WEB_PUBLIC_TEST_TEST_NATIVE_CONTENT_PROVIDER_H_
diff --git a/ios/web/public/test/test_native_content_provider.mm b/ios/web/public/test/test_native_content_provider.mm new file mode 100644 index 0000000..0033b8e --- /dev/null +++ b/ios/web/public/test/test_native_content_provider.mm
@@ -0,0 +1,38 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/web/public/test/test_native_content_provider.h" + +#include <map> + +#include "url/gurl.h" + +@implementation TestNativeContentProvider { + std::map<GURL, id<CRWNativeContent>> _nativeContent; +} + +- (void)setController:(id<CRWNativeContent>)controller forURL:(const GURL&)URL { + _nativeContent[URL] = controller; +} + +- (BOOL)hasControllerForURL:(const GURL&)URL { + return _nativeContent.find(URL) != _nativeContent.end(); +} + +- (id<CRWNativeContent>)controllerForURL:(const GURL&)URL { + auto nativeContent = _nativeContent.find(URL); + if (nativeContent == _nativeContent.end()) { + return nil; + } + return nativeContent->second; +} + +- (id<CRWNativeContent>)controllerForURL:(const GURL&)URL + withError:(NSError*)error + isPost:(BOOL)isPost { + NOTREACHED(); + return nil; +} + +@end
diff --git a/ios/web/public/web_state/ui/crw_native_content.h b/ios/web/public/web_state/ui/crw_native_content.h index 753656d..994ba6d 100644 --- a/ios/web/public/web_state/ui/crw_native_content.h +++ b/ios/web/public/web_state/ui/crw_native_content.h
@@ -85,6 +85,10 @@ // Called when a snapshot of the content will be taken. - (void)willUpdateSnapshot; +// The URL that will be displayed to the user when presenting this native +// content. +- (GURL)virtualURL; + @end // CRWNativeContent delegate protocol.
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 0d450d8..48d769aa 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1424,8 +1424,13 @@ } // Any non-web URL source is trusted. *trustLevel = web::URLVerificationTrustLevel::kAbsolute; - if (self.nativeController) - return [self.nativeController url]; + if (self.nativeController) { + if ([self.nativeController respondsToSelector:@selector(virtualURL)]) { + return [self.nativeController virtualURL]; + } else { + return [self.nativeController url]; + } + } return [self currentNavigationURL]; } @@ -1997,9 +2002,14 @@ const GURL targetURL = [self currentNavigationURL]; const web::Referrer referrer; + id<CRWNativeContent> nativeContent = + [_nativeProvider controllerForURL:targetURL]; // Unlike the WebView case, always create a new controller and view. // TODO(pinkerton): What to do if this does return nil? - [self setNativeController:[_nativeProvider controllerForURL:targetURL]]; + [self setNativeController:nativeContent]; + if ([nativeContent respondsToSelector:@selector(virtualURL)]) { + [self currentNavItem]->SetVirtualURL([nativeContent virtualURL]); + } [self registerLoadRequest:targetURL referrer:referrer transition:[self currentTransition]];
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index 5ed3e78..f7017315 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -19,10 +19,14 @@ #include "ios/web/navigation/navigation_item_impl.h" #import "ios/web/navigation/navigation_manager_impl.h" #include "ios/web/public/referrer.h" +#import "ios/web/public/test/test_native_content.h" +#import "ios/web/public/test/test_native_content_provider.h" #import "ios/web/public/test/test_web_client.h" #include "ios/web/public/test/test_web_view_content_view.h" #import "ios/web/public/web_state/crw_web_controller_observer.h" #import "ios/web/public/web_state/ui/crw_content_view.h" +#import "ios/web/public/web_state/ui/crw_native_content.h" +#import "ios/web/public/web_state/ui/crw_native_content_provider.h" #import "ios/web/public/web_state/ui/crw_web_view_content_view.h" #include "ios/web/public/web_state/url_verification_constants.h" #import "ios/web/test/web_test_with_web_controller.h" @@ -227,7 +231,8 @@ namespace { -NSString* kTestURLString = @"http://www.google.com/"; +const char kTestURLString[] = "http://www.google.com/"; +const char kTestAppSpecificURL[] = "testwebui://test/"; // Returns true if the current device is a large iPhone (6 or 6+). bool IsIPhone6Or6Plus() { @@ -324,7 +329,7 @@ } [[result stub] backForwardList]; - [[[result stub] andReturn:[NSURL URLWithString:kTestURLString]] URL]; + [[[result stub] andReturn:[NSURL URLWithString:@(kTestURLString)]] URL]; [[result stub] setNavigationDelegate:OCMOCK_ANY]; [[result stub] setUIDelegate:OCMOCK_ANY]; [[result stub] setFrame:ExpectedWebViewFrame()]; @@ -795,7 +800,7 @@ } TEST_F(CRWWebControllerTest, WebUrlWithTrustLevel) { - [[[mockWebView_ stub] andReturn:[NSURL URLWithString:kTestURLString]] URL]; + [[[mockWebView_ stub] andReturn:[NSURL URLWithString:@(kTestURLString)]] URL]; [[[mockWebView_ stub] andReturnBool:NO] hasOnlySecureContent]; // Stub out the injection process. @@ -803,8 +808,7 @@ completionHandler:OCMOCK_ANY]; // Simulate registering load request to avoid failing page load simulation. - [web_controller() - simulateLoadRequestWithURL:GURL([kTestURLString UTF8String])]; + [web_controller() simulateLoadRequestWithURL:GURL(kTestURLString)]; // Simulate a page load to trigger a URL update. [static_cast<id<WKNavigationDelegate>>(web_controller()) webView:mockWebView_ didCommitNavigation:nil]; @@ -812,10 +816,79 @@ web::URLVerificationTrustLevel trust_level = web::kNone; GURL gurl = [web_controller() currentURLWithTrustLevel:&trust_level]; - EXPECT_EQ(gurl, GURL(base::SysNSStringToUTF8(kTestURLString))); + EXPECT_EQ(gurl, GURL(kTestURLString)); EXPECT_EQ(web::kAbsolute, trust_level); } +// Test fixture for testing CRWWebController presenting native content. +class CRWWebControllerNativeContentTest : public web::WebTestWithWebController { + protected: + void SetUp() override { + web::WebTestWithWebController::SetUp(); + mock_native_provider_.reset([[TestNativeContentProvider alloc] init]); + [web_controller() setNativeProvider:mock_native_provider_]; + } + + void Load(const GURL& URL) { + NavigationManagerImpl& navigation_manager = + [web_controller() webStateImpl]->GetNavigationManagerImpl(); + navigation_manager.InitializeSession(@"name", nil, NO, 0); + [navigation_manager.GetSessionController() + addPendingEntry:URL + referrer:web::Referrer() + transition:ui::PAGE_TRANSITION_TYPED + rendererInitiated:NO]; + [web_controller() loadCurrentURL]; + } + + base::scoped_nsobject<TestNativeContentProvider> mock_native_provider_; +}; + +// Tests WebState and NavigationManager correctly return native content URL. +TEST_F(CRWWebControllerNativeContentTest, NativeContentURL) { + GURL url_to_load(kTestAppSpecificURL); + base::scoped_nsobject<TestNativeContent> content( + [[TestNativeContent alloc] initWithURL:url_to_load virtualURL:GURL()]); + [mock_native_provider_ setController:content forURL:url_to_load]; + Load(url_to_load); + web::URLVerificationTrustLevel trust_level = web::kNone; + GURL gurl = [web_controller() currentURLWithTrustLevel:&trust_level]; + EXPECT_EQ(gurl, url_to_load); + EXPECT_EQ(web::kAbsolute, trust_level); + EXPECT_EQ([web_controller() webState]->GetVisibleURL(), url_to_load); + NavigationManagerImpl& navigationManager = + [web_controller() webStateImpl]->GetNavigationManagerImpl(); + EXPECT_EQ(navigationManager.GetVisibleItem()->GetURL(), url_to_load); + EXPECT_EQ(navigationManager.GetVisibleItem()->GetVirtualURL(), url_to_load); + EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetURL(), url_to_load); + EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetVirtualURL(), + url_to_load); +} + +// Tests WebState and NavigationManager correctly return native content URL and +// VirtualURL +TEST_F(CRWWebControllerNativeContentTest, NativeContentVirtualURL) { + GURL url_to_load(kTestAppSpecificURL); + GURL virtual_url(kTestURLString); + base::scoped_nsobject<TestNativeContent> content([[TestNativeContent alloc] + initWithURL:virtual_url + virtualURL:virtual_url]); + [mock_native_provider_ setController:content forURL:url_to_load]; + Load(url_to_load); + web::URLVerificationTrustLevel trust_level = web::kNone; + GURL gurl = [web_controller() currentURLWithTrustLevel:&trust_level]; + EXPECT_EQ(gurl, virtual_url); + EXPECT_EQ(web::kAbsolute, trust_level); + EXPECT_EQ([web_controller() webState]->GetVisibleURL(), virtual_url); + NavigationManagerImpl& navigationManager = + [web_controller() webStateImpl]->GetNavigationManagerImpl(); + EXPECT_EQ(navigationManager.GetVisibleItem()->GetURL(), url_to_load); + EXPECT_EQ(navigationManager.GetVisibleItem()->GetVirtualURL(), virtual_url); + EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetURL(), url_to_load); + EXPECT_EQ(navigationManager.GetLastCommittedItem()->GetVirtualURL(), + virtual_url); +} + // A separate test class, as none of the |CRWUIWebViewWebControllerTest| setup // is needed; typedef web::WebTestWithWebController CRWWebControllerObserversTest;
diff --git a/media/audio/alsa/audio_manager_alsa.cc b/media/audio/alsa/audio_manager_alsa.cc index 3886d668..72c48e3 100644 --- a/media/audio/alsa/audio_manager_alsa.cc +++ b/media/audio/alsa/audio_manager_alsa.cc
@@ -127,6 +127,10 @@ kDefaultSampleRate, 16, kDefaultInputBufferSize); } +const char* AudioManagerAlsa::GetName() { + return "ALSA"; +} + void AudioManagerAlsa::GetAlsaAudioDevices(StreamType type, AudioDeviceNames* device_names) { // Constants specified by the ALSA API for device hints.
diff --git a/media/audio/alsa/audio_manager_alsa.h b/media/audio/alsa/audio_manager_alsa.h index a4c6242..8dff467 100644 --- a/media/audio/alsa/audio_manager_alsa.h +++ b/media/audio/alsa/audio_manager_alsa.h
@@ -35,6 +35,7 @@ void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override; AudioParameters GetInputStreamParameters( const std::string& device_id) override; + const char* GetName() override; // Implementation of AudioManagerBase. AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index 9f18d5d..502a8cbf 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc
@@ -161,6 +161,10 @@ return params; } +const char* AudioManagerAndroid::GetName() { + return "Android"; +} + AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( const AudioParameters& params, const std::string& device_id,
diff --git a/media/audio/android/audio_manager_android.h b/media/audio/android/audio_manager_android.h index ec38dcc6..2f3f250 100644 --- a/media/audio/android/audio_manager_android.h +++ b/media/audio/android/audio_manager_android.h
@@ -45,6 +45,7 @@ const LogCallback& log_callback) override; void ReleaseOutputStream(AudioOutputStream* stream) override; void ReleaseInputStream(AudioInputStream* stream) override; + const char* GetName() override; // Implementation of AudioManagerBase. AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index 666fa1b..887521a 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h
@@ -253,6 +253,9 @@ virtual std::unique_ptr<AudioLog> CreateAudioLog( AudioLogFactory::AudioComponent component) = 0; + // Gets the name of the audio manager (e.g., Windows, Mac, PulseAudio). + virtual const char* GetName() = 0; + protected: AudioManager(scoped_refptr<base::SingleThreadTaskRunner> task_runner, scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner);
diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc index a8754ee..37e012a 100644 --- a/media/audio/audio_output_proxy_unittest.cc +++ b/media/audio/audio_output_proxy_unittest.cc
@@ -116,6 +116,7 @@ scoped_refptr<base::SingleThreadTaskRunner>()); MOCK_METHOD1(GetAudioInputDeviceNames, void( media::AudioDeviceNames* device_name)); + MOCK_METHOD0(GetName, const char*()); MOCK_METHOD2(MakeLinearOutputStream, AudioOutputStream*(const AudioParameters& params,
diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc index 6df14bc87..c4bef24 100644 --- a/media/audio/cras/audio_manager_cras.cc +++ b/media/audio/cras/audio_manager_cras.cc
@@ -228,6 +228,10 @@ return params; } +const char* AudioManagerCras::GetName() { + return "CRAS"; +} + AudioOutputStream* AudioManagerCras::MakeLinearOutputStream( const AudioParameters& params, const LogCallback& log_callback) {
diff --git a/media/audio/cras/audio_manager_cras.h b/media/audio/cras/audio_manager_cras.h index ec739468..ddf0aac 100644 --- a/media/audio/cras/audio_manager_cras.h +++ b/media/audio/cras/audio_manager_cras.h
@@ -31,6 +31,7 @@ void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override; AudioParameters GetInputStreamParameters( const std::string& device_id) override; + const char* GetName() override; // AudioManagerBase implementation. AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/fake_audio_manager.cc b/media/audio/fake_audio_manager.cc index 2915e72..07e88a5 100644 --- a/media/audio/fake_audio_manager.cc +++ b/media/audio/fake_audio_manager.cc
@@ -34,6 +34,10 @@ bool FakeAudioManager::HasAudioInputDevices() { return false; } +const char* FakeAudioManager::GetName() { + return "Fake"; +} + // Implementation of AudioManagerBase. AudioOutputStream* FakeAudioManager::MakeLinearOutputStream( const AudioParameters& params,
diff --git a/media/audio/fake_audio_manager.h b/media/audio/fake_audio_manager.h index 94276b2..022c664 100644 --- a/media/audio/fake_audio_manager.h +++ b/media/audio/fake_audio_manager.h
@@ -24,6 +24,7 @@ // Implementation of AudioManager. bool HasAudioOutputDevices() override; bool HasAudioInputDevices() override; + const char* GetName() override; // Implementation of AudioManagerBase. AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 14877a95..37c9658 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc
@@ -603,6 +603,10 @@ return std::string(); } +const char* AudioManagerMac::GetName() { + return "Mac"; +} + AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( const AudioParameters& params, const LogCallback& log_callback) {
diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index 40d98eb..84fdd800 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h
@@ -43,6 +43,7 @@ const std::string& device_id) override; std::string GetAssociatedOutputDeviceID( const std::string& input_device_id) override; + const char* GetName() override; // Implementation of AudioManagerBase. AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/mock_audio_manager.cc b/media/audio/mock_audio_manager.cc index 5676b311..2fbc2859 100644 --- a/media/audio/mock_audio_manager.cc +++ b/media/audio/mock_audio_manager.cc
@@ -105,4 +105,8 @@ return nullptr; } +const char* MockAudioManager::GetName() { + return nullptr; +} + } // namespace media.
diff --git a/media/audio/mock_audio_manager.h b/media/audio/mock_audio_manager.h index e77e85c..735adf6 100644 --- a/media/audio/mock_audio_manager.h +++ b/media/audio/mock_audio_manager.h
@@ -62,6 +62,8 @@ std::unique_ptr<AudioLog> CreateAudioLog( AudioLogFactory::AudioComponent component) override; + const char* GetName() override; + protected: ~MockAudioManager() override;
diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc index afa7064..779bf92e 100644 --- a/media/audio/pulse/audio_manager_pulse.cc +++ b/media/audio/pulse/audio_manager_pulse.cc
@@ -143,6 +143,10 @@ buffer_size); } +const char* AudioManagerPulse::GetName() { + return "PulseAudio"; +} + AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream( const AudioParameters& params, const LogCallback& log_callback) {
diff --git a/media/audio/pulse/audio_manager_pulse.h b/media/audio/pulse/audio_manager_pulse.h index bd66091..662c461 100644 --- a/media/audio/pulse/audio_manager_pulse.h +++ b/media/audio/pulse/audio_manager_pulse.h
@@ -32,6 +32,7 @@ void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override; AudioParameters GetInputStreamParameters( const std::string& device_id) override; + const char* GetName() override; // Implementation of AudioManagerBase. AudioOutputStream* MakeLinearOutputStream(
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index 89e9eab4..21f15cd 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc
@@ -331,6 +331,10 @@ return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); } +const char* AudioManagerWin::GetName() { + return "Windows"; +} + // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR // mode. // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index a8b6206..5a5395c3 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h
@@ -36,6 +36,7 @@ const std::string& device_id) override; std::string GetAssociatedOutputDeviceID( const std::string& input_device_id) override; + const char* GetName() override; // Implementation of AudioManagerBase. AudioOutputStream* MakeLinearOutputStream(
diff --git a/testing/libfuzzer/archive_corpus.py b/testing/libfuzzer/archive_corpus.py index 7e39bb5..71c132b 100755 --- a/testing/libfuzzer/archive_corpus.py +++ b/testing/libfuzzer/archive_corpus.py
@@ -13,6 +13,7 @@ import argparse import os import sys +import warnings import zipfile @@ -31,8 +32,13 @@ corpus_files.append(full_filename) with zipfile.ZipFile(args.output, 'w') as z: - for corpus_file in corpus_files: - z.write(corpus_file, os.path.basename(corpus_file)) + # Turn warnings into errors to interrupt the build: crbug.com/653920. + with warnings.catch_warnings(): + warnings.simplefilter("error") + for i, corpus_file in enumerate(corpus_files): + # To avoid duplication of filenames inside the archive, use numbers. + arcname = '%016d' % i + z.write(corpus_file, arcname) if __name__ == '__main__':
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 2a95d0f..63a69ff 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1927,5 +1927,8 @@ Bug(dpranke) imported/wpt/workers/Worker_cross_origin_security_err.htm [ Failure ] Bug(dpranke) imported/wpt/service-workers/service-worker/register-closed-window.https.html [ Timeout ] +crbug.com/658605 paint/invalidation/flexbox/scrollbars-changed.html [ NeedsRebaseline ] +crbug.com/658605 paint/invalidation/multicol-repaint.html [ NeedsRebaseline ] + # Added 2016-11-30 crbug.com/669911 [ Win7 Win10 ] virtual/threaded/animations/zoom-responsive-transform-animation.html [ Pass Failure Timeout ]
diff --git a/third_party/WebKit/LayoutTests/editing/selection/set_base_and_extent/set_null.html b/third_party/WebKit/LayoutTests/editing/selection/set_base_and_extent/set_null.html new file mode 100644 index 0000000..cca44b4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/editing/selection/set_base_and_extent/set_null.html
@@ -0,0 +1,38 @@ +<!doctype html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script src="../../assert_selection.js"></script> +<div id="log"></div> +<script> +test(() => { +assert_selection( + '<div>^foo|</div>', + selection => { + selection.setBaseAndExtent(null, 0, null, 0); + }, + '<div>foo</div>', + 'Setting both null clears selection'); + +assert_selection( + '<div>^foo|</div>', + selection => { + selection.setBaseAndExtent(null, 1, null, 2); + }, + '<div>foo</div>', + 'Setting both null clears selection'); + +assert_selection( + '<div>^foo|</div>', + selection => selection.setBaseAndExtent(null, 1, selection.document.querySelector('div'), 1), + '<div>foo</div>', + 'Setting only base null clears selection'); + +assert_selection( + '<div>foo</div>', + selection => selection.setBaseAndExtent(selection.document.querySelector('div'), 0, null, 2), + '<div>|foo</div>', + 'Setting base non-null and extent null behaves as collapse.' + + 'This is under discussion: https://github.com/w3c/selection-api/issues/72'); + +}, 'setBaseAndExtent with null.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span-expected.html b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span-expected.html new file mode 100644 index 0000000..1621c09 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span-expected.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<style> +@font-face { + font-family:cssot; + src:url(../../../third_party/adobe-fonts/CSSFWOrientationTest.otf); +} +div { + font-family: Ahem, cssot; + width: 5em; + font-size: 20px; + border: 5px blue solid; + display: inline-block; + margin-bottom: .2em; + margin-right: 3em; +} +.break-all { + color: orange; +} +</style> +<body> + <p>Test break-all applied to span works as expected.</p> + <div>AAAA<span class="break-all">X<br>XXXXX</span></div> + <div>AAAAA<span class="break-all">X<br>XXXXX</span></div> + <div>AAAAAA<span class="break-all">X<br>XXXXX</span></div> + <div>A AA<span class="break-all">X<br>XXXXX</span></div> + <div>AA<br>AA<span class="break-all">XXX</span></div> + <div>AAA<br>AA<span class="break-all">XXX</span></div> + <div>AAAA<br>AA<span class="break-all">XXX</span></div> + <div>AAAAA<br>AA<span class="break-all">XXX</span></div> + <div>AAA<br>A<span class="break-all">XXXX</span></div> + <div>AAAA<br>A<span class="break-all">XXXX</span></div> + <div>AAAAA<br>A<span class="break-all">XXXX</span></div> + <div>国国国国<br>国、<span class="break-all">XXX</span></div> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span.html b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span.html new file mode 100644 index 0000000..9e80231 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css3-text/css3-word-break/word-break-break-all-in-span.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<style> +@font-face { + font-family:cssot; + src:url(../../../third_party/adobe-fonts/CSSFWOrientationTest.otf); +} +div { + font-family: Ahem, cssot; + width: 5em; + font-size: 20px; + border: 5px blue solid; + display: inline-block; + margin-bottom: .2em; + margin-right: 3em; +} +.break-all { + word-break: break-all; + color: orange; +} +</style> +<body> + <p>Test break-all applied to span works as expected.</p> + <div>AAAA<span class="break-all">XXXXXX</span></div> + <div>AAAAA<span class="break-all">XXXXXX</span></div> + <div>AAAAAA<span class="break-all">XXXXXX</span></div> + <div>A AA<span class="break-all">XXXXXX</span></div> + <div>AA AA<span class="break-all">XXX</span></div> + <div>AAA AA<span class="break-all">XXX</span></div> + <div>AAAA AA<span class="break-all">XXX</span></div> + <div>AAAAA AA<span class="break-all">XXX</span></div> + <div>AAA A<span class="break-all">XXXX</span></div> + <div>AAAA A<span class="break-all">XXXX</span></div> + <div>AAAAA A<span class="break-all">XXXX</span></div> + <div>国国国国国、<span class="break-all">XXX</span></div> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html index 1a14e28..7016854 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html +++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/set-inner-outer-optimization.html
@@ -74,8 +74,8 @@ runTest('', 'innerHTML', '<a></a><b></b>', 'modified'); runTest('text', 'innerHTML', '', 'modified'); - runTest('text', 'innerHTML', 'different text', 'modified, with same first child'); - runTest('text', 'innerHTML', 'text', 'not modified'); + runTest('text', 'innerHTML', 'different text', 'modified'); + runTest('text', 'innerHTML', 'text', 'modified'); runTest('text', 'innerHTML', '<a></a>', 'modified'); runTest('text', 'innerHTML', '<a></a><b></b>', 'modified');
diff --git a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash-expected.txt deleted file mode 100644 index b2bf751..0000000 --- a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -Tests for a crash due to modifying the DOM during mutation events due to an adoptNode call. If this page doesn't crash and DOMSubtreeModified is fire, this test succeeds. -DOMSubtreeModified fired -
diff --git a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash.html b/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash.html deleted file mode 100644 index 52b0e62..0000000 --- a/third_party/WebKit/LayoutTests/fast/dom/adopt-node-crash.html +++ /dev/null
@@ -1,24 +0,0 @@ -<!DOCTYPE html> -<div>Tests for a crash due to modifying the DOM during mutation events due to an adoptNode call. If this page doesn't crash and DOMSubtreeModified is fire, this test succeeds.</div> -<div id="result"></div> -<div id="node-to-adopt"></div> -<iframe></iframe> -<script> -if (window.testRunner) - testRunner.dumpAsText(); - -var nodeToAdopt = document.getElementById('node-to-adopt'); - -var mutationHandler = function() { - document.getElementById('result').innerHTML = "DOMSubtreeModified fired"; - document.body.removeEventListener('DOMSubtreeModified', mutationHandler, true); - document.body.appendChild(nodeToAdopt); -}; -document.body.addEventListener('DOMSubtreeModified', mutationHandler, true); - -var iframe = document.querySelector('iframe'); -var iframeDoc = iframe.contentDocument; -iframeDoc.adoptNode(nodeToAdopt); -// The crash happens when the iframe's document is getting detached. -document.body.removeChild(iframe); -</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop-expected.txt b/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop-expected.txt deleted file mode 100644 index 53cdf1e..0000000 --- a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop-expected.txt +++ /dev/null
@@ -1 +0,0 @@ -PASSED
diff --git a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop.html b/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop.html deleted file mode 100644 index e5e2b876..0000000 --- a/third_party/WebKit/LayoutTests/fast/events/crash-on-mutate-during-drop.html +++ /dev/null
@@ -1,41 +0,0 @@ -<html> -<head> -<script> -function foo() { - if (event.type == "DOMNodeInserted" && event.target.nodeType == 3) - document.body.innerHTML = "PASSED"; -} - -function runTest() { - if (!window.testRunner) - return; - - window.testRunner.dumpAsText(); - - document.addEventListener("DOMNodeInserted", function() { foo() }, true); - - // Select the element 'dragSource'. - var selection = window.getSelection(); - var range = document.createRange(); - range.selectNode(document.getElementById("dragSource")); - selection.addRange(range); - - // Drag the source text to the target text. - var source = document.getElementById('dragSource'); - var target = document.getElementById('dragTarget'); - eventSender.mouseMoveTo(source.offsetLeft + 2, source.offsetTop + 2); - eventSender.mouseDown(); - eventSender.leapForward(500); - eventSender.mouseMoveTo(target.offsetLeft + target.offsetWidth / 2, - target.offsetTop + target.offsetHeight / 2); - eventSender.mouseUp(); -} -</script> -</head> -<body contenteditable="true" onload="runTest()"> -<p>This test tests for a crash when a DOM mutation event listener - modifies the text during a drop. If the test doesn't crash, all is good. -<p id="dragSource">drag source text -<p id="dragTarget">drag dest text -</body> -</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fragmentation/first-child-large-top-margin.html b/third_party/WebKit/LayoutTests/fragmentation/first-child-large-top-margin.html new file mode 100644 index 0000000..391d4c5c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fragmentation/first-child-large-top-margin.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<p>There should be a blue square below.</p> +<div style="position:relative; columns:2; column-gap:0; column-fill:auto; width:200px; height:100px;"> + <div id="elm" style="margin-top:150px; height:100px; background:blue;"></div> +</div> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script> +test(() => { + var elm = document.getElementById("elm"); + assert_equals(elm.offsetLeft, 100); + assert_equals(elm.offsetTop, 0); +}, "Margins should collapse with fragmentainer boundaries"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fragmentation/margin-bottom-at-top-of-fragmentainer.html b/third_party/WebKit/LayoutTests/fragmentation/margin-bottom-at-top-of-fragmentainer.html new file mode 100644 index 0000000..12fe70a2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fragmentation/margin-bottom-at-top-of-fragmentainer.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<p>There should be a blue square below.</p> +<div style="position:relative; columns:2; column-gap:0; column-fill:auto; width:200px; height:100px;"> + <div style="margin-bottom:50px; height:100px;"></div> + <div id="elm" style="height:100px; background:blue;"></div> +</div> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script> +test(() => { + var elm = document.getElementById("elm"); + assert_equals(elm.offsetLeft, 100); + assert_equals(elm.offsetTop, 0); +}, "Margins should collapse with fragmentainer boundaries"); +</script>
diff --git a/third_party/WebKit/LayoutTests/fragmentation/margin-top-at-top-of-fragmentainer.html b/third_party/WebKit/LayoutTests/fragmentation/margin-top-at-top-of-fragmentainer.html new file mode 100644 index 0000000..6b20f8e9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fragmentation/margin-top-at-top-of-fragmentainer.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<p>There should be a blue square below.</p> +<div style="position:relative; columns:2; column-gap:0; column-fill:auto; width:200px; height:100px;"> + <div style="height:100px;"></div> + <div id="elm" style="margin-top:50px; height:100px; background:blue;"></div> +</div> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script> +test(() => { + var elm = document.getElementById("elm"); + assert_equals(elm.offsetLeft, 100); + assert_equals(elm.offsetTop, 0); +}, "Margins should collapse with fragmentainer boundaries"); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt index 389fc1c..008fd471 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-basic-blocked-error-event-expected.txt
@@ -4,6 +4,8 @@ CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution. +CONSOLE ERROR: line 37: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution. + CONSOLE ERROR: line 37: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution. This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt index 37e3444..d1217d5 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/1.1/stylehash-svg-style-basic-blocked-error-event-expected.txt
@@ -2,6 +2,8 @@ CONSOLE ERROR: line 19: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution. +CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution. + CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'sha1-pfeR5wMA6np45oqDTP6Pj3tLpJo='". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution. This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt index 1cec67e..b198e81 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-basic-blocked-error-event-expected.txt
@@ -2,6 +2,8 @@ CONSOLE ERROR: line 19: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution. +CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution. + CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution. This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt index 7f155c4..6b7d333 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/nonces/stylenonce-svg-style-basic-blocked-error-event-expected.txt
@@ -2,6 +2,8 @@ CONSOLE ERROR: line 19: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-pckGv9YvNcB5xy+Y4fbqhyo+ib850wyiuWeNbZvLi00='), or a nonce ('nonce-...') is required to enable inline execution. +CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution. + CONSOLE ERROR: line 28: Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'nonce-nonceynonce'". Either the 'unsafe-inline' keyword, a hash ('sha256-QSqLgiKqPxCeZH1d3vWR+4HJOthCVhvG1P/AFaVJfR4='), or a nonce ('nonce-...') is required to enable inline execution. This is a testharness.js-based test.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/MutationObserver-inner-outer-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/MutationObserver-inner-outer-expected.txt deleted file mode 100644 index 901c9c1d..0000000 --- a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/MutationObserver-inner-outer-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -FAIL innerHTML mutation assert_equals: mutation records must match expected 2 but got 1 -PASS innerHTML with 2 children mutation -PASS outerHTML mutation -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html b/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html index 4ad226ef..30bdbe3 100644 --- a/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html +++ b/third_party/WebKit/LayoutTests/shadow-dom/slotchange.html
@@ -309,3 +309,24 @@ n.c1.remove(); }, "slotchange event: Fallback slot's parant slot is assinged to another slot."); </script> + +<div id="test8"> + <div id="host1"> + <template id="shadowroot" data-mode="open"> + <slot id="s1"></slot> + </template> + </div> +</div> + +<script> +async_test((test) => { + const n = createTestTree(window.test8); + removeWhiteSpaceOnlyTextNodes(n.test8); + n.host1.innerHTML = 'hello'; + + window.setTimeout(() => { + doneIfSlotChange([n.s1], test); + n.host1.innerHTML = 'world'; + }, 0); +}, 'slotchange event: Replacing a text node with innerHTML.'); +</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp index 11d65aa..c3e8dea 100644 --- a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
@@ -54,8 +54,8 @@ PerformanceObserverCallback* callback = PerformanceObserverCallback::create(scriptState, v8Callback); - PerformanceObserver* observer = - PerformanceObserver::create(scriptState, performance, callback); + PerformanceObserver* observer = PerformanceObserver::create( + currentExecutionContext(info.GetIsolate()), performance, callback); // TODO(bashi): Don't set private property (and remove this custom // constructor) when we can call setWrapperReference() correctly.
diff --git a/third_party/WebKit/Source/core/css/MediaList.cpp b/third_party/WebKit/Source/core/css/MediaList.cpp index 4ffdd5b..bbb60db 100644 --- a/third_party/WebKit/Source/core/css/MediaList.cpp +++ b/third_party/WebKit/Source/core/css/MediaList.cpp
@@ -65,13 +65,6 @@ return MediaQueryParser::parseMediaQuerySet(mediaString); } -MediaQuerySet* MediaQuerySet::createOffMainThread(const String& mediaString) { - if (mediaString.isEmpty()) - return MediaQuerySet::create(); - - return MediaQueryParser::parseMediaQuerySet(mediaString); -} - bool MediaQuerySet::set(const String& mediaString) { MediaQuerySet* result = create(mediaString); m_queries.swap(result->m_queries);
diff --git a/third_party/WebKit/Source/core/css/MediaList.h b/third_party/WebKit/Source/core/css/MediaList.h index 49af85a..360b92d 100644 --- a/third_party/WebKit/Source/core/css/MediaList.h +++ b/third_party/WebKit/Source/core/css/MediaList.h
@@ -42,7 +42,6 @@ public: static MediaQuerySet* create() { return new MediaQuerySet(); } static MediaQuerySet* create(const String& mediaString); - static MediaQuerySet* createOffMainThread(const String& mediaString); bool set(const String&); bool add(const String&);
diff --git a/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp b/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp index 5cedc1a..600e20c 100644 --- a/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp +++ b/third_party/WebKit/Source/core/css/MediaQuerySetTest.cpp
@@ -13,12 +13,9 @@ typedef struct { const char* input; const char* output; - bool shouldWorkOnOldParser; } TestCase; -static void testMediaQuery(TestCase test, - MediaQuerySet& querySet, - bool oldParser) { +static void testMediaQuery(TestCase test, MediaQuerySet& querySet) { StringBuilder output; size_t j = 0; while (j < querySet.queryVector().size()) { @@ -29,12 +26,10 @@ break; output.append(", "); } - if (!oldParser || test.shouldWorkOnOldParser) { - if (test.output) - ASSERT_STREQ(test.output, output.toString().ascii().data()); - else - ASSERT_STREQ(test.input, output.toString().ascii().data()); - } + if (test.output) + ASSERT_STREQ(test.output, output.toString().ascii().data()); + else + ASSERT_STREQ(test.input, output.toString().ascii().data()); } TEST(MediaQuerySetTest, Basic) { @@ -42,162 +37,153 @@ // The second string represents the output string, if present. // Otherwise, the output string is identical to the first string. TestCase testCases[] = { - {"", 0, true}, - {" ", "", true}, - {"screen", 0, true}, - {"screen and (color)", 0, true}, - {"all and (min-width:500px)", "(min-width: 500px)", true}, - {"all and (min-width:/*bla*/500px)", "(min-width: 500px)", true}, - {"(min-width:500px)", "(min-width: 500px)", true}, - {"screen and (color), projection and (color)", 0, true}, - {"not screen and (color)", 0, true}, - {"only screen and (color)", 0, true}, - {"screen and (color), projection and (color)", 0, true}, - {"aural and (device-aspect-ratio: 16/9)", 0, true}, - {"speech and (min-device-width: 800px)", 0, true}, - {"example", 0, true}, + {"", nullptr}, + {" ", ""}, + {"screen", nullptr}, + {"screen and (color)", nullptr}, + {"all and (min-width:500px)", "(min-width: 500px)"}, + {"all and (min-width:/*bla*/500px)", "(min-width: 500px)"}, + {"(min-width:500px)", "(min-width: 500px)"}, + {"screen and (color), projection and (color)", nullptr}, + {"not screen and (color)", nullptr}, + {"only screen and (color)", nullptr}, + {"screen and (color), projection and (color)", nullptr}, + {"aural and (device-aspect-ratio: 16/9)", nullptr}, + {"speech and (min-device-width: 800px)", nullptr}, + {"example", nullptr}, {"screen and (max-weight: 3kg) and (color), (monochrome)", - "not all, (monochrome)", true}, - {"(min-width: -100px)", "not all", true}, - {"(example, all,), speech", "not all, speech", true}, - {"&test, screen", "not all, screen", true}, - {"print and (min-width: 25cm)", 0, true}, + "not all, (monochrome)"}, + {"(min-width: -100px)", "not all"}, + {"(example, all,), speech", "not all, speech"}, + {"&test, screen", "not all, screen"}, + {"print and (min-width: 25cm)", nullptr}, {"screen and (min-width: 400px) and (max-width: 700px)", - "screen and (max-width: 700px) and (min-width: 400px)", true}, - {"screen and (device-width: 800px)", 0, true}, - {"screen and (device-height: 60em)", 0, true}, - {"screen and (device-height: 60rem)", 0, true}, - {"screen and (device-height: 60ch)", 0, true}, - {"screen and (device-aspect-ratio: 16/9)", 0, true}, - {"(device-aspect-ratio: 16.0/9.0)", "not all", true}, - {"(device-aspect-ratio: 16/ 9)", "(device-aspect-ratio: 16/9)", true}, - {"(device-aspect-ratio: 16/\r9)", "(device-aspect-ratio: 16/9)", true}, - {"all and (color)", "(color)", true}, - {"all and (min-color: 1)", "(min-color: 1)", true}, - {"all and (min-color: 1.0)", "not all", true}, - {"all and (min-color: 2)", "(min-color: 2)", true}, - {"all and (color-index)", "(color-index)", true}, - {"all and (min-color-index: 1)", "(min-color-index: 1)", true}, - {"all and (monochrome)", "(monochrome)", true}, - {"all and (min-monochrome: 1)", "(min-monochrome: 1)", true}, - {"all and (min-monochrome: 2)", "(min-monochrome: 2)", true}, - {"print and (monochrome)", 0, true}, - {"handheld and (grid) and (max-width: 15em)", 0, true}, - {"handheld and (grid) and (max-device-height: 7em)", 0, true}, - {"screen and (max-width: 50%)", "not all", true}, - {"screen and (max-WIDTH: 500px)", "screen and (max-width: 500px)", true}, - {"screen and (max-width: 24.4em)", 0, true}, - {"screen and (max-width: 24.4EM)", "screen and (max-width: 24.4em)", - true}, - {"screen and (max-width: blabla)", "not all", true}, - {"screen and (max-width: 1)", "not all", true}, - {"screen and (max-width: 0)", 0, true}, - {"screen and (max-width: 1deg)", "not all", true}, + "screen and (max-width: 700px) and (min-width: 400px)"}, + {"screen and (device-width: 800px)", nullptr}, + {"screen and (device-height: 60em)", nullptr}, + {"screen and (device-height: 60rem)", nullptr}, + {"screen and (device-height: 60ch)", nullptr}, + {"screen and (device-aspect-ratio: 16/9)", nullptr}, + {"(device-aspect-ratio: 16.0/9.0)", "not all"}, + {"(device-aspect-ratio: 16/ 9)", "(device-aspect-ratio: 16/9)"}, + {"(device-aspect-ratio: 16/\r9)", "(device-aspect-ratio: 16/9)"}, + {"all and (color)", "(color)"}, + {"all and (min-color: 1)", "(min-color: 1)"}, + {"all and (min-color: 1.0)", "not all"}, + {"all and (min-color: 2)", "(min-color: 2)"}, + {"all and (color-index)", "(color-index)"}, + {"all and (min-color-index: 1)", "(min-color-index: 1)"}, + {"all and (monochrome)", "(monochrome)"}, + {"all and (min-monochrome: 1)", "(min-monochrome: 1)"}, + {"all and (min-monochrome: 2)", "(min-monochrome: 2)"}, + {"print and (monochrome)", nullptr}, + {"handheld and (grid) and (max-width: 15em)", nullptr}, + {"handheld and (grid) and (max-device-height: 7em)", nullptr}, + {"screen and (max-width: 50%)", "not all"}, + {"screen and (max-WIDTH: 500px)", "screen and (max-width: 500px)"}, + {"screen and (max-width: 24.4em)", nullptr}, + {"screen and (max-width: 24.4EM)", "screen and (max-width: 24.4em)"}, + {"screen and (max-width: blabla)", "not all"}, + {"screen and (max-width: 1)", "not all"}, + {"screen and (max-width: 0)", nullptr}, + {"screen and (max-width: 1deg)", "not all"}, {"handheld and (min-width: 20em), \nscreen and (min-width: 20em)", - "handheld and (min-width: 20em), screen and (min-width: 20em)", true}, - {"print and (min-resolution: 300dpi)", 0, true}, - {"print and (min-resolution: 118dpcm)", 0, true}, + "handheld and (min-width: 20em), screen and (min-width: 20em)"}, + {"print and (min-resolution: 300dpi)", nullptr}, + {"print and (min-resolution: 118dpcm)", nullptr}, {"(resolution: 0.83333333333333333333dppx)", - "(resolution: 0.833333333333333dppx)", true}, - {"(resolution: 2.4dppx)", 0, true}, - {"all and(color)", "not all", true}, - {"all and (", "not all", true}, - {"test;,all", "not all, all", true}, - {"(color:20example)", "not all", false}, - {"not braille", 0, true}, - {",screen", "not all, screen", true}, - {",all", "not all, all", true}, - {",,all,,", "not all, not all, all, not all, not all", true}, - {",,all,, ", "not all, not all, all, not all, not all", true}, + "(resolution: 0.833333333333333dppx)"}, + {"(resolution: 2.4dppx)", nullptr}, + {"all and(color)", "not all"}, + {"all and (", "not all"}, + {"test;,all", "not all, all"}, + {"(color:20example)", "not all"}, + {"not braille", nullptr}, + {",screen", "not all, screen"}, + {",all", "not all, all"}, + {",,all,,", "not all, not all, all, not all, not all"}, + {",,all,, ", "not all, not all, all, not all, not all"}, {",screen,,&invalid,,", - "not all, screen, not all, not all, not all, not all", true}, + "not all, screen, not all, not all, not all, not all"}, {",screen,,(invalid,),,", - "not all, screen, not all, not all, not all, not all", true}, - {",(all,),,", "not all, not all, not all, not all", true}, - {",", "not all, not all", true}, - {" ", "", true}, - {"(color", "(color)", true}, - {"(min-color: 2", "(min-color: 2)", true}, - {"(orientation: portrait)", 0, true}, - {"tv and (scan: progressive)", 0, true}, - {"(pointer: coarse)", 0, true}, - {"(min-orientation:portrait)", "not all", true}, - {"all and (orientation:portrait)", "(orientation: portrait)", true}, - {"all and (orientation:landscape)", "(orientation: landscape)", true}, + "not all, screen, not all, not all, not all, not all"}, + {",(all,),,", "not all, not all, not all, not all"}, + {",", "not all, not all"}, + {" ", ""}, + {"(color", "(color)"}, + {"(min-color: 2", "(min-color: 2)"}, + {"(orientation: portrait)", nullptr}, + {"tv and (scan: progressive)", nullptr}, + {"(pointer: coarse)", nullptr}, + {"(min-orientation:portrait)", "not all"}, + {"all and (orientation:portrait)", "(orientation: portrait)"}, + {"all and (orientation:landscape)", "(orientation: landscape)"}, {"NOT braille, tv AND (max-width: 200px) and (min-WIDTH: 100px) and " "(orientation: landscape), (color)", "not braille, tv and (max-width: 200px) and (min-width: 100px) and " - "(orientation: landscape), (color)", - true}, - {"(m\\61x-width: 300px)", "(max-width: 300px)", true}, - {"(max-width: 400\\70\\78)", "(max-width: 400px)", false}, - {"(max-width: 500\\0070\\0078)", "(max-width: 500px)", false}, - {"(max-width: 600\\000070\\000078)", "(max-width: 600px)", false}, + "(orientation: landscape), (color)"}, + {"(m\\61x-width: 300px)", "(max-width: 300px)"}, + {"(max-width: 400\\70\\78)", "(max-width: 400px)"}, + {"(max-width: 500\\0070\\0078)", "(max-width: 500px)"}, + {"(max-width: 600\\000070\\000078)", "(max-width: 600px)"}, {"(max-width: 700px), (max-width: 700px)", - "(max-width: 700px), (max-width: 700px)", true}, + "(max-width: 700px), (max-width: 700px)"}, {"(max-width: 800px()), (max-width: 800px)", - "not all, (max-width: 800px)", true}, - {"(max-width: 900px(()), (max-width: 900px)", "not all", true}, + "not all, (max-width: 800px)"}, + {"(max-width: 900px(()), (max-width: 900px)", "not all"}, {"(max-width: 600px(())))), (max-width: 600px)", - "not all, (max-width: 600px)", true}, - {"(max-width: 500px(((((((((())))), (max-width: 500px)", "not all", true}, + "not all, (max-width: 600px)"}, + {"(max-width: 500px(((((((((())))), (max-width: 500px)", "not all"}, {"(max-width: 800px[]), (max-width: 800px)", - "not all, (max-width: 800px)", true}, - {"(max-width: 900px[[]), (max-width: 900px)", "not all", true}, + "not all, (max-width: 800px)"}, + {"(max-width: 900px[[]), (max-width: 900px)", "not all"}, {"(max-width: 600px[[]]]]), (max-width: 600px)", - "not all, (max-width: 600px)", true}, - {"(max-width: 500px[[[[[[[[[[]]]]), (max-width: 500px)", "not all", true}, + "not all, (max-width: 600px)"}, + {"(max-width: 500px[[[[[[[[[[]]]]), (max-width: 500px)", "not all"}, {"(max-width: 800px{}), (max-width: 800px)", - "not all, (max-width: 800px)", true}, - {"(max-width: 900px{{}), (max-width: 900px)", "not all", true}, + "not all, (max-width: 800px)"}, + {"(max-width: 900px{{}), (max-width: 900px)", "not all"}, {"(max-width: 600px{{}}}}), (max-width: 600px)", - "not all, (max-width: 600px)", true}, - {"(max-width: 500px{{{{{{{{{{}}}}), (max-width: 500px)", "not all", true}, - {"[(), (max-width: 400px)", "not all", true}, - {"[{}, (max-width: 500px)", "not all", true}, - {"[{]}], (max-width: 900px)", "not all, (max-width: 900px)", true}, - {"[{[]{}{{{}}}}], (max-width: 900px)", "not all, (max-width: 900px)", - true}, - {"[{[}], (max-width: 900px)", "not all", true}, - {"[({)}], (max-width: 900px)", "not all", true}, - {"[]((), (max-width: 900px)", "not all", true}, - {"((), (max-width: 900px)", "not all", true}, - {"(foo(), (max-width: 900px)", "not all", true}, - {"[](()), (max-width: 900px)", "not all, (max-width: 900px)", true}, + "not all, (max-width: 600px)"}, + {"(max-width: 500px{{{{{{{{{{}}}}), (max-width: 500px)", "not all"}, + {"[(), (max-width: 400px)", "not all"}, + {"[{}, (max-width: 500px)", "not all"}, + {"[{]}], (max-width: 900px)", "not all, (max-width: 900px)"}, + {"[{[]{}{{{}}}}], (max-width: 900px)", "not all, (max-width: 900px)"}, + {"[{[}], (max-width: 900px)", "not all"}, + {"[({)}], (max-width: 900px)", "not all"}, + {"[]((), (max-width: 900px)", "not all"}, + {"((), (max-width: 900px)", "not all"}, + {"(foo(), (max-width: 900px)", "not all"}, + {"[](()), (max-width: 900px)", "not all, (max-width: 900px)"}, {"all an[isdfs bla())()]icalc(i)(()), (max-width: 400px)", - "not all, (max-width: 400px)", true}, - {"all an[isdfs bla())(]icalc(i)(()), (max-width: 500px)", "not all", - true}, - {"all an[isdfs bla())(]icalc(i)(())), (max-width: 600px)", "not all", - true}, + "not all, (max-width: 400px)"}, + {"all an[isdfs bla())(]icalc(i)(()), (max-width: 500px)", "not all"}, + {"all an[isdfs bla())(]icalc(i)(())), (max-width: 600px)", "not all"}, {"all an[isdfs bla())(]icalc(i)(()))], (max-width: 800px)", - "not all, (max-width: 800px)", true}, - {"(max-width: '40px')", "not all", true}, - {"('max-width': 40px)", "not all", true}, - {"'\"'\", (max-width: 900px)", "not all", true}, - {"'\"\"\"', (max-width: 900px)", "not all, (max-width: 900px)", true}, - {"\"'\"', (max-width: 900px)", "not all", true}, - {"\"'''\", (max-width: 900px)", "not all, (max-width: 900px)", true}, - {"not not", "not all", true}, - {"not and", "not all", true}, - {"not only", "not all", true}, - {"not or", "not all", true}, - {"only not", "not all", true}, - {"only and", "not all", true}, - {"only only", "not all", true}, - {"only or", "not all", true}, - {"not (orientation)", "not all", true}, - {"only (orientation)", "not all", true}, - {0, 0} // Do not remove the terminator line. + "not all, (max-width: 800px)"}, + {"(max-width: '40px')", "not all"}, + {"('max-width': 40px)", "not all"}, + {"'\"'\", (max-width: 900px)", "not all"}, + {"'\"\"\"', (max-width: 900px)", "not all, (max-width: 900px)"}, + {"\"'\"', (max-width: 900px)", "not all"}, + {"\"'''\", (max-width: 900px)", "not all, (max-width: 900px)"}, + {"not not", "not all"}, + {"not and", "not all"}, + {"not only", "not all"}, + {"not or", "not all"}, + {"only not", "not all"}, + {"only and", "not all"}, + {"only only", "not all"}, + {"only or", "not all"}, + {"not (orientation)", "not all"}, + {"only (orientation)", "not all"}, + {nullptr, nullptr} // Do not remove the terminator line. }; for (unsigned i = 0; testCases[i].input; ++i) { - MediaQuerySet* oldParserQuerySet = - MediaQuerySet::create(testCases[i].input); - MediaQuerySet* threadSafeQuerySet = - MediaQuerySet::createOffMainThread(testCases[i].input); - testMediaQuery(testCases[i], *oldParserQuerySet, true); - testMediaQuery(testCases[i], *threadSafeQuerySet, false); + MediaQuerySet* querySet = MediaQuerySet::create(testCases[i].input); + testMediaQuery(testCases[i], *querySet); } }
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp index 645e0b9f..8e46d3dc 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp +++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -785,6 +785,7 @@ void ContainerNode::childrenChanged(const ChildrenChange& change) { document().incDOMTreeVersion(); + document().notifyChangeChildren(*this); invalidateNodeListCachesInAncestors(); if (change.isChildInsertion() && !childNeedsStyleRecalc()) { setChildNeedsStyleRecalc();
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index fca88932..5cc3d95 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5730,9 +5730,8 @@ m_frame->console().addMessage(consoleMessage); } -// FIXME(crbug.com/305497): This should be removed after -// ExecutionContext-LocalDOMWindow migration. -void Document::postTask(const WebTraceLocation& location, +void Document::postTask(TaskType, + const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task, const String& taskNameForInstrumentation) { m_taskRunner->postTask(location, std::move(task), taskNameForInstrumentation);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 38cbd58e..62bceac 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -990,9 +990,9 @@ bool isDNSPrefetchEnabled() const { return m_isDNSPrefetchEnabled; } void parseDNSPrefetchControlHeader(const String&); - // FIXME(crbug.com/305497): This should be removed once LocalDOMWindow is an - // ExecutionContext. - void postTask(const WebTraceLocation&, + using ExecutionContext::postTask; + void postTask(TaskType, + const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>, const String& taskNameForInstrumentation = emptyString()) override; // Executes the task on context's thread asynchronously. @@ -1229,7 +1229,6 @@ void notifyResizeForViewportUnits(); void updateActiveStyle(); - void updateStyleInvalidationIfNeeded(); DECLARE_VIRTUAL_TRACE(); @@ -1363,6 +1362,7 @@ void updateUseShadowTreesIfNeeded(); void evaluateMediaQueryListIfNeeded(); + void updateStyleInvalidationIfNeeded(); void updateStyle(); void notifyLayoutTreeOfSubtreeChanges();
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp index 0554841b..5aa5712d 100644 --- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp +++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -114,6 +114,10 @@ return m_contextDestroyedCalledCounter; } + const HeapVector<Member<const ContainerNode>>& childrenChangedNodes() const { + return m_childrenChangedNodes; + } + const HeapVector<Member<MergeTextNodesRecord>>& mergeTextNodesRecords() const { return m_mergeTextNodesRecords; @@ -141,6 +145,7 @@ private: // Implement |SynchronousMutationObserver| member functions. void contextDestroyed() final; + void didChangeChildren(const ContainerNode&) final; void didMergeTextNodes(Text&, unsigned) final; void didSplitTextNode(const Text&) final; void didUpdateCharacterData(CharacterData*, @@ -151,6 +156,7 @@ void nodeWillBeRemoved(Node&) final; int m_contextDestroyedCalledCounter = 0; + HeapVector<Member<const ContainerNode>> m_childrenChangedNodes; HeapVector<Member<MergeTextNodesRecord>> m_mergeTextNodesRecords; HeapVector<Member<ContainerNode>> m_removedChildrenNodes; HeapVector<Member<Node>> m_removedNodes; @@ -169,6 +175,11 @@ ++m_contextDestroyedCalledCounter; } +void TestSynchronousMutationObserver::didChangeChildren( + const ContainerNode& container) { + m_childrenChangedNodes.append(&container); +} + void TestSynchronousMutationObserver::didMergeTextNodes(Text& node, unsigned offset) { m_mergeTextNodesRecords.append(new MergeTextNodesRecord(&node, offset)); @@ -197,6 +208,7 @@ } DEFINE_TRACE(TestSynchronousMutationObserver) { + visitor->trace(m_childrenChangedNodes); visitor->trace(m_mergeTextNodesRecords); visitor->trace(m_removedChildrenNodes); visitor->trace(m_removedNodes); @@ -469,6 +481,21 @@ EXPECT_EQ(observer.countContextDestroyedCalled(), 1); } +TEST_F(DocumentTest, SynchronousMutationNotifieAppendChild) { + auto& observer = *new TestSynchronousMutationObserver(document()); + document().body()->appendChild(document().createTextNode("a123456789")); + ASSERT_EQ(1u, observer.childrenChangedNodes().size()); + EXPECT_EQ(document().body(), observer.childrenChangedNodes()[0]); +} + +TEST_F(DocumentTest, SynchronousMutationNotifieInsertBefore) { + auto& observer = *new TestSynchronousMutationObserver(document()); + document().documentElement()->insertBefore( + document().createTextNode("a123456789"), document().body()); + ASSERT_EQ(1u, observer.childrenChangedNodes().size()); + EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[0]); +} + TEST_F(DocumentTest, SynchronousMutationNotifierMergeTextNodes) { auto& observer = *new TestSynchronousMutationObserver(document()); @@ -486,6 +513,26 @@ EXPECT_EQ(observer.mergeTextNodesRecords()[0]->m_offset, 10u); } +TEST_F(DocumentTest, SynchronousMutationNotifieRemoveChild) { + auto& observer = *new TestSynchronousMutationObserver(document()); + document().documentElement()->removeChild(document().body()); + ASSERT_EQ(1u, observer.childrenChangedNodes().size()); + EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[0]); +} + +TEST_F(DocumentTest, SynchronousMutationNotifieReplaceChild) { + auto& observer = *new TestSynchronousMutationObserver(document()); + Element* const replacedNode = document().body(); + document().documentElement()->replaceChild(document().createElement("div"), + document().body()); + ASSERT_EQ(2u, observer.childrenChangedNodes().size()); + EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[0]); + EXPECT_EQ(document().documentElement(), observer.childrenChangedNodes()[1]); + + ASSERT_EQ(1u, observer.removedNodes().size()); + EXPECT_EQ(replacedNode, observer.removedNodes()[0]); +} + TEST_F(DocumentTest, SynchronousMutationNotifierSplitTextNode) { auto& observer = *new TestSynchronousMutationObserver(document());
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp index 6dd66ea..bafadfdc 100644 --- a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp +++ b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
@@ -29,6 +29,7 @@ #include "bindings/core/v8/SourceLocation.h" #include "core/dom/ExecutionContextTask.h" +#include "core/dom/TaskRunnerHelper.h" #include "core/events/ErrorEvent.h" #include "core/events/EventTarget.h" #include "core/fetch/MemoryCache.h" @@ -164,6 +165,13 @@ return virtualCompleteURL(url); } +void ExecutionContext::postTask(const WebTraceLocation& location, + std::unique_ptr<ExecutionContextTask> task, + const String& taskNameForInstrumentation) { + postTask(TaskType::Unspecified, location, std::move(task), + taskNameForInstrumentation); +} + void ExecutionContext::allowWindowInteraction() { ++m_windowInteractionTokens; }
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h index e0c259d..899b3d2b 100644 --- a/third_party/WebKit/Source/core/dom/ExecutionContext.h +++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h
@@ -53,6 +53,7 @@ class LocalDOMWindow; class PublicURLManager; class SecurityOrigin; +enum class TaskType : unsigned; class CORE_EXPORT ExecutionContext : public ContextLifecycleNotifier, public Supplementable<ExecutionContext> { @@ -94,9 +95,13 @@ virtual String userAgent() const = 0; // Executes the task on context's thread asynchronously. virtual void postTask( + TaskType, const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>, const String& taskNameForInstrumentation = emptyString()) = 0; + void postTask(const WebTraceLocation&, + std::unique_ptr<ExecutionContextTask>, + const String& taskNameForInstrumentation = emptyString()); // Gets the DOMTimerCoordinator which maintains the "active timer // list" of tasks created by setTimeout and setInterval. The @@ -127,6 +132,10 @@ void suspendScheduledTasks(); void resumeScheduledTasks(); + + // TODO(haraken): Remove these methods by making the customers inherit from + // ActiveDOMObject. ActiveDOMObject is a standard way to observe context + // suspension/resumption. virtual bool tasksNeedSuspension() { return false; } virtual void tasksWereSuspended() {} virtual void tasksWereResumed() {}
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp index b045d71..8084bdc9 100644 --- a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp +++ b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.cpp
@@ -11,6 +11,12 @@ SynchronousMutationNotifier::SynchronousMutationNotifier() = default; +void SynchronousMutationNotifier::notifyChangeChildren( + const ContainerNode& container) { + for (SynchronousMutationObserver* observer : m_observers) + observer->didChangeChildren(container); +} + void SynchronousMutationNotifier::notifyMergeTextNodes(Text& node, unsigned offset) { for (SynchronousMutationObserver* observer : m_observers)
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h index a54b8e24..b8005d1 100644 --- a/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h +++ b/third_party/WebKit/Source/core/dom/SynchronousMutationNotifier.h
@@ -23,6 +23,7 @@ public: // TODO(yosin): We will have |notifyXXX()| functions defined in // |SynchronousMutationObserver|. + void notifyChangeChildren(const ContainerNode&); void notifyMergeTextNodes(Text&, unsigned); void notifySplitTextNode(const Text&); void notifyUpdateCharacterData(CharacterData*,
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp index 3aee82b3..4add663 100644 --- a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp +++ b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.cpp
@@ -12,6 +12,7 @@ SynchronousMutationObserver::SynchronousMutationObserver() : LifecycleObserver(nullptr) {} +void SynchronousMutationObserver::didChangeChildren(const ContainerNode&) {} void SynchronousMutationObserver::didMergeTextNodes(Text&, unsigned) {} void SynchronousMutationObserver::didSplitTextNode(const Text&) {} void SynchronousMutationObserver::didUpdateCharacterData(CharacterData*,
diff --git a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h index bb6a20e..b52fb0b 100644 --- a/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h +++ b/third_party/WebKit/Source/core/dom/SynchronousMutationObserver.h
@@ -39,6 +39,9 @@ // - didInsertText(Node*, unsigned offset, unsigned length); // - didRemoveText(Node*, unsigned offset, unsigned length); + // Called after child nodes changed. + virtual void didChangeChildren(const ContainerNode&); + // TODO(yosin): We should use |const Text& oldNode|. // Called after characters in |oldNode| is appended at |offset| in // |oldNdoe->previousSibling()|.
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp index 0667f7b0..377d45d 100644 --- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp +++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
@@ -35,11 +35,11 @@ return frame ? frame->frameScheduler()->loadingTaskRunner() : Platform::current()->currentThread()->getWebTaskRunner(); case TaskType::Unthrottled: + case TaskType::Unspecified: return frame ? frame->frameScheduler()->unthrottledTaskRunner() : Platform::current()->currentThread()->getWebTaskRunner(); - default: - NOTREACHED(); } + NOTREACHED(); return nullptr; }
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h index 0cdddb8..ffd59c3 100644 --- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h +++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h
@@ -42,6 +42,10 @@ // Tasks that must not be throttled should be posted here, but the usage // should be very limited. Unthrottled, + + // Tasks that any other TaskType is not assigned to. This should be + // transitional and should be removed. + Unspecified, }; // HashTraits for TaskType.
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp index 91d8dbe..e7c2c90 100644 --- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp +++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -272,8 +272,17 @@ return; } - if (!baseNode || !extentNode) + // TODO(editing-dev): Behavior on where base or extent is null is still + // under discussion: https://github.com/w3c/selection-api/issues/72 + if (!baseNode) { UseCounter::count(frame(), UseCounter::SelectionSetBaseAndExtentNull); + frame()->selection().clear(); + return; + } + if (!extentNode) { + UseCounter::count(frame(), UseCounter::SelectionSetBaseAndExtentNull); + extentOffset = 0; + } if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode)) return;
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp index 92edae8..bae3cea 100644 --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -84,9 +84,11 @@ DCHECK(compositionType == TypingCommand::TextCompositionType::TextCompositionUpdate || compositionType == - TypingCommand::TextCompositionType::TextCompositionConfirm) + TypingCommand::TextCompositionType::TextCompositionConfirm || + compositionType == + TypingCommand::TextCompositionType::TextCompositionCancel) << "compositionType should be TextCompositionUpdate or " - "TextCompositionConfirm, but got " + "TextCompositionConfirm or TextCompositionCancel, but got " << static_cast<int>(compositionType); if (!frame.document()) return; @@ -126,6 +128,7 @@ compositionType); break; case TypingCommand::TextCompositionType::TextCompositionConfirm: + case TypingCommand::TextCompositionType::TextCompositionCancel: // TODO(chongz): Use TypingCommand::insertText after TextEvent was // removed. (Removed from spec since 2012) // See TextEvent.idl. @@ -379,7 +382,7 @@ dispatchCompositionUpdateEvent(frame(), emptyString()); insertTextDuringCompositionWithEvents( frame(), emptyString(), 0, - TypingCommand::TextCompositionType::TextCompositionConfirm); + TypingCommand::TextCompositionType::TextCompositionCancel); // Event handler might destroy document. if (!isAvailable()) return;
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h index f1259d0..a21fa517 100644 --- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h +++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -45,7 +45,8 @@ enum TextCompositionType { TextCompositionNone, TextCompositionUpdate, - TextCompositionConfirm + TextCompositionConfirm, + TextCompositionCancel }; enum Option {
diff --git a/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp b/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp index bf02c4e..c91ae783 100644 --- a/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp +++ b/third_party/WebKit/Source/core/editing/serializers/Serialization.cpp
@@ -713,13 +713,6 @@ return; } - // FIXME: This is wrong if containerNode->firstChild() has more than one ref! - if (containerNode->hasOneTextChild() && fragment->hasOneTextChild()) { - toText(containerNode->firstChild()) - ->setData(toText(fragment->firstChild())->data()); - return; - } - // FIXME: No need to replace the child it is a text node and its contents are // already == text. if (containerNode->hasOneChild()) {
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp index fc48a38..49e2abc7 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -126,8 +126,7 @@ static bool mediaAttributeMatches(const MediaValuesCached& mediaValues, const String& attributeValue) { - MediaQuerySet* mediaQueries = - MediaQuerySet::createOffMainThread(attributeValue); + MediaQuerySet* mediaQueries = MediaQuerySet::create(attributeValue); MediaQueryEvaluator mediaQueryEvaluator(mediaValues); return mediaQueryEvaluator.eval(mediaQueries); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index 1fdd612..f114f6e 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -1887,15 +1887,6 @@ return createAnonymousWithParentAndDisplay(parent, style()->display()); } -LayoutUnit LayoutBlock::nextPageLogicalTop(LayoutUnit logicalOffset) const { - LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); - if (!pageLogicalHeight) - return logicalOffset; - - return logicalOffset + pageRemainingLogicalHeightForOffset( - logicalOffset, AssociateWithLatterPage); -} - void LayoutBlock::paginatedContentWasLaidOut( LayoutUnit logicalBottomOffsetAfterPagination) { if (LayoutFlowThread* flowThread = flowThreadContainingBlock())
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h index dd75d49..47922010 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -511,9 +511,6 @@ return pageLogicalHeightForOffset(LayoutUnit()); } - // Returns the logical offset at the top of the next page, for a given offset. - LayoutUnit nextPageLogicalTop(LayoutUnit logicalOffset) const; - // Paginated content inside this block was laid out. // |logicalBottomOffsetAfterPagination| is the logical bottom offset of the // child content after applying any forced or unforced breaks as needed.
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp index cb24181e..c16002b9 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -815,7 +815,7 @@ // Now determine the correct ypos based off examination of collapsing margin // values. LayoutUnit logicalTopBeforeClear = - collapseMargins(child, marginInfo, childIsSelfCollapsing, + collapseMargins(child, layoutInfo, childIsSelfCollapsing, childDiscardMarginBefore, childDiscardMarginAfter); // Now check for clear. @@ -1599,11 +1599,38 @@ childAfterPositive, childAfterNegative); } +LayoutUnit LayoutBlockFlow::adjustedMarginBeforeForPagination( + const LayoutBox& child, + LayoutUnit logicalTopMarginEdge, + LayoutUnit logicalTopBorderEdge, + const BlockChildrenLayoutInfo& layoutInfo) const { + LayoutUnit effectiveMargin = logicalTopBorderEdge - logicalTopMarginEdge; + DCHECK(isPageLogicalHeightKnown()); + if (effectiveMargin <= LayoutUnit()) + return effectiveMargin; + // If margins would pull us past the top of the next fragmentainer, then we + // need to pull back and let the margins collapse into the fragmentainer + // boundary. If we're at a fragmentainer boundary, and there's no forced break + // involved, collapse the margin with the boundary we're at. Otherwise, + // preserve the margin at the top of the fragmentainer, but collapse it with + // the next fragmentainer boundary, since no margin should ever live in more + // than one fragmentainer. + PageBoundaryRule rule = AssociateWithLatterPage; + if (!child.needsForcedBreakBefore(layoutInfo.previousBreakAfterValue()) && + offsetFromLogicalTopOfFirstPage() + logicalTopMarginEdge > LayoutUnit()) + rule = AssociateWithFormerPage; + LayoutUnit remainingSpace = + pageRemainingLogicalHeightForOffset(logicalTopMarginEdge, rule); + return std::min(effectiveMargin, remainingSpace); +} + LayoutUnit LayoutBlockFlow::collapseMargins(LayoutBox& child, - MarginInfo& marginInfo, + BlockChildrenLayoutInfo& layoutInfo, bool childIsSelfCollapsing, bool childDiscardMarginBefore, bool childDiscardMarginAfter) { + MarginInfo& marginInfo = layoutInfo.marginInfo(); + // The child discards the before margin when the the after margin has discard // in the case of a self collapsing block. childDiscardMarginBefore = childDiscardMarginBefore || @@ -1765,14 +1792,11 @@ marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(&child)); } - // If margins would pull us past the top of the next page, then we need to - // pull back and pretend like the margins collapsed into the page edge. - LayoutState* layoutState = view()->layoutState(); - if (layoutState->isPaginated() && isPageLogicalHeightKnown() && - logicalTop > beforeCollapseLogicalTop) { + if (view()->layoutState()->isPaginated() && isPageLogicalHeightKnown()) { LayoutUnit oldLogicalTop = logicalTop; - logicalTop = - std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop)); + LayoutUnit margin = adjustedMarginBeforeForPagination( + child, beforeCollapseLogicalTop, logicalTop, layoutInfo); + logicalTop = beforeCollapseLogicalTop + margin; setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); } @@ -2063,13 +2087,12 @@ std::max(marginInfo.negativeMargin(), negativeMarginBefore); } - // Adjust logicalTopEstimate down to the next page if the margins are so large - // that we don't fit on the current page. LayoutState* layoutState = view()->layoutState(); - if (layoutState->isPaginated() && isPageLogicalHeightKnown() && - logicalTopEstimate > logicalHeight()) - logicalTopEstimate = - std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight())); + if (layoutState->isPaginated() && isPageLogicalHeightKnown()) { + LayoutUnit margin = adjustedMarginBeforeForPagination( + child, logicalHeight(), logicalTopEstimate, layoutInfo); + logicalTopEstimate = logicalHeight() + margin; + } logicalTopEstimate += getClearDelta(&child, logicalTopEstimate);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h index 13872c04..3ae25bc 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -778,8 +778,14 @@ return maxPositiveMarginAfter() - maxNegativeMarginAfter(); } + LayoutUnit adjustedMarginBeforeForPagination( + const LayoutBox&, + LayoutUnit logicalTopMarginEdge, + LayoutUnit logicalTopBorderEdge, + const BlockChildrenLayoutInfo&) const; + LayoutUnit collapseMargins(LayoutBox& child, - MarginInfo&, + BlockChildrenLayoutInfo&, bool childIsSelfCollapsing, bool childDiscardMarginBefore, bool childDiscardMarginAfter);
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h index 0fd887de..75cb21f4 100644 --- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h +++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -161,6 +161,7 @@ bool breakAll, int& nextBreakablePositionForBreakAll); bool rewindToMidWordBreak(WordMeasurement&, int end, float width); + bool canMidWordBreakBefore(LineLayoutText); bool rewindToFirstMidWordBreak(LineLayoutText, const ComputedStyle&, const Font&, @@ -760,6 +761,28 @@ return true; } +ALWAYS_INLINE bool BreakingContext::canMidWordBreakBefore(LineLayoutText text) { + // No break opportunities at the beginning of a line. + if (!m_width.currentWidth()) + return false; + // If this text node is not the first child of an inline, the parent and the + // preivous have the same style. + if (text.previousSibling()) + return true; + // Element boundaries belong to the parent of the element. + // TODO(kojii): Not all cases of element boundaries are supported yet. + // crbug.com/282134 + if (LineLayoutItem element = text.parent()) { + if (LineLayoutItem parent = element.parent()) { + const ComputedStyle& parentStyle = parent.styleRef(); + return parentStyle.autoWrap() && + ((parentStyle.breakWords() && !m_width.committedWidth()) || + parentStyle.wordBreak() == BreakAllWordBreak); + } + } + return false; +} + ALWAYS_INLINE bool BreakingContext::rewindToFirstMidWordBreak( LineLayoutText text, const ComputedStyle& style, @@ -767,21 +790,24 @@ bool breakAll, WordMeasurement& wordMeasurement) { int start = wordMeasurement.startOffset; - int end; + int end = canMidWordBreakBefore(text) ? start : start + 1; if (breakAll) { LazyLineBreakIterator lineBreakIterator(text.text(), style.locale()); - end = -1; - lineBreakIterator.isBreakable(start + 1, end, LineBreakType::BreakAll); - if (end < 0) + int nextBreakable = -1; + lineBreakIterator.isBreakable(end, nextBreakable, LineBreakType::BreakAll); + if (nextBreakable < 0) return false; - } else { - end = start + 1; + end = nextBreakable; } if (end >= wordMeasurement.endOffset) return false; float width = textWidth(text, start, end - start, font, m_width.currentWidth(), m_collapseWhiteSpace); + // If the first break opportunity doesn't fit, and if there's a break + // opportunity in previous runs, break at the opportunity. + if (!m_width.fitsOnLine(width) && m_width.committedWidth()) + return false; return rewindToMidWordBreak(wordMeasurement, end, width); } @@ -795,23 +821,27 @@ int len = wordMeasurement.endOffset - start; if (!len) return false; - if (m_width.availableWidth() <= LayoutUnit::epsilon()) + float xPosToBreak = m_width.availableWidth() - m_width.currentWidth(); + if (xPosToBreak <= LayoutUnit::epsilon()) { + // There were no space left. Skip computing how many characters can fit. return rewindToFirstMidWordBreak(text, style, font, breakAll, wordMeasurement); + } TextRun run = constructTextRun(font, text, start, len, style); run.setTabSize(!m_collapseWhiteSpace, style.getTabSize()); run.setXPos(m_width.currentWidth()); // TODO(kojii): should be replaced with safe-to-break when hb is ready. - float x = - m_width.availableWidth() + LayoutUnit::epsilon() - m_width.currentWidth(); + xPosToBreak += LayoutUnit::epsilon(); if (run.rtl()) - x = wordMeasurement.width - x; - len = font.offsetForPosition(run, x, false); - if (!len && !m_width.currentWidth()) + xPosToBreak = wordMeasurement.width - xPosToBreak; + len = font.offsetForPosition(run, xPosToBreak, false); + if (!len) { + // No characters can fit in the available space. return rewindToFirstMidWordBreak(text, style, font, breakAll, wordMeasurement); + } int end = start + len; if (breakAll) {
diff --git a/third_party/WebKit/Source/core/loader/resource/FontResource.cpp b/third_party/WebKit/Source/core/loader/resource/FontResource.cpp index d17d3a9..15569e19 100644 --- a/third_party/WebKit/Source/core/loader/resource/FontResource.cpp +++ b/third_party/WebKit/Source/core/loader/resource/FontResource.cpp
@@ -110,7 +110,7 @@ } void FontResource::startLoadLimitTimers() { - CHECK(isLoading()); + DCHECK(isLoading()); DCHECK_EQ(m_loadLimitState, LoadNotStarted); m_loadLimitState = UnderLimit; m_fontLoadShortLimitTimer.startOneShot(fontLoadWaitShortLimitSec, @@ -144,7 +144,6 @@ } void FontResource::fontLoadShortLimitCallback(TimerBase*) { - CHECK(isLoading()); if (!isLoading()) return; DCHECK_EQ(m_loadLimitState, UnderLimit); @@ -155,7 +154,6 @@ } void FontResource::fontLoadLongLimitCallback(TimerBase*) { - CHECK(isLoading()); if (!isLoading()) return; DCHECK_EQ(m_loadLimitState, ShortLimitExceeded);
diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp index 6041b8d5..e25dd0a 100644 --- a/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp +++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.cpp
@@ -28,7 +28,8 @@ m_isSecureContext(true), m_queue(new NullEventQueue()) {} -void NullExecutionContext::postTask(const WebTraceLocation&, +void NullExecutionContext::postTask(TaskType, + const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>, const String&) {}
diff --git a/third_party/WebKit/Source/core/testing/NullExecutionContext.h b/third_party/WebKit/Source/core/testing/NullExecutionContext.h index 987c02d..a4617fff 100644 --- a/third_party/WebKit/Source/core/testing/NullExecutionContext.h +++ b/third_party/WebKit/Source/core/testing/NullExecutionContext.h
@@ -29,6 +29,7 @@ String userAgent() const override { return String(); } void postTask( + TaskType, const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>, const String& taskNameForInstrumentation = emptyString()) override;
diff --git a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp index fa6848f..1ff271cd 100644 --- a/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp +++ b/third_party/WebKit/Source/core/timing/PerformanceBaseTest.cpp
@@ -40,7 +40,8 @@ v8::Function::New(scriptState->context(), nullptr).ToLocalChecked(); m_base = new TestPerformanceBase(); m_cb = PerformanceObserverCallback::create(scriptState, callback); - m_observer = PerformanceObserver::create(scriptState, m_base, m_cb); + m_observer = PerformanceObserver::create(scriptState->getExecutionContext(), + m_base, m_cb); } void SetUp() override {
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp index b1c8982..a0148f0 100644 --- a/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp +++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.cpp
@@ -17,17 +17,17 @@ namespace blink { PerformanceObserver* PerformanceObserver::create( - ScriptState* scriptState, + ExecutionContext* executionContext, PerformanceBase* performance, PerformanceObserverCallback* callback) { ASSERT(isMainThread()); - return new PerformanceObserver(scriptState, performance, callback); + return new PerformanceObserver(executionContext, performance, callback); } -PerformanceObserver::PerformanceObserver(ScriptState* scriptState, +PerformanceObserver::PerformanceObserver(ExecutionContext* executionContext, PerformanceBase* performance, PerformanceObserverCallback* callback) - : m_scriptState(scriptState), + : m_executionContext(executionContext), m_callback(this, callback), m_performance(performance), m_filterOptions(PerformanceEntry::Invalid), @@ -77,8 +77,7 @@ } bool PerformanceObserver::shouldBeSuspended() const { - return m_scriptState->getExecutionContext() && - m_scriptState->getExecutionContext()->activeDOMObjectsAreSuspended(); + return m_executionContext->activeDOMObjectsAreSuspended(); } void PerformanceObserver::deliver() { @@ -95,6 +94,7 @@ } DEFINE_TRACE(PerformanceObserver) { + visitor->trace(m_executionContext); visitor->trace(m_callback); visitor->trace(m_performance); visitor->trace(m_performanceEntries);
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.h b/third_party/WebKit/Source/core/timing/PerformanceObserver.h index 1219062..cea36e1 100644 --- a/third_party/WebKit/Source/core/timing/PerformanceObserver.h +++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.h
@@ -13,12 +13,12 @@ namespace blink { +class ExecutionContext; class ExceptionState; class PerformanceBase; class PerformanceObserver; class PerformanceObserverCallback; class PerformanceObserverInit; -class ScriptState; using PerformanceEntryVector = HeapVector<Member<PerformanceEntry>>; @@ -31,7 +31,7 @@ friend class PerformanceObserverTest; public: - static PerformanceObserver* create(ScriptState*, + static PerformanceObserver* create(ExecutionContext*, PerformanceBase*, PerformanceObserverCallback*); static void resumeSuspendedObservers(); @@ -45,13 +45,13 @@ DECLARE_TRACE_WRAPPERS(); private: - PerformanceObserver(ScriptState*, + PerformanceObserver(ExecutionContext*, PerformanceBase*, PerformanceObserverCallback*); void deliver(); bool shouldBeSuspended() const; - RefPtr<ScriptState> m_scriptState; + Member<ExecutionContext> m_executionContext; TraceWrapperMember<PerformanceObserverCallback> m_callback; WeakMember<PerformanceBase> m_performance; PerformanceEntryVector m_performanceEntries;
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp index bebd97c..16aa20c 100644 --- a/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp +++ b/third_party/WebKit/Source/core/timing/PerformanceObserverTest.cpp
@@ -29,7 +29,8 @@ v8::Function::New(scriptState->context(), nullptr).ToLocalChecked(); m_base = new MockPerformanceBase(); m_cb = PerformanceObserverCallback::create(scriptState, callback); - m_observer = PerformanceObserver::create(scriptState, m_base, m_cb); + m_observer = PerformanceObserver::create(scriptState->getExecutionContext(), + m_base, m_cb); } bool isRegistered() { return m_observer->m_isRegistered; }
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp index 0be4de5..f5be192 100644 --- a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.cpp
@@ -41,6 +41,7 @@ } void ThreadedWorkletGlobalScope::postTask( + TaskType, const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task, const String& taskNameForInstrumentation) {
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h index 37c27d4..0b1a5dc 100644 --- a/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletGlobalScope.h
@@ -20,7 +20,8 @@ // ExecutionContext bool isThreadedWorkletGlobalScope() const final { return true; } bool isContextThread() const final; - void postTask(const WebTraceLocation&, + void postTask(TaskType, + const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>, const String& taskNameForInstrumentation) final; void addConsoleMessage(ConsoleMessage*) final;
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp index 37f2e08f..72a392b 100644 --- a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp +++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.cpp
@@ -4,14 +4,12 @@ #include "core/workers/ThreadedWorkletObjectProxy.h" -#include "bindings/core/v8/SerializedScriptValue.h" -#include "bindings/core/v8/SourceLocation.h" -#include "core/dom/Document.h" #include "core/dom/ExecutionContext.h" -#include "core/dom/ExecutionContextTask.h" #include "core/inspector/ConsoleMessage.h" #include "core/workers/ParentFrameTaskRunners.h" #include "core/workers/ThreadedWorkletMessagingProxy.h" +#include "platform/CrossThreadFunctional.h" +#include "platform/WebTaskRunner.h" #include "wtf/Functional.h" #include "wtf/PtrUtil.h" #include <memory> @@ -33,18 +31,18 @@ MessageLevel level, const String& message, SourceLocation* location) { - // TODO(nhiroki): Replace this with getParentFrameTaskRunners(). - // (https://crbug.com/667310) - getExecutionContext()->postTask( - BLINK_FROM_HERE, createCrossThreadTask( - &ThreadedWorkletMessagingProxy::reportConsoleMessage, - m_messagingProxyWeakPtr, source, level, message, - passed(location->clone()))); + getParentFrameTaskRunners() + ->get(TaskType::Internal) + ->postTask( + BLINK_FROM_HERE, + crossThreadBind(&ThreadedWorkletMessagingProxy::reportConsoleMessage, + m_messagingProxyWeakPtr, source, level, message, + passed(location->clone()))); } void ThreadedWorkletObjectProxy::postMessageToPageInspector( const String& message) { - DCHECK(getExecutionContext()->isDocument()); + DCHECK(m_messagingProxyWeakPtr->getExecutionContext()->isDocument()); // The TaskType of Inspector tasks need to be Unthrottled because they need to // run even on a suspended page. getParentFrameTaskRunners() @@ -61,31 +59,26 @@ } void ThreadedWorkletObjectProxy::didCloseWorkerGlobalScope() { - // TODO(nhiroki): Replace this with getParentFrameTaskRunners(). - // (https://crbug.com/667310) - getExecutionContext()->postTask( - BLINK_FROM_HERE, createCrossThreadTask( - &ThreadedWorkletMessagingProxy::terminateGlobalScope, - m_messagingProxyWeakPtr)); + getParentFrameTaskRunners() + ->get(TaskType::Internal) + ->postTask( + BLINK_FROM_HERE, + crossThreadBind(&ThreadedWorkletMessagingProxy::terminateGlobalScope, + m_messagingProxyWeakPtr)); } void ThreadedWorkletObjectProxy::didTerminateWorkerThread() { // This will terminate the MessagingProxy. - // TODO(nhiroki): Replace this with getParentFrameTaskRunners(). - // (https://crbug.com/667310) - getExecutionContext()->postTask( - BLINK_FROM_HERE, - createCrossThreadTask( - &ThreadedWorkletMessagingProxy::workerThreadTerminated, - m_messagingProxyWeakPtr)); + getParentFrameTaskRunners() + ->get(TaskType::Internal) + ->postTask(BLINK_FROM_HERE, + crossThreadBind( + &ThreadedWorkletMessagingProxy::workerThreadTerminated, + m_messagingProxyWeakPtr)); } ThreadedWorkletObjectProxy::ThreadedWorkletObjectProxy( const WeakPtr<ThreadedWorkletMessagingProxy>& messagingProxyWeakPtr) : m_messagingProxyWeakPtr(messagingProxyWeakPtr) {} -ExecutionContext* ThreadedWorkletObjectProxy::getExecutionContext() const { - return m_messagingProxyWeakPtr->getExecutionContext(); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h index 0b4bfe83..0ce5f6e 100644 --- a/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h +++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletObjectProxy.h
@@ -12,7 +12,6 @@ namespace blink { -class ExecutionContext; class ThreadedWorkletMessagingProxy; // A proxy to talk to the parent worklet object. This object is created on the @@ -49,8 +48,6 @@ ThreadedWorkletObjectProxy(const WeakPtr<ThreadedWorkletMessagingProxy>&); private: - ExecutionContext* getExecutionContext() const; - // No guarantees about the lifetimes of tasks posted by this proxy wrt the // ThreadedWorkletMessagingProxy so a weak pointer must be used when posting // the tasks.
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp index dbeaca5..608ede32 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -272,7 +272,8 @@ m_scriptController->disableEval(errorMessage); } -void WorkerGlobalScope::postTask(const WebTraceLocation& location, +void WorkerGlobalScope::postTask(TaskType, + const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task, const String& taskNameForInstrumentation) { thread()->postTask(location, std::move(task),
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h index ec2c76f..81eaca5 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -126,7 +126,8 @@ bool isContextThread() const final; void disableEval(const String& errorMessage) final; String userAgent() const final { return m_userAgent; } - void postTask(const WebTraceLocation&, + void postTask(TaskType, + const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>, const String& taskNameForInstrumentation) final; DOMTimerCoordinator* timers() final { return &m_timers; }
diff --git a/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h index df0192e..d527e3c 100644 --- a/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/WorkletGlobalScope.h
@@ -74,7 +74,8 @@ NOTREACHED(); return nullptr; } // WorkletGlobalScopes don't have timers. - void postTask(const WebTraceLocation&, + void postTask(TaskType, + const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>, const String&) override { // TODO(ikilpatrick): implement.
diff --git a/third_party/WebKit/Source/web/TextFinder.cpp b/third_party/WebKit/Source/web/TextFinder.cpp index f674f1ce..150b2c2a 100644 --- a/third_party/WebKit/Source/web/TextFinder.cpp +++ b/third_party/WebKit/Source/web/TextFinder.cpp
@@ -70,10 +70,9 @@ static DeferredScopeStringMatches* create(TextFinder* textFinder, int identifier, const WebString& searchText, - const WebFindOptions& options, - bool reset) { + const WebFindOptions& options) { return new DeferredScopeStringMatches(textFinder, identifier, searchText, - options, reset); + options); } DEFINE_INLINE_TRACE() { visitor->trace(m_textFinder); } @@ -84,20 +83,18 @@ DeferredScopeStringMatches(TextFinder* textFinder, int identifier, const WebString& searchText, - const WebFindOptions& options, - bool reset) + const WebFindOptions& options) : m_timer(this, &DeferredScopeStringMatches::doTimeout), m_textFinder(textFinder), m_identifier(identifier), m_searchText(searchText), - m_options(options), - m_reset(reset) { + m_options(options) { m_timer.startOneShot(0.0, BLINK_FROM_HERE); } void doTimeout(TimerBase*) { - m_textFinder->callScopeStringMatches(this, m_identifier, m_searchText, - m_options, m_reset); + m_textFinder->resumeScopingStringMatches(m_identifier, m_searchText, + m_options); } Timer<DeferredScopeStringMatches> m_timer; @@ -105,7 +102,6 @@ const int m_identifier; const WebString m_searchText; const WebFindOptions m_options; - const bool m_reset; }; bool TextFinder::find(int identifier, @@ -263,45 +259,45 @@ } } +void TextFinder::startScopingStringMatches(int identifier, + const WebString& searchText, + const WebFindOptions& options) { + cancelPendingScopingEffort(); + + // This is a brand new search, so we need to reset everything. + // Scoping is just about to begin. + m_scopingInProgress = true; + + // Need to keep the current identifier locally in order to finish the + // request in case the frame is detached during the process. + m_findRequestIdentifier = identifier; + + // Clear highlighting for this frame. + unmarkAllTextMatches(); + + // Clear the tickmarks and results cache. + clearFindMatchesCache(); + + // Clear the total match count and increment markers version. + resetMatchCount(); + + // Clear the counters from last operation. + m_lastMatchCount = 0; + m_nextInvalidateAfter = 0; + m_resumeScopingFromRange = nullptr; + + // The view might be null on detached frames. + LocalFrame* frame = ownerFrame().frame(); + if (frame && frame->page()) + m_frameScoping = true; + + // Now, defer scoping until later to allow find operation to finish quickly. + scopeStringMatchesSoon(identifier, searchText, options); +} + void TextFinder::scopeStringMatches(int identifier, const WebString& searchText, - const WebFindOptions& options, - bool reset) { - // TODO(dglazkov): The reset/continue cases need to be untangled into two - // separate functions. This collation of logic is unnecessary and adds to - // overall complexity of the code. - if (reset) { - // This is a brand new search, so we need to reset everything. - // Scoping is just about to begin. - m_scopingInProgress = true; - - // Need to keep the current identifier locally in order to finish the - // request in case the frame is detached during the process. - m_findRequestIdentifier = identifier; - - // Clear highlighting for this frame. - unmarkAllTextMatches(); - - // Clear the tickmarks and results cache. - clearFindMatchesCache(); - - // Clear the counters from last operation. - m_lastMatchCount = 0; - m_nextInvalidateAfter = 0; - m_resumeScopingFromRange = nullptr; - - // The view might be null on detached frames. - LocalFrame* frame = ownerFrame().frame(); - if (frame && frame->page()) - m_frameScoping = true; - - // Now, defer scoping until later to allow find operation to finish quickly. - scopeStringMatchesSoon( - identifier, searchText, options, - false); // false means just reset, so don't do it again. - return; - } - + const WebFindOptions& options) { if (!shouldScopeMatches(searchText, options)) { finishCurrentScopingEffort(identifier); return; @@ -429,8 +425,7 @@ invalidateIfNecessary(); // Scoping effort ran out of time, lets ask for another time-slice. - scopeStringMatchesSoon(identifier, searchText, options, - false); // don't reset. + scopeStringMatchesSoon(identifier, searchText, options); return; // Done for now, resume work later. } @@ -456,9 +451,10 @@ } void TextFinder::cancelPendingScopingEffort() { - for (DeferredScopeStringMatches* deferredWork : m_deferredScopingWork) - deferredWork->dispose(); - m_deferredScopingWork.clear(); + if (m_deferredScopingWork) { + m_deferredScopingWork->dispose(); + m_deferredScopingWork.clear(); + } m_activeMatchIndex = -1; @@ -731,21 +727,18 @@ void TextFinder::scopeStringMatchesSoon(int identifier, const WebString& searchText, - const WebFindOptions& options, - bool reset) { - m_deferredScopingWork.append(DeferredScopeStringMatches::create( - this, identifier, searchText, options, reset)); + const WebFindOptions& options) { + DCHECK_EQ(m_deferredScopingWork, nullptr); + m_deferredScopingWork = + DeferredScopeStringMatches::create(this, identifier, searchText, options); } -void TextFinder::callScopeStringMatches(DeferredScopeStringMatches* caller, - int identifier, - const WebString& searchText, - const WebFindOptions& options, - bool reset) { - size_t index = m_deferredScopingWork.find(caller); - m_deferredScopingWork.remove(index); +void TextFinder::resumeScopingStringMatches(int identifier, + const WebString& searchText, + const WebFindOptions& options) { + m_deferredScopingWork.clear(); - scopeStringMatches(identifier, searchText, options, reset); + scopeStringMatches(identifier, searchText, options); } void TextFinder::invalidateIfNecessary() {
diff --git a/third_party/WebKit/Source/web/TextFinder.h b/third_party/WebKit/Source/web/TextFinder.h index 6c04b1e..ea5dd0a 100644 --- a/third_party/WebKit/Source/web/TextFinder.h +++ b/third_party/WebKit/Source/web/TextFinder.h
@@ -72,20 +72,11 @@ void findMatchRects(WebVector<WebFloatRect>&); int selectNearestFindMatch(const WebFloatPoint&, WebRect* selectionRect); - // Counts how many times a particular string occurs within the frame. It - // also retrieves the location of the string and updates a vector in the - // frame so that tick-marks and highlighting can be drawn. This function - // does its work asynchronously, by running for a certain time-slice and - // then scheduling itself (co-operative multitasking) to be invoked later - // (repeating the process until all matches have been found). This allows - // multiple frames to be searched at the same time and provides a way to - // cancel at any time (see cancelPendingScopingEffort). The parameter - // searchText specifies what to look for and |reset| signals whether this is - // a brand new request or a continuation of the last scoping effort. - void scopeStringMatches(int identifier, - const WebString& searchText, - const WebFindOptions&, - bool reset); + // Starts brand new scoping request: resets the scoping state and + // asyncronously calls scopeStringMatches(). + void startScopingStringMatches(int identifier, + const WebString& searchText, + const WebFindOptions&); // Cancels any outstanding requests for scoping string matches on the frame. void cancelPendingScopingEffort(); @@ -187,18 +178,28 @@ // appropriate. void finishCurrentScopingEffort(int identifier); + // Counts how many times a particular string occurs within the frame. It + // also retrieves the location of the string and updates a vector in the + // frame so that tick-marks and highlighting can be drawn. This function + // does its work asynchronously, by running for a certain time-slice and + // then scheduling itself (co-operative multitasking) to be invoked later + // (repeating the process until all matches have been found). This allows + // multiple frames to be searched at the same time and provides a way to + // cancel at any time (see cancelPendingScopingEffort). The parameter + // searchText specifies what to look for. + void scopeStringMatches(int identifier, + const WebString& searchText, + const WebFindOptions&); + // Queue up a deferred call to scopeStringMatches. void scopeStringMatchesSoon(int identifier, const WebString& searchText, - const WebFindOptions&, - bool reset); + const WebFindOptions&); // Called by a DeferredScopeStringMatches instance. - void callScopeStringMatches(DeferredScopeStringMatches*, - int identifier, - const WebString& searchText, - const WebFindOptions&, - bool reset); + void resumeScopingStringMatches(int identifier, + const WebString& searchText, + const WebFindOptions&); // Determines whether to invalidate the content area and scrollbar. void invalidateIfNecessary(); @@ -254,8 +255,8 @@ // and the frame area. int m_nextInvalidateAfter; - // A list of all of the pending calls to scopeStringMatches. - HeapVector<Member<DeferredScopeStringMatches>> m_deferredScopingWork; + // Pending call to scopeStringMatches. + Member<DeferredScopeStringMatches> m_deferredScopingWork; // Version number incremented whenever this frame's find-in-page match // markers change.
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index 7c317d7..7ae12c4a 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -2125,14 +2125,9 @@ return; } - // Scoping effort begins. - ensureTextFinder().resetMatchCount(); - textFinder()->cancelPendingScopingEffort(); - // Start a new scoping request. If the scoping function determines that it // needs to scope, it will defer until later. - textFinder()->scopeStringMatches(identifier, searchText, options, - true /* reset */); + ensureTextFinder().startScopingStringMatches(identifier, searchText, options); } bool WebLocalFrameImpl::find(int identifier,
diff --git a/third_party/WebKit/Source/web/tests/TextFinderTest.cpp b/third_party/WebKit/Source/web/tests/TextFinderTest.cpp index 25a588b..534f3d87 100644 --- a/third_party/WebKit/Source/web/tests/TextFinderTest.cpp +++ b/third_party/WebKit/Source/web/tests/TextFinderTest.cpp
@@ -308,7 +308,7 @@ WebFindOptions findOptions; // Default. textFinder().resetMatchCount(); - textFinder().scopeStringMatches(identifier, searchText, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchText, findOptions); while (textFinder().scopingInProgress()) runPendingTasks(); @@ -320,6 +320,32 @@ EXPECT_EQ(findInPageRect(textNode, 14, textNode, 20), matchRects[1]); } +TEST_F(TextFinderTest, ScopeTextMatchesRepeated) { + document().body()->setInnerHTML("XXXXFindMeYYYYfindmeZZZZ"); + document().updateStyleAndLayout(); + + Node* textNode = document().body()->firstChild(); + + int identifier = 0; + WebString searchText1(String("XFindMe")); + WebString searchText2(String("FindMe")); + WebFindOptions findOptions; // Default. + + textFinder().resetMatchCount(); + textFinder().startScopingStringMatches(identifier, searchText1, findOptions); + textFinder().startScopingStringMatches(identifier, searchText2, findOptions); + while (textFinder().scopingInProgress()) + runPendingTasks(); + + // Only searchText2 should be highlighted. + EXPECT_EQ(2, textFinder().totalMatchCount()); + WebVector<WebFloatRect> matchRects; + textFinder().findMatchRects(matchRects); + ASSERT_EQ(2u, matchRects.size()); + EXPECT_EQ(findInPageRect(textNode, 4, textNode, 10), matchRects[0]); + EXPECT_EQ(findInPageRect(textNode, 14, textNode, 20), matchRects[1]); +} + TEST_F(TextFinderTest, ScopeTextMatchesWithShadowDOM) { document().body()->setInnerHTML("<b>FOO</b><i>foo</i>"); ShadowRoot* shadowRoot = document().body()->createShadowRootInternal( @@ -336,7 +362,7 @@ WebFindOptions findOptions; // Default. textFinder().resetMatchCount(); - textFinder().scopeStringMatches(identifier, searchText, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchText, findOptions); while (textFinder().scopingInProgress()) runPendingTasks(); @@ -366,7 +392,7 @@ WebFindOptions findOptions; // Default. textFinder().resetMatchCount(); - textFinder().scopeStringMatches(identifier, searchText, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchText, findOptions); while (textFinder().scopingInProgress()) runPendingTasks(); @@ -389,7 +415,7 @@ WebFindOptions findOptions; // Default. textFinder().resetMatchCount(); - textFinder().scopeStringMatches(identifier, searchText, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchText, findOptions); while (textFinder().scopingInProgress()) runPendingTasks(); @@ -412,7 +438,7 @@ WebFindOptions findOptions; // Default. textFinder().resetMatchCount(); - textFinder().scopeStringMatches(identifier, searchText, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchText, findOptions); while (textFinder().scopingInProgress()) runPendingTasks(); @@ -436,7 +462,7 @@ bool activeNow; textFinder().resetMatchCount(); - textFinder().scopeStringMatches(identifier, searchText, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchText, findOptions); while (textFinder().scopingInProgress()) runPendingTasks(); @@ -466,7 +492,7 @@ findOptions.findNext = false; textFinder().resetMatchCount(); textFinder().cancelPendingScopingEffort(); - textFinder().scopeStringMatches(identifier, searchText, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchText, findOptions); while (textFinder().scopingInProgress()) runPendingTasks(); EXPECT_EQ(2, textFinder().totalMatchCount()); @@ -526,7 +552,8 @@ // There will be only one iteration before timeout, because increment // of the TimeProxyPlatform timer is greater than timeout threshold. - textFinder().scopeStringMatches(identifier, searchPattern, findOptions, true); + textFinder().startScopingStringMatches(identifier, searchPattern, + findOptions); while (textFinder().scopingInProgress()) runPendingTasks();
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index ade7eb5..97c161a 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -4647,9 +4647,10 @@ mainFrame->ensureTextFinder().resetMatchCount(); for (WebLocalFrameImpl* frame = mainFrame; frame; - frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) - frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText, - options, true); + frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) { + frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchText, options); + } runPendingTasks(); EXPECT_TRUE(client.findResultsAreReady()); @@ -4710,18 +4711,20 @@ mainFrame->ensureTextFinder().resetMatchCount(); for (WebLocalFrameImpl* frame = mainFrame; frame; - frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) - frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText, - options, true); + frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) { + frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchText, options); + } runPendingTasks(); EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false)); mainFrame->stopFinding(WebLocalFrame::StopFindActionClearSelection); for (WebLocalFrameImpl* frame = mainFrame; frame; - frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) - frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText, - options, true); + frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) { + frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchText, options); + } runPendingTasks(); EXPECT_TRUE(client.findResultsAreReady()); @@ -4734,9 +4737,10 @@ mainFrame->ensureTextFinder().resetMatchCount(); for (WebLocalFrameImpl* frame = mainFrame; frame; - frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) - frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchTextNew, - options, true); + frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) { + frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchTextNew, options); + } runPendingTasks(); EXPECT_TRUE(client.findResultsAreReady()); @@ -4775,9 +4779,10 @@ mainFrame->ensureTextFinder().resetMatchCount(); for (WebLocalFrameImpl* frame = mainFrame; frame; - frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) - frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText, - options, true); + frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) { + frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchText, options); + } runPendingTasks(); EXPECT_TRUE(client.findResultsAreReady()); @@ -4814,9 +4819,10 @@ mainFrame->ensureTextFinder().resetMatchCount(); for (WebLocalFrameImpl* frame = mainFrame; frame; - frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) - frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText, - options, true); + frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) { + frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchText, options); + } runPendingTasks(); EXPECT_TRUE(client.findResultsAreReady()); @@ -4850,12 +4856,13 @@ mainFrame->ensureTextFinder().resetMatchCount(); for (WebLocalFrameImpl* frame = mainFrame; frame; - frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) - frame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText, - options, true); + frame = static_cast<WebLocalFrameImpl*>(frame->traverseNext())) { + frame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchText, options); + } - // The first scopeStringMatches will have reset the state. Detach before it - // actually scopes. + // The first startScopingStringMatches will have reset the state. Detach + // before it actually scopes. removeElementById(mainFrame, "frame"); runPendingTasks(); @@ -4910,8 +4917,8 @@ EXPECT_TRUE(mainFrame->find(kFindIdentifier, searchText, options, false)); mainFrame->ensureTextFinder().resetMatchCount(); - mainFrame->ensureTextFinder().scopeStringMatches(kFindIdentifier, searchText, - options, true); + mainFrame->ensureTextFinder().startScopingStringMatches(kFindIdentifier, + searchText, options); runPendingTasks(); EXPECT_TRUE(client.findResultsAreReady()); @@ -4962,8 +4969,8 @@ bool activeNow; frame->ensureTextFinder().resetMatchCount(); - frame->ensureTextFinder().scopeStringMatches(findIdentifier, searchText, - options, true); + frame->ensureTextFinder().startScopingStringMatches(findIdentifier, + searchText, options); runPendingTasks(); EXPECT_TRUE(client.findResultsAreReady());
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h index 00315e70..52cf175 100644 --- a/third_party/WebKit/public/platform/WebURLResponse.h +++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -98,7 +98,7 @@ const WebString& issuer, double validFrom, double validTo, - WebVector<WebString>& certificate, + const WebVector<WebString>& certificate, const SignedCertificateTimestampList& sctList) : protocol(protocol), keyExchange(keyExchange),
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 589b88cf..b9c9aae 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -82260,6 +82260,9 @@ <int value="54" label="Device identification missing"> Device model or serial number missing from VPD. </int> + <int value="55" label="AD policy fetch fail"> + Active Directory policy fetch failed. + </int> </enum> <enum name="EnterprisePolicies" type="int">
diff --git a/ui/views/test/event_generator_delegate_mac.mm b/ui/views/test/event_generator_delegate_mac.mm index bc17c37..6fe8fb3 100644 --- a/ui/views/test/event_generator_delegate_mac.mm +++ b/ui/views/test/event_generator_delegate_mac.mm
@@ -401,6 +401,13 @@ [NSApp sendEvent:ns_event]; break; case Target::WINDOW: + // -[NSApp sendEvent:] sends -performKeyEquivalent: if Command or Control + // modifiers are pressed. Emulate that behavior. + if ([ns_event type] == NSKeyDown && + ([ns_event modifierFlags] & (NSControlKeyMask | NSCommandKeyMask)) && + [window_ performKeyEquivalent:ns_event]) + break; // Handled by performKeyEquivalent:. + [window_ sendEvent:ns_event]; break; case Target::WIDGET: