diff --git a/AUTHORS b/AUTHORS index ec18c04f..fa1e9e16 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -879,6 +879,7 @@ Sylvestre Ledru <sylvestre.ledru@gmail.com> Szabolcs David <davidsz@inf.u-szeged.hu> Szymon Piechowicz <szymonpiechowicz@o2.pl> +Taeheon Kim <skyrabbits1@gmail.com> Taehoon Lee <taylor.hoon@gmail.com> Takashi Fujita <tgfjt.mail@gmail.com> Takeshi Kurosawa <taken.spc@gmail.com>
diff --git a/DEPS b/DEPS index ddfd58a5..31be4229 100644 --- a/DEPS +++ b/DEPS
@@ -133,11 +133,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'bcbd30b7dcaf8dbc78aeaff4ef2995d20ba00af6', + 'skia_revision': '69258ffdb88a4338c2e59a0c0fa198570822b6a8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '9cbdd437a824bc61e9677ae1cf4504632226ebdc', + 'v8_revision': '8642c0be41ae5f9f62e09f247e3cab302d27b755', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -149,7 +149,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '40a6ed8d5cbbcf0f0bf0bd8742b8c26bd53c566b', + 'swiftshader_revision': '69c37491787a39b4219311c9f03d16c4eb85679d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -196,7 +196,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '701ac9a6e80f82e38ecfd41e5497b43df947933d', + 'catapult_revision': '88ad352aa1c60e7239c3a3259fd4fdc0f7727090', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -252,7 +252,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': 'e935dac9ef8a01fdb6d0a4b7898563e6f62d1081', + 'spv_tools_revision': 'f815e6fe51af7d4c3df293af11acb7a233745412', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -802,7 +802,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '13e06be378d8e26143cccadce83c3d565c6f0325', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '40748dc575b75a353c9e3afea5236892674d6df5', 'condition': 'checkout_linux', }, @@ -827,7 +827,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8a96493270cb124267952248cd186fc145960e12', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9f1377b76560ba96b1c23c27c9f7878de188aa6c', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1071,7 +1071,7 @@ }, 'src/third_party/libvpx/source/libvpx': - Var('chromium_git') + '/webm/libvpx.git' + '@' + '4d0fe85c1957cea215085e7da41ee797e6a51f01', + Var('chromium_git') + '/webm/libvpx.git' + '@' + '78c44e2dc26e383fdc54eb4bf406a76e52ea361e', 'src/third_party/libwebm/source': Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1', @@ -1177,7 +1177,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '0ee3cd37199bffdfe162e51bd96e58bcf93f8bee', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '031ad2bc420ab6c1a0e7b3dcfb218d9d1e543859', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1389,7 +1389,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@69d66c506c56fb67746e0be29e4b971d255b447f', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ddf034cde9e9e4015dd5051331d486148325ccce', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index b734e80f..33a25b4 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -936,8 +936,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) { if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h index c2f1f21..30da0a0 100644 --- a/android_webview/browser/aw_content_browser_client.h +++ b/android_webview/browser/aw_content_browser_client.h
@@ -213,8 +213,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) override; void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index e24d2c4d..0d564ef 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -2118,6 +2118,7 @@ "metrics/user_metrics_recorder_test_api.h", "mojo_test_interface_factory.cc", "mojo_test_interface_factory.h", + "public/cpp/test/shell_test_api.h", "rotator/screen_rotation_animator_test_api.cc", "rotator/screen_rotation_animator_test_api.h", "session/test_pref_service_provider.cc", @@ -2135,7 +2136,6 @@ "shell/toplevel_window.cc", "shell/toplevel_window.h", "shell_test_api.cc", - "shell_test_api.h", "system/palette/palette_tray_test_api.cc", "system/palette/palette_tray_test_api.h", "system/power/power_button_controller_test_api.cc",
diff --git a/ash/PRESUBMIT.py b/ash/PRESUBMIT.py deleted file mode 100644 index f04a6ac..0000000 --- a/ash/PRESUBMIT.py +++ /dev/null
@@ -1,76 +0,0 @@ -# Copyright 2018 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. - -"""Presubmit script for ash (Chrome OS system UI). - -See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts -for more details about the presubmit API built into depot_tools. -""" - - -# Tuples of (func_name, message, excluded_paths). -_BANNED_FUNCTIONS = ( - ( - r'aura::Env::GetInstance', - ( - 'aura::Env::GetInstance is banned in //ash because it will return the', - 'wrong aura::Env in SingleProcessMash mode. See //ash/README.md.', - 'Use ash::Shell::Get()->aura_env() instead.' - ), - ( - # Components are mini-apps that run in their own process and only have - # a single aura::Env. - r'^ash/components/', - - # ash_shell is a separate test binary. - r'^ash/shell/', - ) - ), -) - - -def _CheckBannedFunctions(input_api, output_api): - """Make sure that banned functions are not used.""" - errors = [] - - def IsExcludedFile(affected_file, excluded_paths): - local_path = affected_file.LocalPath() - for item in excluded_paths: - if input_api.re.match(item, local_path): - return True - return False - - def CheckForMatch(affected_file, line_num, line, func_name, message): - if func_name in line: - errors.append(' %s:%d:' % (affected_file.LocalPath(), line_num)) - for message_line in message: - errors.append(' %s' % message_line) - - file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h')) - for f in input_api.AffectedFiles(file_filter=file_filter): - for line_num, line in f.ChangedContents(): - for func_name, message, excluded_paths in _BANNED_FUNCTIONS: - if IsExcludedFile(f, excluded_paths): - continue - CheckForMatch(f, line_num, line, func_name, message) - - result = [] - if (errors): - result.append(output_api.PresubmitError( - 'Banned functions were used.\n' + '\n'.join(errors))) - return result - - -def CheckChange(input_api, output_api): - results = [] - results += _CheckBannedFunctions(input_api, output_api) - return results - - -def CheckChangeOnUpload(input_api, output_api): - return CheckChange(input_api, output_api) - - -def CheckChangeOnCommit(input_api, output_api): - return CheckChange(input_api, output_api)
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index cc30e1c..2654e0d 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -23,11 +23,11 @@ #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/interfaces/ime_info.mojom.h" #include "ash/session/session_controller_impl.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/brightness_control_delegate.h" #include "ash/system/keyboard_brightness_control_delegate.h" #include "ash/system/power/power_button_controller_test_api.h"
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc index dd6b339..01c18ca 100644 --- a/ash/app_list/app_list_presenter_delegate_unittest.cc +++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -27,6 +27,7 @@ #include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/interfaces/app_list_view.mojom.h" #include "ash/root_window_controller.h" #include "ash/shelf/shelf.h" @@ -34,7 +35,6 @@ #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_view.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/test/ash_test_base.h" #include "ash/wallpaper/wallpaper_controller_test_api.h" @@ -1813,8 +1813,7 @@ // Test backdrop exists for active non-fullscreen window in tablet mode. TEST_F(AppListPresenterDelegateHomeLauncherTest, BackdropTest) { - WorkspaceControllerTestApi test_helper( - ShellTestApi(Shell::Get()).workspace_controller()); + WorkspaceControllerTestApi test_helper(ShellTestApi().workspace_controller()); EnableTabletMode(true); GetAppListTestHelper()->CheckVisibility(true); EXPECT_FALSE(test_helper.GetBackdropWindow());
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc index 423de1cd..5b2f609 100644 --- a/ash/ash_prefs.cc +++ b/ash/ash_prefs.cc
@@ -7,6 +7,8 @@ #include "ash/accessibility/accessibility_controller.h" #include "ash/app_list/app_list_controller_impl.h" #include "ash/assistant/assistant_controller.h" +#include "ash/detachable_base/detachable_base_handler.h" +#include "ash/display/display_prefs.h" #include "ash/kiosk_next/kiosk_next_shell_controller.h" #include "ash/login/login_screen_controller.h" #include "ash/magnifier/docked_magnifier_controller.h" @@ -21,6 +23,7 @@ #include "ash/system/power/power_prefs.h" #include "ash/system/session/logout_button_tray.h" #include "ash/touch/touch_devices_controller.h" +#include "ash/wallpaper/wallpaper_controller.h" namespace ash { @@ -48,6 +51,15 @@ } // namespace +void RegisterLocalStatePrefs(PrefRegistrySimple* registry, bool for_test) { + PaletteTray::RegisterLocalStatePrefs(registry); + WallpaperController::RegisterLocalStatePrefs(registry); + BluetoothPowerController::RegisterLocalStatePrefs(registry); + DetachableBaseHandler::RegisterPrefs(registry); + PowerPrefs::RegisterLocalStatePrefs(registry); + DisplayPrefs::RegisterLocalStatePrefs(registry); +} + void RegisterSigninProfilePrefs(PrefRegistrySimple* registry, bool for_test) { RegisterProfilePrefs(registry, for_test); PowerPrefs::RegisterSigninProfilePrefs(registry, for_test);
diff --git a/ash/display/display_prefs.cc b/ash/display/display_prefs.cc index ac630e2..868890a 100644 --- a/ash/display/display_prefs.cc +++ b/ash/display/display_prefs.cc
@@ -37,32 +37,6 @@ namespace ash { -class DisplayPrefs::LocalState { - public: - explicit LocalState(std::unique_ptr<base::Value> initial_prefs) - : initial_prefs_(std::move(initial_prefs)) {} - ~LocalState() = default; - - bool has_initial_prefs() const { return !!initial_prefs_.get(); } - void set_pref_service(PrefService* pref_service) { - pref_service_ = pref_service; - } - PrefService* pref_service() { return pref_service_; } - - const base::Value* Get(const std::string& path) const { - if (pref_service_) - return pref_service_->Get(path); - CHECK(initial_prefs_); - return initial_prefs_->FindKey(path); - } - - private: - std::unique_ptr<base::Value> initial_prefs_; - class PrefService* pref_service_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(LocalState); -}; - namespace { constexpr char kInsetsTopKey[] = "insets_top"; @@ -217,7 +191,7 @@ *user_type == user_manager::USER_TYPE_KIOSK_APP; } -void LoadDisplayLayouts(DisplayPrefs::LocalState* local_state) { +void LoadDisplayLayouts(PrefService* local_state) { display::DisplayLayoutStore* layout_store = GetDisplayManager()->layout_store(); @@ -246,7 +220,7 @@ } } -void LoadDisplayProperties(DisplayPrefs::LocalState* local_state) { +void LoadDisplayProperties(PrefService* local_state) { const base::Value* properties = local_state->Get(prefs::kDisplayProperties); for (const auto& it : properties->DictItems()) { const base::DictionaryValue* dict_value = nullptr; @@ -302,7 +276,7 @@ } } -void LoadDisplayRotationState(DisplayPrefs::LocalState* local_state) { +void LoadDisplayRotationState(PrefService* local_state) { const base::Value* properties = local_state->Get(prefs::kDisplayRotationLock); DCHECK(properties->is_dict()); const base::Value* rotation_lock = @@ -320,7 +294,7 @@ static_cast<display::Display::Rotation>(rotation->GetInt())); } -void LoadDisplayTouchAssociations(DisplayPrefs::LocalState* local_state) { +void LoadDisplayTouchAssociations(PrefService* local_state) { const base::Value* properties = local_state->Get(prefs::kDisplayTouchAssociations); DCHECK(properties->is_dict()); @@ -430,7 +404,7 @@ // Loads mirror info for each external display, the info will later be used to // restore mirror mode. -void LoadExternalDisplayMirrorInfo(DisplayPrefs::LocalState* local_state) { +void LoadExternalDisplayMirrorInfo(PrefService* local_state) { const base::Value* pref_data = local_state->Get(prefs::kExternalDisplayMirrorInfo); std::set<int64_t> external_display_mirror_info; @@ -451,7 +425,7 @@ // Loads mixed mirror mode parameters which will later be used to restore mixed // mirror mode. Return false if the parameters fail to be loaded. -void LoadDisplayMixedMirrorModeParams(DisplayPrefs::LocalState* local_state) { +void LoadDisplayMixedMirrorModeParams(PrefService* local_state) { const base::Value* pref_data = local_state->Get(prefs::kDisplayMixedMirrorModeParams); @@ -786,38 +760,6 @@ } // namespace // static -std::unique_ptr<base::Value> -DisplayPrefs::GetInitialDisplayPrefsFromPrefService(PrefService* pref_service) { - auto initial_display_prefs = - std::make_unique<base::Value>(base::Value::Type::DICTIONARY); - initial_display_prefs->SetKey( - ash::prefs::kDisplayMixedMirrorModeParams, - pref_service->Get(ash::prefs::kDisplayMixedMirrorModeParams)->Clone()); - initial_display_prefs->SetKey( - ash::prefs::kDisplayPowerState, - pref_service->Get(ash::prefs::kDisplayPowerState)->Clone()); - initial_display_prefs->SetKey( - ash::prefs::kDisplayProperties, - pref_service->Get(ash::prefs::kDisplayProperties)->Clone()); - initial_display_prefs->SetKey( - ash::prefs::kDisplayRotationLock, - pref_service->Get(ash::prefs::kDisplayRotationLock)->Clone()); - initial_display_prefs->SetKey( - ash::prefs::kDisplayTouchAssociations, - pref_service->Get(ash::prefs::kDisplayTouchAssociations)->Clone()); - initial_display_prefs->SetKey( - ash::prefs::kDisplayTouchPortAssociations, - pref_service->Get(ash::prefs::kDisplayTouchPortAssociations)->Clone()); - initial_display_prefs->SetKey( - ash::prefs::kExternalDisplayMirrorInfo, - pref_service->Get(ash::prefs::kExternalDisplayMirrorInfo)->Clone()); - initial_display_prefs->SetKey( - ash::prefs::kSecondaryDisplays, - pref_service->Get(ash::prefs::kSecondaryDisplays)->Clone()); - return initial_display_prefs; -} - -// static void DisplayPrefs::RegisterLocalStatePrefs(PrefRegistrySimple* registry) { registry->RegisterDictionaryPref(prefs::kSecondaryDisplays, PrefRegistry::PUBLIC); @@ -837,44 +779,17 @@ PrefRegistry::PUBLIC); } -// static -void DisplayPrefs::RegisterForeignPrefs(PrefRegistry* registry) { - registry->RegisterForeignPref(prefs::kSecondaryDisplays); - registry->RegisterForeignPref(prefs::kDisplayProperties); - registry->RegisterForeignPref(prefs::kDisplayPowerState); - registry->RegisterForeignPref(prefs::kDisplayRotationLock); - registry->RegisterForeignPref(prefs::kDisplayTouchAssociations); - registry->RegisterForeignPref(prefs::kDisplayTouchPortAssociations); - registry->RegisterForeignPref(prefs::kExternalDisplayMirrorInfo); - registry->RegisterForeignPref(prefs::kDisplayMixedMirrorModeParams); -} - -DisplayPrefs::DisplayPrefs(std::unique_ptr<base::Value> initial_prefs) - : local_state_(std::make_unique<LocalState>(std::move(initial_prefs))) { - Shell::Get()->AddShellObserver(this); +DisplayPrefs::DisplayPrefs(PrefService* local_state) + : local_state_(local_state) { Shell::Get()->session_controller()->AddObserver(this); - // If |initial_prefs| is not null, load the initial display prefs. Otherwise - // the initial prefs will be loaded from OnLocalStatePrefServiceInitialized. - if (local_state_->has_initial_prefs()) + + // |local_state_| could be null in tests. + if (local_state_) LoadDisplayPreferences(); } DisplayPrefs::~DisplayPrefs() { Shell::Get()->session_controller()->RemoveObserver(this); - Shell::Get()->RemoveShellObserver(this); -} - -void DisplayPrefs::OnLocalStatePrefServiceInitialized( - PrefService* pref_service) { - DCHECK(!local_state_->pref_service()); - local_state_->set_pref_service(pref_service); - - // Only load the display prefs if no initial prefs were provided. - if (!local_state_->has_initial_prefs()) - LoadDisplayPreferences(); - - if (store_requested_) - MaybeStoreDisplayPrefs(); } void DisplayPrefs::OnFirstSessionStarted() { @@ -884,17 +799,12 @@ void DisplayPrefs::MaybeStoreDisplayPrefs() { DCHECK(local_state_); - PrefService* pref_service = local_state_->pref_service(); - if (!pref_service) { - store_requested_ = true; - return; - } // Stores the power state regardless of the login status, because the power // state respects to the current status (close/open) of the lid which can be // changed in any situation. See http://crbug.com/285360 - StoreCurrentDisplayPowerState(pref_service); - StoreCurrentDisplayRotationLockPrefs(pref_service); + StoreCurrentDisplayPowerState(local_state_); + StoreCurrentDisplayRotationLockPrefs(local_state_); // We cannot really decide whether to store display prefs until there is an // active user session. |OnFirstSessionStarted()| should eventually attempt to @@ -913,26 +823,25 @@ } store_requested_ = false; - StoreCurrentDisplayLayoutPrefs(pref_service); - StoreCurrentDisplayProperties(pref_service); - StoreDisplayTouchAssociations(pref_service); - StoreExternalDisplayMirrorInfo(pref_service); - StoreCurrentDisplayMixedMirrorModeParams(pref_service); + StoreCurrentDisplayLayoutPrefs(local_state_); + StoreCurrentDisplayProperties(local_state_); + StoreDisplayTouchAssociations(local_state_); + StoreExternalDisplayMirrorInfo(local_state_); + StoreCurrentDisplayMixedMirrorModeParams(local_state_); // The display prefs need to be committed immediately to guarantee they're not // lost, and are restored properly on reboot. https://crbug.com/936884. // This sends a request via mojo to commit the prefs to disk. - pref_service->CommitPendingWrite(); + local_state_->CommitPendingWrite(); } void DisplayPrefs::LoadDisplayPreferences() { - LocalState* local_state = local_state_.get(); - LoadDisplayLayouts(local_state); - LoadDisplayProperties(local_state); - LoadExternalDisplayMirrorInfo(local_state); - LoadDisplayMixedMirrorModeParams(local_state); - LoadDisplayRotationState(local_state); - LoadDisplayTouchAssociations(local_state); + LoadDisplayLayouts(local_state_); + LoadDisplayProperties(local_state_); + LoadExternalDisplayMirrorInfo(local_state_); + LoadDisplayMixedMirrorModeParams(local_state_); + LoadDisplayRotationState(local_state_); + LoadDisplayTouchAssociations(local_state_); // Now that the display prefs have been loaded, request to reconfigure the // displays, but signal the display manager to restore the mirror state of @@ -953,7 +862,7 @@ // Restore DisplayPowerState: const std::string value = - local_state->Get(prefs::kDisplayPowerState)->GetString(); + local_state_->Get(prefs::kDisplayPowerState)->GetString(); chromeos::DisplayPowerState power_state; if (GetDisplayPowerStateFromString(value, &power_state)) Shell::Get()->display_configurator()->SetInitialDisplayPower(power_state); @@ -962,30 +871,28 @@ void DisplayPrefs::StoreDisplayRotationPrefsForTest( display::Display::Rotation rotation, bool rotation_lock) { - StoreDisplayRotationPrefs(local_state_->pref_service(), rotation, - rotation_lock); + StoreDisplayRotationPrefs(local_state_, rotation, rotation_lock); } void DisplayPrefs::StoreDisplayLayoutPrefForTest( const display::DisplayIdList& list, const display::DisplayLayout& layout) { - StoreDisplayLayoutPref(local_state_->pref_service(), list, layout); + StoreDisplayLayoutPref(local_state_, list, layout); } void DisplayPrefs::StoreDisplayPowerStateForTest( DisplayPowerState power_state) { - StoreDisplayPowerState(local_state_->pref_service(), power_state); + StoreDisplayPowerState(local_state_, power_state); } void DisplayPrefs::LoadTouchAssociationPreferenceForTest() { - LoadDisplayTouchAssociations(local_state_.get()); + LoadDisplayTouchAssociations(local_state_); } void DisplayPrefs::StoreLegacyTouchDataForTest( int64_t display_id, const display::TouchCalibrationData& data) { - DictionaryPrefUpdate update(local_state_->pref_service(), - prefs::kDisplayProperties); + DictionaryPrefUpdate update(local_state_, prefs::kDisplayProperties); base::DictionaryValue* pref_data = update.Get(); std::unique_ptr<base::DictionaryValue> property_value = std::make_unique<base::DictionaryValue>(); @@ -1001,12 +908,11 @@ void DisplayPrefs::StoreDisplayMixedMirrorModeParamsForTest( const base::Optional<display::MixedMirrorModeParams>& mixed_params) { - StoreDisplayMixedMirrorModeParams(local_state_->pref_service(), mixed_params); + StoreDisplayMixedMirrorModeParams(local_state_, mixed_params); } -void DisplayPrefs::SetPrefServiceForTest(PrefService* pref_service) { - DCHECK(local_state_); - local_state_->set_pref_service(pref_service); +void DisplayPrefs::SetPrefServiceForTest(PrefService* local_state) { + local_state_ = local_state; } } // namespace ash
diff --git a/ash/display/display_prefs.h b/ash/display/display_prefs.h index e5530efc..bb42e6ce 100644 --- a/ash/display/display_prefs.h +++ b/ash/display/display_prefs.h
@@ -7,24 +7,17 @@ #include <stdint.h> #include <array> -#include <memory> #include "ash/ash_export.h" #include "ash/session/session_observer.h" -#include "ash/shell_observer.h" #include "base/optional.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/display/display.h" #include "ui/display/display_layout.h" -class PrefRegistry; class PrefRegistrySimple; class PrefService; -namespace base { -class Value; -} - namespace gfx { class Point; } @@ -40,22 +33,14 @@ // Manages display preference settings. Settings are stored in the local state // for the session. -class ASH_EXPORT DisplayPrefs : public ShellObserver, public SessionObserver { +class ASH_EXPORT DisplayPrefs : public SessionObserver { public: - // Returns a dictionary of display pref values stored in PrefService. - // See chrome/browser/ui/ash/ash_shell_init.cc for details. - static std::unique_ptr<base::Value> GetInitialDisplayPrefsFromPrefService( - PrefService* pref_service); // Registers the prefs associated with display settings. static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); - static void RegisterForeignPrefs(PrefRegistry* registry); - explicit DisplayPrefs(std::unique_ptr<base::Value> initial_prefs); + explicit DisplayPrefs(PrefService* local_state); ~DisplayPrefs() override; - // ShellObserver - void OnLocalStatePrefServiceInitialized(PrefService* pref_service) override; - // SessionObserver: void OnFirstSessionStarted() override; @@ -84,21 +69,17 @@ void StoreDisplayMixedMirrorModeParamsForTest( const base::Optional<display::MixedMirrorModeParams>& mixed_params); - // Class wrapping a PrefService and a dictionary of initial pref values to use - // until OnLocalStatePrefServiceInitialized is called. - class LocalState; - protected: friend class DisplayPrefsTest; // Loads display preferences from |local_state_|. void LoadDisplayPreferences(); - // Constructs a LocalState instance with |pref_service| for testing. - void SetPrefServiceForTest(PrefService* pref_service); + // Sets |local_state| for testing. + void SetPrefServiceForTest(PrefService* local_state); private: - std::unique_ptr<LocalState> local_state_; + PrefService* local_state_ = nullptr; // Non-owned and must out-live this. bool store_requested_ = false; DISALLOW_COPY_AND_ASSIGN(DisplayPrefs);
diff --git a/ash/display/screen_position_controller_unittest.cc b/ash/display/screen_position_controller_unittest.cc index 2242c82..fc67cee 100644 --- a/ash/display/screen_position_controller_unittest.cc +++ b/ash/display/screen_position_controller_unittest.cc
@@ -7,9 +7,9 @@ #include <memory> #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/screen_util.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "ash/window_factory.h" #include "base/run_loop.h" @@ -30,8 +30,7 @@ namespace { ScreenPositionController* GetScreenPositionController() { - ShellTestApi test_api(Shell::Get()); - return test_api.screen_position_controller(); + return ShellTestApi().screen_position_controller(); } class ScreenPositionControllerTest : public AshTestBase {
diff --git a/ash/mojo_test_interface_factory.cc b/ash/mojo_test_interface_factory.cc index 026e60d35..a1f8918 100644 --- a/ash/mojo_test_interface_factory.cc +++ b/ash/mojo_test_interface_factory.cc
@@ -10,12 +10,10 @@ #include "ash/metrics/time_to_first_present_recorder_test_api.h" #include "ash/public/interfaces/login_screen_test_api.test-mojom.h" #include "ash/public/interfaces/shelf_test_api.test-mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "ash/public/interfaces/status_area_widget_test_api.test-mojom.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "ash/public/interfaces/time_to_first_present_recorder_test_api.test-mojom.h" #include "ash/shelf/shelf_test_api.h" -#include "ash/shell_test_api.h" #include "ash/system/status_area_widget_test_api.h" #include "ash/system/unified/unified_system_tray_test_api.h" #include "base/bind.h" @@ -37,10 +35,6 @@ ShelfTestApi::BindRequest(std::move(request)); } -void BindShellTestApiOnMainThread(mojom::ShellTestApiRequest request) { - ShellTestApi::BindRequest(std::move(request)); -} - void BindStatusAreaWidgetTestApiOnMainThread( mojom::StatusAreaWidgetTestApiRequest request) { StatusAreaWidgetTestApi::BindRequest(std::move(request)); @@ -65,8 +59,6 @@ main_thread_task_runner); registry->AddInterface(base::Bind(&BindShelfTestApiOnMainThread), main_thread_task_runner); - registry->AddInterface(base::Bind(&BindShellTestApiOnMainThread), - main_thread_task_runner); registry->AddInterface(base::Bind(&BindStatusAreaWidgetTestApiOnMainThread), main_thread_task_runner); registry->AddInterface(base::Bind(&BindSystemTrayTestApiOnMainThread),
diff --git a/ash/public/cpp/app_list/app_list_struct_traits.h b/ash/public/cpp/app_list/app_list_struct_traits.h index b7f8d97..ff27216 100644 --- a/ash/public/cpp/app_list/app_list_struct_traits.h +++ b/ash/public/cpp/app_list/app_list_struct_traits.h
@@ -103,10 +103,6 @@ return ash::mojom::SearchResultType::kInstantApp; case ash::SearchResultType::kInternalApp: return ash::mojom::SearchResultType::kInternalApp; - case ash::SearchResultType::kWebStoreApp: - return ash::mojom::SearchResultType::kWebStoreApp; - case ash::SearchResultType::kWebStoreSearch: - return ash::mojom::SearchResultType::kWebStoreSearch; case ash::SearchResultType::kOmnibox: return ash::mojom::SearchResultType::kOmnibox; case ash::SearchResultType::kLauncher: @@ -139,12 +135,6 @@ case ash::mojom::SearchResultType::kInternalApp: *out = ash::SearchResultType::kInternalApp; return true; - case ash::mojom::SearchResultType::kWebStoreApp: - *out = ash::SearchResultType::kWebStoreApp; - return true; - case ash::mojom::SearchResultType::kWebStoreSearch: - *out = ash::SearchResultType::kWebStoreSearch; - return true; case ash::mojom::SearchResultType::kOmnibox: *out = ash::SearchResultType::kOmnibox; return true;
diff --git a/ash/public/cpp/app_list/app_list_types.h b/ash/public/cpp/app_list/app_list_types.h index de305a51..16ec50f 100644 --- a/ash/public/cpp/app_list/app_list_types.h +++ b/ash/public/cpp/app_list/app_list_types.h
@@ -49,8 +49,6 @@ kPlayStoreApp, // Installable apps from PlayStore. kInstantApp, // Instant apps. kInternalApp, // Chrome OS apps. - kWebStoreApp, // Installable apps from WebStore. - kWebStoreSearch, // A search query in WebStore. kOmnibox, // Results from Omnibox. kLauncher, // Results from launcher search (currently only from Files). kAnswerCard, // WebContents based answer card.
diff --git a/ash/public/cpp/ash_prefs.h b/ash/public/cpp/ash_prefs.h index 68df2815..85f0821 100644 --- a/ash/public/cpp/ash_prefs.h +++ b/ash/public/cpp/ash_prefs.h
@@ -11,6 +11,10 @@ namespace ash { +// Registers all ash related local state prefs to the given |registry|. +ASH_EXPORT void RegisterLocalStatePrefs(PrefRegistrySimple* registry, + bool for_test = false); + // Register ash related sign-in/user profile prefs to |registry|. When // |for_test| is true this registers foreign user profile prefs (e.g. chrome // prefs) as if they are owned by ash. This allows test code to read the pref
diff --git a/ash/public/cpp/test/shell_test_api.h b/ash/public/cpp/test/shell_test_api.h new file mode 100644 index 0000000..e23379f --- /dev/null +++ b/ash/public/cpp/test/shell_test_api.h
@@ -0,0 +1,105 @@ +// Copyright 2019 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 ASH_PUBLIC_CPP_TEST_SHELL_TEST_API_H_ +#define ASH_PUBLIC_CPP_TEST_SHELL_TEST_API_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/public/interfaces/app_list_view.mojom-forward.h" +#include "base/callback_forward.h" +#include "base/macros.h" + +class PrefService; + +namespace ash { +class DragDropController; +class MessageCenterController; +class NativeCursorManagerAsh; +class PowerPrefs; +class ScreenPositionController; +class Shell; +class SystemGestureEventFilter; +class WorkspaceController; + +enum class OverviewAnimationState : int32_t { + kEnterAnimationComplete, + kExitAnimationComplete, +}; + +// Accesses private data from a Shell for testing. +class ASH_EXPORT ShellTestApi { + public: + ShellTestApi(); + ~ShellTestApi(); + + MessageCenterController* message_center_controller(); + SystemGestureEventFilter* system_gesture_event_filter(); + WorkspaceController* workspace_controller(); + ScreenPositionController* screen_position_controller(); + NativeCursorManagerAsh* native_cursor_manager_ash(); + DragDropController* drag_drop_controller(); + PowerPrefs* power_prefs(); + + // Calls the private method. + void OnLocalStatePrefServiceInitialized(PrefService* pref_service); + + // Resets |shell_->power_button_controller_| to hold a new object to simulate + // Chrome starting. + void ResetPowerButtonControllerForTest(); + + // Simulates a modal dialog being open. + void SimulateModalWindowOpenForTest(bool modal_window_open); + + // Returns true if a system modal window is open (e.g. the Wi-Fi network + // password dialog). + bool IsSystemModalWindowOpen(); + + // Enables or disables the tablet mode window manager. + void EnableTabletModeWindowManager(bool enable); + + // Enables the keyboard and associates it with the primary root window + // controller. In tablet mode, enables the virtual keyboard. + void EnableVirtualKeyboard(); + + // Fullscreens the active window, as if the user had pressed the hardware + // fullscreen button. + void ToggleFullscreen(); + + // Enters or exits overview mode. + void ToggleOverviewMode(); + + // Returns true if it is in overview selecting mode. + bool IsOverviewSelecting(); + + // Used to emulate display change when run in a desktop environment instead + // of on a device. + void AddRemoveDisplay(); + + // Runs the callback when the WindowTreeHost of the primary display is no + // longer holding pointer events. See + // |aura::WindowTreeHost::holding_pointer_moves_| for details. + void WaitForNoPointerHoldLock(); + + // Runs the callback when the compositor of the primary display has presented + // a frame on screen. + void WaitForNextFrame(base::OnceClosure closure); + + // Runs the callback when the overview state becomes |state|. + void WaitForOverviewAnimationState(OverviewAnimationState state); + + // Runs the callback when the launcher state becomes |state| after + // state transition animation. + void WaitForLauncherAnimationState(mojom::AppListViewState state); + + private: + Shell* shell_; // not owned + + DISALLOW_COPY_AND_ASSIGN(ShellTestApi); +}; + +} // namespace ash + +#endif // ASH_PUBLIC_CPP_TEST_SHELL_TEST_API_H_
diff --git a/ash/public/cpp/test_manifest.cc b/ash/public/cpp/test_manifest.cc index 6bacb0f1e0..73c598d2 100644 --- a/ash/public/cpp/test_manifest.cc +++ b/ash/public/cpp/test_manifest.cc
@@ -6,7 +6,6 @@ #include "ash/public/interfaces/login_screen_test_api.test-mojom.h" #include "ash/public/interfaces/shelf_test_api.test-mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "ash/public/interfaces/status_area_widget_test_api.test-mojom.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "ash/public/interfaces/time_to_first_present_recorder_test_api.test-mojom.h" @@ -19,11 +18,11 @@ static base::NoDestructor<service_manager::Manifest> manifest{ service_manager::ManifestBuilder() .ExposeCapability( - "test", service_manager::Manifest::InterfaceList< - mojom::LoginScreenTestApi, mojom::ShelfTestApi, - mojom::ShellTestApi, mojom::StatusAreaWidgetTestApi, - mojom::SystemTrayTestApi, - mojom::TimeToFirstPresentRecorderTestApi>()) + "test", + service_manager::Manifest::InterfaceList< + mojom::LoginScreenTestApi, mojom::ShelfTestApi, + mojom::StatusAreaWidgetTestApi, mojom::SystemTrayTestApi, + mojom::TimeToFirstPresentRecorderTestApi>()) .Build()}; return *manifest; }
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn index 0678249..fe8d646f 100644 --- a/ash/public/interfaces/BUILD.gn +++ b/ash/public/interfaces/BUILD.gn
@@ -98,7 +98,6 @@ sources = [ "login_screen_test_api.test-mojom", "shelf_test_api.test-mojom", - "shell_test_api.test-mojom", "status_area_widget_test_api.test-mojom", "system_tray_test_api.test-mojom", "time_to_first_present_recorder_test_api.test-mojom",
diff --git a/ash/public/interfaces/app_list.mojom b/ash/public/interfaces/app_list.mojom index 45128e1a..86d636c 100644 --- a/ash/public/interfaces/app_list.mojom +++ b/ash/public/interfaces/app_list.mojom
@@ -139,8 +139,6 @@ kPlayStoreApp, // Installable apps from PlayStore. kInstantApp, // Instant apps. kInternalApp, // Chrome OS apps. - kWebStoreApp, // Installable apps from WebStore. - kWebStoreSearch, // A search query in WebStore. kOmnibox, // Results from Omninbox. kLauncher, // Results from launcher search (currently only from Files). kAnswerCard, // WebContents based answer card.
diff --git a/ash/public/interfaces/shell_test_api.test-mojom b/ash/public/interfaces/shell_test_api.test-mojom deleted file mode 100644 index 08fd6a2..0000000 --- a/ash/public/interfaces/shell_test_api.test-mojom +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module ash.mojom; - -import "ash/public/interfaces/app_list_view.mojom"; - -enum OverviewAnimationState { - kEnterAnimationComplete, - kExitAnimationComplete, -}; - -interface ShellTestApi { - // Returns true if a system modal window is open (e.g. the Wi-Fi network - // password dialog). - IsSystemModalWindowOpen() => (bool visible); - - // Enables or disables the tablet mode window manager. - EnableTabletModeWindowManager(bool enable); - - // Enables the keyboard and associates it with the primary root window - // controller. In tablet mode, enables the virtual keyboard. - EnableVirtualKeyboard() => (); - - // Fullscreens the active window, as if the user had pressed the hardware - // fullscreen button. - ToggleFullscreen() => (); - - // Enters or exits overview mode. - ToggleOverviewMode() => (); - - // Returns true if it is in overview selecting mode. - IsOverviewSelecting() => (bool is_selecting); - - // Used to emulate display change when run in a desktop environment instead - // of on a device. - AddRemoveDisplay(); - - // Set the minimum velocity to cause fling gesture. - SetMinFlingVelocity(float velocity); - - // Runs the callback when the WindowTreeHost of the primary display is no - // longer holding pointer events. See - // |aura::WindowTreeHost::holding_pointer_moves_| for details. - WaitForNoPointerHoldLock() => (); - - // Runs the callback when the compositor of the primary display has presented - // a frame on screen. - WaitForNextFrame() => (); - - // Runs the callback when the overview state becomes |state|. - WaitForOverviewAnimationState(OverviewAnimationState state) => (); - - // Runs the callback when the launcher state becomes |state| after - // state transition animation. - WaitForLauncherAnimationState(AppListViewState state) => (); -};
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc index 9dd3e81..cfbecbd 100644 --- a/ash/shelf/shelf_layout_manager_unittest.cc +++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -25,6 +25,7 @@ #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_properties.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" @@ -36,7 +37,6 @@ #include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/status_area_widget.h" #include "ash/system/status_area_widget_test_helper.h" #include "ash/system/unified/unified_system_tray.h"
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index fcc0e76..0907cc8c 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -38,7 +38,6 @@ #include "ash/shelf/shelf_view_test_api.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/strings/grit/ash_strings.h" #include "ash/system/status_area_widget.h" #include "ash/test/ash_test_base.h"
diff --git a/ash/shell.cc b/ash/shell.cc index b19eebb6..d6326ef 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -104,10 +104,10 @@ #include "ash/system/locale/locale_update_controller.h" #include "ash/system/message_center/message_center_controller.h" #include "ash/system/model/system_tray_model.h" +#include "ash/system/model/virtual_keyboard_model.h" #include "ash/system/network/sms_observer.h" #include "ash/system/network/vpn_list.h" #include "ash/system/night_light/night_light_controller.h" -#include "ash/system/palette/palette_tray.h" #include "ash/system/power/backlights_forced_off_setter.h" #include "ash/system/power/notification_reporter.h" #include "ash/system/power/peripheral_battery_notifier.h" @@ -177,8 +177,6 @@ #include "components/prefs/pref_service.h" #include "components/viz/host/host_frame_sink_manager.h" #include "dbus/bus.h" -#include "services/preferences/public/cpp/pref_service_factory.h" -#include "services/preferences/public/mojom/preferences.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/env.h" @@ -251,10 +249,10 @@ Shell* Shell::CreateInstance(ShellInitParams init_params) { CHECK(!instance_); instance_ = new Shell(std::move(init_params.delegate), init_params.connector); - instance_->Init( - init_params.context_factory, init_params.context_factory_private, - std::move(init_params.initial_display_prefs), - std::move(init_params.keyboard_ui_factory), init_params.dbus_bus); + instance_->Init(init_params.context_factory, + init_params.context_factory_private, init_params.local_state, + std::move(init_params.keyboard_ui_factory), + init_params.dbus_bus); return instance_; } @@ -362,22 +360,6 @@ return GetOpenSystemModalWindowContainerId() >= 0; } -// static -void Shell::RegisterLocalStatePrefs(PrefRegistrySimple* registry, - bool for_test) { - PaletteTray::RegisterLocalStatePrefs(registry); - WallpaperController::RegisterLocalStatePrefs(registry); - BluetoothPowerController::RegisterLocalStatePrefs(registry); - DetachableBaseHandler::RegisterPrefs(registry); - PowerPrefs::RegisterLocalStatePrefs(registry); - // Note: DisplayPrefs are registered in chrome in AshShellInit::RegisterPrefs - // (see comment there for details). - if (for_test) - DisplayPrefs::RegisterLocalStatePrefs(registry); - else - DisplayPrefs::RegisterForeignPrefs(registry); -} - display::DisplayConfigurator* Shell::display_configurator() { return display_manager_->configurator(); } @@ -886,7 +868,6 @@ // Destroys the MessageCenter singleton, so must happen late. message_center_controller_.reset(); - local_state_.reset(); shell_delegate_.reset(); if (!::features::IsMultiProcessMash()) { @@ -904,7 +885,7 @@ void Shell::Init( ui::ContextFactory* context_factory, ui::ContextFactoryPrivate* context_factory_private, - std::unique_ptr<base::Value> initial_display_prefs, + PrefService* local_state, std::unique_ptr<keyboard::KeyboardUIFactory> keyboard_ui_factory, scoped_refptr<dbus::Bus> dbus_bus) { // Required by DetachableBaseHandler. @@ -932,17 +913,6 @@ multidevice_notification_presenter_ = std::make_unique<MultiDeviceNotificationPresenter>( message_center::MessageCenter::Get(), connector_); - - // Connect to local state prefs now, but wait for an active user before - // connecting to the profile pref service. The login screen has a temporary - // user profile that is not associated with a real user. - auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>(); - RegisterLocalStatePrefs(pref_registry.get(), false); - prefs::ConnectToPrefService( - connector_, std::move(pref_registry), - base::Bind(&Shell::OnLocalStatePrefServiceInitialized, - weak_factory_.GetWeakPtr()), - prefs::mojom::kLocalStateServiceName); } kiosk_next_shell_controller_ = std::make_unique<KioskNextShellController>(); tablet_mode_controller_ = std::make_unique<TabletModeController>(); @@ -970,12 +940,7 @@ InitializeDisplayManager(); - // In CLASSIC mode, |initial_display_prefs| contains the synchronously - // loaded display pref values. Otherwise |initial_display_prefs| is null and - // the pref values will be loaded once |local_state_| is available. (Any store - // requests in the meanwhile will be queued). - display_prefs_ = - std::make_unique<DisplayPrefs>(std::move(initial_display_prefs)); + display_prefs_ = std::make_unique<DisplayPrefs>(local_state); // This will initialize aura::Env which requires |display_manager_| to // be initialized first. @@ -1217,6 +1182,10 @@ // By this point ash shell should have initialized its D-Bus signal // listeners, so inform the session manager that Ash is initialized. session_controller_->EmitAshInitialized(); + + // Associates with local state. + if (local_state) + OnLocalStatePrefServiceInitialized(local_state); } void Shell::InitializeDisplayManager() { @@ -1373,19 +1342,14 @@ #endif } -void Shell::OnLocalStatePrefServiceInitialized( - std::unique_ptr<::PrefService> pref_service) { +void Shell::OnLocalStatePrefServiceInitialized(PrefService* pref_service) { DCHECK(!local_state_); - // |pref_service| is null if can't connect to Chrome (as happens when - // running mash outside of chrome --enable-features=Mash and chrome isn't - // built). - if (!pref_service) - return; + DCHECK(pref_service); - local_state_ = std::move(pref_service); + local_state_ = pref_service; for (auto& observer : shell_observers_) - observer.OnLocalStatePrefServiceInitialized(local_state_.get()); + observer.OnLocalStatePrefServiceInitialized(local_state_); } } // namespace ash
diff --git a/ash/shell.h b/ash/shell.h index cd1e686..656c933 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -26,7 +26,6 @@ #include "ui/wm/core/cursor_manager.h" #include "ui/wm/public/activation_change_observer.h" -class PrefRegistrySimple; class PrefService; namespace aura { @@ -273,10 +272,6 @@ // Returns true if a system-modal dialog window is currently open. static bool IsSystemModalWindowOpen(); - // Registers all ash related local state prefs to the given |registry|. - static void RegisterLocalStatePrefs(PrefRegistrySimple* registry, - bool for_test); - // If necessary, initializes the Wayland server. void InitWaylandServer(std::unique_ptr<exo::FileHelper> file_helper); void DestroyWaylandServer(); @@ -633,7 +628,7 @@ void Init(ui::ContextFactory* context_factory, ui::ContextFactoryPrivate* context_factory_private, - std::unique_ptr<base::Value> initial_display_prefs, + PrefService* local_state, std::unique_ptr<keyboard::KeyboardUIFactory> keyboard_ui_factory, scoped_refptr<dbus::Bus> dbus_bus); @@ -666,9 +661,7 @@ void OnLoginStatusChanged(LoginStatus login_status) override; void OnLockStateChanged(bool locked) override; - // Callback for prefs::ConnectToPrefService. - void OnLocalStatePrefServiceInitialized( - std::unique_ptr<::PrefService> pref_service); + void OnLocalStatePrefServiceInitialized(PrefService* pref_service); static Shell* instance_; @@ -754,7 +747,7 @@ std::unique_ptr<::wm::ShadowController> shadow_controller_; std::unique_ptr<::wm::VisibilityController> visibility_controller_; std::unique_ptr<::wm::WindowModalityController> window_modality_controller_; - std::unique_ptr<PrefService> local_state_; + PrefService* local_state_ = nullptr; std::unique_ptr<views::corewm::TooltipController> tooltip_controller_; std::unique_ptr<PowerButtonController> power_button_controller_; std::unique_ptr<LockStateController> lock_state_controller_;
diff --git a/ash/shell_init_params.h b/ash/shell_init_params.h index b0128ce..5f4fac24 100644 --- a/ash/shell_init_params.h +++ b/ash/shell_init_params.h
@@ -11,9 +11,7 @@ #include "base/memory/scoped_refptr.h" #include "dbus/bus.h" -namespace base { -class Value; -} +class PrefService; namespace keyboard { class KeyboardUIFactory; @@ -40,9 +38,7 @@ std::unique_ptr<ShellDelegate> delegate; ui::ContextFactory* context_factory = nullptr; // Non-owning. ui::ContextFactoryPrivate* context_factory_private = nullptr; // Non-owning. - // Dictionary of pref values used by DisplayPrefs before - // ShellObserver::OnLocalStatePrefServiceInitialized is called. - std::unique_ptr<base::Value> initial_display_prefs; + PrefService* local_state = nullptr; // Non-owning. // Connector used by Shell to establish connections. service_manager::Connector* connector = nullptr;
diff --git a/ash/shell_test_api.cc b/ash/shell_test_api.cc index aba234c..a4e85a2 100644 --- a/ash/shell_test_api.cc +++ b/ash/shell_test_api.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/shell_test_api.h" +#include "ash/public/cpp/test/shell_test_api.h" #include <memory> #include <utility> @@ -72,10 +72,9 @@ // after executing the callback. class OverviewAnimationStateWaiter : public OverviewObserver { public: - OverviewAnimationStateWaiter( - mojom::OverviewAnimationState state, - ShellTestApi::WaitForOverviewAnimationStateCallback callback) - : state_(state), callback_(std::move(callback)) { + OverviewAnimationStateWaiter(OverviewAnimationState state, + base::OnceClosure closure) + : state_(state), closure_(std::move(closure)) { Shell::Get()->overview_controller()->AddObserver(this); } ~OverviewAnimationStateWaiter() override { @@ -84,21 +83,21 @@ // OverviewObserver: void OnOverviewModeStartingAnimationComplete(bool canceled) override { - if (state_ == mojom::OverviewAnimationState::kEnterAnimationComplete) { - std::move(callback_).Run(); + if (state_ == OverviewAnimationState::kEnterAnimationComplete) { + std::move(closure_).Run(); delete this; } } void OnOverviewModeEndingAnimationComplete(bool canceled) override { - if (state_ == mojom::OverviewAnimationState::kExitAnimationComplete) { - std::move(callback_).Run(); + if (state_ == OverviewAnimationState::kExitAnimationComplete) { + std::move(closure_).Run(); delete this; } } private: - mojom::OverviewAnimationState state_; - ShellTestApi::WaitForOverviewAnimationStateCallback callback_; + OverviewAnimationState state_; + base::OnceClosure closure_; DISALLOW_COPY_AND_ASSIGN(OverviewAnimationStateWaiter); }; @@ -107,10 +106,9 @@ // execute the callback. This self destruction upon completion. class LauncherStateWaiter { public: - LauncherStateWaiter( - ash::mojom::AppListViewState state, - ShellTestApi::WaitForLauncherAnimationStateCallback callback) - : target_state_(state), callback_(std::move(callback)) { + LauncherStateWaiter(ash::mojom::AppListViewState state, + base::OnceClosure closure) + : target_state_(state), closure_(std::move(closure)) { Shell::Get()->app_list_controller()->SetStateTransitionAnimationCallback( base::BindRepeating(&LauncherStateWaiter::OnStateChanged, base::Unretained(this))); @@ -122,28 +120,22 @@ void OnStateChanged(ash::mojom::AppListViewState state) { if (target_state_ == state) { - std::move(callback_).Run(); + std::move(closure_).Run(); delete this; } } private: ash::mojom::AppListViewState target_state_; - ShellTestApi::WaitForLauncherAnimationStateCallback callback_; + base::OnceClosure closure_; DISALLOW_COPY_AND_ASSIGN(LauncherStateWaiter); }; } // namespace -ShellTestApi::ShellTestApi() : ShellTestApi(Shell::Get()) {} - -ShellTestApi::ShellTestApi(Shell* shell) : shell_(shell) {} - -// static -void ShellTestApi::BindRequest(mojom::ShellTestApiRequest request) { - mojo::MakeStrongBinding(std::make_unique<ShellTestApi>(), std::move(request)); -} +ShellTestApi::ShellTestApi() : shell_(Shell::Get()) {} +ShellTestApi::~ShellTestApi() = default; MessageCenterController* ShellTestApi::message_center_controller() { return shell_->message_center_controller_.get(); @@ -175,8 +167,8 @@ } void ShellTestApi::OnLocalStatePrefServiceInitialized( - std::unique_ptr<PrefService> pref_service) { - shell_->OnLocalStatePrefServiceInitialized(std::move(pref_service)); + PrefService* pref_service) { + shell_->OnLocalStatePrefServiceInitialized(pref_service); } void ShellTestApi::ResetPowerButtonControllerForTest() { @@ -189,8 +181,8 @@ shell_->simulate_modal_window_open_for_test_ = modal_window_open; } -void ShellTestApi::IsSystemModalWindowOpen(IsSystemModalWindowOpenCallback cb) { - std::move(cb).Run(Shell::IsSystemModalWindowOpen()); +bool ShellTestApi::IsSystemModalWindowOpen() { + return Shell::IsSystemModalWindowOpen(); } void ShellTestApi::EnableTabletModeWindowManager(bool enable) { @@ -198,80 +190,70 @@ shell_->tablet_mode_controller()->EnableTabletModeWindowManager(enable); } -void ShellTestApi::EnableVirtualKeyboard(EnableVirtualKeyboardCallback cb) { +void ShellTestApi::EnableVirtualKeyboard() { shell_->ash_keyboard_controller()->SetEnableFlag( keyboard::mojom::KeyboardEnableFlag::kCommandLineEnabled); - std::move(cb).Run(); } -void ShellTestApi::ToggleFullscreen(ToggleFullscreenCallback cb) { +void ShellTestApi::ToggleFullscreen() { ash::accelerators::ToggleFullscreen(); - std::move(cb).Run(); } -void ShellTestApi::ToggleOverviewMode(ToggleOverviewModeCallback cb) { +void ShellTestApi::ToggleOverviewMode() { shell_->overview_controller()->ToggleOverview(); - std::move(cb).Run(); } -void ShellTestApi::IsOverviewSelecting(IsOverviewSelectingCallback callback) { - std::move(callback).Run(shell_->overview_controller()->InOverviewSession()); +bool ShellTestApi::IsOverviewSelecting() { + return shell_->overview_controller()->InOverviewSession(); } void ShellTestApi::AddRemoveDisplay() { shell_->display_manager()->AddRemoveDisplay(); } -void ShellTestApi::SetMinFlingVelocity(float velocity) { - ui::GestureConfiguration::GetInstance()->set_min_fling_velocity(velocity); -} - -void ShellTestApi::WaitForNoPointerHoldLock( - WaitForNoPointerHoldLockCallback callback) { +void ShellTestApi::WaitForNoPointerHoldLock() { aura::WindowTreeHost* primary_host = Shell::GetPrimaryRootWindowController()->GetHost(); if (primary_host->holding_pointer_moves()) PointerMoveLoopWaiter(primary_host).Wait(); - std::move(callback).Run(); } -void ShellTestApi::WaitForNextFrame(WaitForNextFrameCallback callback) { +void ShellTestApi::WaitForNextFrame(base::OnceClosure closure) { Shell::GetPrimaryRootWindowController() ->GetHost() ->compositor() ->RequestPresentationTimeForNextFrame(base::BindOnce( - [](WaitForNextFrameCallback callback, + [](base::OnceClosure closure, const gfx::PresentationFeedback& feedback) { - std::move(callback).Run(); + std::move(closure).Run(); }, - std::move(callback))); + std::move(closure))); } -void ShellTestApi::WaitForOverviewAnimationState( - mojom::OverviewAnimationState state, - WaitForOverviewAnimationStateCallback callback) { - auto* overview_controller = Shell::Get()->overview_controller(); - if (state == mojom::OverviewAnimationState::kEnterAnimationComplete && +void ShellTestApi::WaitForOverviewAnimationState(OverviewAnimationState state) { + auto* overview_controller = shell_->overview_controller(); + if (state == OverviewAnimationState::kEnterAnimationComplete && overview_controller->InOverviewSession() && !overview_controller->IsInStartAnimation()) { // If there is no animation applied, call the callback immediately. - std::move(callback).Run(); return; } - if (state == mojom::OverviewAnimationState::kExitAnimationComplete && + if (state == OverviewAnimationState::kExitAnimationComplete && !overview_controller->InOverviewSession() && !overview_controller->IsCompletingShutdownAnimations()) { // If there is no animation applied, call the callback immediately. - std::move(callback).Run(); return; } - new OverviewAnimationStateWaiter(state, std::move(callback)); + base::RunLoop run_loop; + new OverviewAnimationStateWaiter(state, run_loop.QuitWhenIdleClosure()); + run_loop.Run(); } void ShellTestApi::WaitForLauncherAnimationState( - ash::mojom::AppListViewState target_state, - WaitForLauncherAnimationStateCallback callback) { - new LauncherStateWaiter(target_state, std::move(callback)); + ash::mojom::AppListViewState target_state) { + base::RunLoop run_loop; + new LauncherStateWaiter(target_state, run_loop.QuitWhenIdleClosure()); + run_loop.Run(); } } // namespace ash
diff --git a/ash/shell_test_api.h b/ash/shell_test_api.h deleted file mode 100644 index 1f83fa9..0000000 --- a/ash/shell_test_api.h +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright (c) 2012 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 ASH_SHELL_TEST_API_H_ -#define ASH_SHELL_TEST_API_H_ - -#include <memory> - -#include "ash/public/interfaces/shell_test_api.test-mojom.h" -#include "base/macros.h" - -class PrefService; - -namespace ash { -class DragDropController; -class MessageCenterController; -class NativeCursorManagerAsh; -class PowerPrefs; -class ScreenPositionController; -class Shell; -class SystemGestureEventFilter; -class WorkspaceController; - -// Accesses private data from a Shell for testing. -class ShellTestApi : public mojom::ShellTestApi { - public: - ShellTestApi(); - explicit ShellTestApi(Shell* shell); - - // Creates and binds an instance from a remote request (e.g. from chrome). - static void BindRequest(mojom::ShellTestApiRequest request); - - MessageCenterController* message_center_controller(); - SystemGestureEventFilter* system_gesture_event_filter(); - WorkspaceController* workspace_controller(); - ScreenPositionController* screen_position_controller(); - NativeCursorManagerAsh* native_cursor_manager_ash(); - DragDropController* drag_drop_controller(); - PowerPrefs* power_prefs(); - - // Calls the private method. - void OnLocalStatePrefServiceInitialized( - std::unique_ptr<PrefService> pref_service); - - // Resets |shell_->power_button_controller_| to hold a new object to simulate - // Chrome starting. - void ResetPowerButtonControllerForTest(); - - // Simulates a modal dialog being open. - void SimulateModalWindowOpenForTest(bool modal_window_open); - - // mojom::ShellTestApi: - void IsSystemModalWindowOpen(IsSystemModalWindowOpenCallback cb) override; - void EnableTabletModeWindowManager(bool enable) override; - void EnableVirtualKeyboard(EnableVirtualKeyboardCallback cb) override; - void ToggleFullscreen(ToggleFullscreenCallback cb) override; - void ToggleOverviewMode(ToggleOverviewModeCallback cb) override; - void IsOverviewSelecting(IsOverviewSelectingCallback callback) override; - void AddRemoveDisplay() override; - void SetMinFlingVelocity(float velocity) override; - void WaitForNoPointerHoldLock( - WaitForNoPointerHoldLockCallback callback) override; - void WaitForNextFrame(WaitForNextFrameCallback callback) override; - void WaitForOverviewAnimationState( - mojom::OverviewAnimationState state, - WaitForOverviewAnimationStateCallback callback) override; - void WaitForLauncherAnimationState( - ash::mojom::AppListViewState state, - WaitForLauncherAnimationStateCallback callback) override; - - private: - Shell* shell_; // not owned - - DISALLOW_COPY_AND_ASSIGN(ShellTestApi); -}; - -} // namespace ash - -#endif // ASH_SHELL_TEST_API_H_
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc index 97a926c..c55f035 100644 --- a/ash/shell_unittest.cc +++ b/ash/shell_unittest.cc
@@ -16,7 +16,9 @@ #include "ash/keyboard/ui/keyboard_util.h" #include "ash/keyboard/ui/public/keyboard_switches.h" #include "ash/public/cpp/ash_features.h" +#include "ash/public/cpp/ash_prefs.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/root_window_controller.h" #include "ash/scoped_root_window_for_new_windows.h" #include "ash/session/session_controller_impl.h" @@ -24,7 +26,6 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" -#include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/test_shell_delegate.h" @@ -556,7 +557,7 @@ TEST_F(ShellTest, TestPreTargetHandlerOrder) { Shell* shell = Shell::Get(); ui::EventTargetTestApi test_api(shell); - ShellTestApi shell_test_api(shell); + ShellTestApi shell_test_api; ui::EventHandlerList handlers = test_api.GetPreTargetHandlers(); ui::EventHandlerList::const_iterator cursor_filter = @@ -668,6 +669,9 @@ class ShellLocalStateTest : public AshTestBase { public: ShellLocalStateTest() { disable_provide_local_state(); } + + protected: + std::unique_ptr<TestingPrefServiceSimple> local_state_; }; TEST_F(ShellLocalStateTest, LocalState) { @@ -675,11 +679,10 @@ Shell::Get()->AddShellObserver(&observer); // Prefs service wrapper code creates a PrefService. - std::unique_ptr<TestingPrefServiceSimple> local_state = - std::make_unique<TestingPrefServiceSimple>(); - Shell::RegisterLocalStatePrefs(local_state->registry(), true); - TestingPrefServiceSimple* local_state_ptr = local_state.get(); - ShellTestApi().OnLocalStatePrefServiceInitialized(std::move(local_state)); + local_state_ = std::make_unique<TestingPrefServiceSimple>(); + RegisterLocalStatePrefs(local_state_->registry(), true); + TestingPrefServiceSimple* local_state_ptr = local_state_.get(); + ShellTestApi().OnLocalStatePrefServiceInitialized(local_state_ptr); EXPECT_EQ(local_state_ptr, observer.last_local_state_); EXPECT_EQ(local_state_ptr, ash_test_helper()->GetLocalStatePrefService()); @@ -690,7 +693,7 @@ TEST_F(ShellLoginTest, DragAndDropDisabledBeforeLogin) { DragDropController* drag_drop_controller = - ShellTestApi(Shell::Get()).drag_drop_controller(); + ShellTestApi().drag_drop_controller(); DragDropControllerTestApi drag_drop_controller_test_api(drag_drop_controller); EXPECT_FALSE(drag_drop_controller_test_api.enabled());
diff --git a/ash/system/message_center/inactive_user_notification_blocker_unittest.cc b/ash/system/message_center/inactive_user_notification_blocker_unittest.cc index aa655e5e..2f542d28 100644 --- a/ash/system/message_center/inactive_user_notification_blocker_unittest.cc +++ b/ash/system/message_center/inactive_user_notification_blocker_unittest.cc
@@ -4,9 +4,9 @@ #include "ash/system/message_center/inactive_user_notification_blocker.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/message_center/message_center_controller.h" #include "ash/test/ash_test_base.h" #include "base/macros.h"
diff --git a/ash/system/message_center/unified_message_center_view.cc b/ash/system/message_center/unified_message_center_view.cc index fc694959..0fa27e8 100644 --- a/ash/system/message_center/unified_message_center_view.cc +++ b/ash/system/message_center/unified_message_center_view.cc
@@ -43,6 +43,8 @@ constexpr base::TimeDelta kHideStackingBarAnimationDuration = base::TimeDelta::FromMilliseconds(330); +constexpr base::TimeDelta kCollapseAnimationDuration = + base::TimeDelta::FromMilliseconds(640); enum ClearAllButtonTag { kStackingBarClearAllButtonTag, @@ -338,6 +340,8 @@ if (stacking_counter_->visible() && message_list_view_->GetTotalNotificationCount() <= 1) { StartHideStackingBarAnimation(); + } else if (!message_list_view_->GetTotalNotificationCount()) { + StartCollapseAnimation(); } } @@ -409,6 +413,12 @@ // Hide Clear All button at the buttom from initial viewport. preferred_size.set_height(preferred_size.height() - kClearAllButtonRowHeight); + + if (animation_state_ == UnifiedMessageCenterAnimationState::COLLAPSE) { + int height = preferred_size.height() * (1.0 - GetAnimationValue()); + preferred_size.set_height(height); + } + return preferred_size; } @@ -474,12 +484,12 @@ case UnifiedMessageCenterAnimationState::HIDE_STACKING_BAR: break; case UnifiedMessageCenterAnimationState::COLLAPSE: - NOTIMPLEMENTED(); break; } animation_state_ = UnifiedMessageCenterAnimationState::IDLE; stacking_counter_->SetAnimationState(animation_state_); + UpdateVisibility(); } void UnifiedMessageCenterView::AnimationProgressed( @@ -505,6 +515,14 @@ animation_->Start(); } +void UnifiedMessageCenterView::StartCollapseAnimation() { + animation_->End(); + animation_state_ = UnifiedMessageCenterAnimationState::COLLAPSE; + stacking_counter_->SetAnimationState(animation_state_); + animation_->SetDuration(kCollapseAnimationDuration); + animation_->Start(); +} + double UnifiedMessageCenterView::GetAnimationValue() const { return gfx::Tween::CalculateValue(gfx::Tween::FAST_OUT_SLOW_IN, animation_->GetCurrentValue()); @@ -513,11 +531,13 @@ void UnifiedMessageCenterView::UpdateVisibility() { SessionControllerImpl* session_controller = Shell::Get()->session_controller(); - SetVisible(available_height_ >= kUnifiedNotificationMinimumHeight && - message_list_view_->GetPreferredSize().height() > 0 && - session_controller->ShouldShowNotificationTray() && - (!session_controller->IsScreenLocked() || - AshMessageCenterLockScreenController::IsEnabled())); + SetVisible( + available_height_ >= kUnifiedNotificationMinimumHeight && + (animation_state_ == UnifiedMessageCenterAnimationState::COLLAPSE || + message_list_view_->GetPreferredSize().height() > 0) && + session_controller->ShouldShowNotificationTray() && + (!session_controller->IsScreenLocked() || + AshMessageCenterLockScreenController::IsEnabled())); // When notification list went invisible, the last notification should be // targeted next time.
diff --git a/ash/system/message_center/unified_message_center_view.h b/ash/system/message_center/unified_message_center_view.h index d34eb9eb..fa5918b0 100644 --- a/ash/system/message_center/unified_message_center_view.h +++ b/ash/system/message_center/unified_message_center_view.h
@@ -152,6 +152,9 @@ // Starts the animation to hide the notification stacking bar. void StartHideStackingBarAnimation(); + // Starts the animation to collapse the message center. + void StartCollapseAnimation(); + // Returns the current animation value after tweening. double GetAnimationValue() const;
diff --git a/ash/system/message_center/unified_message_center_view_unittest.cc b/ash/system/message_center/unified_message_center_view_unittest.cc index 183f14a..27998d9b 100644 --- a/ash/system/message_center/unified_message_center_view_unittest.cc +++ b/ash/system/message_center/unified_message_center_view_unittest.cc
@@ -227,10 +227,20 @@ GetScrollerContents()->height() - GetScroller()->GetVisibleRect().bottom()); + // The notification first slides out of the list. MessageCenter::Get()->RemoveNotification(id0, true /* by_user */); AnimateMessageListToEnd(); + + // After all the last notifiation slides out, the message center and list + // should collapse. + auto* collapse_animation = GetMessageCenterAnimation(); + collapse_animation->SetCurrentValue(0.5); + message_center_view()->AnimationProgressed(collapse_animation); AnimateMessageListToMiddle(); EXPECT_TRUE(message_center_view()->visible()); + + // The message center is now hidden after all animations complete. + collapse_animation->End(); AnimateMessageListToEnd(); EXPECT_FALSE(message_center_view()->visible()); }
diff --git a/ash/system/network/network_info.cc b/ash/system/network/network_info.cc index 7d4ecd6..fdde654e 100644 --- a/ash/system/network/network_info.cc +++ b/ash/system/network/network_info.cc
@@ -6,26 +6,19 @@ namespace ash { -NetworkInfo::NetworkInfo() - : disable(false), - connected(false), - connecting(false), - type(Type::UNKNOWN) {} +NetworkInfo::NetworkInfo() = default; -NetworkInfo::NetworkInfo(const std::string& guid) - : guid(guid), - disable(false), - connected(false), - connecting(false), - type(Type::UNKNOWN) {} +NetworkInfo::NetworkInfo(const std::string& guid) : guid(guid) {} NetworkInfo::~NetworkInfo() = default; bool NetworkInfo::operator==(const NetworkInfo& other) const { return guid == other.guid && label == other.label && tooltip == other.tooltip && image.BackedBySameObjectAs(other.image) && - disable == other.disable && connected == other.connected && - connecting == other.connecting && type == other.type; + type == other.type && disable == other.disable && + connection_state == other.connection_state && source == other.source && + battery_percentage == other.battery_percentage && + captive_portal_provider_name == other.captive_portal_provider_name; } } // namespace ash
diff --git a/ash/system/network/network_info.h b/ash/system/network/network_info.h index 04d5b294..8509ba46 100644 --- a/ash/system/network/network_info.h +++ b/ash/system/network/network_info.h
@@ -8,6 +8,7 @@ #include <string> #include "base/strings/string16.h" +#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" #include "ui/gfx/image/image_skia.h" namespace gfx { @@ -19,10 +20,8 @@ // Includes information necessary about a network for displaying the appropriate // UI to the user. struct NetworkInfo { - enum class Type { UNKNOWN, WIFI, MOBILE }; - NetworkInfo(); - NetworkInfo(const std::string& guid); + explicit NetworkInfo(const std::string& guid); ~NetworkInfo(); bool operator==(const NetworkInfo& other) const; @@ -32,10 +31,15 @@ base::string16 label; base::string16 tooltip; gfx::ImageSkia image; - bool disable; - bool connected; - bool connecting; - Type type; + bool disable = false; + chromeos::network_config::mojom::ConnectionStateType connection_state = + chromeos::network_config::mojom::ConnectionStateType::kNotConnected; + chromeos::network_config::mojom::NetworkType type = + chromeos::network_config::mojom::NetworkType::kWiFi; + chromeos::network_config::mojom::ONCSource source = + chromeos::network_config::mojom::ONCSource::kUnknown; + int battery_percentage = 0; + std::string captive_portal_provider_name; }; } // namespace ash
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc index f34e175..a52366599 100644 --- a/ash/system/network/network_list.cc +++ b/ash/system/network/network_list.cc
@@ -25,9 +25,12 @@ #include "ash/system/tray/tri_view.h" #include "base/i18n/number_formatting.h" #include "base/strings/utf_string_conversions.h" -#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/network_handler.h" #include "chromeos/network/proxy/ui_proxy_config_service.h" +#include "chromeos/services/network_config/public/cpp/cros_network_config_util.h" +#include "chromeos/services/network_config/public/mojom/constants.mojom.h" #include "components/device_event_log/device_event_log.h" +#include "services/service_manager/public/cpp/connector.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_features.h" #include "ui/gfx/image/image_skia_operations.h" @@ -37,9 +40,18 @@ #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/separator.h" -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; -using chromeos::NetworkTypePattern; +using chromeos::network_config::NetworkTypeMatchesType; +using chromeos::network_config::StateIsConnected; + +using chromeos::network_config::mojom::ActivationStateType; +using chromeos::network_config::mojom::ConnectionStateType; +using chromeos::network_config::mojom::DeviceStatePropertiesPtr; +using chromeos::network_config::mojom::DeviceStateType; +using chromeos::network_config::mojom::FilterType; +using chromeos::network_config::mojom::NetworkFilter; +using chromeos::network_config::mojom::NetworkStatePropertiesPtr; +using chromeos::network_config::mojom::NetworkType; +using chromeos::network_config::mojom::ONCSource; namespace ash { namespace tray { @@ -61,7 +73,9 @@ NetworkListView::NetworkListView(DetailedViewDelegate* delegate, LoginStatus login) - : NetworkStateListDetailedView(delegate, LIST_TYPE_NETWORK, login) {} + : NetworkStateListDetailedView(delegate, LIST_TYPE_NETWORK, login) { + BindCrosNetworkConfig(); +} NetworkListView::~NetworkListView() { network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); @@ -69,14 +83,9 @@ void NetworkListView::UpdateNetworkList() { CHECK(scroll_content()); - - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - - NetworkStateHandler::NetworkStateList network_list; - handler->GetVisibleNetworkList(&network_list); - UpdateNetworks(network_list); - UpdateNetworkIcons(); - UpdateNetworkListInternal(); + DCHECK(cros_network_config_ptr_); + cros_network_config_ptr_->GetDeviceStateList(base::BindOnce( + &NetworkListView::OnGetDeviceStateList, base::Unretained(this))); } bool NetworkListView::IsNetworkEntry(views::View* view, @@ -89,71 +98,106 @@ return true; } -void NetworkListView::UpdateNetworks( - const NetworkStateHandler::NetworkStateList& networks) { - SCOPED_NET_LOG_IF_SLOW(); +void NetworkListView::BindCrosNetworkConfig() { + // Ensure binding is reset in case this is called after a failure. + cros_network_config_ptr_.reset(); + + service_manager::Connector* connector = Shell::Get()->connector(); + if (!connector) + return; + connector->BindInterface(chromeos::network_config::mojom::kServiceName, + &cros_network_config_ptr_); + + // If the connection is lost (e.g. due to a crash), attempt to rebind it. + cros_network_config_ptr_.set_connection_error_handler(base::BindOnce( + &NetworkListView::BindCrosNetworkConfig, base::Unretained(this))); +} + +void NetworkListView::OnGetDeviceStateList( + std::vector<DeviceStatePropertiesPtr> devices) { + device_states_.clear(); + for (auto& device : devices) + device_states_[device->type] = device->state; + + cros_network_config_ptr_->GetNetworkStateList( + NetworkFilter::New(FilterType::kVisible, NetworkType::kAll, + chromeos::network_config::mojom::kNoLimit), + base::BindOnce(&NetworkListView::OnGetNetworkStateList, + base::Unretained(this))); +} + +void NetworkListView::OnGetNetworkStateList( + std::vector<NetworkStatePropertiesPtr> networks) { // |network_list_| contains all the info and is going to be cleared and // recreated. Save them to |last_network_info_map_|. last_network_info_map_.clear(); for (auto& info : network_list_) last_network_info_map_[info->guid] = std::move(info); - bool cellular_enabled = - NetworkHandler::Get()->network_state_handler()->IsTechnologyEnabled( - NetworkTypePattern::Cellular()); - network_list_.clear(); - for (const auto* network : networks) { - if (!NetworkTypePattern::NonVirtual().MatchesType(network->type())) - continue; - // If cellular is disabled, skip the default cellular service. - if (network->IsDefaultCellular() && !cellular_enabled) - continue; - network_list_.push_back(std::make_unique<NetworkInfo>(network->guid())); - } -} - -void NetworkListView::UpdateNetworkIcons() { - SCOPED_NET_LOG_IF_SLOW(); - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - bool animating = false; - for (auto& info : network_list_) { - const chromeos::NetworkState* network = - handler->GetNetworkStateFromGuid(info->guid); - if (!network) + network_list_.clear(); + vpn_connected_ = false; + wifi_has_networks_ = false; + for (auto& network : networks) { + ConnectionStateType connection_state = network->connection_state; + if (network->type == NetworkType::kVPN) { + if (chromeos::network_config::StateIsConnected(connection_state)) + vpn_connected_ = true; continue; - bool prohibited_by_policy = network->blocked_by_policy(); - network_icon::NetworkIconState network_icon_state(network); + } + // If cellular is not enabled, skip cellular networks with no service. + ActivationStateType activation_state = + network->cellular ? network->cellular->activation_state + : ActivationStateType::kUnknown; + if (network->type == NetworkType::kCellular && + GetDeviceState(NetworkType::kCellular) != DeviceStateType::kEnabled && + activation_state == ActivationStateType::kNoService) { + continue; + } + if (network->type == NetworkType::kWiFi) + wifi_has_networks_ = true; + + auto info = std::make_unique<NetworkInfo>(network->guid); + + network_icon::NetworkIconState network_icon_state(network.get()); info->label = network_icon::GetLabelForNetwork( network_icon_state, network_icon::ICON_TYPE_MENU_LIST); // |network_list_| only contains non virtual networks. info->image = network_icon::GetImageForNonVirtualNetwork( network_icon_state, network_icon::ICON_TYPE_LIST, false /* badge_vpn */); - info->disable = - (network->activation_state() == shill::kActivationStateActivating) || - prohibited_by_policy; - info->connected = network->IsConnectedState(); - info->connecting = network->IsConnectingState(); - if (network->Matches(NetworkTypePattern::WiFi())) - info->type = NetworkInfo::Type::WIFI; - else if (network->Matches(NetworkTypePattern::Mobile())) - info->type = NetworkInfo::Type::MOBILE; - if (prohibited_by_policy) { + info->disable = activation_state == ActivationStateType::kActivating || + network->prohibited_by_policy; + if (network->prohibited_by_policy) { info->tooltip = l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED); } - if (!animating && network->IsConnectingState()) + + info->connection_state = connection_state; + + if (network->tether) + info->battery_percentage = network->tether->battery_percentage; + if (network->captive_portal_provider) { + info->captive_portal_provider_name = + network->captive_portal_provider->name; + } + + info->type = network->type; + info->source = network->source; + + if (!animating && connection_state == ConnectionStateType::kConnecting) animating = true; + network_list_.push_back(std::move(info)); } if (animating) network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); else network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + + UpdateNetworkListInternal(); } void NetworkListView::UpdateNetworkListInternal() { - SCOPED_NET_LOG_IF_SLOW(); // Get the updated list entries. needs_relayout_ = false; network_map_.clear(); @@ -191,34 +235,29 @@ std::unique_ptr<std::set<std::string>> NetworkListView::UpdateNetworkListEntries() { - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - // Keep an index where the next child should be inserted. int index = 0; - // Show a warning that the connection might be monitored if connected to a VPN - // or if the default network has a proxy installed. - const bool using_vpn = - !!NetworkHandler::Get()->network_state_handler()->ConnectedNetworkByType( - NetworkTypePattern::VPN()); bool using_proxy = false; - // TODO(jamescook): Create UIProxyConfigService under mash. This will require - // the mojo pref service to work with prefs in Local State. - // http://crbug.com/718072 + // TODO(https://crbug.com/718072): Create UIProxyConfigService under mash, or + // provide this via network_config.mojom. if (!::features::IsMultiProcessMash()) { - using_proxy = NetworkHandler::Get() + using_proxy = chromeos::NetworkHandler::Get() ->ui_proxy_config_service() ->HasDefaultNetworkProxyConfigured(); } - if (using_vpn || using_proxy) { + + // Show a warning that the connection might be monitored if connected to a VPN + // or if the default network has a proxy installed. + if (vpn_connected_ || using_proxy) { if (!connection_warning_) connection_warning_ = CreateConnectionWarning(); PlaceViewAtIndex(connection_warning_, index++); } - // First add high-priority networks (neither Wi-Fi nor Mobile). + // First add Ethernet networks. std::unique_ptr<std::set<std::string>> new_guids = - UpdateNetworkChildren(NetworkInfo::Type::UNKNOWN, index); + UpdateNetworkChildren(NetworkType::kEthernet, index); index += new_guids->size(); if (ShouldMobileDataSectionBeShown()) { @@ -226,11 +265,11 @@ mobile_header_view_ = new MobileSectionHeaderView(); index = UpdateNetworkSectionHeader( - NetworkTypePattern::Mobile(), false /* enabled */, index, - mobile_header_view_, &mobile_separator_view_); + NetworkType::kMobile, false /* enabled */, index, mobile_header_view_, + &mobile_separator_view_); std::unique_ptr<std::set<std::string>> new_cellular_guids = - UpdateNetworkChildren(NetworkInfo::Type::MOBILE, index); + UpdateNetworkChildren(NetworkType::kMobile, index); int mobile_status_message = mobile_header_view_->UpdateToggleAndGetStatusMessage(); // |mobile_status_message| may be zero. Passing zero to UpdateInfoLabel @@ -245,20 +284,19 @@ if (!wifi_header_view_) wifi_header_view_ = new WifiSectionHeaderView(); - index = UpdateNetworkSectionHeader( - NetworkTypePattern::WiFi(), - handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), index, - wifi_header_view_, &wifi_separator_view_); + bool wifi_enabled = + GetDeviceState(NetworkType::kWiFi) == DeviceStateType::kEnabled; + index = UpdateNetworkSectionHeader(NetworkType::kWiFi, wifi_enabled, index, + wifi_header_view_, &wifi_separator_view_); - // "Wifi Enabled / Disabled". - if (!handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())) { + if (!wifi_enabled) { UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED, index, &wifi_status_message_); return new_guids; } bool should_clear_info_label = true; - if (!handler->FirstNetworkByType(NetworkTypePattern::WiFi())) { + if (!wifi_has_networks_) { UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED, index, &wifi_status_message_); ++index; @@ -267,7 +305,7 @@ // Add Wi-Fi networks. std::unique_ptr<std::set<std::string>> new_wifi_guids = - UpdateNetworkChildren(NetworkInfo::Type::WIFI, index); + UpdateNetworkChildren(NetworkType::kWiFi, index); index += new_wifi_guids->size(); new_guids->insert(new_wifi_guids->begin(), new_wifi_guids->end()); @@ -284,26 +322,23 @@ } bool NetworkListView::ShouldMobileDataSectionBeShown() { - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - // The section should always be shown if Cellular networks are available. - if (handler->IsTechnologyAvailable(NetworkTypePattern::Cellular())) + if (GetDeviceState(NetworkType::kCellular) != DeviceStateType::kUnavailable) return true; + DeviceStateType tether_state = GetDeviceState(NetworkType::kTether); // Hide the section if both Cellular and Tether are UNAVAILABLE. - if (!handler->IsTechnologyAvailable(NetworkTypePattern::Tether())) + if (tether_state == DeviceStateType::kUnavailable) return false; // Hide the section if Tether is PROHIBITED. - if (handler->IsTechnologyProhibited(NetworkTypePattern::Tether())) + if (tether_state == DeviceStateType::kProhibited) return false; // Secondary users cannot enable Bluetooth, and Tether is only UNINITIALIZED // if Bluetooth is disabled. Hide the section in this case. - if (handler->IsTechnologyUninitialized(NetworkTypePattern::Tether()) && - IsSecondaryUser()) { + if (tether_state == DeviceStateType::kUninitialized && IsSecondaryUser()) return false; - } return true; } @@ -312,8 +347,8 @@ const NetworkInfo& info) { view->Reset(); gfx::ImageSkia network_image; - if (info.type == NetworkInfo::Type::MOBILE && - (!info.connected && !info.connecting)) { + if (NetworkTypeMatchesType(info.type, NetworkType::kMobile) && + info.connection_state == ConnectionStateType::kNotConnected) { // Mobile icons which are not connecting or connected should display a small // "X" icon superimposed so that it is clear that they are disconnected. network_image = gfx::ImageSkiaOperations::CreateSuperimposedImage( @@ -324,9 +359,9 @@ network_image = info.image; } view->AddIconAndLabel(network_image, info.label); - if (info.connected) + if (StateIsConnected(info.connection_state)) SetupConnectedScrollListItem(view); - else if (info.connecting) + else if (info.connection_state == ConnectionStateType::kConnecting) SetupConnectingScrollListItem(view); view->SetTooltipText(info.tooltip); @@ -350,36 +385,30 @@ views::View* NetworkListView::CreatePowerStatusView(const NetworkInfo& info) { // Mobile can be Cellular or Tether. - if (info.type != NetworkInfo::Type::MOBILE) + if (!NetworkTypeMatchesType(info.type, NetworkType::kMobile)) return nullptr; - const chromeos::NetworkState* network = - NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( - info.guid); - // Only return a battery icon for Tether network type. - if (!NetworkTypePattern::Tether().MatchesType(network->type())) + if (info.type != NetworkType::kTether) return nullptr; views::ImageView* icon = TrayPopupUtils::CreateMoreImageView(); PowerStatus::BatteryImageInfo icon_info; - icon_info.charge_percent = network->battery_percentage(); + icon_info.charge_percent = info.battery_percentage; icon->SetImage( PowerStatus::GetBatteryImage(icon_info, kMobileNetworkBatteryIconSize, kMenuIconColorDisabled, kMenuIconColor)); // Show the numeric battery percentage on hover. - icon->set_tooltip_text(base::FormatPercent(network->battery_percentage())); + icon->set_tooltip_text(base::FormatPercent(info.battery_percentage)); return icon; } views::View* NetworkListView::CreatePolicyView(const NetworkInfo& info) { // Check if the network is managed by policy. - const chromeos::NetworkState* network = - NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( - info.guid); - if (!network || !network->IsManagedByPolicy()) + ONCSource source = info.source; + if (source != ONCSource::kDevicePolicy && source != ONCSource::kUserPolicy) return nullptr; views::ImageView* controlled_icon = TrayPopupUtils::CreateMainImageView(); @@ -390,10 +419,7 @@ views::View* NetworkListView::CreateControlledByExtensionView( const NetworkInfo& info) { - const chromeos::NetworkState* network = - NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( - info.guid); - if (!network || !network->captive_portal_provider()) + if (info.captive_portal_provider_name.empty()) return nullptr; views::ImageView* controlled_icon = TrayPopupUtils::CreateMainImageView(); @@ -401,17 +427,17 @@ gfx::CreateVectorIcon(kCaptivePortalIcon, kMenuIconColor)); controlled_icon->set_tooltip_text(l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI, - base::UTF8ToUTF16(network->captive_portal_provider()->name))); + base::UTF8ToUTF16(info.captive_portal_provider_name))); controlled_icon->SetID(VIEW_ID_EXTENSION_CONTROLLED_WIFI); return controlled_icon; } std::unique_ptr<std::set<std::string>> NetworkListView::UpdateNetworkChildren( - NetworkInfo::Type type, + NetworkType type, int index) { std::unique_ptr<std::set<std::string>> new_guids(new std::set<std::string>); for (const auto& info : network_list_) { - if (info->type != type) + if (!NetworkTypeMatchesType(info->type, type)) continue; UpdateNetworkChild(index++, info.get()); new_guids->insert(info->guid); @@ -473,7 +499,7 @@ } int NetworkListView::UpdateNetworkSectionHeader( - NetworkTypePattern pattern, + chromeos::network_config::mojom::NetworkType type, bool enabled, int child_index, NetworkSectionHeaderView* view, @@ -492,7 +518,7 @@ bool default_toggle_enabled = !IsSecondaryUser(); // Mobile updates its toggle state independently. - if (!pattern.MatchesPattern(NetworkTypePattern::Mobile())) + if (!NetworkTypeMatchesType(type, NetworkType::kMobile)) view->SetToggleState(default_toggle_enabled, enabled /* is_on */); PlaceViewAtIndex(view, child_index++); return child_index; @@ -542,5 +568,12 @@ return connection_warning; } +DeviceStateType NetworkListView::GetDeviceState(NetworkType type) const { + auto iter = device_states_.find(type); + if (iter == device_states_.end()) + return DeviceStateType::kUnavailable; + return iter->second; +} + } // namespace tray } // namespace ash
diff --git a/ash/system/network/network_list.h b/ash/system/network/network_list.h index 55fdf2a..da69afd 100644 --- a/ash/system/network/network_list.h +++ b/ash/system/network/network_list.h
@@ -14,14 +14,14 @@ #include "ash/system/network/network_icon_animation_observer.h" #include "ash/system/network/network_info.h" #include "ash/system/network/network_state_list_detailed_view.h" +#include "base/containers/flat_map.h" #include "base/macros.h" -#include "chromeos/network/network_state_handler.h" -#include "chromeos/network/network_type_pattern.h" +#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" namespace views { class Separator; class View; -} +} // namespace views namespace ash { class HoverHighlightView; @@ -46,18 +46,13 @@ bool IsNetworkEntry(views::View* view, std::string* guid) const override; private: - // Clears |network_list_| and adds to it |networks| that match |delegate_|'s - // network type pattern. - void UpdateNetworks( - const chromeos::NetworkStateHandler::NetworkStateList& networks); - - // Updates |network_list_| entries and sets |this| to observe network icon - // animations when any of the networks are in connecting state. - void UpdateNetworkIcons(); - - // Orders entries in |network_list_| such that higher priority network types - // are at the top of the list. - void OrderNetworks(); + void BindCrosNetworkConfig(); + void OnGetDeviceStateList( + std::vector<chromeos::network_config::mojom::DeviceStatePropertiesPtr> + devices); + void OnGetNetworkStateList( + std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr> + networks); // Refreshes a list of child views, updates |network_map_| and // |network_guid_map_| and performs layout making sure selected view if any is @@ -97,7 +92,7 @@ // |child_index|. Returns a set of guids for the added network // connections. std::unique_ptr<std::set<std::string>> UpdateNetworkChildren( - NetworkInfo::Type type, + chromeos::network_config::mojom::NetworkType type, int child_index); void UpdateNetworkChild(int index, const NetworkInfo* info); @@ -119,11 +114,12 @@ // |scroll_content()| placing the |view| at |child_index|. Returns the index // where the next child should be inserted, i.e., the index directly after the // last inserted child. - int UpdateNetworkSectionHeader(chromeos::NetworkTypePattern pattern, - bool enabled, - int child_index, - NetworkSectionHeaderView* view, - views::Separator** separator_view); + int UpdateNetworkSectionHeader( + chromeos::network_config::mojom::NetworkType type, + bool enabled, + int child_index, + NetworkSectionHeaderView* view, + views::Separator** separator_view); // network_icon::AnimationObserver: void NetworkIconChanged() override; @@ -132,6 +128,9 @@ // otherwise false. bool NeedUpdateViewForNetwork(const NetworkInfo& info) const; + chromeos::network_config::mojom::DeviceStateType GetDeviceState( + chromeos::network_config::mojom::NetworkType type) const; + bool needs_relayout_ = false; // Owned by the views heirarchy. @@ -143,6 +142,15 @@ views::Separator* wifi_separator_view_ = nullptr; TriView* connection_warning_ = nullptr; + chromeos::network_config::mojom::CrosNetworkConfigPtr + cros_network_config_ptr_; + + base::flat_map<chromeos::network_config::mojom::NetworkType, + chromeos::network_config::mojom::DeviceStateType> + device_states_; + bool vpn_connected_ = false; + bool wifi_has_networks_ = false; + // An owned list of network info. std::vector<std::unique_ptr<NetworkInfo>> network_list_;
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc index 3927687f..f6ec4b40 100644 --- a/ash/system/network/vpn_list_view.cc +++ b/ash/system/network/vpn_list_view.cc
@@ -26,12 +26,12 @@ #include "ash/system/tray/view_click_listener.h" #include "base/strings/utf_string_conversions.h" #include "chromeos/network/network_connect.h" -#include "chromeos/network/network_handler.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_type_pattern.h" +#include "chromeos/services/network_config/public/cpp/cros_network_config_util.h" +#include "chromeos/services/network_config/public/mojom/constants.mojom.h" #include "components/onc/onc_constants.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" +#include "services/service_manager/public/cpp/connector.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/image/image_skia.h" @@ -45,10 +45,13 @@ #include "ui/views/layout/fill_layout.h" #include "ui/views/view.h" -using chromeos::NetworkHandler; -using chromeos::NetworkState; -using chromeos::NetworkStateHandler; -using chromeos::NetworkTypePattern; +using chromeos::network_config::mojom::ConnectionStateType; +using chromeos::network_config::mojom::FilterType; +using chromeos::network_config::mojom::NetworkFilter; +using chromeos::network_config::mojom::NetworkStateProperties; +using chromeos::network_config::mojom::NetworkStatePropertiesPtr; +using chromeos::network_config::mojom::NetworkType; +using chromeos::network_config::mojom::VPNType; namespace ash { namespace tray { @@ -62,23 +65,22 @@ // Indicates whether |network| belongs to this VPN provider. bool VpnProviderMatchesNetwork(const VPNProvider& provider, - const NetworkState& network) { - const NetworkState::VpnProviderInfo* network_vpn_provider = - network.vpn_provider(); + const NetworkStateProperties* network) { + DCHECK(network); // Never display non-VPN networks or VPNs with no provider info. - if (network.type() != shill::kTypeVPN || !network_vpn_provider) + if (network->type != NetworkType::kVPN) return false; // Package name is the vpn provider id for ArcVPNProvider in network state. - if (network_vpn_provider->type == shill::kProviderArcVpn) { + if (network->vpn->type == VPNType::kArcVPN) { return provider.provider_type == VPNProvider::ARC_VPN && - network_vpn_provider->id == provider.package_name; - } else if (network_vpn_provider->type == shill::kProviderThirdPartyVpn) { - return provider.provider_type == VPNProvider::THIRD_PARTY_VPN && - network_vpn_provider->id == provider.app_id; - } else { - return provider.provider_type == VPNProvider::BUILT_IN_VPN; + network->vpn->provider_id == provider.package_name; } + if (network->vpn->type == VPNType::kThirdPartyVPN) { + return provider.provider_type == VPNProvider::THIRD_PARTY_VPN && + network->vpn->provider_id == provider.app_id; + } + return provider.provider_type == VPNProvider::BUILT_IN_VPN; } // Returns the PrefService that should be used for kVpnConfigAllowed, which is @@ -163,7 +165,8 @@ class VPNListNetworkEntry : public HoverHighlightView, public network_icon::AnimationObserver { public: - VPNListNetworkEntry(VPNListView* vpn_list_view, const NetworkState* network); + VPNListNetworkEntry(VPNListView* vpn_list_view, + const NetworkStateProperties* network); ~VPNListNetworkEntry() override; // network_icon::AnimationObserver: @@ -173,7 +176,8 @@ void ButtonPressed(Button* sender, const ui::Event& event) override; private: - void UpdateFromNetworkState(const NetworkState* network); + void OnGetNetworkState(NetworkStatePropertiesPtr result); + void UpdateFromNetworkState(const NetworkStateProperties* network); VPNListView* const owner_; const std::string guid_; @@ -184,8 +188,8 @@ }; VPNListNetworkEntry::VPNListNetworkEntry(VPNListView* owner, - const NetworkState* network) - : HoverHighlightView(owner), owner_(owner), guid_(network->guid()) { + const NetworkStateProperties* network) + : HoverHighlightView(owner), owner_(owner), guid_(network->guid) { UpdateFromNetworkState(network); } @@ -194,9 +198,13 @@ } void VPNListNetworkEntry::NetworkIconChanged() { - UpdateFromNetworkState( - NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( - guid_)); + chromeos::network_config::mojom::CrosNetworkConfig* cros_network_config = + owner_->cros_network_config(); + if (!cros_network_config) + return; + cros_network_config->GetNetworkState( + guid_, base::BindOnce(&VPNListNetworkEntry::OnGetNetworkState, + base::Unretained(this))); } void VPNListNetworkEntry::ButtonPressed(Button* sender, @@ -206,11 +214,17 @@ return; } + // TODO(stevenjb): Replace with mojo API. https://crbug.com/862420. chromeos::NetworkConnect::Get()->DisconnectFromNetworkId(guid_); } -void VPNListNetworkEntry::UpdateFromNetworkState(const NetworkState* vpn) { - if (vpn && vpn->IsConnectingState()) +void VPNListNetworkEntry::OnGetNetworkState(NetworkStatePropertiesPtr result) { + UpdateFromNetworkState(result.get()); +} + +void VPNListNetworkEntry::UpdateFromNetworkState( + const NetworkStateProperties* vpn) { + if (vpn && vpn->connection_state == ConnectionStateType::kConnecting) network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); else network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); @@ -229,7 +243,7 @@ base::string16 label = network_icon::GetLabelForNetwork( vpn_icon_state, network_icon::ICON_TYPE_MENU_LIST); AddIconAndLabel(image, label); - if (vpn->IsConnectedState()) { + if (chromeos::network_config::StateIsConnected(vpn->connection_state)) { owner_->SetupConnectedScrollListItem(this); if (IsVpnConfigAllowed()) { disconnect_button_ = TrayPopupUtils::CreateTrayPopupButton( @@ -241,7 +255,7 @@ views::CreateEmptyBorder( 0, kTrayPopupButtonEndMargin - kTrayPopupLabelHorizontalPadding, 0, kTrayPopupButtonEndMargin)); - } else if (vpn->IsConnectingState()) { + } else if (vpn->connection_state == ConnectionStateType::kConnecting) { owner_->SetupConnectingScrollListItem(this); } @@ -253,6 +267,7 @@ VPNListView::VPNListView(DetailedViewDelegate* delegate, LoginStatus login) : NetworkStateListDetailedView(delegate, LIST_TYPE_VPN, login) { Shell::Get()->vpn_list()->AddObserver(this); + BindCrosNetworkConfig(); } VPNListView::~VPNListView() { @@ -260,6 +275,15 @@ } void VPNListView::UpdateNetworkList() { + DCHECK(cros_network_config_ptr_); + cros_network_config_ptr_->GetNetworkStateList( + NetworkFilter::New(FilterType::kVisible, NetworkType::kVPN, + chromeos::network_config::mojom::kNoLimit), + base::BindOnce(&VPNListView::OnGetNetworkStateList, + base::Unretained(this))); +} + +void VPNListView::OnGetNetworkStateList(NetworkStateList networks) { // Before updating the list, determine whether the user was hovering over one // of the VPN provider or network entries. std::unique_ptr<VPNProvider> hovered_provider; @@ -287,11 +311,6 @@ network_view_guid_map_.clear(); list_empty_ = true; - // Get the list of available VPN networks, in shill's priority order. - NetworkStateHandler::NetworkStateList networks; - NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkListByType( - NetworkTypePattern::VPN(), &networks); - // Show all VPN providers and all networks that are currently disconnected. AddProvidersAndNetworks(networks); @@ -344,20 +363,34 @@ PrefRegistry::PUBLIC); } -void VPNListView::AddNetwork(const NetworkState* network) { +void VPNListView::BindCrosNetworkConfig() { + // Ensure binding is reset in case this is called after a failure. + cros_network_config_ptr_.reset(); + + service_manager::Connector* connector = Shell::Get()->connector(); + if (!connector) + return; + connector->BindInterface(chromeos::network_config::mojom::kServiceName, + &cros_network_config_ptr_); + + // If the connection is lost (e.g. due to a crash), attempt to rebind it. + cros_network_config_ptr_.set_connection_error_handler(base::BindOnce( + &VPNListView::BindCrosNetworkConfig, base::Unretained(this))); +} + +void VPNListView::AddNetwork(const NetworkStateProperties* network) { views::View* entry(new VPNListNetworkEntry(this, network)); scroll_content()->AddChildView(entry); - network_view_guid_map_[entry] = network->guid(); + network_view_guid_map_[entry] = network->guid; list_empty_ = false; } void VPNListView::AddProviderAndNetworks(const VPNProvider& vpn_provider) { - AddProviderAndNetworks(vpn_provider, NetworkStateHandler::NetworkStateList()); + AddProviderAndNetworks(vpn_provider, {}); } -void VPNListView::AddProviderAndNetworks( - const VPNProvider& vpn_provider, - const NetworkStateHandler::NetworkStateList& networks) { +void VPNListView::AddProviderAndNetworks(const VPNProvider& vpn_provider, + const NetworkStateList& networks) { // Add a visual separator, unless this is the topmost entry in the list. if (!list_empty_) { scroll_content()->AddChildView(CreateListSubHeaderSeparator()); @@ -376,19 +409,19 @@ list_empty_ = false; // Add the networks belonging to this provider, in the priority order returned // by shill. - for (const NetworkState* const& network : networks) { - if (VpnProviderMatchesNetwork(vpn_provider, *network)) - AddNetwork(network); + for (const auto& network : networks) { + if (VpnProviderMatchesNetwork(vpn_provider, network.get())) + AddNetwork(network.get()); } } bool VPNListView::ProcessProviderForNetwork( - const NetworkState* network, - const NetworkStateHandler::NetworkStateList& networks, + const NetworkStateProperties* network, + const NetworkStateList& networks, std::vector<VPNProvider>* providers) { for (auto provider_iter = providers->begin(); provider_iter != providers->end(); ++provider_iter) { - if (!VpnProviderMatchesNetwork(*provider_iter, *network)) + if (!VpnProviderMatchesNetwork(*provider_iter, network)) continue; AddProviderAndNetworks(*provider_iter, networks); providers->erase(provider_iter); @@ -397,8 +430,7 @@ return false; } -void VPNListView::AddProvidersAndNetworks( - const NetworkStateHandler::NetworkStateList& networks) { +void VPNListView::AddProvidersAndNetworks(const NetworkStateList& networks) { // Get the list of VPN providers enabled in the primary user's profile. std::vector<VPNProvider> extension_providers = Shell::Get()->vpn_list()->extension_vpn_providers(); @@ -410,23 +442,23 @@ // Add connected ARCVPN network. If we can find the correct provider, nest // the network under the provider. Otherwise list it unnested. - for (const NetworkState* network : networks) { - if (!network->IsConnectingOrConnected()) + for (const auto& network : networks) { + if (network->connection_state == ConnectionStateType::kNotConnected) break; - if (network->GetVpnProviderType() != shill::kProviderArcVpn) + if (network->vpn->type != VPNType::kArcVPN) continue; // If no matched provider found for this network. Show it unnested. // TODO(lgcheng@) add UMA status to track this. - if (!ProcessProviderForNetwork(network, networks, &arc_providers)) - AddNetwork(network); + if (!ProcessProviderForNetwork(network.get(), networks, &arc_providers)) + AddNetwork(network.get()); } // Add providers with at least one configured network along with their // networks. Providers are added in the order of their highest priority // network. - for (const NetworkState* network : networks) - ProcessProviderForNetwork(network, networks, &extension_providers); + for (const auto& network : networks) + ProcessProviderForNetwork(network.get(), networks, &extension_providers); // Add providers without any configured networks, in the order that the // providers were returned by the extensions system.
diff --git a/ash/system/network/vpn_list_view.h b/ash/system/network/vpn_list_view.h index a1032e82..4ff980da 100644 --- a/ash/system/network/vpn_list_view.h +++ b/ash/system/network/vpn_list_view.h
@@ -11,14 +11,10 @@ #include "ash/system/network/network_state_list_detailed_view.h" #include "ash/system/network/vpn_list.h" #include "base/macros.h" -#include "chromeos/network/network_state_handler.h" +#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h" class PrefRegistrySimple; -namespace chromeos { -class NetworkState; -} - namespace views { class View; } @@ -56,12 +52,22 @@ // VpnList::Observer: void OnVPNProvidersChanged() override; + chromeos::network_config::mojom::CrosNetworkConfig* cros_network_config() { + return cros_network_config_ptr_.get(); + } + // See Shell::RegisterProfilePrefs(). static void RegisterProfilePrefs(PrefRegistrySimple* registry); private: + using NetworkStateList = + std::vector<chromeos::network_config::mojom::NetworkStatePropertiesPtr>; + void BindCrosNetworkConfig(); + void OnGetNetworkStateList(NetworkStateList networks); + // Adds a network to the list. - void AddNetwork(const chromeos::NetworkState* network); + void AddNetwork( + const chromeos::network_config::mojom::NetworkStateProperties* network); // Adds the VPN provider identified by |vpn_provider| to the list, along with // no networks that belong to this provider. @@ -69,9 +75,8 @@ // Adds the VPN provider identified by |vpn_provider| to the list, along with // any networks that belong to this provider. - void AddProviderAndNetworks( - const VPNProvider& vpn_provider, - const chromeos::NetworkStateHandler::NetworkStateList& networks); + void AddProviderAndNetworks(const VPNProvider& vpn_provider, + const NetworkStateList& networks); // Finds VPN provider from |providers| that matches given |network|. Then adds // the VPN provider along with any networks that belong to this provider. Will @@ -79,13 +84,15 @@ // entry in VPN list view. // Returns true if finds a match, returns false otherwise. bool ProcessProviderForNetwork( - const chromeos::NetworkState* network, - const chromeos::NetworkStateHandler::NetworkStateList& networks, + const chromeos::network_config::mojom::NetworkStateProperties* network, + const NetworkStateList& networks, std::vector<VPNProvider>* providers); // Adds all available VPN providers and networks to the list. - void AddProvidersAndNetworks( - const chromeos::NetworkStateHandler::NetworkStateList& networks); + void AddProvidersAndNetworks(const NetworkStateList& networks); + + chromeos::network_config::mojom::CrosNetworkConfigPtr + cros_network_config_ptr_; // A mapping from each VPN provider's list entry to the provider. std::map<const views::View* const, VPNProvider> provider_view_map_;
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc index 27c42436..f2d6953 100644 --- a/ash/system/palette/palette_tray_unittest.cc +++ b/ash/system/palette/palette_tray_unittest.cc
@@ -19,7 +19,6 @@ #include "ash/session/session_controller_impl.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/palette/palette_tray_test_api.h" #include "ash/system/palette/palette_utils.h" #include "ash/system/palette/palette_welcome_bubble.h"
diff --git a/ash/system/palette/tools/create_note_unittest.cc b/ash/system/palette/tools/create_note_unittest.cc index bd79e61..274000eaf 100644 --- a/ash/system/palette/tools/create_note_unittest.cc +++ b/ash/system/palette/tools/create_note_unittest.cc
@@ -6,7 +6,6 @@ #include "ash/note_taking_controller.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/palette/mock_palette_tool_delegate.h" #include "ash/system/palette/palette_ids.h" #include "ash/system/palette/palette_tool.h"
diff --git a/ash/system/palette/tools/metalayer_unittest.cc b/ash/system/palette/tools/metalayer_unittest.cc index 67cc204..a6db795b 100644 --- a/ash/system/palette/tools/metalayer_unittest.cc +++ b/ash/system/palette/tools/metalayer_unittest.cc
@@ -8,7 +8,6 @@ #include "ash/highlighter/highlighter_controller_test_api.h" #include "ash/public/interfaces/voice_interaction_controller.mojom.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/palette/mock_palette_tool_delegate.h" #include "ash/system/palette/palette_ids.h" #include "ash/system/palette/palette_tool.h"
diff --git a/ash/system/palette/tools/screenshot_unittest.cc b/ash/system/palette/tools/screenshot_unittest.cc index 149d8a90..0ef288ee 100644 --- a/ash/system/palette/tools/screenshot_unittest.cc +++ b/ash/system/palette/tools/screenshot_unittest.cc
@@ -5,7 +5,6 @@ #include <memory> #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/palette/mock_palette_tool_delegate.h" #include "ash/system/palette/palette_ids.h" #include "ash/system/palette/palette_tool.h"
diff --git a/ash/system/power/power_button_test_base.cc b/ash/system/power/power_button_test_base.cc index c405777..2c0f5ea 100644 --- a/ash/system/power/power_button_test_base.cc +++ b/ash/system/power/power_button_test_base.cc
@@ -5,10 +5,10 @@ #include "ash/system/power/power_button_test_base.h" #include "ash/public/cpp/ash_switches.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/session/session_controller_impl.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/power/power_button_controller.h" #include "ash/system/power/power_button_controller_test_api.h" #include "ash/wm/lock_state_controller.h"
diff --git a/ash/system/power/power_prefs_unittest.cc b/ash/system/power/power_prefs_unittest.cc index 08127ea..7f4a8cb3 100644 --- a/ash/system/power/power_prefs_unittest.cc +++ b/ash/system/power/power_prefs_unittest.cc
@@ -10,10 +10,10 @@ #include <vector> #include "ash/public/cpp/ash_pref_names.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/session/session_controller_impl.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "base/json/json_reader.h" #include "base/macros.h" @@ -187,7 +187,7 @@ NoSessionAshTestBase::SetUp(); power_policy_controller_ = chromeos::PowerPolicyController::Get(); - power_prefs_ = ShellTestApi(Shell::Get()).power_prefs(); + power_prefs_ = ShellTestApi().power_prefs(); // Advance the clock an arbitrary amount of time so it won't report zero. tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index 9778d6c..df435adc 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc
@@ -15,6 +15,7 @@ #include "ash/keyboard/ash_keyboard_controller.h" #include "ash/keyboard/test_keyboard_ui.h" #include "ash/mojo_test_interface_factory.h" +#include "ash/public/cpp/ash_prefs.h" #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/test/test_keyboard_controller_observer.h" #include "ash/session/test_pref_service_provider.h" @@ -24,6 +25,7 @@ #include "ash/system/screen_layout_observer.h" #include "ash/test/ash_test_views_delegate.h" #include "ash/test_shell_delegate.h" +#include "ash/wallpaper/wallpaper_controller.h" #include "ash/wm/overview/overview_controller.h" #include "base/bind.h" #include "base/run_loop.h" @@ -134,7 +136,7 @@ ui::MaterialDesignController::Initialize(); - CreateShell(); + CreateShell(provide_local_state); // Reset aura::Env to eliminate test dependency (https://crbug.com/586514). aura::test::EnvTestHelper env_helper(Shell::Get()->aura_env()); @@ -151,12 +153,6 @@ if (shell->cursor_manager()) shell->cursor_manager()->ShowCursor(); - if (provide_local_state) { - auto pref_service = std::make_unique<TestingPrefServiceSimple>(); - Shell::RegisterLocalStatePrefs(pref_service->registry(), true); - Shell::Get()->OnLocalStatePrefServiceInitialized(std::move(pref_service)); - } - prefs_provider_ = std::make_unique<TestPrefServiceProvider>(); session_controller_client_.reset(new TestSessionControllerClient( shell->session_controller(), prefs_provider_.get())); @@ -187,6 +183,9 @@ // Remove the app dragging animations delay for testing purposes. shell->overview_controller()->set_delayed_animation_task_delay_for_test( base::TimeDelta()); + + // Ensure tests have a wallpaper as placeholder. + shell->wallpaper_controller()->CreateEmptyWallpaperForTesting(); } void AshTestHelper::TearDown() { @@ -257,7 +256,7 @@ } PrefService* AshTestHelper::GetLocalStatePrefService() { - return Shell::Get()->local_state_.get(); + return Shell::Get()->local_state_; } aura::Window* AshTestHelper::CurrentContext() { @@ -272,7 +271,7 @@ return Shell::Get()->display_manager()->GetSecondaryDisplay(); } -void AshTestHelper::CreateShell() { +void AshTestHelper::CreateShell(bool provide_local_state) { const bool enable_pixel_output = false; context_factories_ = std::make_unique<ui::TestContextFactories>(enable_pixel_output); @@ -282,6 +281,15 @@ init_params.context_factory_private = context_factories_->GetContextFactoryPrivate(); init_params.keyboard_ui_factory = std::make_unique<TestKeyboardUIFactory>(); + + if (provide_local_state) { + auto pref_service = std::make_unique<TestingPrefServiceSimple>(); + RegisterLocalStatePrefs(pref_service->registry(), true); + + local_state_ = std::move(pref_service); + init_params.local_state = local_state_.get(); + } + Shell::CreateInstance(std::move(init_params)); }
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h index 184febc..d3cc44cb 100644 --- a/ash/test/ash_test_helper.h +++ b/ash/test/ash_test_helper.h
@@ -107,7 +107,7 @@ private: // Called when running in ash to create Shell. - void CreateShell(); + void CreateShell(bool provide_local_state); std::unique_ptr<chromeos::system::ScopedFakeStatisticsProvider> statistics_provider_; @@ -134,6 +134,8 @@ std::unique_ptr<TestKeyboardControllerObserver> test_keyboard_controller_observer_; + std::unique_ptr<PrefService> local_state_; + DISALLOW_COPY_AND_ASSIGN(AshTestHelper); };
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc index d0740db..7a69f01d 100644 --- a/ash/wallpaper/wallpaper_controller.cc +++ b/ash/wallpaper/wallpaper_controller.cc
@@ -860,6 +860,10 @@ const base::FilePath& device_policy_wallpaper_path) { DCHECK(!wallpaper_controller_client_.get()); wallpaper_controller_client_ = std::move(client); + + DCHECK(local_state_); + wallpaper_controller_client_->OnReadyToSetWallpaper(); + SetGlobalUserDataDir(user_data_path); SetGlobalChromeOSWallpapersDir(chromeos_wallpapers_path); SetGlobalChromeOSCustomWallpapersDir(chromeos_custom_wallpapers_path); @@ -1364,13 +1368,8 @@ void WallpaperController::OnLocalStatePrefServiceInitialized( PrefService* pref_service) { + DCHECK(!wallpaper_controller_client_); local_state_ = pref_service; - if (wallpaper_controller_client_) { - wallpaper_controller_client_->OnReadyToSetWallpaper(); - } else { - // Ensure unit tests have a wallpaper as placeholder. - CreateEmptyWallpaperForTesting(); - } } void WallpaperController::OnShellInitialized() {
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc index 9c227ec5..f962980 100644 --- a/ash/wallpaper/wallpaper_controller_unittest.cc +++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -9,11 +9,11 @@ #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller_impl.h" #include "ash/session/test_session_controller_client.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "ash/wallpaper/wallpaper_controller_observer.h" #include "ash/wallpaper/wallpaper_utils/wallpaper_resizer.h" @@ -31,7 +31,6 @@ #include "base/test/bind_test_util.h" #include "base/time/time_override.h" #include "chromeos/constants/chromeos_switches.h" -#include "components/prefs/testing_pref_service.h" #include "mojo/public/cpp/bindings/associated_binding.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" @@ -2562,73 +2561,4 @@ EXPECT_EQ(kShellWindowId_WallpaperContainer, GetWallpaperContainerId()); } -// A test wallpaper controller client class. -class TestWallpaperControllerClient : public mojom::WallpaperControllerClient { - public: - TestWallpaperControllerClient() : binding_(this) {} - ~TestWallpaperControllerClient() override = default; - - int ready_to_set_wallpaper_count() const { - return ready_to_set_wallpaper_count_; - } - - mojom::WallpaperControllerClientPtr CreateInterfacePtr() { - mojom::WallpaperControllerClientPtr ptr; - binding_.Bind(mojo::MakeRequest(&ptr)); - return ptr; - } - - // mojom::WallpaperControllerClient: - void OnReadyToSetWallpaper() override { ++ready_to_set_wallpaper_count_; } - void OpenWallpaperPicker() override {} - void OnFirstWallpaperAnimationFinished() override {} - - private: - int ready_to_set_wallpaper_count_ = 0; - mojo::Binding<mojom::WallpaperControllerClient> binding_; - - DISALLOW_COPY_AND_ASSIGN(TestWallpaperControllerClient); -}; - -// Tests for cases when local state is not available. -class WallpaperControllerDisableLocalStateTest - : public WallpaperControllerTest { - public: - WallpaperControllerDisableLocalStateTest() = default; - ~WallpaperControllerDisableLocalStateTest() override = default; - - void SetUp() override { - disable_provide_local_state(); - WallpaperControllerTest::SetUp(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(WallpaperControllerDisableLocalStateTest); -}; - -TEST_F(WallpaperControllerDisableLocalStateTest, IgnoreShowUserWallpaper) { - TestWallpaperControllerClient client; - controller_->SetClientForTesting(client.CreateInterfacePtr()); - SimulateUserLogin(kUser1); - - // When local state is not available, verify |ShowUserWallpaper| request is - // ignored. - controller_->ShowUserWallpaper(InitializeUser(account_id_1)); - RunAllTasksUntilIdle(); - EXPECT_EQ(0, GetWallpaperCount()); - EXPECT_EQ(0, client.ready_to_set_wallpaper_count()); - - // Make local state available, verify |ShowUserWallpaper| successfully shows - // the wallpaper, and |OnReadyToSetWallpaper| is invoked. - std::unique_ptr<TestingPrefServiceSimple> local_state = - std::make_unique<TestingPrefServiceSimple>(); - Shell::RegisterLocalStatePrefs(local_state->registry(), true); - ShellTestApi().OnLocalStatePrefServiceInitialized(std::move(local_state)); - - controller_->ShowUserWallpaper(InitializeUser(account_id_1)); - RunAllTasksUntilIdle(); - EXPECT_EQ(1, GetWallpaperCount()); - EXPECT_EQ(1, client.ready_to_set_wallpaper_count()); -} - } // namespace ash
diff --git a/ash/wm/cursor_manager_test_api.cc b/ash/wm/cursor_manager_test_api.cc index 019a202..f4410da 100644 --- a/ash/wm/cursor_manager_test_api.cc +++ b/ash/wm/cursor_manager_test_api.cc
@@ -4,8 +4,8 @@ #include "ash/wm/cursor_manager_test_api.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/wm/native_cursor_manager_ash.h" #include "ui/base/cursor/image_cursors.h" #include "ui/display/display.h" @@ -29,11 +29,11 @@ display::Display::Rotation CursorManagerTestApi::GetCurrentCursorRotation() const { - return ShellTestApi(Shell::Get()).native_cursor_manager_ash()->GetRotation(); + return ShellTestApi().native_cursor_manager_ash()->GetRotation(); } float CursorManagerTestApi::GetCurrentCursorScale() const { - return ShellTestApi(Shell::Get()).native_cursor_manager_ash()->GetScale(); + return ShellTestApi().native_cursor_manager_ash()->GetScale(); } } // namespace ash
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc index 136ef55..e10938d7 100644 --- a/ash/wm/system_gesture_event_filter_unittest.cc +++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -8,7 +8,6 @@ #include "ash/accelerators/accelerator_controller_impl.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "ash/window_factory.h" #include "ash/wm/window_positioning_utils.h"
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc index 49eeeda5..47d22fb 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -8,6 +8,7 @@ #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/shelf_prefs.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/cpp/window_state_type.h" #include "ash/root_window_controller.h" @@ -16,7 +17,6 @@ #include "ash/session/test_session_controller_client.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/overview_controller.h"
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc index 074d552d..9edb6f7 100644 --- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc +++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -6,9 +6,9 @@ #include "ash/frame/non_client_frame_view_ash.h" #include "ash/public/cpp/ash_constants.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/shelf/shelf_constants.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/test/ash_test_base.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" @@ -60,7 +60,7 @@ void SetUp() override { AshTestBase::SetUp(); - WorkspaceController* wc = ShellTestApi(Shell::Get()).workspace_controller(); + WorkspaceController* wc = ShellTestApi().workspace_controller(); WorkspaceEventHandler* event_handler = WorkspaceControllerTestApi(wc).GetEventHandler(); resize_controller_ =
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index 22ef4e0..5b08381 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -19,6 +19,7 @@ #include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/app_types.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_properties.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" @@ -29,7 +30,6 @@ #include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" #include "ash/shell_observer.h" -#include "ash/shell_test_api.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/test/ash_test_base.h" #include "ash/wallpaper/wallpaper_controller_test_api.h" @@ -1315,7 +1315,7 @@ } TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropTest) { - WorkspaceController* wc = ShellTestApi(Shell::Get()).workspace_controller(); + WorkspaceController* wc = ShellTestApi().workspace_controller(); WorkspaceControllerTestApi test_helper(wc); std::unique_ptr<aura::Window> window1( @@ -1475,7 +1475,7 @@ TEST_F(WorkspaceLayoutManagerBackdropTest, DoNotShowBackdropDuringWallpaperPreview) { - WorkspaceController* wc = ShellTestApi(Shell::Get()).workspace_controller(); + WorkspaceController* wc = ShellTestApi().workspace_controller(); WorkspaceControllerTestApi test_helper(wc); WallpaperControllerTestApi wallpaper_test_api( Shell::Get()->wallpaper_controller()); @@ -1512,7 +1512,7 @@ } TEST_F(WorkspaceLayoutManagerBackdropTest, SpokenFeedbackFullscreenBackground) { - WorkspaceController* wc = ShellTestApi(Shell::Get()).workspace_controller(); + WorkspaceController* wc = ShellTestApi().workspace_controller(); WorkspaceControllerTestApi test_helper(wc); AccessibilityController* controller = Shell::Get()->accessibility_controller(); @@ -1571,7 +1571,7 @@ // TODO(crbug.com/803286): The npot texture check failed on asan tests bot. // TODO(crbug.com/838756): Very flaky on mash_ash_unittests. TEST_F(WorkspaceLayoutManagerBackdropTest, DISABLED_OpenAppListInOverviewMode) { - WorkspaceController* wc = ShellTestApi(Shell::Get()).workspace_controller(); + WorkspaceController* wc = ShellTestApi().workspace_controller(); WorkspaceControllerTestApi test_helper(wc); std::unique_ptr<aura::Window> window( @@ -1596,7 +1596,7 @@ } TEST_F(WorkspaceLayoutManagerBackdropTest, SpokenFeedbackForArc) { - WorkspaceController* wc = ShellTestApi(Shell::Get()).workspace_controller(); + WorkspaceController* wc = ShellTestApi().workspace_controller(); WorkspaceControllerTestApi test_helper(wc); AccessibilityController* controller = Shell::Get()->accessibility_controller(); @@ -2051,7 +2051,7 @@ TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropWindowIsNotReparentedFromAlwaysOnTopContainer) { - WorkspaceController* wc = ShellTestApi(Shell::Get()).workspace_controller(); + WorkspaceController* wc = ShellTestApi().workspace_controller(); WorkspaceControllerTestApi test_helper(wc); RootWindowController* controller = Shell::GetPrimaryRootWindowController(); AlwaysOnTopController* always_on_top_controller =
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc index 0394a68f..f18a36e 100644 --- a/ash/wm/workspace_controller_unittest.cc +++ b/ash/wm/workspace_controller_unittest.cc
@@ -13,7 +13,6 @@ #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/status_area_widget.h" #include "ash/test/ash_test_base.h" #include "ash/window_factory.h"
diff --git a/base/BUILD.gn b/base/BUILD.gn index da61f4b..04e650d 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2978,7 +2978,7 @@ if (is_win) { deps += [ "//base:scoped_handle_test_dll" ] - if (current_cpu == "x64") { + if (current_cpu == "x64" || current_cpu == "arm64") { sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ] data_deps += [ ":base_profiler_test_support_library" ] }
diff --git a/base/fuchsia/filtered_service_directory.cc b/base/fuchsia/filtered_service_directory.cc index 28ee3a2..02cf09a5 100644 --- a/base/fuchsia/filtered_service_directory.cc +++ b/base/fuchsia/filtered_service_directory.cc
@@ -36,11 +36,11 @@ FilteredServiceDirectory::ConnectClient() { fidl::InterfaceHandle<::fuchsia::io::Directory> client; - // ServiceDirectory puts public services under ./public . Connect to that + // ServiceDirectory puts public services under ./svc . Connect to that // directory and return client handle for the connection, - zx_status_t status = fdio_service_connect_at( - outgoing_directory_client_.channel().get(), "public", - client.NewRequest().TakeChannel().release()); + zx_status_t status = + fdio_service_connect_at(outgoing_directory_client_.channel().get(), "svc", + client.NewRequest().TakeChannel().release()); ZX_CHECK(status == ZX_OK, status) << "fdio_service_connect_at()"; return client;
diff --git a/base/fuchsia/service_directory.cc b/base/fuchsia/service_directory.cc index 334ef9a..58b3cb7 100644 --- a/base/fuchsia/service_directory.cc +++ b/base/fuchsia/service_directory.cc
@@ -60,11 +60,17 @@ std::string name_str = name.as_string(); services_[name_str] = connect_callback; + // Publish to "svc". zx_status_t status = - svc_dir_add_service(svc_dir_, "public", name_str.c_str(), this, + svc_dir_add_service(svc_dir_, "svc", name_str.c_str(), this, &ServiceDirectory::HandleConnectRequest); ZX_DCHECK(status == ZX_OK, status); + // Publish to "public" for compatibility. + status = svc_dir_add_service(svc_dir_, "public", name_str.c_str(), this, + &ServiceDirectory::HandleConnectRequest); + ZX_DCHECK(status == ZX_OK, status); + // Publish to the legacy "flat" namespace, which is required by some clients. status = svc_dir_add_service(svc_dir_, nullptr, name_str.c_str(), this, &ServiceDirectory::HandleConnectRequest); @@ -81,11 +87,12 @@ DCHECK(it != services_.end()); services_.erase(it); + // Unregister from "svc", "public", and flat namespace. zx_status_t status = - svc_dir_remove_service(svc_dir_, "public", name_str.c_str()); + svc_dir_remove_service(svc_dir_, "svc", name_str.c_str()); ZX_DCHECK(status == ZX_OK, status); - - // Unregister from the legacy "flat" namespace. + status = svc_dir_remove_service(svc_dir_, "public", name_str.c_str()); + ZX_DCHECK(status == ZX_OK, status); status = svc_dir_remove_service(svc_dir_, nullptr, name_str.c_str()); ZX_DCHECK(status == ZX_OK, status); }
diff --git a/base/fuchsia/service_directory_test_base.cc b/base/fuchsia/service_directory_test_base.cc index 7067d94..5fabd10b 100644 --- a/base/fuchsia/service_directory_test_base.cc +++ b/base/fuchsia/service_directory_test_base.cc
@@ -22,13 +22,23 @@ std::make_unique<ScopedServiceBinding<testfidl::TestInterface>>( service_directory_.get(), &test_service_); - // Create the ServiceDirectoryClient, connected to the "public" sub-directory. + // Create the ServiceDirectoryClient, connected to the "svc" sub-directory. + fidl::InterfaceHandle<::fuchsia::io::Directory> svc_directory; + CHECK_EQ(fdio_service_connect_at( + directory.channel().get(), "/svc/.", + svc_directory.NewRequest().TakeChannel().release()), + ZX_OK); + public_service_directory_client_ = + std::make_unique<ServiceDirectoryClient>(std::move(svc_directory)); + + // Create the ServiceDirectoryClient, connected to the "public" sub-directory + // (same contents as "svc", provided for compatibility). fidl::InterfaceHandle<::fuchsia::io::Directory> public_directory; CHECK_EQ(fdio_service_connect_at( directory.channel().get(), "/public/.", public_directory.NewRequest().TakeChannel().release()), ZX_OK); - public_service_directory_client_ = + legacy_public_service_directory_client_ = std::make_unique<ServiceDirectoryClient>(std::move(public_directory)); // Create a ServiceDirectoryClient for the "private" part of the directory.
diff --git a/base/fuchsia/service_directory_test_base.h b/base/fuchsia/service_directory_test_base.h index bef8286..6b2c7ca6 100644 --- a/base/fuchsia/service_directory_test_base.h +++ b/base/fuchsia/service_directory_test_base.h
@@ -35,6 +35,8 @@ service_binding_; std::unique_ptr<ServiceDirectoryClient> public_service_directory_client_; + std::unique_ptr<ServiceDirectoryClient> + legacy_public_service_directory_client_; std::unique_ptr<ServiceDirectoryClient> root_service_directory_client_; DISALLOW_COPY_AND_ASSIGN(ServiceDirectoryTestBase);
diff --git a/base/fuchsia/service_directory_unittest.cc b/base/fuchsia/service_directory_unittest.cc index 2f8d1b9..cd9b471 100644 --- a/base/fuchsia/service_directory_unittest.cc +++ b/base/fuchsia/service_directory_unittest.cc
@@ -47,7 +47,17 @@ run_loop.Run(); } -// Verifies that we can connect to the service service more than once. +// Verify that we can connect to a service through both "public" and "svc". +TEST_F(ServiceDirectoryTest, ConnectNewAndLegacyServices) { + auto stub = public_service_directory_client_ + ->ConnectToService<testfidl::TestInterface>(); + auto stub2 = legacy_public_service_directory_client_ + ->ConnectToService<testfidl::TestInterface>(); + VerifyTestInterface(&stub, ZX_OK); + VerifyTestInterface(&stub2, ZX_OK); +} + +// Verify that we can connect to the same service more than once. TEST_F(ServiceDirectoryTest, ConnectMulti) { auto stub = public_service_directory_client_ ->ConnectToService<testfidl::TestInterface>();
diff --git a/base/fuchsia/startup_context.h b/base/fuchsia/startup_context.h index dd0dd174..fa4e330 100644 --- a/base/fuchsia/startup_context.h +++ b/base/fuchsia/startup_context.h
@@ -32,7 +32,7 @@ return incoming_services_.get(); } - // Returns the "public" directory into which this component binds services. + // Returns the outgoing directory into which this component binds services. // Note that all services should be bound immediately after the first call to // this API, before returning control to the message loop, at which point we // will start processing service connection requests.
diff --git a/base/immediate_crash_unittest.cc b/base/immediate_crash_unittest.cc index d733013..08685df 100644 --- a/base/immediate_crash_unittest.cc +++ b/base/immediate_crash_unittest.cc
@@ -8,10 +8,12 @@ #include <algorithm> +#include "base/base_paths.h" #include "base/containers/span.h" #include "base/files/file_path.h" #include "base/native_library.h" #include "base/optional.h" +#include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,11 +31,18 @@ // TestFunction1() and TestFunction2() are defined in a shared library in an // attempt to guarantee that they are located next to each other. NativeLibraryLoadError load_error; + FilePath helper_library_path; +#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA) + // On Android M, DIR_EXE == /system/bin when running base_unittests. + // On Fuchsia, NativeLibrary understands the native convention that libraries + // are not colocated with the binary. + ASSERT_TRUE(PathService::Get(DIR_EXE, &helper_library_path)); +#endif + helper_library_path = helper_library_path.AppendASCII( + GetNativeLibraryName("immediate_crash_test_helper")); // TODO(dcheng): Shouldn't GetNativeLibraryName just return a FilePath? - NativeLibrary helper_library = LoadNativeLibrary( - FilePath::FromUTF8Unsafe( - GetNativeLibraryName("immediate_crash_test_helper")), - &load_error); + NativeLibrary helper_library = + LoadNativeLibrary(helper_library_path, &load_error); ASSERT_TRUE(helper_library) << "shared library load failed: " << load_error.ToString();
diff --git a/base/profiler/native_unwinder_win.cc b/base/profiler/native_unwinder_win.cc index bd93438..813351c 100644 --- a/base/profiler/native_unwinder_win.cc +++ b/base/profiler/native_unwinder_win.cc
@@ -4,6 +4,8 @@ #include "base/profiler/native_unwinder_win.h" +#include <winnt.h> + #include "base/profiler/native_unwinder.h" #include "base/profiler/win32_stack_frame_unwinder.h" @@ -49,8 +51,7 @@ return UnwindResult::UNRECOGNIZED_FRAME; } - const uintptr_t prev_stack_pointer = - RegisterContextStackPointer(thread_context); + uintptr_t prev_stack_pointer = RegisterContextStackPointer(thread_context); if (!frame_unwinder.TryUnwind(stack->size() == 1u, thread_context, stack->back().module)) { return UnwindResult::ABORTED; @@ -60,6 +61,13 @@ return UnwindResult::COMPLETED; // Abort if the unwind produced an invalid stack pointer. +#if defined(ARCH_CPU_ARM64) + // Leaf frames on Arm can re-use the stack pointer, so they can validly have + // the same stack pointer as the previous frame. + if (stack->size() == 1u) { + prev_stack_pointer--; + } +#endif if (RegisterContextStackPointer(thread_context) <= prev_stack_pointer || RegisterContextStackPointer(thread_context) >= stack_top) { return UnwindResult::ABORTED;
diff --git a/base/profiler/stack_sampler_win.cc b/base/profiler/stack_sampler_win.cc index 214cf0d..fb09fb7 100644 --- a/base/profiler/stack_sampler_win.cc +++ b/base/profiler/stack_sampler_win.cc
@@ -16,7 +16,7 @@ PlatformThreadId thread_id, ModuleCache* module_cache, StackSamplerTestDelegate* test_delegate) { -#if defined(ARCH_CPU_X86_64) +#if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM64) return std::make_unique<StackSamplerImpl>( std::make_unique<ThreadDelegateWin>(thread_id), std::make_unique<NativeUnwinderWin>(), module_cache, test_delegate);
diff --git a/base/profiler/win32_stack_frame_unwinder.cc b/base/profiler/win32_stack_frame_unwinder.cc index 82bea4f..700e747 100644 --- a/base/profiler/win32_stack_frame_unwinder.cc +++ b/base/profiler/win32_stack_frame_unwinder.cc
@@ -55,7 +55,7 @@ PRUNTIME_FUNCTION runtime_function, CONTEXT* context) { #ifdef _WIN64 - void* handler_data; + void* handler_data = nullptr; ULONG64 establisher_frame; KNONVOLATILE_CONTEXT_POINTERS nvcontext = {}; ::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, program_counter,
diff --git a/base/profiler/win32_stack_frame_unwinder_unittest.cc b/base/profiler/win32_stack_frame_unwinder_unittest.cc index 2282a28..6158661 100644 --- a/base/profiler/win32_stack_frame_unwinder_unittest.cc +++ b/base/profiler/win32_stack_frame_unwinder_unittest.cc
@@ -99,19 +99,33 @@ EXPECT_EQ(&runtime_functions_.back(), runtime_function); } +static void SetContextPc(CONTEXT* context, DWORD64 val) { +#if defined(ARCH_CPU_ARM64) + context->Pc = val; +#else + context->Rip = val; +#endif +} + void TestUnwindFunctions::SetHasRuntimeFunction(CONTEXT* context) { RUNTIME_FUNCTION runtime_function = {}; runtime_function.BeginAddress = 16; +#if defined(ARCH_CPU_ARM64) + runtime_function.FunctionLength = 256; +#else runtime_function.EndAddress = runtime_function.BeginAddress + 256; +#endif + runtime_functions_.push_back(runtime_function); next_runtime_function_ = &runtime_functions_.back(); - - expected_program_counter_ = context->Rip = + expected_program_counter_ = next_image_base_ + runtime_function.BeginAddress + 8; + SetContextPc(context, expected_program_counter_); } void TestUnwindFunctions::SetNoRuntimeFunction(CONTEXT* context) { - expected_program_counter_ = context->Rip = 100; + expected_program_counter_ = 100; + SetContextPc(context, expected_program_counter_); next_runtime_function_ = nullptr; } @@ -166,13 +180,23 @@ CONTEXT context = {0}; DWORD64 next_ip = 0x0123456789abcdef; DWORD64 original_rsp = reinterpret_cast<DWORD64>(&next_ip); +#if defined(ARCH_CPU_ARM64) + context.Sp = original_rsp; + context.Lr = next_ip; + context.ContextFlags |= CONTEXT_UNWOUND_TO_CALL; +#else context.Rsp = original_rsp; +#endif TestModule stub_module(kImageBaseIncrement); unwind_functions_->SetNoRuntimeFunction(&context); EXPECT_TRUE(unwinder->TryUnwind(true, &context, &stub_module)); +#if defined(ARCH_CPU_ARM64) + EXPECT_EQ(next_ip, context.Pc); +#else EXPECT_EQ(next_ip, context.Rip); EXPECT_EQ(original_rsp + 8, context.Rsp); +#endif } // Checks that a frame below the top of the stack with missing unwind info
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index c362365..f501a921 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8913494742826269904 \ No newline at end of file +8913465501118992272 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 374e6fa96..613e233 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8913500794202025136 \ No newline at end of file +8913468411235898544 \ No newline at end of file
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 1f0d576..34007a05 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -601,6 +601,10 @@ inputs_.backdrop_filter_bounds = backdrop_filter_bounds; } +void Layer::ClearBackdropFilterBounds() { + inputs_.backdrop_filter_bounds.reset(); +} + void Layer::SetBackdropFilterQuality(const float quality) { inputs_.backdrop_filter_quality = quality; }
diff --git a/cc/layers/layer.h b/cc/layers/layer.h index 696009b4..5766981 100644 --- a/cc/layers/layer.h +++ b/cc/layers/layer.h
@@ -316,7 +316,8 @@ } void SetBackdropFilterBounds(const gfx::RRectF& backdrop_filter_bounds); - const gfx::RRectF& backdrop_filter_bounds() const { + void ClearBackdropFilterBounds(); + const base::Optional<gfx::RRectF>& backdrop_filter_bounds() const { return inputs_.backdrop_filter_bounds; } @@ -952,7 +953,7 @@ FilterOperations filters; FilterOperations backdrop_filters; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; gfx::PointF filters_origin; float backdrop_filter_quality;
diff --git a/cc/layers/layer_impl_test_properties.h b/cc/layers/layer_impl_test_properties.h index c29aee7..a06e0b6 100644 --- a/cc/layers/layer_impl_test_properties.h +++ b/cc/layers/layer_impl_test_properties.h
@@ -49,7 +49,7 @@ float opacity; FilterOperations filters; FilterOperations backdrop_filters; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; float backdrop_filter_quality; gfx::PointF filters_origin; SkBlendMode blend_mode;
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc index 546f68d..6acd6825c 100644 --- a/cc/layers/render_surface_impl.cc +++ b/cc/layers/render_surface_impl.cc
@@ -153,7 +153,7 @@ return OwningEffectNode()->backdrop_filters; } -const gfx::RRectF& RenderSurfaceImpl::BackdropFilterBounds() const { +base::Optional<gfx::RRectF> RenderSurfaceImpl::BackdropFilterBounds() const { return OwningEffectNode()->backdrop_filter_bounds; }
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h index 15dd8c9..89a270c 100644 --- a/cc/layers/render_surface_impl.h +++ b/cc/layers/render_surface_impl.h
@@ -159,7 +159,7 @@ const FilterOperations& Filters() const; const FilterOperations& BackdropFilters() const; - const gfx::RRectF& BackdropFilterBounds() const; + base::Optional<gfx::RRectF> BackdropFilterBounds() const; gfx::PointF FiltersOrigin() const; gfx::Transform SurfaceScale() const;
diff --git a/cc/trees/effect_node.cc b/cc/trees/effect_node.cc index acf8f94..dc8464c 100644 --- a/cc/trees/effect_node.cc +++ b/cc/trees/effect_node.cc
@@ -43,6 +43,8 @@ EffectNode::EffectNode(const EffectNode& other) = default; +EffectNode::~EffectNode() = default; + bool EffectNode::operator==(const EffectNode& other) const { return id == other.id && parent_id == other.parent_id && stable_id == other.stable_id && opacity == other.opacity &&
diff --git a/cc/trees/effect_node.h b/cc/trees/effect_node.h index 46d285e9..5a485d36 100644 --- a/cc/trees/effect_node.h +++ b/cc/trees/effect_node.h
@@ -50,6 +50,7 @@ struct CC_EXPORT EffectNode { EffectNode(); EffectNode(const EffectNode& other); + ~EffectNode(); enum StableIdLabels { INVALID_STABLE_ID = 0 }; @@ -68,7 +69,7 @@ FilterOperations filters; FilterOperations backdrop_filters; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; float backdrop_filter_quality; gfx::PointF filters_origin;
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc index e291e0b..188d146 100644 --- a/cc/trees/layer_tree_host_pixeltest_blending.cc +++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -320,9 +320,8 @@ background->AddChild(green_lane); FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(.75)); - gfx::RRectF backdrop_filter_bounds; green_lane->SetBackdropFilters(filters); - green_lane->SetBackdropFilterBounds(backdrop_filter_bounds); + green_lane->ClearBackdropFilterBounds(); green_lane->SetBlendMode(current_blend_mode()); SkBitmap expected;
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc index 27e926e..ff3b2353 100644 --- a/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -276,8 +276,12 @@ filters.Append(FilterOperation::CreateBlurFilter( 2.f, SkBlurImageFilter::kClamp_TileMode)); blur->SetBackdropFilters(filters); - // TODO(916311): Fix clipping for 3D transformed elements. - blur->SetBackdropFilterBounds(gfx::RRectF()); + // TODO(916311): We should be able to set the bounds like this, but the + // resulting output is clipped incorrectly. + // gfx::RRectF + // backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())),0); + // blur->SetBackdropFilterBounds(backdrop_filter_bounds); + blur->ClearBackdropFilterBounds(); #if defined(OS_WIN) || defined(ARCH_CPU_ARM64) #if defined(OS_WIN) @@ -496,7 +500,7 @@ FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f)); filter->SetBackdropFilters(filters); - filter->SetBackdropFilterBounds(gfx::RRectF()); + filter->ClearBackdropFilterBounds(); #if defined(OS_WIN) || defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64) #if defined(OS_WIN) @@ -560,12 +564,9 @@ filters.Append(FilterOperation::CreateBlurFilter( 5.0f, SkBlurImageFilter::kClamp_TileMode)); filter_layer->SetBackdropFilters(filters); - // TODO(916311): Adding filter bounds here should work, but it clips - // the corner of the red box. - // gfx::RectF backdrop_filter_bounds(gfx::SizeF(filter_layer->bounds())); - gfx::RRectF backdrop_filter_bounds; + gfx::RRectF backdrop_filter_bounds( + gfx::RectF(gfx::SizeF(filter_layer->bounds())), 0); filter_layer->SetBackdropFilterBounds(backdrop_filter_bounds); - background->AddChild(filter_layer); // Allow some fuzziness so that this doesn't fail when Skia makes minor @@ -997,7 +998,7 @@ filters.Append(FilterOperation::CreateReferenceFilter( sk_make_sp<OffsetPaintFilter>(0, 80, nullptr))); filtered->SetBackdropFilters(filters); - filtered->SetBackdropFilterBounds(gfx::RRectF()); + filtered->ClearBackdropFilterBounds(); root->AddChild(filtered); // This should appear as a grid of 4 100x100 squares which are:
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc index aac9b10..7d85a9f 100644 --- a/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -832,9 +832,8 @@ FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0)); - gfx::RRectF backdrop_filter_bounds; blur->SetBackdropFilters(filters); - blur->SetBackdropFilterBounds(backdrop_filter_bounds); + blur->ClearBackdropFilterBounds(); gfx::Size mask_bounds(100, 100); CircleContentLayerClient mask_client(mask_bounds); @@ -1294,8 +1293,7 @@ FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0)); picture_horizontal->SetBackdropFilters(filters); - gfx::RRectF backdrop_filter_bounds; - picture_horizontal->SetBackdropFilterBounds(backdrop_filter_bounds); + picture_horizontal->ClearBackdropFilterBounds(); background->AddChild(picture_vertical); background->AddChild(picture_horizontal);
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc index 073e50c..b00fbb5 100644 --- a/cc/trees/property_tree_builder.cc +++ b/cc/trees/property_tree_builder.cc
@@ -795,11 +795,13 @@ return layer->test_properties()->backdrop_filters; } -static inline const gfx::RRectF& BackdropFilterBounds(Layer* layer) { +static inline const base::Optional<gfx::RRectF>& BackdropFilterBounds( + Layer* layer) { return layer->backdrop_filter_bounds(); } -static inline const gfx::RRectF& BackdropFilterBounds(LayerImpl* layer) { +static inline const base::Optional<gfx::RRectF>& BackdropFilterBounds( + LayerImpl* layer) { return layer->test_properties()->backdrop_filter_bounds; }
diff --git a/chrome/android/java/res/drawable/ic_offline_pin_24dp.xml b/chrome/android/java/res/drawable/ic_offline_pin_24dp.xml deleted file mode 100644 index 1a830666..0000000 --- a/chrome/android/java/res/drawable/ic_offline_pin_24dp.xml +++ /dev/null
@@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2019 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. --> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - tools:targetApi="21" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <group> - <clip-path android:pathData="M0,0h24v24H0V0z M 0,0"/> - <path - android:pathData="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10,-4.5 10,-10S17.5 2 12 2zm5 16H7v-2h10v2zm-6.7,-4L7 10.7l1.4,-1.4 1.9 1.9 5.3,-5.3L17 7.3 10.3 14z" - android:fillColor="@color/default_icon_color_secondary"/> - </group> -</vector>
diff --git a/chrome/android/java/res/drawable/ic_play_circle_filled_24dp.xml b/chrome/android/java/res/drawable/ic_play_circle_filled_24dp.xml deleted file mode 100644 index c8c7846..0000000 --- a/chrome/android/java/res/drawable/ic_play_circle_filled_24dp.xml +++ /dev/null
@@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 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. --> - -<!-- Note: hand-tweaked for foreground and background colors, not canonical icon. --> -<vector - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - tools:targetApi="21" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="@android:color/transparent" - android:pathData="M 6,6 H 18 V 18 H 6 z" /> - <path - android:fillColor="@color/default_icon_color_secondary" - android:pathData="M 12,2 C 6.475,2 2,6.475 2,12 2,17.525 6.475,22 12,22 17.525,22 22,17.525 - 22,12 22,6.475 17.525,2 12,2 z M 9.9999998,16.5 v -9 L 16,12 9.9999998,16.5 z" /> -</vector>
diff --git a/chrome/android/java/res/values/drawables.xml b/chrome/android/java/res/values/drawables.xml index e6eeff455..13b97976 100644 --- a/chrome/android/java/res/values/drawables.xml +++ b/chrome/android/java/res/values/drawables.xml
@@ -7,4 +7,8 @@ <drawable name="ntp_search_box">@drawable/modern_toolbar_text_box_background</drawable> <drawable name="badge_update">@drawable/badge_update_dark</drawable> <drawable name="ic_error_24dp_filled">@drawable/ic_error_grey800_24dp_filled</drawable> + <drawable name="ic_offline_pin_24dp">@drawable/ic_offline_pin_24dp_on_light_bg</drawable> + <drawable name="ic_play_circle_filled_24dp"> + @drawable/ic_play_circle_filled_24dp_on_light_bg + </drawable> </resources> \ No newline at end of file
diff --git a/chrome/android/java/res_night/values-night/drawables.xml b/chrome/android/java/res_night/values-night/drawables.xml index d51dc6d..0d6929ad 100644 --- a/chrome/android/java/res_night/values-night/drawables.xml +++ b/chrome/android/java/res_night/values-night/drawables.xml
@@ -5,4 +5,8 @@ <resources> <drawable name="badge_update">@drawable/badge_update_light</drawable> <drawable name="ic_error_24dp_filled">@drawable/ic_error_white_24dp_filled</drawable> + <drawable name="ic_offline_pin_24dp">@drawable/ic_offline_pin_24dp_on_dark_bg</drawable> + <drawable name="ic_play_circle_filled_24dp"> + @drawable/ic_play_circle_filled_24dp_on_dark_bg + </drawable> </resources> \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java index adb72c5f..7b8283d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.appmenu; import android.annotation.SuppressLint; -import android.content.ComponentCallbacks; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; @@ -25,6 +24,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver; import org.chromium.chrome.browser.lifecycle.StartStopWithNativeObserver; import org.chromium.chrome.browser.widget.textbubble.TextBubble; @@ -34,8 +34,8 @@ * Object responsible for handling the creation, showing, hiding of the AppMenu and notifying the * AppMenuObservers about these actions. */ -public class AppMenuHandler - implements StartStopWithNativeObserver, OverviewModeBehavior.OverviewModeObserver { +public class AppMenuHandler implements StartStopWithNativeObserver, ConfigurationChangedObserver, + OverviewModeBehavior.OverviewModeObserver { private AppMenu mAppMenu; private AppMenuDragHelper mAppMenuDragHelper; private Menu mMenu; @@ -47,7 +47,6 @@ private final AppMenuCoordinator.AppMenuDelegate mAppMenuDelegate; private final View mDecorView; private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher; - private final ComponentCallbacks mComponentCallbacks; private OverviewModeBehavior mOverviewModeBehavior; /** @@ -86,17 +85,6 @@ mActivityLifecycleDispatcher = activityLifecycleDispatcher; mActivityLifecycleDispatcher.register(this); - mComponentCallbacks = new ComponentCallbacks() { - @Override - public void onConfigurationChanged(Configuration configuration) { - hideAppMenu(); - } - - @Override - public void onLowMemory() {} - }; - mDecorView.getContext().registerComponentCallbacks(mComponentCallbacks); - assert mHardwareButtonMenuAnchor != null : "Using AppMenu requires to have menu_anchor_stub view"; } @@ -113,7 +101,6 @@ mOverviewModeBehavior.removeOverviewModeObserver(this); } - mDecorView.getContext().unregisterComponentCallbacks(mComponentCallbacks); } /** @@ -314,6 +301,11 @@ hideAppMenu(); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + hideAppMenu(); + } + // OverviewModeBehavior.OverviewModeObserver implementation @Override public void onOverviewModeStartedShowing(boolean showToolbar) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java index f64d281..c1c09c99 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ActivityLifecycleDispatcherImpl.java
@@ -5,11 +5,13 @@ package org.chromium.chrome.browser.init; import android.content.Intent; +import android.content.res.Configuration; import android.os.Bundle; import org.chromium.base.ObserverList; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.ActivityResultWithNativeObserver; +import org.chromium.chrome.browser.lifecycle.ConfigurationChangedObserver; import org.chromium.chrome.browser.lifecycle.Destroyable; import org.chromium.chrome.browser.lifecycle.InflationObserver; import org.chromium.chrome.browser.lifecycle.LifecycleObserver; @@ -39,6 +41,8 @@ new ObserverList<>(); private final ObserverList<ActivityResultWithNativeObserver> mActivityResultWithNativeObservers = new ObserverList<>(); + private final ObserverList<ConfigurationChangedObserver> mConfigurationChangedListeners = + new ObserverList<>(); @Override public void register(LifecycleObserver observer) { @@ -67,6 +71,9 @@ mActivityResultWithNativeObservers.addObserver( (ActivityResultWithNativeObserver) observer); } + if (observer instanceof ConfigurationChangedObserver) { + mConfigurationChangedListeners.addObserver((ConfigurationChangedObserver) observer); + } } @Override @@ -96,6 +103,9 @@ mActivityResultWithNativeObservers.removeObserver( (ActivityResultWithNativeObserver) observer); } + if (observer instanceof ConfigurationChangedObserver) { + mConfigurationChangedListeners.removeObserver((ConfigurationChangedObserver) observer); + } } void dispatchPreInflationStartup() { @@ -175,4 +185,10 @@ observer.onActivityResultWithNative(requestCode, resultCode, data); } } + + void dispatchOnConfigurationChanged(Configuration newConfig) { + for (ConfigurationChangedObserver observer : mConfigurationChangedListeners) { + observer.onConfigurationChanged(newConfig); + } + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java index 1e14f08..de444554 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -555,6 +555,12 @@ } @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mLifecycleDispatcher.dispatchOnConfigurationChanged(newConfig); + } + + @Override public abstract boolean shouldStartGpuProcess(); @CallSuper
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java index 26c6771..91b55c5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -163,9 +163,6 @@ } else if (PREF_CAN_MAKE_PAYMENT.equals(key)) { PrefServiceBridge.getInstance().setBoolean( Pref.CAN_MAKE_PAYMENT_ENABLED, (boolean) newValue); - } else if (PREF_USAGE_STATS.equals(key)) { - PrefServiceBridge.getInstance().setBoolean( - Pref.USAGE_STATS_ENABLED, (boolean) newValue); } return true; @@ -248,7 +245,14 @@ if (usageStatsPref != null) { if (BuildInfo.isAtLeastQ() && prefServiceBridge.getBoolean(Pref.USAGE_STATS_ENABLED)) { usageStatsPref.setOnPreferenceClickListener(preference -> { - UsageStatsConsentDialog.create(getActivity(), true, false).show(); + UsageStatsConsentDialog + .create(getActivity(), true, + (didConfirm) -> { + if (didConfirm) { + updateSummaries(); + } + }) + .show(); return true; }); } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/NavigationRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/NavigationRecorder.java index 79f355a..dd8a7b7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/NavigationRecorder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/NavigationRecorder.java
@@ -81,7 +81,7 @@ @Override public void onDestroyed(Tab tab) { - endRecording(null, null); + endRecording(tab, null); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentActivity.java index 92bc9d0..b2049082 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentActivity.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.usage_stats; +import android.app.Activity; import android.content.ComponentName; import android.os.Bundle; import android.text.TextUtils; @@ -37,6 +38,12 @@ public void onAttachedToWindow() { String action = getIntent().getAction(); boolean isRevocation = TextUtils.equals(action, UNAUTHORIZE_ACTION); - UsageStatsConsentDialog.create(this, isRevocation, true).show(); + UsageStatsConsentDialog + .create(this, isRevocation, + (didConfirm) -> { + setResult(didConfirm ? Activity.RESULT_OK : Activity.RESULT_CANCELED); + finish(); + }) + .show(); } -} \ No newline at end of file +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentDialog.java index c4d6592..0b439106 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/UsageStatsConsentDialog.java
@@ -7,6 +7,7 @@ import android.app.Activity; import android.content.res.Resources; +import org.chromium.base.Callback; import org.chromium.chrome.R; import org.chromium.chrome.browser.modaldialog.AppModalPresenter; import org.chromium.ui.modaldialog.ModalDialogManager; @@ -26,11 +27,11 @@ private PropertyModel mDialogModel; private boolean mIsRevocation; - private boolean mIsStandaloneActivity; + private Callback<Boolean> mDidConfirmCallback; public static UsageStatsConsentDialog create( - Activity activity, boolean isRevocation, boolean isStandaloneActivity) { - return new UsageStatsConsentDialog(activity, isRevocation, isStandaloneActivity); + Activity activity, boolean isRevocation, Callback<Boolean> didConfirmCallback) { + return new UsageStatsConsentDialog(activity, isRevocation, didConfirmCallback); } /** Show this dialog in the context of its enclosing activity. */ @@ -60,10 +61,10 @@ } private UsageStatsConsentDialog( - Activity activity, boolean isRevocation, boolean isStandaloneActivity) { + Activity activity, boolean isRevocation, Callback<Boolean> didConfirmCallback) { mActivity = activity; mIsRevocation = isRevocation; - mIsStandaloneActivity = isStandaloneActivity; + mDidConfirmCallback = didConfirmCallback; } private ModalDialogProperties.Controller makeController() { @@ -71,31 +72,26 @@ @Override public void onClick(PropertyModel model, int buttonType) { UsageStatsService service = UsageStatsService.getInstance(); - int result = Activity.RESULT_CANCELED; + boolean didConfirm = false; switch (buttonType) { case ModalDialogProperties.ButtonType.POSITIVE: - service.setOptInState(!mIsRevocation); - result = Activity.RESULT_OK; + didConfirm = true; break; case ModalDialogProperties.ButtonType.NEGATIVE: - service.setOptInState(mIsRevocation); - result = Activity.RESULT_CANCELED; break; } - if (mIsStandaloneActivity) { - mActivity.setResult(result); + if (didConfirm) { + service.setOptInState(!mIsRevocation); } + mDidConfirmCallback.onResult(didConfirm); dismiss(); } @Override public void onDismiss(PropertyModel model, int dismissalCause) { - if (mIsStandaloneActivity) { - mActivity.finish(); - } - + mDidConfirmCallback.onResult(false); mManager.destroy(); } }; @@ -104,4 +100,4 @@ private void dismiss() { mManager.destroy(); } -} \ No newline at end of file +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java index 1158066..b692dc4d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
@@ -7,6 +7,7 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.support.test.InstrumentationRegistry; import android.support.test.filters.LargeTest; import android.support.test.filters.MediumTest; @@ -25,6 +26,7 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.task.PostTask; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeSwitches; @@ -125,7 +127,10 @@ @Test @Feature("CustomTabFromChrome") @LargeTest - public void testIntentWithRedirectToApp() throws Exception { + @DisableIf.Build(message = "Flaky on K, https://crbug.com/962974", + sdk_is_less_than = Build.VERSION_CODES.LOLLIPOP) + public void + testIntentWithRedirectToApp() throws Exception { final String redirectUrl = "https://maps.google.com/maps?q=1600+amphitheatre+parkway"; final String initialUrl = mTestServer.getURL("/chrome/test/data/android/redirect/js_redirect.html"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java index bcb7e60..cc65b51 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceTest.java
@@ -15,6 +15,7 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.AdvancedMockContext; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.components.signin.AccountManagerFacade; @@ -93,6 +94,7 @@ @Test @SmallTest @Feature({"Sync"}) + @DisabledTest(message = "https://crbug.com/962976") public void testGetOAuth2AccessTokenWithTimeoutOnSuccess() { String authToken = "someToken"; // Auth token should be successfully received. @@ -102,6 +104,7 @@ @Test @SmallTest @Feature({"Sync"}) + @DisabledTest(message = "https://crbug.com/962976") public void testGetOAuth2AccessTokenWithTimeoutOnError() { String authToken = null; // Should not crash when auth token is null.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java index b220885..05fbe22 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserWebInputEditingTest.java
@@ -22,7 +22,6 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.ChromeSwitches; @@ -439,7 +438,6 @@ @Test @MediumTest @Feature({"Browser", "RenderTest"}) - @DisabledTest(message = "https://crbug.com/962397") public void testFullscreenVideoControls() throws InterruptedException, TimeoutException, IOException { // There's occasionally slight AA differences along the play button, so tolerate a small
diff --git a/chrome/android/public/lifecycle/BUILD.gn b/chrome/android/public/lifecycle/BUILD.gn index 5b823649..5d86649 100644 --- a/chrome/android/public/lifecycle/BUILD.gn +++ b/chrome/android/public/lifecycle/BUILD.gn
@@ -8,6 +8,7 @@ java_files = [ "java/src/org/chromium/chrome/browser/lifecycle/ActivityLifecycleDispatcher.java", "java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java", + "java/src/org/chromium/chrome/browser/lifecycle/ConfigurationChangedObserver.java", "java/src/org/chromium/chrome/browser/lifecycle/Destroyable.java", "java/src/org/chromium/chrome/browser/lifecycle/InflationObserver.java", "java/src/org/chromium/chrome/browser/lifecycle/LifecycleObserver.java",
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java index 06b5903..1a91f957 100644 --- a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/ActivityResultWithNativeObserver.java
@@ -7,8 +7,8 @@ import android.content.Intent; /** - * Implement this interface and register in {@link - * org.chromium.chrome.browser.init.ActivityLifecycleDispatcher} to receive activity result methods. + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to receive + * activity result methods. */ public interface ActivityResultWithNativeObserver extends LifecycleObserver { /**
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/ConfigurationChangedObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/ConfigurationChangedObserver.java new file mode 100644 index 0000000..742328917 --- /dev/null +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/ConfigurationChangedObserver.java
@@ -0,0 +1,19 @@ +// Copyright 2019 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. + +package org.chromium.chrome.browser.lifecycle; + +import android.content.res.Configuration; + +/** + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to be notified of + * configuration changes. + */ +public interface ConfigurationChangedObserver { + /** + * Called when the Activity configuration changes. See + * {@link android.app.Activity#onConfigurationChanged(Configuration)}. + */ + void onConfigurationChanged(Configuration newConfig); +}
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/InflationObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/InflationObserver.java index dceeec83..64cb630 100644 --- a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/InflationObserver.java +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/InflationObserver.java
@@ -5,9 +5,8 @@ package org.chromium.chrome.browser.lifecycle; /** - * Implement this interface and register in {@link - * org.chromium.chrome.browser.init.ActivityLifecycleDispatcher} to receive inflation-related - * events. + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to receive + * inflation-related events. */ public interface InflationObserver extends LifecycleObserver { /**
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/NativeInitObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/NativeInitObserver.java index 81a040c..f51175ac 100644 --- a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/NativeInitObserver.java +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/NativeInitObserver.java
@@ -5,9 +5,8 @@ package org.chromium.chrome.browser.lifecycle; /** - * Implement this interface and register in {@link - * org.chromium.chrome.browser.init.ActivityLifecycleDispatcher} to get notified of native having - * been loaded. + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to get notified of + * native having been loaded. */ public interface NativeInitObserver extends LifecycleObserver { /**
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/PauseResumeWithNativeObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/PauseResumeWithNativeObserver.java index 9cb5f9b..91ad4ce 100644 --- a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/PauseResumeWithNativeObserver.java +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/PauseResumeWithNativeObserver.java
@@ -5,9 +5,8 @@ package org.chromium.chrome.browser.lifecycle; /** - * Implement this interface and register in {@link - * org.chromium.chrome.browser.init.ActivityLifecycleDispatcher} to receive pause and resume with - * native events. + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to receive pause and + * resume with native events. */ public interface PauseResumeWithNativeObserver extends LifecycleObserver { /**
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/SaveInstanceStateObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/SaveInstanceStateObserver.java index c814f97e..6194b42 100644 --- a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/SaveInstanceStateObserver.java +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/SaveInstanceStateObserver.java
@@ -7,9 +7,8 @@ import android.os.Bundle; /** - * Implement this interface and register in {@link - * org.chromium.chrome.browser.init.ActivityLifecycleDispatcher} to receive onSaveInstanceState - * events. + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to receive + * onSaveInstanceState events. */ public interface SaveInstanceStateObserver extends LifecycleObserver { /**
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/StartStopWithNativeObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/StartStopWithNativeObserver.java index 89d4b58..28c3588 100644 --- a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/StartStopWithNativeObserver.java +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/StartStopWithNativeObserver.java
@@ -5,9 +5,8 @@ package org.chromium.chrome.browser.lifecycle; /** - * Implement this interface and register in {@link - * org.chromium.chrome.browser.init.ActivityLifecycleDispatcher} to receive start and stop with - * native events. + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to receive start and + * stop with native events. */ public interface StartStopWithNativeObserver extends LifecycleObserver { /**
diff --git a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/WindowFocusChangedObserver.java b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/WindowFocusChangedObserver.java index e472cb82..f0627467 100644 --- a/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/WindowFocusChangedObserver.java +++ b/chrome/android/public/lifecycle/java/src/org/chromium/chrome/browser/lifecycle/WindowFocusChangedObserver.java
@@ -5,9 +5,8 @@ package org.chromium.chrome.browser.lifecycle; /** - * Implement this interface and register in {@link - * org.chromium.chrome.browser.init.ActivityLifecycleDispatcher} to receive onWindowFocusChange - * events. + * Implement this interface and register in {@link ActivityLifecycleDispatcher} to receive + * onWindowFocusChange events. */ public interface WindowFocusChangedObserver extends LifecycleObserver { /**
diff --git a/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java b/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java new file mode 100644 index 0000000..c188e9b --- /dev/null +++ b/chrome/android/touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java
@@ -0,0 +1,103 @@ +// Copyright 2019 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. + +package org.chromium.chrome.browser.touchless; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.Callback; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.UrlConstants; +import org.chromium.chrome.browser.suggestions.NavigationRecorder; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.ChromeTabUtils; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.net.test.EmbeddedTestServer; + +import java.util.concurrent.TimeoutException; + +/** + * Instrumentation tests for {@link NavigationRecorder} run in the context of a SingleTabActivity. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class TouchlessNavigationRecorderTest { + @Rule + public ChromeActivityTestRule<NoTouchActivity> mActivityTestRule = + new ChromeActivityTestRule<>(NoTouchActivity.class); + + private EmbeddedTestServer mTestServer; + private String mNavUrl; + private Tab mInitialTab; + + private NoTouchActivity mActivity; + + @Before + public void setUp() throws InterruptedException { + mActivityTestRule.startMainActivityFromLauncher(); + mActivity = mActivityTestRule.getActivity(); + + mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); + mNavUrl = mTestServer.getURL("/chrome/test/data/android/google.html"); + + mActivityTestRule.loadUrl(UrlConstants.NTP_URL); + TestThreadUtils.runOnUiThreadBlocking( + () + -> Assert.assertEquals( + mActivity.getActivityTab().getWebContents().getLastCommittedUrl(), + UrlConstants.NTP_URL)); + + mInitialTab = mActivityTestRule.getActivity().getActivityTab(); + } + + @After + public void tearDown() { + // If setUp() fails, tearDown() still needs to be able to execute without exceptions. + if (mTestServer != null) { + mTestServer.stopAndDestroyServer(); + } + } + + @Test + @SmallTest + public void testRecordVisitOnDestroy() throws InterruptedException, TimeoutException { + final CallbackHelper callback = new CallbackHelper(); + loadUrlAndRecordVisit(mNavUrl, (NavigationRecorder.VisitData visit) -> { + // While we are navigation back to the NTP, NavigationRecorder always passed null as + // the URL unless a 'back 'navigation is performed. + Assert.assertEquals(null, visit.endUrl); + callback.notifyCalled(); + }); + + ChromeTabUtils.waitForTabPageLoaded(mInitialTab, (String) null); + + // This will cause the existing tab to be destroyed and replaced with a new tab, because we + // are running in a SingleTabActivity (which NoTouchActivity extends). This test verifies + // that the NavigationRecorder correctly cleans up observers when this happens, see + // https://crbug.com/959230 for an example of when this didn't happen correctly. + mActivityTestRule.getActivity().getTabCreator(false).launchNTP(); + callback.waitForCallback(0); + } + + /** Loads the provided URL in the current tab and sets up navigation recording for it. */ + private void loadUrlAndRecordVisit( + final String url, Callback<NavigationRecorder.VisitData> visitCallback) { + TestThreadUtils.runOnUiThreadBlocking( + () -> { mInitialTab.loadUrl(new LoadUrlParams(url)); }); + NavigationRecorder.record(mInitialTab, visitCallback); + } +}
diff --git a/chrome/android/touchless/touchless_java_sources.gni b/chrome/android/touchless/touchless_java_sources.gni index 98ffbcf..b377af860 100644 --- a/chrome/android/touchless/touchless_java_sources.gni +++ b/chrome/android/touchless/touchless_java_sources.gni
@@ -63,7 +63,10 @@ "touchless/java/src/org/chromium/chrome/browser/touchless/ui/tooltip/TooltipView.java", ] -touchless_test_java_sources = [ "touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java" ] +touchless_test_java_sources = [ + "touchless/javatests/src/org/chromium/chrome/browser/touchless/NoTouchActivityTest.java", + "touchless/javatests/src/org/chromium/chrome/browser/touchless/TouchlessNavigationRecorderTest.java", +] touchless_junit_test_java_sources = [ "touchless/junit/src/org/chromium/chrome/browser/touchless/ScrollPositionInfoTest.java" ]
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 08551bf5..c74f016 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -3868,6 +3868,9 @@ <message name="IDS_PLUGIN_VM_LAUNCHER_ERROR_MESSAGE" desc="Description of the current state of PluginVm environment setting." translateable="false"> The <ph name="APP_NAME">Plugin VM</ph> installation failed. Please try again. </message> + <message name="IDS_PLUGIN_VM_LAUNCHER_NOT_ALLOWED_MESSAGE" desc="Error message to be shown if a setup/launch is attempted although PluginVm is disabled." translateable="false"> + Please contact your admin to enable <ph name="APP_NAME">Plugin VM</ph> on this device. + </message> <message name="IDS_PLUGIN_VM_LAUNCHER_DOWNLOAD_PROGRESS_MESSAGE" desc="Text shown in the PluginVm launcher during downloading PluginVm image that shows download progress." translateable="false"> <ph name="DOWNLOADED_SIZE">$1<ex>1.2</ex></ph>/<ph name="DOWNLOAD_SIZE">$2<ex>3.4 GB</ex></ph> </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 4647047..7879610 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -4445,6 +4445,15 @@ <message name="IDS_SETTINGS_STORAGE_DELETE_ALL_BUTTON_TITLE" desc="In storage manager confirmation dialog, label for the button to delete offline files."> Delete files </message> + <message name="IDS_SETTINGS_STORAGE_EXTERNAL" desc="In Device Settings > Storage, label for the subpage for setting preferences for external storage."> + External storage preferences + </message> + <message name="IDS_SETTINGS_STORAGE_ANDROID_APPS_ACCESS_EXTERNAL_DRIVES" desc="Label for the control to allow Android apps to access external drives."> + Allow Play Store applications to access external drives + </message> + <message name="IDS_SETTINGS_STORAGE_ANDROID_APPS_ACCESS_EXTERNAL_DRIVES_NOTE" desc="Label for the additional note for the subpage for setting preferences for external storage."> + Google Play Store applications may require access to external storage devices in order to read and write files and folders on them. + </message> <!-- Power --> <message name="IDS_SETTINGS_POWER_TITLE" desc="In Device Settings, the title for power management.">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 316d460..bd18f56 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -3604,7 +3604,7 @@ if (is_chrome_branded) { deps += [ - ":conflicts_module_list_proto", + "//chrome/browser/conflicts:module_list_proto", "//chrome/chrome_elf:sha1", "//chrome/chrome_elf:third_party_shared_defines", "//google_update", @@ -5011,12 +5011,6 @@ "//chrome/common:constants", ] } - - proto_library("conflicts_module_list_proto") { - sources = [ - "conflicts/proto/module_list.proto", - ] - } } # This source set is built into both //chrome:chrome_initial (chrome.exe) and @@ -5402,8 +5396,6 @@ "chromeos/policy/fake_device_cloud_policy_manager.h", "chromeos/settings/device_settings_test_helper.cc", "chromeos/settings/device_settings_test_helper.h", - "ui/ash/ash_test_util.cc", - "ui/ash/ash_test_util.h", "ui/ash/tablet_mode_client_test_util.cc", "ui/ash/tablet_mode_client_test_util.h", ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index d44d112..a99778cd 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1911,9 +1911,6 @@ ENABLE_DISABLE_VALUE_TYPE(switches::kEnableInputImeAPI, switches::kDisableInputImeAPI)}, #endif // OS_WIN || OS_LINUX - {"enable-brotli", flag_descriptions::kEnableBrotliName, - flag_descriptions::kEnableBrotliDescription, kOsAll, - FEATURE_VALUE_TYPE(features::kBrotliEncoding)}, #if defined(OS_ANDROID) {"force-update-menu-type", flag_descriptions::kUpdateMenuTypeName, flag_descriptions::kUpdateMenuTypeDescription, kOsAndroid, @@ -2073,9 +2070,6 @@ FEATURE_VALUE_TYPE(features::kGoogleBrandedContextMenu)}, #endif // !OS_ANDROID && GOOGLE_CHROME_BUILD #if defined(OS_MACOSX) - {"enable-content-fullscreen", flag_descriptions::kContentFullscreenName, - flag_descriptions::kContentFullscreenDescription, kOsMac, - FEATURE_VALUE_TYPE(features::kContentFullscreen)}, {"enable-immersive-fullscreen-toolbar", flag_descriptions::kImmersiveFullscreenName, flag_descriptions::kImmersiveFullscreenDescription, kOsMac, @@ -2873,13 +2867,6 @@ flag_descriptions::kBundledConnectionHelpDescription, kOsAll, FEATURE_VALUE_TYPE(features::kBundledConnectionHelpFeature)}, -#if defined(OS_CHROMEOS) - {"enable-oobe-recommend-apps-screen", - flag_descriptions::kEnableOobeRecommendAppsScreenName, - flag_descriptions::kEnableOobeRecommendAppsScreenDescription, kOsCrOS, - FEATURE_VALUE_TYPE(features::kOobeRecommendAppsScreen)}, -#endif // OS_CHROMEOS - {"enable-query-in-omnibox", flag_descriptions::kQueryInOmniboxName, flag_descriptions::kQueryInOmniboxDescription, kOsAll, FEATURE_VALUE_TYPE(omnibox::kQueryInOmnibox)}, @@ -3403,6 +3390,11 @@ flag_descriptions::kSendTabToSelfDescription, kOsAll, FEATURE_VALUE_TYPE(switches::kSyncSendTabToSelf)}, + {"enable-send-tab-to-self-history", + flag_descriptions::kSendTabToSelfHistoryName, + flag_descriptions::kSendTabToSelfHistoryDescription, kOsAll, + FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfHistory)}, + {"enable-send-tab-to-self-show-sending-ui", flag_descriptions::kSendTabToSelfShowSendingUIName, flag_descriptions::kSendTabToSelfShowSendingUIDescription, kOsAll,
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 6545fd3..01798f7 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -5216,8 +5216,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) { #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 3419194..31f4e73 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -541,8 +541,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) override; std::unique_ptr<content::OverlayWindow> CreateWindowForPictureInPicture(
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index dc85a8a8..bdb0192 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -624,11 +624,11 @@ "attestation/attestation_ca_client.h", "attestation/attestation_policy_observer.cc", "attestation/attestation_policy_observer.h", - "attestation/certificate_uploader.h", "attestation/enrollment_policy_observer.cc", "attestation/enrollment_policy_observer.h", - "attestation/machine_certificate_uploader.cc", "attestation/machine_certificate_uploader.h", + "attestation/machine_certificate_uploader_impl.cc", + "attestation/machine_certificate_uploader_impl.h", "attestation/platform_verification_dialog.cc", "attestation/platform_verification_dialog.h", "attestation/platform_verification_flow.cc", @@ -2165,8 +2165,8 @@ "android_sms/fake_connection_establisher.h", "app_mode/test_kiosk_extension_builder.cc", "app_mode/test_kiosk_extension_builder.h", - "attestation/mock_certificate_uploader.cc", - "attestation/mock_certificate_uploader.h", + "attestation/mock_machine_certificate_uploader.cc", + "attestation/mock_machine_certificate_uploader.h", "crostini/crostini_test_helper.cc", "crostini/crostini_test_helper.h", "drive/drivefs_test_support.cc", @@ -2311,7 +2311,7 @@ "attestation/enrollment_policy_observer_unittest.cc", "attestation/fake_certificate.cc", "attestation/fake_certificate.h", - "attestation/machine_certificate_uploader_unittest.cc", + "attestation/machine_certificate_uploader_impl_unittest.cc", "attestation/platform_verification_flow_unittest.cc", "authpolicy/auth_policy_credentials_manager_unittest.cc", "authpolicy/authpolicy_helper.unittest.cc",
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc index 23f15169..0508f539 100644 --- a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc +++ b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
@@ -8,7 +8,7 @@ #include <utility> #include "base/bind.h" -#include "chrome/browser/chromeos/attestation/certificate_uploader.h" +#include "chrome/browser/chromeos/attestation/machine_certificate_uploader.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "content/public/browser/browser_thread.h" @@ -16,7 +16,7 @@ namespace attestation { AttestationPolicyObserver::AttestationPolicyObserver( - CertificateUploader* certificate_uploader) + MachineCertificateUploader* certificate_uploader) : cros_settings_(CrosSettings::Get()), certificate_uploader_(certificate_uploader) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer.h b/chrome/browser/chromeos/attestation/attestation_policy_observer.h index 48c02cc4..36097fc 100644 --- a/chrome/browser/chromeos/attestation/attestation_policy_observer.h +++ b/chrome/browser/chromeos/attestation/attestation_policy_observer.h
@@ -17,7 +17,7 @@ namespace chromeos { namespace attestation { -class CertificateUploader; +class MachineCertificateUploader; // A class which observes policy changes and uploads a certificate if necessary. class AttestationPolicyObserver { @@ -25,7 +25,8 @@ // The observer immediately connects with CrosSettings to listen for policy // changes. The CertificateUploader is used to obtain and upload a // certificate. This class does not take ownership of |certificate_uploader|. - explicit AttestationPolicyObserver(CertificateUploader* certificate_uploader); + explicit AttestationPolicyObserver( + MachineCertificateUploader* certificate_uploader); ~AttestationPolicyObserver(); @@ -37,7 +38,7 @@ void Start(); CrosSettings* cros_settings_; - CertificateUploader* certificate_uploader_; + MachineCertificateUploader* certificate_uploader_; std::unique_ptr<CrosSettings::ObserverSubscription> attestation_subscription_;
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc index 30c1ca8..9dc86390 100644 --- a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc +++ b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
@@ -13,7 +13,7 @@ #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/attestation/attestation_policy_observer.h" -#include "chrome/browser/chromeos/attestation/mock_certificate_uploader.h" +#include "chrome/browser/chromeos/attestation/mock_machine_certificate_uploader.h" #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" #include "chromeos/settings/cros_settings_names.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -40,7 +40,7 @@ content::TestBrowserThreadBundle test_browser_thread_bundle_; ScopedCrosSettingsTestHelper settings_helper_; - StrictMock<MockCertificateUploader> certificate_uploader_; + StrictMock<MockMachineCertificateUploader> certificate_uploader_; }; TEST_F(AttestationPolicyObserverTest, FeatureEnabled) {
diff --git a/chrome/browser/chromeos/attestation/certificate_uploader.h b/chrome/browser/chromeos/attestation/certificate_uploader.h deleted file mode 100644 index ef98be4..0000000 --- a/chrome/browser/chromeos/attestation/certificate_uploader.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2019 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_ATTESTATION_CERTIFICATE_UPLOADER_H_ -#define CHROME_BROWSER_CHROMEOS_ATTESTATION_CERTIFICATE_UPLOADER_H_ - -#include "base/callback.h" - -namespace chromeos { -namespace attestation { - -// An abstract class for certificate uploaders. -class CertificateUploader { - public: - using UploadCallback = base::OnceCallback<void(bool)>; - - virtual ~CertificateUploader() = default; - - // Checks if the certificate has been uploaded, and if not, do so. - // A certificate will be obtained if needed. - virtual void UploadCertificateIfNeeded(UploadCallback callback) = 0; - - // Forces the refreshing of the certificate and uploads it. - virtual void RefreshAndUploadCertificate(UploadCallback callback) = 0; -}; - -} // namespace attestation -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_ATTESTATION_CERTIFICATE_UPLOADER_H_
diff --git a/chrome/browser/chromeos/attestation/machine_certificate_uploader.h b/chrome/browser/chromeos/attestation/machine_certificate_uploader.h index c778eb1..f833f3f 100644 --- a/chrome/browser/chromeos/attestation/machine_certificate_uploader.h +++ b/chrome/browser/chromeos/attestation/machine_certificate_uploader.h
@@ -5,108 +5,24 @@ #ifndef CHROME_BROWSER_CHROMEOS_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_H_ #define CHROME_BROWSER_CHROMEOS_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_H_ -#include <string> - #include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/chromeos/attestation/certificate_uploader.h" -#include "chromeos/dbus/constants/attestation_constants.h" - -namespace policy { -class CloudPolicyClient; -} namespace chromeos { - -class CryptohomeClient; - namespace attestation { -class AttestationFlow; - -// A class which uploads enterprise machine certificates. -class MachineCertificateUploader : public CertificateUploader { +// An abstract class for machine certificate uploaders. +class MachineCertificateUploader { public: - explicit MachineCertificateUploader(policy::CloudPolicyClient* policy_client); - - // A constructor which allows custom CryptohomeClient and AttestationFlow - // implementations. Useful for testing. - MachineCertificateUploader(policy::CloudPolicyClient* policy_client, - CryptohomeClient* cryptohome_client, - AttestationFlow* attestation_flow); - - ~MachineCertificateUploader() override; - - // Sets the retry limit in number of tries; useful in testing. - void set_retry_limit(int limit) { retry_limit_ = limit; } - // Sets the retry delay in seconds; useful in testing. - void set_retry_delay(int retry_delay) { retry_delay_ = retry_delay; } - using UploadCallback = base::OnceCallback<void(bool)>; - // Checks if the machine certificate has been uploaded, and if not, do so. + virtual ~MachineCertificateUploader() = default; + + // Checks if the certificate has been uploaded, and if not, do so. // A certificate will be obtained if needed. - void UploadCertificateIfNeeded(UploadCallback callback) override; + virtual void UploadCertificateIfNeeded(UploadCallback callback) = 0; - // Forces the refreshing of the machine certificate and uploads it. - void RefreshAndUploadCertificate(UploadCallback callback) override; - - private: - // Starts certificate obtention and upload. - void Start(); - - // Gets a new certificate for the Enterprise Machine Key (EMK). - void GetNewCertificate(); - - // Gets the existing EMK certificate and sends it to CheckCertificateExpiry. - void GetExistingCertificate(); - - // Checks if any certificate in the given pem_certificate_chain is expired - // and, if so, gets a new one. If not renewing, calls CheckIfUploaded. - void CheckCertificateExpiry(const std::string& pem_certificate_chain); - - // Uploads a machine certificate to the policy server. - void UploadCertificate(const std::string& pem_certificate_chain); - - // Checks if a certificate has already been uploaded and, if not, upload. - void CheckIfUploaded(const std::string& pem_certificate_chain, - const std::string& key_payload); - - // Gets the payload associated with the EMK and sends it to |callback|, - // or call |on_failure| with no arguments if the payload cannot be obtained. - void GetKeyPayload(base::RepeatingCallback<void(const std::string&)> callback, - base::RepeatingCallback<void()> on_failure); - - // Called when a certificate upload operation completes. On success, |status| - // will be true. - void OnUploadComplete(bool status); - - // Marks a key as uploaded in the payload proto. - void MarkAsUploaded(const std::string& key_payload); - - // Handles failure of getting a certificate. - void HandleGetCertificateFailure(AttestationStatus status); - - // Reschedules a policy check (i.e. a call to Start) for a later time. - // TODO(dkrahn): A better solution would be to wait for a dbus signal which - // indicates the system is ready to process this task. See crbug.com/256845. - void Reschedule(); - - policy::CloudPolicyClient* policy_client_; - CryptohomeClient* cryptohome_client_; - AttestationFlow* attestation_flow_; - std::unique_ptr<AttestationFlow> default_attestation_flow_; - bool refresh_certificate_; - UploadCallback callback_; - int num_retries_; - int retry_limit_; - int retry_delay_; - - // Note: This should remain the last member so it'll be destroyed and - // invalidate the weak pointers before any other members are destroyed. - base::WeakPtrFactory<MachineCertificateUploader> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(MachineCertificateUploader); + // Forces the obtention of a fresh certificate and uploads it. + virtual void RefreshAndUploadCertificate(UploadCallback callback) = 0; }; } // namespace attestation
diff --git a/chrome/browser/chromeos/attestation/machine_certificate_uploader.cc b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.cc similarity index 83% rename from chrome/browser/chromeos/attestation/machine_certificate_uploader.cc rename to chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.cc index 83b9fe6..0006634 100644 --- a/chrome/browser/chromeos/attestation/machine_certificate_uploader.cc +++ b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/attestation/machine_certificate_uploader.h" +#include "chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.h" #include <string> #include <utility> @@ -109,7 +109,7 @@ namespace chromeos { namespace attestation { -MachineCertificateUploader::MachineCertificateUploader( +MachineCertificateUploaderImpl::MachineCertificateUploaderImpl( policy::CloudPolicyClient* policy_client) : policy_client_(policy_client), cryptohome_client_(nullptr), @@ -121,7 +121,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -MachineCertificateUploader::MachineCertificateUploader( +MachineCertificateUploaderImpl::MachineCertificateUploaderImpl( policy::CloudPolicyClient* policy_client, CryptohomeClient* cryptohome_client, AttestationFlow* attestation_flow) @@ -134,11 +134,11 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -MachineCertificateUploader::~MachineCertificateUploader() { +MachineCertificateUploaderImpl::~MachineCertificateUploaderImpl() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -void MachineCertificateUploader::UploadCertificateIfNeeded( +void MachineCertificateUploaderImpl::UploadCertificateIfNeeded( UploadCallback callback) { refresh_certificate_ = false; callback_ = std::move(callback); @@ -146,7 +146,7 @@ Start(); } -void MachineCertificateUploader::RefreshAndUploadCertificate( +void MachineCertificateUploaderImpl::RefreshAndUploadCertificate( UploadCallback callback) { refresh_certificate_ = true; callback_ = std::move(callback); @@ -154,10 +154,10 @@ Start(); } -void MachineCertificateUploader::Start() { +void MachineCertificateUploaderImpl::Start() { // We expect a registered CloudPolicyClient. if (!policy_client_->is_registered()) { - LOG(ERROR) << "MachineCertificateUploader: Invalid CloudPolicyClient."; + LOG(ERROR) << "MachineCertificateUploaderImpl: Invalid CloudPolicyClient."; return; } @@ -181,23 +181,23 @@ // Start a dbus call to check if an Enterprise Machine Key already exists. base::RepeatingClosure on_does_not_exist = - base::BindRepeating(&MachineCertificateUploader::GetNewCertificate, + base::BindRepeating(&MachineCertificateUploaderImpl::GetNewCertificate, weak_factory_.GetWeakPtr()); - base::RepeatingClosure on_does_exist = - base::BindRepeating(&MachineCertificateUploader::GetExistingCertificate, - weak_factory_.GetWeakPtr()); + base::RepeatingClosure on_does_exist = base::BindRepeating( + &MachineCertificateUploaderImpl::GetExistingCertificate, + weak_factory_.GetWeakPtr()); cryptohome_client_->TpmAttestationDoesKeyExist( KEY_DEVICE, cryptohome::AccountIdentifier(), // Not used. kEnterpriseMachineKey, base::BindOnce( DBusBoolRedirectCallback, on_does_exist, on_does_not_exist, - base::BindRepeating(&MachineCertificateUploader::Reschedule, + base::BindRepeating(&MachineCertificateUploaderImpl::Reschedule, weak_factory_.GetWeakPtr()), FROM_HERE)); } -void MachineCertificateUploader::GetNewCertificate() { +void MachineCertificateUploaderImpl::GetNewCertificate() { // We can reuse the dbus callback handler logic. attestation_flow_->GetCertificate( PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, @@ -212,15 +212,16 @@ DBusPrivacyCACallback(on_success, on_failure, from_here, status, std::move(data)); }, - base::BindRepeating(&MachineCertificateUploader::UploadCertificate, - weak_factory_.GetWeakPtr()), base::BindRepeating( - &MachineCertificateUploader::HandleGetCertificateFailure, + &MachineCertificateUploaderImpl::UploadCertificate, + weak_factory_.GetWeakPtr()), + base::BindRepeating( + &MachineCertificateUploaderImpl::HandleGetCertificateFailure, weak_factory_.GetWeakPtr()), FROM_HERE)); } -void MachineCertificateUploader::GetExistingCertificate() { +void MachineCertificateUploaderImpl::GetExistingCertificate() { cryptohome_client_->TpmAttestationGetCertificate( KEY_DEVICE, cryptohome::AccountIdentifier(), // Not used. @@ -228,14 +229,14 @@ base::BindRepeating( DBusStringCallback, base::BindRepeating( - &MachineCertificateUploader::CheckCertificateExpiry, + &MachineCertificateUploaderImpl::CheckCertificateExpiry, weak_factory_.GetWeakPtr()), - base::BindRepeating(&MachineCertificateUploader::Reschedule, + base::BindRepeating(&MachineCertificateUploaderImpl::Reschedule, weak_factory_.GetWeakPtr()), FROM_HERE)); } -void MachineCertificateUploader::CheckCertificateExpiry( +void MachineCertificateUploaderImpl::CheckCertificateExpiry( const std::string& pem_certificate_chain) { int num_certificates = 0; net::PEMTokenizer pem_tokenizer(pem_certificate_chain, {"CERTIFICATE"}); @@ -268,21 +269,21 @@ } // Get the payload and check if the certificate has already been uploaded. GetKeyPayload( - base::BindRepeating(&MachineCertificateUploader::CheckIfUploaded, + base::BindRepeating(&MachineCertificateUploaderImpl::CheckIfUploaded, weak_factory_.GetWeakPtr(), pem_certificate_chain), - base::BindRepeating(&MachineCertificateUploader::Reschedule, + base::BindRepeating(&MachineCertificateUploaderImpl::Reschedule, weak_factory_.GetWeakPtr())); } -void MachineCertificateUploader::UploadCertificate( +void MachineCertificateUploaderImpl::UploadCertificate( const std::string& pem_certificate_chain) { policy_client_->UploadEnterpriseMachineCertificate( pem_certificate_chain, - base::BindRepeating(&MachineCertificateUploader::OnUploadComplete, + base::BindRepeating(&MachineCertificateUploaderImpl::OnUploadComplete, weak_factory_.GetWeakPtr())); } -void MachineCertificateUploader::CheckIfUploaded( +void MachineCertificateUploaderImpl::CheckIfUploaded( const std::string& pem_certificate_chain, const std::string& key_payload) { AttestationKeyPayload payload_pb; @@ -294,7 +295,7 @@ UploadCertificate(pem_certificate_chain); } -void MachineCertificateUploader::GetKeyPayload( +void MachineCertificateUploaderImpl::GetKeyPayload( base::RepeatingCallback<void(const std::string&)> callback, base::RepeatingCallback<void()> on_failure) { cryptohome_client_->TpmAttestationGetKeyPayload( @@ -304,18 +305,18 @@ base::BindRepeating(DBusStringCallback, callback, on_failure, FROM_HERE)); } -void MachineCertificateUploader::OnUploadComplete(bool status) { +void MachineCertificateUploaderImpl::OnUploadComplete(bool status) { if (status) { VLOG(1) << "Enterprise Machine Certificate uploaded to DMServer."; GetKeyPayload( - base::BindRepeating(&MachineCertificateUploader::MarkAsUploaded, + base::BindRepeating(&MachineCertificateUploaderImpl::MarkAsUploaded, weak_factory_.GetWeakPtr()), base::DoNothing()); } std::move(callback_).Run(status); } -void MachineCertificateUploader::MarkAsUploaded( +void MachineCertificateUploaderImpl::MarkAsUploaded( const std::string& key_payload) { AttestationKeyPayload payload_pb; if (!key_payload.empty()) @@ -335,7 +336,7 @@ FROM_HERE)); } -void MachineCertificateUploader::HandleGetCertificateFailure( +void MachineCertificateUploaderImpl::HandleGetCertificateFailure( AttestationStatus status) { if (status != ATTESTATION_SERVER_BAD_REQUEST_FAILURE) Reschedule(); @@ -343,15 +344,15 @@ std::move(callback_).Run(false); } -void MachineCertificateUploader::Reschedule() { +void MachineCertificateUploaderImpl::Reschedule() { if (++num_retries_ < retry_limit_) { base::PostDelayedTaskWithTraits( FROM_HERE, {content::BrowserThread::UI}, - base::BindRepeating(&MachineCertificateUploader::Start, + base::BindRepeating(&MachineCertificateUploaderImpl::Start, weak_factory_.GetWeakPtr()), base::TimeDelta::FromSeconds(retry_delay_)); } else { - LOG(WARNING) << "MachineCertificateUploader: Retry limit exceeded."; + LOG(WARNING) << "MachineCertificateUploaderImpl: Retry limit exceeded."; std::move(callback_).Run(false); } }
diff --git a/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.h b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.h new file mode 100644 index 0000000..686e4f0 --- /dev/null +++ b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.h
@@ -0,0 +1,116 @@ +// Copyright 2019 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_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_IMPL_H_ +#define CHROME_BROWSER_CHROMEOS_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_IMPL_H_ + +#include <string> + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/attestation/machine_certificate_uploader.h" +#include "chromeos/dbus/constants/attestation_constants.h" + +namespace policy { +class CloudPolicyClient; +} + +namespace chromeos { + +class CryptohomeClient; + +namespace attestation { + +class AttestationFlow; + +// A class which uploads enterprise machine certificates. +class MachineCertificateUploaderImpl : public MachineCertificateUploader { + public: + explicit MachineCertificateUploaderImpl( + policy::CloudPolicyClient* policy_client); + + // A constructor which allows custom CryptohomeClient and AttestationFlow + // implementations. Useful for testing. + MachineCertificateUploaderImpl(policy::CloudPolicyClient* policy_client, + CryptohomeClient* cryptohome_client, + AttestationFlow* attestation_flow); + + ~MachineCertificateUploaderImpl() override; + + // Sets the retry limit in number of tries; useful in testing. + void set_retry_limit(int limit) { retry_limit_ = limit; } + // Sets the retry delay in seconds; useful in testing. + void set_retry_delay(int retry_delay) { retry_delay_ = retry_delay; } + + using UploadCallback = base::OnceCallback<void(bool)>; + + // Checks if the machine certificate has been uploaded, and if not, do so. + // A certificate will be obtained if needed. + void UploadCertificateIfNeeded(UploadCallback callback) override; + + // Refreshs a fresh machine certificate and uploads it. + void RefreshAndUploadCertificate(UploadCallback callback) override; + + private: + // Starts certificate obtention and upload. + void Start(); + + // Gets a new certificate for the Enterprise Machine Key (EMK). + void GetNewCertificate(); + + // Gets the existing EMK certificate and sends it to CheckCertificateExpiry. + void GetExistingCertificate(); + + // Checks if any certificate in the given pem_certificate_chain is expired + // and, if so, gets a new one. If not renewing, calls CheckIfUploaded. + void CheckCertificateExpiry(const std::string& pem_certificate_chain); + + // Uploads a machine certificate to the policy server. + void UploadCertificate(const std::string& pem_certificate_chain); + + // Checks if a certificate has already been uploaded and, if not, upload. + void CheckIfUploaded(const std::string& pem_certificate_chain, + const std::string& key_payload); + + // Gets the payload associated with the EMK and sends it to |callback|, + // or call |on_failure| with no arguments if the payload cannot be obtained. + void GetKeyPayload(base::RepeatingCallback<void(const std::string&)> callback, + base::RepeatingCallback<void()> on_failure); + + // Called when a certificate upload operation completes. On success, |status| + // will be true. + void OnUploadComplete(bool status); + + // Marks a key as uploaded in the payload proto. + void MarkAsUploaded(const std::string& key_payload); + + // Handles failure of getting a certificate. + void HandleGetCertificateFailure(AttestationStatus status); + + // Reschedules a policy check (i.e. a call to Start) for a later time. + // TODO(dkrahn): A better solution would be to wait for a dbus signal which + // indicates the system is ready to process this task. See crbug.com/256845. + void Reschedule(); + + policy::CloudPolicyClient* policy_client_; + CryptohomeClient* cryptohome_client_; + AttestationFlow* attestation_flow_; + std::unique_ptr<AttestationFlow> default_attestation_flow_; + bool refresh_certificate_; + UploadCallback callback_; + int num_retries_; + int retry_limit_; + int retry_delay_; + + // Note: This should remain the last member so it'll be destroyed and + // invalidate the weak pointers before any other members are destroyed. + base::WeakPtrFactory<MachineCertificateUploaderImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(MachineCertificateUploaderImpl); +}; + +} // namespace attestation +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_ATTESTATION_MACHINE_CERTIFICATE_UPLOADER_IMPL_H_
diff --git a/chrome/browser/chromeos/attestation/machine_certificate_uploader_unittest.cc b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl_unittest.cc similarity index 97% rename from chrome/browser/chromeos/attestation/machine_certificate_uploader_unittest.cc rename to chrome/browser/chromeos/attestation/machine_certificate_uploader_impl_unittest.cc index fabee7b..fa48c71 100644 --- a/chrome/browser/chromeos/attestation/machine_certificate_uploader_unittest.cc +++ b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl_unittest.cc
@@ -14,7 +14,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/attestation/attestation_key_payload.pb.h" #include "chrome/browser/chromeos/attestation/fake_certificate.h" -#include "chrome/browser/chromeos/attestation/machine_certificate_uploader.h" +#include "chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.h" #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" #include "chromeos/attestation/mock_attestation_flow.h" #include "chromeos/dbus/cryptohome/fake_cryptohome_client.h" @@ -116,8 +116,8 @@ } void Run() { - MachineCertificateUploader uploader(&policy_client_, &cryptohome_client_, - &attestation_flow_); + MachineCertificateUploaderImpl uploader( + &policy_client_, &cryptohome_client_, &attestation_flow_); uploader.set_retry_limit(3); uploader.set_retry_delay(0); if (GetParam())
diff --git a/chrome/browser/chromeos/attestation/mock_certificate_uploader.cc b/chrome/browser/chromeos/attestation/mock_certificate_uploader.cc deleted file mode 100644 index 9dd21d5b..0000000 --- a/chrome/browser/chromeos/attestation/mock_certificate_uploader.cc +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2019 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/attestation/mock_certificate_uploader.h" - -namespace chromeos { -namespace attestation { - -MockCertificateUploader::MockCertificateUploader() = default; - -MockCertificateUploader::~MockCertificateUploader() = default; - -} // namespace attestation -} // namespace chromeos
diff --git a/chrome/browser/chromeos/attestation/mock_certificate_uploader.h b/chrome/browser/chromeos/attestation/mock_certificate_uploader.h deleted file mode 100644 index 1d4f6f15..0000000 --- a/chrome/browser/chromeos/attestation/mock_certificate_uploader.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2019 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_ATTESTATION_MOCK_CERTIFICATE_UPLOADER_H_ -#define CHROME_BROWSER_CHROMEOS_ATTESTATION_MOCK_CERTIFICATE_UPLOADER_H_ - -#include "base/macros.h" -#include "chrome/browser/chromeos/attestation/certificate_uploader.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace chromeos { -namespace attestation { - -class MockCertificateUploader : public CertificateUploader { - public: - MockCertificateUploader(); - ~MockCertificateUploader(); - - MOCK_METHOD1(UploadCertificateIfNeeded, void(UploadCallback)); - MOCK_METHOD1(RefreshAndUploadCertificate, void(UploadCallback)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockCertificateUploader); -}; - -} // namespace attestation -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_ATTESTATION_MOCK_CERTIFICATE_UPLOADER_H_
diff --git a/chrome/browser/chromeos/attestation/mock_machine_certificate_uploader.cc b/chrome/browser/chromeos/attestation/mock_machine_certificate_uploader.cc new file mode 100644 index 0000000..4a4b5fa --- /dev/null +++ b/chrome/browser/chromeos/attestation/mock_machine_certificate_uploader.cc
@@ -0,0 +1,15 @@ +// Copyright 2019 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/attestation/mock_machine_certificate_uploader.h" + +namespace chromeos { +namespace attestation { + +MockMachineCertificateUploader::MockMachineCertificateUploader() = default; + +MockMachineCertificateUploader::~MockMachineCertificateUploader() = default; + +} // namespace attestation +} // namespace chromeos
diff --git a/chrome/browser/chromeos/attestation/mock_machine_certificate_uploader.h b/chrome/browser/chromeos/attestation/mock_machine_certificate_uploader.h new file mode 100644 index 0000000..601d952 --- /dev/null +++ b/chrome/browser/chromeos/attestation/mock_machine_certificate_uploader.h
@@ -0,0 +1,30 @@ +// Copyright 2019 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_ATTESTATION_MOCK_MACHINE_CERTIFICATE_UPLOADER_H_ +#define CHROME_BROWSER_CHROMEOS_ATTESTATION_MOCK_MACHINE_CERTIFICATE_UPLOADER_H_ + +#include "base/macros.h" +#include "chrome/browser/chromeos/attestation/machine_certificate_uploader.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { +namespace attestation { + +class MockMachineCertificateUploader : public MachineCertificateUploader { + public: + MockMachineCertificateUploader(); + ~MockMachineCertificateUploader(); + + MOCK_METHOD1(UploadCertificateIfNeeded, void(UploadCallback)); + MOCK_METHOD1(RefreshAndUploadCertificate, void(UploadCallback)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockMachineCertificateUploader); +}; + +} // namespace attestation +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_ATTESTATION_MOCK_MACHINE_CERTIFICATE_UPLOADER_H_
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc index 5bf78be3..f806b499 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -10,9 +10,7 @@ #include <memory> #include <utility> -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/containers/circular_deque.h" @@ -2292,13 +2290,7 @@ void FileManagerBrowserTestBase::EnableVirtualKeyboard() { CHECK(IsTabletModeTest()); - - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - ash::mojom::ShellTestApiAsyncWaiter waiter(shell_test_api.get()); - waiter.EnableVirtualKeyboard(); + ash::ShellTestApi().EnableVirtualKeyboard(); } } // namespace file_manager
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index c5152d6..dd9a437 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -16,7 +16,6 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" -#include "base/feature_list.h" #include "base/json/json_string_value_serializer.h" #include "base/location.h" #include "base/logging.h" @@ -126,7 +125,6 @@ #include "chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h" #include "chrome/browser/ui/webui/help/help_utils_chromeos.h" #include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chromeos/audio/cras_audio_handler.h" #include "chromeos/constants/chromeos_constants.h" @@ -264,8 +262,7 @@ ->GetProfilePolicyConnector() ->IsManaged(); bool is_child_account = user_manager->IsLoggedInAsChildUser(); - return !is_managed_account && !is_child_account && - base::FeatureList::IsEnabled(features::kOobeRecommendAppsScreen); + return !is_managed_account && !is_child_account; } chromeos::LoginDisplayHost* GetLoginDisplayHost() {
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc index bfb71b4..a83e8a18 100644 --- a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc +++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager.cc
@@ -15,6 +15,7 @@ #include "base/task/post_task.h" #include "base/task/task_traits.h" #include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h" +#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "components/download/public/background_service/download_metadata.h" @@ -50,6 +51,16 @@ return; } + // Defensive check preventing any download attempts when PluginVm is + // not allowed to run (this might happen in rare cases if PluginVm has + // been disabled but the installer icon is still visible). + if (!IsPluginVmAllowedForProfile(profile_)) { + LOG(ERROR) << "Download of PluginVm image cannot be started because " + << "the user is not allowed to run PluginVm"; + OnDownloadFailed(); + return; + } + state_ = State::DOWNLOADING; GURL url = GetPluginVmImageDownloadUrl(); if (url.is_empty()) {
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc index b0b82a5..506f3a4 100644 --- a/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc +++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_unittest.cc
@@ -11,11 +11,15 @@ #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/optional.h" +#include "chrome/browser/chromeos/login/users/mock_user_manager.h" #include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_download_client.h" #include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_manager_factory.h" #include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/test/base/testing_profile.h" +#include "components/account_id/account_id.h" #include "components/download/public/background_service/test/test_download_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/sync_preferences/testing_pref_service_syncable.h" @@ -44,6 +48,7 @@ const char kContent2[] = "This is content #2."; const int kContent2Size = strlen(kContent2); const int kContentSize = kContent1Size + kContent2Size; +const char kLicenseKey[] = "LICENSE_KEY"; } // namespace @@ -73,6 +78,8 @@ : download_service_(new download::test::TestDownloadService()) {} protected: + chromeos::MockUserManager user_manager_; + chromeos::ScopedCrosSettingsTestHelper settings_helper_; content::TestBrowserThreadBundle test_browser_thread_bundle_; std::unique_ptr<TestingProfile> profile_; PluginVmImageManager* manager_; @@ -95,6 +102,9 @@ manager_->SetObserver(observer_.get()); fake_downloaded_plugin_vm_image_archive_ = CreateZipFile(); + + SetPluginVmDevicePolicies(); + SetUserWithAffiliation(); } void TearDown() override { @@ -102,6 +112,21 @@ observer_.reset(); } + void SetPluginVmDevicePolicies() { + settings_helper_.ReplaceDeviceSettingsProviderWithStub(); + settings_helper_.SetBoolean(chromeos::kPluginVmAllowed, true); + settings_helper_.SetString(chromeos::kPluginVmLicenseKey, kLicenseKey); + } + + void SetUserWithAffiliation() { + const AccountId account_id( + AccountId::FromUserEmailGaiaId(profile_->GetProfileUserName(), "id")); + user_manager_.AddUserWithAffiliationAndType( + account_id, true, user_manager::USER_TYPE_REGULAR); + chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting( + user_manager_.GetActiveUser()); + } + void SetPluginVmImagePref(std::string url, std::string hash) { DictionaryPrefUpdate update(profile_->GetPrefs(), plugin_vm::prefs::kPluginVmImage); @@ -398,4 +423,10 @@ EXPECT_FALSE(manager_->VerifyDownload(std::string())); } +TEST_F(PluginVmImageManagerTest, CannotStartDownloadIfPluginVmGetsDisabled) { + settings_helper_.SetBoolean(chromeos::kPluginVmAllowed, false); + EXPECT_CALL(*observer_, OnDownloadFailed()); + ProcessImageUntilUnzipping(); +} + } // namespace plugin_vm
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc index ece7fb0..2b851f3b 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -22,7 +22,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/attestation/attestation_policy_observer.h" #include "chrome/browser/chromeos/attestation/enrollment_policy_observer.h" -#include "chrome/browser/chromeos/attestation/machine_certificate_uploader.h" +#include "chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.h" #include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h" #include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h" #include "chrome/browser/chromeos/login/startup_utils.h" @@ -311,7 +311,7 @@ if (!(base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kDisableMachineCertRequest))) { machine_certificate_uploader_.reset( - new chromeos::attestation::MachineCertificateUploader(client())); + new chromeos::attestation::MachineCertificateUploaderImpl(client())); attestation_policy_observer_.reset( new chromeos::attestation::AttestationPolicyObserver( machine_certificate_uploader_.get()));
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index 7792926..8b6f353 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc
@@ -9,6 +9,7 @@ #include "ash/public/cpp/ash_constants.h" #include "ash/public/cpp/ash_pref_names.h" +#include "ash/public/cpp/ash_prefs.h" #include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/cros_display_config.mojom.h" #include "base/bind.h" @@ -34,7 +35,6 @@ #include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/prefs/pref_service_syncable_util.h" -#include "chrome/browser/ui/ash/ash_shell_init.h" #include "chrome/browser/ui/ash/system_tray_client.h" #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" @@ -180,7 +180,7 @@ // Carrier deal notification shown count defaults to 0. registry->RegisterIntegerPref(prefs::kCarrierDealPromoShown, 0); - AshShellInit::RegisterDisplayPrefs(registry); + ash::RegisterLocalStatePrefs(registry); } // static
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager.h b/chrome/browser/chromeos/printing/cups_print_job_manager.h index f9ad6cf5..775938ce 100644 --- a/chrome/browser/chromeos/printing/cups_print_job_manager.h +++ b/chrome/browser/chromeos/printing/cups_print_job_manager.h
@@ -75,12 +75,13 @@ void NotifyJobDone(base::WeakPtr<CupsPrintJob> job); Profile* profile_; - std::unique_ptr<CupsPrintJobNotificationManager> notification_manager_; - base::ObserverList<Observer>::Unchecked observers_; private: void RecordJobDuration(base::WeakPtr<CupsPrintJob> job); + std::unique_ptr<CupsPrintJobNotificationManager> notification_manager_; + base::ObserverList<Observer>::Unchecked observers_; + // Keyed by CupsPrintJob's unique ID std::map<std::string, base::TimeTicks> print_job_start_times_;
diff --git a/chrome/browser/conflicts/BUILD.gn b/chrome/browser/conflicts/BUILD.gn index ab0d8bfd..4d3659f 100644 --- a/chrome/browser/conflicts/BUILD.gn +++ b/chrome/browser/conflicts/BUILD.gn
@@ -2,6 +2,20 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chrome_build.gni") +import("//third_party/protobuf/proto_library.gni") + +assert(is_win) + +# Note: Most of the files in this directory are directly added as source files +# to the //chrome/browser target (chrome/browser/BUILD.gn). + +proto_library("module_list_proto") { + sources = [ + "proto/module_list.proto", + ] +} + source_set("module_info") { sources = [ "module_info_util_win.cc", @@ -20,3 +34,74 @@ "//chrome/common/safe_browsing:binary_feature_extractor", ] } + +loadable_module("conflicts_dll") { + testonly = true + sources = [ + "test/conflicts_dll.cc", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "enumerate_input_method_editors_win_unittest.cc", + "enumerate_shell_extensions_win_unittest.cc", + "inspection_results_cache_win_unittest.cc", + "module_database_win_unittest.cc", + "module_event_sink_impl_win_unittest.cc", + "module_info_util_win_unittest.cc", + "module_info_win_unittest.cc", + "module_inspector_win_unittest.cc", + ] + + deps = [ + ":conflicts_dll", + ":module_info", + "//chrome/browser", + "//chrome/services/util_win:lib", + "//chrome/test:test_support", + "//content/test:test_support", + "//services/service_manager/public/cpp/test:test_support", + "//testing/gtest", + ] + + if (is_chrome_branded) { + sources += [ + "incompatible_applications_updater_win_unittest.cc", + "installed_applications_win_unittest.cc", + "module_blacklist_cache_updater_win_unittest.cc", + "module_blacklist_cache_util_win_unittest.cc", + "module_list_filter_win_unittest.cc", + "module_load_attempt_log_listener_win_unittest.cc", + "registry_key_watcher_win_unittest.cc", + "third_party_conflicts_manager_win_unittest.cc", + ] + + deps += [ + ":module_list_proto", + "//chrome/chrome_elf:third_party_shared_defines", + ] + } +} + +if (is_chrome_branded) { + source_set("browser_tests") { + defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] + + testonly = true + sources = [ + "incompatible_applications_browsertest.cc", + "third_party_blocking_browsertest.cc", + ] + + deps = [ + ":conflicts_dll", + ":module_list_proto", + "//chrome/browser", + "//chrome/chrome_elf:third_party_shared_defines", + "//chrome/test:test_support_ui", + "//testing/gtest", + ] + } +}
diff --git a/chrome/test/conflicts/conflicts_dll.cc b/chrome/browser/conflicts/test/conflicts_dll.cc similarity index 100% rename from chrome/test/conflicts/conflicts_dll.cc rename to chrome/browser/conflicts/test/conflicts_dll.cc
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 2122104..7155c905 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -521,6 +521,8 @@ settings_api::PrefType::PREF_TYPE_DICTIONARY; (*s_whitelist)[chromeos::kDisplayRotationDefault] = settings_api::PrefType::PREF_TYPE_DICTIONARY; + (*s_whitelist)[arc::prefs::kArcHasAccessToRemovableMedia] = + settings_api::PrefType::PREF_TYPE_BOOLEAN; // Native Printing settings. (*s_whitelist)[::prefs::kUserNativePrintersAllowed] =
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index 20f7433e..b913acdc 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -1505,8 +1505,9 @@ *new_index = target_tab_strip->count(); content::WebContents* web_contents_raw = web_contents.get(); - target_tab_strip->InsertWebContentsAt(*new_index, std::move(web_contents), - TabStripModel::ADD_NONE); + + *new_index = target_tab_strip->InsertWebContentsAt( + *new_index, std::move(web_contents), TabStripModel::ADD_NONE); if (has_callback()) { tab_values->Append(ExtensionTabUtil::CreateTabObject( @@ -1527,7 +1528,8 @@ *new_index = source_tab_strip->count() - 1; if (*new_index != tab_index) - source_tab_strip->MoveWebContentsAt(tab_index, *new_index, false); + *new_index = + source_tab_strip->MoveWebContentsAt(tab_index, *new_index, false); if (has_callback()) { tab_values->Append(ExtensionTabUtil::CreateTabObject(
diff --git a/chrome/browser/extensions/api/web_request/OWNERS b/chrome/browser/extensions/api/web_request/OWNERS index d5f125f04..77b56cf0 100644 --- a/chrome/browser/extensions/api/web_request/OWNERS +++ b/chrome/browser/extensions/api/web_request/OWNERS
@@ -1 +1,3 @@ -battre@chromium.org +file://extensions/browser/api/web_request/OWNERS + +# COMPONENT: Platform>Extensions>API
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc index f4921846..bd3f42c6 100644 --- a/chrome/browser/extensions/content_script_apitest.cc +++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -30,6 +30,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" #include "extensions/browser/browsertest_util.h" #include "extensions/browser/extension_registry.h" @@ -939,6 +940,223 @@ ASSERT_TRUE(RunExtensionTest("content_scripts/messaging")) << message_; } +// A test suite designed for exercising the behavior of content script +// injection into opaque URLs (like about:blank). +class ContentScriptOpaqueOriginTest : public ContentScriptApiTest { + public: + ContentScriptOpaqueOriginTest() {} + ~ContentScriptOpaqueOriginTest() override {} + + void SetUpOnMainThread() override; + + // Returns true if the extension's content script executed in the specified + // |frame|. + bool DidScriptRunInFrame(content::RenderFrameHost* host); + + // Navigates the current active tab to the specified |url|, ensuring the + // navigation succeeds. Returns the active tab's WebContents. + content::WebContents* NavigateTab(const GURL& url); + + // Opens a popup to the specified |url| from the given |opener_web_contents|. + // Ensures the navigation succeeds, and returns the newly-opened popup's + // WebContents. + content::WebContents* OpenPopup(content::WebContents* opener_web_contents, + const GURL& url); + + // Navigates an iframe to the specified |url| from the context of + // |navigating_host|. The iframe is retrieved from |navigating_host| by + // evaluating |frame_getter| (e.g., `frames[0]`). + void NavigateIframe(content::RenderFrameHost* navigating_host, + const std::string& frame_getter, + const GURL& url); + + const GURL& about_blank() const { return about_blank_; } + const GURL& allowed_url() const { return allowed_url_; } + const GURL& disallowed_url() const { return disallowed_url_; } + const GURL& allowed_url_with_iframe() const { + return allowed_url_with_iframe_; + } + const GURL& disallowed_url_with_iframe() const { + return disallowed_url_with_iframe_; + } + + private: + static constexpr char kMarkerSpanId[] = "content-script-marker"; + + // The about:blank URL. + GURL about_blank_; + // A simple URL the extension is allowed to access. + GURL allowed_url_; + // A simple URL the extension is not allowed to access. + GURL disallowed_url_; + // A URL the extension can access with an iframe in the DOM. + GURL allowed_url_with_iframe_; + // A URL the extension is not allowed to access with an iframe in the DOM. + GURL disallowed_url_with_iframe_; + + // The test directory used to load our extension. + TestExtensionDir test_extension_dir_; + + DISALLOW_COPY_AND_ASSIGN(ContentScriptOpaqueOriginTest); +}; + +constexpr char ContentScriptOpaqueOriginTest::kMarkerSpanId[]; + +void ContentScriptOpaqueOriginTest::SetUpOnMainThread() { + ContentScriptApiTest::SetUpOnMainThread(); + ASSERT_TRUE(StartEmbeddedTestServer()); + about_blank_ = GURL(url::kAboutBlankURL); + allowed_url_ = embedded_test_server()->GetURL("example.com", "/simple.html"); + disallowed_url_ = + embedded_test_server()->GetURL("chromium.org", "/simple.html"); + allowed_url_with_iframe_ = + embedded_test_server()->GetURL("example.com", "/iframe.html"); + disallowed_url_with_iframe_ = + embedded_test_server()->GetURL("chromium.org", "/iframe.html"); + + constexpr char kManifest[] = + R"({ + "name": "Content Script in opaque URLs", + "manifest_version": 2, + "version": "0.1", + "content_scripts": [{ + "matches": ["http://example.com/*"], + "js": ["script.js"], + "run_at": "document_end", + "all_frames": true, + "match_about_blank": true + }] + })"; + test_extension_dir_.WriteManifest(kManifest); + + std::string background_script = base::StringPrintf( + R"(let span = document.createElement('span'); + span.id = '%s'; + document.body.appendChild(span);)", + kMarkerSpanId); + test_extension_dir_.WriteFile(FILE_PATH_LITERAL("script.js"), + background_script); + ASSERT_TRUE(LoadExtension(test_extension_dir_.UnpackedPath())); +} + +bool ContentScriptOpaqueOriginTest::DidScriptRunInFrame( + content::RenderFrameHost* host) { + // The WebContents needs to have stopped loading at this point for this check + // to be guaranteed. Since the script runs at document_end (which runs + // after DOMContentLoaded is fired, before window.onload), this check will be + // guaranteed to run after it. + EXPECT_FALSE(content::WebContents::FromRenderFrameHost(host)->IsLoading()); + return content::EvalJs( + host, + content::JsReplace("!!document.getElementById($1)", kMarkerSpanId)) + .ExtractBool(); +} + +content::WebContents* ContentScriptOpaqueOriginTest::NavigateTab( + const GURL& url) { + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::TestNavigationObserver observer(web_contents); + ui_test_utils::NavigateToURL(browser(), url); + EXPECT_TRUE(observer.last_navigation_succeeded()); + EXPECT_EQ(url, web_contents->GetLastCommittedURL()); + return web_contents; +} + +content::WebContents* ContentScriptOpaqueOriginTest::OpenPopup( + content::WebContents* opener_web_contents, + const GURL& url) { + int initial_tab_count = browser()->tab_strip_model()->count(); + content::TestNavigationObserver popup_observer(nullptr /* web_contents */); + popup_observer.StartWatchingNewWebContents(); + EXPECT_TRUE(content::ExecuteScript( + opener_web_contents, content::JsReplace("window.open($1);", url.spec()))); + popup_observer.Wait(); + EXPECT_EQ(initial_tab_count + 1, browser()->tab_strip_model()->count()); + content::WebContents* popup = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_EQ(url, popup->GetLastCommittedURL()); + EXPECT_NE(popup, opener_web_contents); + return popup; +} + +void ContentScriptOpaqueOriginTest::NavigateIframe( + content::RenderFrameHost* navigating_host, + const std::string& frame_getter, + const GURL& url) { + constexpr char kScriptTemplate[] = + R"({ + let frame = %s; + frame.location.href = '%s'; + })"; + + std::string script = base::StringPrintf(kScriptTemplate, frame_getter.c_str(), + url.spec().c_str()); + content::TestNavigationObserver navigation_observer(url); + navigation_observer.WatchExistingWebContents(); + EXPECT_TRUE(content::ExecuteScript(navigating_host, script)); + navigation_observer.WaitForNavigationFinished(); + EXPECT_TRUE(navigation_observer.last_navigation_succeeded()); + + // Also wait for the full WebContents to stop loading, in case the iframe's + // new source has nested iframes. + EXPECT_TRUE(content::WaitForLoadStop( + content::WebContents::FromRenderFrameHost(navigating_host))); +} + +// Injection should succeed on a popup to about:blank created by an allowed +// site. +IN_PROC_BROWSER_TEST_F(ContentScriptOpaqueOriginTest, + MatchAboutBlank_Iframe_Allowed) { + content::WebContents* tab = NavigateTab(allowed_url_with_iframe()); + NavigateIframe(tab->GetMainFrame(), "frames[0]", about_blank()); + content::RenderFrameHost* render_frame_host = + content::ChildFrameAt(tab->GetMainFrame(), 0); + ASSERT_TRUE(render_frame_host); + EXPECT_EQ(about_blank(), render_frame_host->GetLastCommittedURL()); + EXPECT_TRUE(DidScriptRunInFrame(render_frame_host)); +} + +// Injection should fail on an iframe to about:blank created by a disallowed +// site. +IN_PROC_BROWSER_TEST_F(ContentScriptOpaqueOriginTest, + MatchAboutBlank_Iframe_Disallowed) { + content::WebContents* tab = NavigateTab(disallowed_url_with_iframe()); + NavigateIframe(tab->GetMainFrame(), "frames[0]", about_blank()); + content::RenderFrameHost* render_frame_host = + content::ChildFrameAt(tab->GetMainFrame(), 0); + ASSERT_TRUE(render_frame_host); + EXPECT_EQ(about_blank(), render_frame_host->GetLastCommittedURL()); + EXPECT_FALSE(DidScriptRunInFrame(render_frame_host)); +} + +// Injection should succeed on a popup to about:blank created by an allowed +// site. +IN_PROC_BROWSER_TEST_F(ContentScriptOpaqueOriginTest, + MatchAboutBlank_Popup_Allowed) { + content::WebContents* tab = NavigateTab(allowed_url()); + content::WebContents* popup = OpenPopup(tab, about_blank()); + EXPECT_TRUE(DidScriptRunInFrame(popup->GetMainFrame())); +} + +// Injection should fail on a popup to about:blank created by a disallowed site. +IN_PROC_BROWSER_TEST_F(ContentScriptOpaqueOriginTest, + MatchAboutBlank_Popup_Disallowed) { + content::WebContents* tab = NavigateTab(disallowed_url()); + content::WebContents* popup = OpenPopup(tab, about_blank()); + EXPECT_FALSE(DidScriptRunInFrame(popup->GetMainFrame())); +} + +// Browser-initiated navigations do not have a separate precursor tuple, so +// injection should be disallowed. +IN_PROC_BROWSER_TEST_F(ContentScriptOpaqueOriginTest, + MatchAboutBlank_BrowserOpened) { + content::WebContents* tab = NavigateTab(about_blank()); + EXPECT_FALSE(DidScriptRunInFrame(tab->GetMainFrame())); +} + +// TODO(devlin): Add support for and exercise behavior of data: URL injection. + // Test fixture which sets a custom NTP Page. // TODO(karandeepb): Similar logic to set up a custom NTP is used elsewhere as // well. Abstract this away into a reusable test fixture class.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index ad0e7598..4e42b9f 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -892,11 +892,6 @@ "expiry_milestone": 75 }, { - "name": "enable-brotli", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "enable-bulk-printers", "owners": [ "skau" ], "expiry_milestone": 76 @@ -929,11 +924,6 @@ "expiry_milestone": -1 }, { - "name": "enable-content-fullscreen", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "enable-immersive-fullscreen-toolbar", "owners": [ "sdy", "chrome/browser/ui/cocoa/OWNERS" ], "expiry_milestone": 76 @@ -1383,11 +1373,6 @@ "expiry_milestone": -1 }, { - "name": "enable-oobe-recommend-apps-screen", - // "owners": [ "your-team" ], - "expiry_milestone": 76 - }, - { "name": "enable-oop-rasterization", "owners": [ "enne", "khushalsagar" ], "expiry_milestone": 76 @@ -1517,6 +1502,11 @@ "expiry_milestone": 76 }, { + "name": "enable-send-tab-to-self-history", + "owners": [ "//components/send_tab_to_self/OWNERS" ], + "expiry_milestone": 78 + }, + { "name": "enable-send-tab-to-self-show-sending-ui", "owners": [ "//components/send_tab_to_self/OWNERS" ], "expiry_milestone": 77 @@ -2745,7 +2735,7 @@ { "name": "scheduler-configuration", "owners": [ "kerrnel", "mnissler" ], - "expiry_milestone": 76 + "expiry_milestone": 77 }, { "name": "session-restore-prioritizes-background-use-cases",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 260e66f..f197354 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -472,10 +472,6 @@ "If enabled, adds the status of certain experiment variations when making " "calls to Google Payments."; -const char kEnableBrotliName[] = "Brotli Content-Encoding."; -const char kEnableBrotliDescription[] = - "Enable Brotli Content-Encoding support."; - const char kEnableSaveDataName[] = "Enables save data feature"; const char kEnableSaveDataDescription[] = "Enables save data feature. May cause user's traffic to be proxied via " @@ -1591,17 +1587,23 @@ "Allows users to access tabs by scrolling when they no longer fit in the " "tabstrip."; -const char kSendTabToSelfBroadcastName[] = "Send tab to self broadcast"; -const char kSendTabToSelfBroadcastDescription[] = - "Allows users to broadcast the tab they send to all of their devices " - "instead of targetting only one device."; - const char kSendTabToSelfName[] = "Send tab to self"; const char kSendTabToSelfDescription[] = "Allows users to receive tabs from other synced devices, in order to " "easily transition those tabs to this device. This enables the sync " "infrastructure for this feature."; +const char kSendTabToSelfBroadcastName[] = "Send tab to self broadcast"; +const char kSendTabToSelfBroadcastDescription[] = + "Allows users to broadcast the tab they send to all of their devices " + "instead of targetting only one device."; + +const char kSendTabToSelfHistoryName[] = "Send tab to self history"; +const char kSendTabToSelfHistoryDescription[] = + "Allows users to view tabs that were sent to other synced devices by " + "accessing these tabs through a landing page either in history or in " + "recent tabs. Requires Send tab to self to also be enabled"; + const char kSendTabToSelfShowSendingUIName[] = "Send tab to self show sending UI"; const char kSendTabToSelfShowSendingUIDescription[] = @@ -2762,11 +2764,6 @@ #if defined(OS_MACOSX) -const char kContentFullscreenName[] = "Improved Content Fullscreen"; -const char kContentFullscreenDescription[] = - "Fullscreen content window detaches from main browser window and goes to " - "a new space without moving or changing the original browser window."; - const char kImmersiveFullscreenName[] = "Immersive Fullscreen Toolbar"; const char kImmersiveFullscreenDescription[] = "Automatically hide and show the toolbar in fullscreen."; @@ -3064,12 +3061,6 @@ "Enables use of MyFiles as a read/write volume. This should be only " "used for testing or for trying to restore the previous Downloads content."; -const char kEnableOobeRecommendAppsScreenName[] = - "Enable OOBE Recommend Apps Screen"; -const char kEnableOobeRecommendAppsScreenDescription[] = - "Enable the Recommend Apps Screen in OOBE which allows user to install apps" - "from other devices"; - const char kEnablePlayStoreSearchName[] = "Enable Play Store search"; const char kEnablePlayStoreSearchDescription[] = "Enable Play Store search in launcher.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index a2e71e3..ebf0fcf 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -305,9 +305,6 @@ extern const char kEnableAutofillSendExperimentIdsInPaymentsRPCsName[]; extern const char kEnableAutofillSendExperimentIdsInPaymentsRPCsDescription[]; -extern const char kEnableBrotliName[]; -extern const char kEnableBrotliDescription[]; - extern const char kEnableSaveDataName[]; extern const char kEnableSaveDataDescription[]; @@ -957,11 +954,14 @@ extern const char kScrollableTabStripName[]; extern const char kScrollableTabStripDescription[]; +extern const char kSendTabToSelfName[]; +extern const char kSendTabToSelfDescription[]; + extern const char kSendTabToSelfBroadcastName[]; extern const char kSendTabToSelfBroadcastDescription[]; -extern const char kSendTabToSelfName[]; -extern const char kSendTabToSelfDescription[]; +extern const char kSendTabToSelfHistoryName[]; +extern const char kSendTabToSelfHistoryDescription[]; extern const char kSendTabToSelfShowSendingUIName[]; extern const char kSendTabToSelfShowSendingUIDescription[]; @@ -1645,9 +1645,6 @@ #if defined(OS_MACOSX) -extern const char kContentFullscreenName[]; -extern const char kContentFullscreenDescription[]; - extern const char kImmersiveFullscreenName[]; extern const char kImmersiveFullscreenDescription[]; @@ -1844,9 +1841,6 @@ extern const char kEnableMyFilesVolumeName[]; extern const char kEnableMyFilesVolumeDescription[]; -extern const char kEnableOobeRecommendAppsScreenName[]; -extern const char kEnableOobeRecommendAppsScreenDescription[]; - extern const char kEnablePlayStoreSearchName[]; extern const char kEnablePlayStoreSearchDescription[];
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc index cf8b2c0..9571518 100644 --- a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc +++ b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
@@ -318,12 +318,12 @@ const GURL& url = GetTestURL("/page_with_same_host_anchor_element.html"); ui_test_utils::NavigateToURL(browser(), url); - base::RunLoop().RunUntilIdle(); + WaitForLayout(&histogram_tester); EXPECT_TRUE(content::ExecuteScript( browser()->tab_strip_model()->GetActiveWebContents(), "document.getElementById('google').click();")); - WaitForLayout(&histogram_tester); + base::RunLoop().RunUntilIdle(); histogram_tester.ExpectUniqueSample( "AnchorElementMetrics.Visible.NumberOfAnchorElements", 2, 1);
diff --git a/chrome/browser/net/chrome_url_request_context_getter.cc b/chrome/browser/net/chrome_url_request_context_getter.cc index 180fa7de..a931ece0 100644 --- a/chrome/browser/net/chrome_url_request_context_getter.cc +++ b/chrome/browser/net/chrome_url_request_context_getter.cc
@@ -178,10 +178,10 @@ // run and complete before the constructor returns, which would reduce the // reference count from 1 to 0 on completion, and delete the object // immediately. - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(&ChromeURLRequestContextGetter::Init, - url_request_context_getter, - base::Passed(std::move(factory)))); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&ChromeURLRequestContextGetter::Init, + url_request_context_getter, std::move(factory))); return url_request_context_getter; }
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc index 058f193b..6545262 100644 --- a/chrome/browser/net/system_network_context_manager.cc +++ b/chrome/browser/net/system_network_context_manager.cc
@@ -595,8 +595,7 @@ content::UpdateCorsExemptHeader(network_context_params.get()); variations::UpdateCorsExemptHeaderForVariations(network_context_params.get()); - network_context_params->enable_brotli = - base::FeatureList::IsEnabled(features::kBrotliEncoding); + network_context_params->enable_brotli = true; network_context_params->user_agent = GetUserAgent();
diff --git a/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc index 50726946..e0b3b15 100644 --- a/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc +++ b/chrome/browser/offline_pages/prefetch/prefetch_service_factory.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/image_fetcher/image_fetcher_service_factory.h" +#include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/ntp_snippets/content_suggestions_service_factory.h" #include "chrome/browser/offline_pages/offline_page_model_factory.h" #include "chrome/browser/offline_pages/prefetch/offline_metrics_collector_impl.h" @@ -105,9 +106,21 @@ auto prefetch_dispatcher = std::make_unique<PrefetchDispatcherImpl>(profile->GetPrefs()); + auto* system_network_context_manager = + SystemNetworkContextManager::GetInstance(); + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory; + if (system_network_context_manager) { + url_loader_factory = + system_network_context_manager->GetSharedURLLoaderFactory(); + } else { + // In unit_tests, NetworkService might not be available and + // |system_network_context_manager| would be null. + url_loader_factory = nullptr; + } + auto prefetch_network_request_factory = std::make_unique<PrefetchNetworkRequestFactoryImpl>( - profile->GetURLLoaderFactory(), chrome::GetChannel(), GetUserAgent(), + url_loader_factory, chrome::GetChannel(), GetUserAgent(), profile->GetPrefs()); scoped_refptr<base::SequencedTaskRunner> background_task_runner =
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index 71323fb4..064fb909 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -66,6 +66,7 @@ #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/context_menu_params.h" +#include "content/public/common/mime_handler_view_mode.h" #include "content/public/common/url_constants.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/hit_test_region_observer.h" @@ -1568,13 +1569,13 @@ } void ClickLeftSideOfEditableComboBox() { - content::SimulateMouseClickAt(GetActiveWebContents(), 0, + content::SimulateMouseClickAt(GetWebContentsForInputRouting(), 0, blink::WebMouseEvent::Button::kLeft, GetEditableComboBoxLeftPosition()); } void TypeHello() { - auto* web_contents = GetActiveWebContents(); + auto* web_contents = GetWebContentsForInputRouting(); content::SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('H'), ui::DomCode::US_H, ui::VKEY_H, false, false, false, false); @@ -1595,28 +1596,29 @@ // Presses the left arrow key. void PressLeftArrow() { content::SimulateKeyPressWithoutChar( - GetActiveWebContents(), ui::DomKey::ARROW_LEFT, ui::DomCode::ARROW_LEFT, - ui::VKEY_LEFT, false, false, false, false); + GetWebContentsForInputRouting(), ui::DomKey::ARROW_LEFT, + ui::DomCode::ARROW_LEFT, ui::VKEY_LEFT, false, false, false, false); } // Presses down shift, presses the left arrow, and lets go of shift. void PressShiftLeftArrow() { - content::SimulateKeyPressWithoutChar( - GetActiveWebContents(), ui::DomKey::ARROW_LEFT, ui::DomCode::ARROW_LEFT, - ui::VKEY_LEFT, false, /*shift=*/true, false, false); + content::SimulateKeyPressWithoutChar(GetWebContentsForInputRouting(), + ui::DomKey::ARROW_LEFT, + ui::DomCode::ARROW_LEFT, ui::VKEY_LEFT, + false, /*shift=*/true, false, false); } // Presses the right arrow key. void PressRightArrow() { content::SimulateKeyPressWithoutChar( - GetActiveWebContents(), ui::DomKey::ARROW_RIGHT, + GetWebContentsForInputRouting(), ui::DomKey::ARROW_RIGHT, ui::DomCode::ARROW_RIGHT, ui::VKEY_RIGHT, false, false, false, false); } // Presses down shift, presses the right arrow, and lets go of shift. void PressShiftRightArrow() { content::SimulateKeyPressWithoutChar( - GetActiveWebContents(), ui::DomKey::ARROW_RIGHT, + GetWebContentsForInputRouting(), ui::DomKey::ARROW_RIGHT, ui::DomCode::ARROW_RIGHT, ui::VKEY_RIGHT, false, /*shift=*/true, false, false); } @@ -1633,10 +1635,16 @@ // SimulateKeyPress(). Using IDC_COPY does not work on Mac in browser_tests. void SendCopyCommandAndCheckCopyPasteClipboard(const std::string& expected) { content::RunAllPendingInMessageLoop(); - GetActiveWebContents()->Copy(); + GetWebContentsForInputRouting()->Copy(); CheckClipboard(ui::CLIPBOARD_TYPE_COPY_PASTE, expected); } + content::WebContents* GetWebContentsForInputRouting() { + return content::MimeHandlerViewMode::UsesCrossProcessFrame() + ? guest_contents_ + : GetActiveWebContents(); + } + private: // Waits and polls the clipboard of a given |clipboard_type| until its // contents reaches the length of |expected|. Then checks and see if the @@ -1745,7 +1753,7 @@ // Press shift + right arrow 3 times. Holding down shift in between. { content::ScopedSimulateModifierKeyPress hold_shift( - GetActiveWebContents(), false, true, false, false); + GetWebContentsForInputRouting(), false, true, false, false); hold_shift.KeyPressWithoutChar(ui::DomKey::ARROW_RIGHT, ui::DomCode::ARROW_RIGHT, ui::VKEY_RIGHT); CheckSelectionClipboard("H"); @@ -1776,7 +1784,7 @@ // Press shift + left arrow 3 times. Holding down shift in between. { content::ScopedSimulateModifierKeyPress hold_shift( - GetActiveWebContents(), false, true, false, false); + GetWebContentsForInputRouting(), false, true, false, false); hold_shift.KeyPressWithoutChar(ui::DomKey::ARROW_LEFT, ui::DomCode::ARROW_LEFT, ui::VKEY_LEFT); CheckSelectionClipboard("L"); @@ -1792,7 +1800,7 @@ // Press shift + right arrow 2 times. Holding down shift in between. { content::ScopedSimulateModifierKeyPress hold_shift( - GetActiveWebContents(), false, true, false, false); + GetWebContentsForInputRouting(), false, true, false, false); hold_shift.KeyPressWithoutChar(ui::DomKey::ARROW_RIGHT, ui::DomCode::ARROW_RIGHT, ui::VKEY_RIGHT); CheckSelectionClipboard("EL");
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc index 4d8f93d..d21e737 100644 --- a/chrome/browser/renderer_preferences_util.cc +++ b/chrome/browser/renderer_preferences_util.cc
@@ -109,7 +109,7 @@ ParsePortRange(webrtc_udp_port_range, &prefs->webrtc_udp_min_port, &prefs->webrtc_udp_max_port); -#if BUILDFLAG(USE_DEFAULT_RENDER_THEME) +#if defined(USE_AURA) prefs->focus_ring_color = SkColorSetRGB(0x4D, 0x90, 0xFE); #if defined(OS_CHROMEOS) // This color is 0x544d90fe modulated with 0xffffff. @@ -118,6 +118,8 @@ prefs->inactive_selection_bg_color = SkColorSetRGB(0xEA, 0xEA, 0xEA); prefs->inactive_selection_fg_color = SK_ColorBLACK; #endif +#else + prefs->use_custom_colors = false; #endif #if defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.js b/chrome/browser/resources/local_ntp/custom_backgrounds.js index e07c58c..0261b9e 100644 --- a/chrome/browser/resources/local_ntp/custom_backgrounds.js +++ b/chrome/browser/resources/local_ntp/custom_backgrounds.js
@@ -104,6 +104,7 @@ RESTORE_DEFAULT: 'edit-bg-restore-default', RESTORE_DEFAULT_TEXT: 'edit-bg-restore-default-text', SHORTCUTS_BUTTON: 'shortcuts-button', + SHORTCUTS_MENU: 'shortcuts-menu', UPLOAD_IMAGE: 'edit-bg-upload-image', UPLOAD_IMAGE_TEXT: 'edit-bg-upload-image-text', TILES: 'bg-sel-tiles', @@ -1346,10 +1347,16 @@ $(customBackgrounds.IDS.BACKGROUNDS_BUTTON).onclick = function() { $(customBackgrounds.IDS.BACKGROUNDS_MENU) .classList.toggle(customBackgrounds.CLASSES.MENU_SHOWN, true); + $(customBackgrounds.IDS.SHORTCUTS_MENU) + .classList.toggle(customBackgrounds.CLASSES.MENU_SHOWN, false); }; $(customBackgrounds.IDS.SHORTCUTS_BUTTON).onclick = function() { customBackgrounds.richerPicker_resetImageMenu(false); + $(customBackgrounds.IDS.BACKGROUNDS_MENU) + .classList.toggle(customBackgrounds.CLASSES.MENU_SHOWN, false); + $(customBackgrounds.IDS.SHORTCUTS_MENU) + .classList.toggle(customBackgrounds.CLASSES.MENU_SHOWN, true); }; $(customBackgrounds.IDS.COLORS_BUTTON).onclick = function() {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css index 159f3bc..0ede361 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.css +++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -913,6 +913,10 @@ background-color: rgb(var(--GB600-rgb)); } +#shortcuts-icon { + -webkit-mask-image: url(icons/link.svg); +} + .menu-option-label { display: inline-block; height: 32px; @@ -1133,3 +1137,115 @@ opacity: 1; width: 174px; } + +#shortcuts-menu { + line-height: 20px; + overflow-y: unset; + width: calc(100% - 24px); +} + +#sh-options { + display: flex; +} + +.sh-option { + width: 268px; +} + +#sh-option-cl { + margin-inline-end: 9px; +} + +.sh-option-select { + position: absolute; + visibility: none; +} + +.sh-option-image { + background-color: white; + border: 1px solid rgb(var(--GG300-rgb)); + border-radius: 4px; + height: 176px; + position: relative; + width: 268px; +} + +.sh-option-mini { + background-color: white; + border: 1px solid rgb(var(--GG300-rgb)); + border-radius: 4px; + height: 144px; + position: absolute; + right: 40px; + top: 16px; + width: 144px; +} + +html[dir=rtl] .sh-option-mini { + left: 40px; + right: unset; +} + +.sh-option-icon { + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 100%; + background: 96px 96px rgb(var(--GG200-rgb)); + height: 96px; + left: 16px; + position: absolute; + top: 48px; + width: 96px; +} + +#sh-option-cl .sh-option-icon { + -webkit-mask-image: url(../../../../ui/webui/resources/images/account_circle.svg); +} + +#sh-option-mv .sh-option-icon { + -webkit-mask-image: url(../../../../components/neterror/resources/images/generic-globe.svg); +} + +html[dir=rtl] .sh-option-icon { + right: 16px; +} + +.sh-title { + font-weight: bold; + margin: 8px 0; +} + +#sh-hide { + background-color: white; + border: 1px solid rgb(var(--GG300-rgb)); + border-radius: 4px; + display: flex; + height: 64px; + margin-top: 24px; + max-width: 544px; + width: 100%; +} + +#sh-hide > div { + margin-bottom: auto; + margin-top: auto; +} + +#sh-hide-icon { + -webkit-mask-image: url(../../../../ui/webui/resources/images/icon_visibility_off.svg); + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: 100%; + background: 24px 24px rgb(var(--GG700-rgb)); + height: 24px; + margin-inline-end: 20px; + margin-inline-start: 24px; + width: 24px; +} + +#sh-hide-title { + font-weight: bold; +} + +#sh-hide-toggle { + margin-inline-end: 20px; + margin-inline-start: auto; +}
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html index d8c9efb..9236f9d9 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.html +++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -187,7 +187,7 @@ </div> <div id="shortcuts-button" class="menu-option" tabindex="0"> <div class="menu-option-icon-wrapper"> - <div ids="shortcuts-icon" class="menu-option-icon"></div> + <div id="shortcuts-icon" class="menu-option-icon"></div> </div> <div class="menu-option-label">$i18n{shortcutsOption}</div> </div> @@ -210,6 +210,38 @@ </div> </div> <div id="backgrounds-image-menu" class="menu-panel"></div> + <div id="shortcuts-menu" class="menu-panel"> + <div id="sh-options"> + <div id="sh-option-cl" class="sh-option"> + <div class="sh-option-image"> + <div class="sh-option-icon"></div> + <div class="sh-option-mini"></div> + <div class="sh-option-select"></div> + </div> + <div class="sh-title">My shortcuts</div> + Your personalized shortcuts + </div> + <div id="sh-option-mv" class="sh-option"> + <div class="sh-option-image"> + <div class="sh-option-icon"></div> + <div class="sh-option-mini"></div> + <div class="sh-option-select"></div> + </div> + <div class="sh-title">Most visited sites</div> + Link suggestions from Chrome based on your browsing activity + </div> + </div> + <div id="sh-hide"> + <div id="sh-hide-icon"></div> + <div> + <div id="sh-hide-title">Hide shortcuts</div> + Do not show shortcuts on the new tab page. + </div> + <div id="sh-hide-toggle"> + <input type="checkbox"></input> + </div> + </div> + </div> </div> <div id="menu-footer"> <button id="menu-cancel" class="bg-sel-footer-button paper secondary
diff --git a/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chrome/browser/resources/plugin_metadata/plugins_linux.json index 78d32ee..722e064f 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_linux.json +++ b/chrome/browser/resources/plugin_metadata/plugins_linux.json
@@ -1,5 +1,5 @@ { - "x-version": 39, + "x-version": 40, "adobe-flash-player": { "mime_types": [ "application/futuresplash", @@ -10,9 +10,9 @@ ], "versions": [ { - "version": "32.0.0.171", + "version": "32.0.0.192", "status": "up_to_date", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-19.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-26.html" } ], "lang": "en-US",
diff --git a/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chrome/browser/resources/plugin_metadata/plugins_mac.json index ed22d33..7d0f49a 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_mac.json +++ b/chrome/browser/resources/plugin_metadata/plugins_mac.json
@@ -1,5 +1,5 @@ { - "x-version": 45, + "x-version": 46, "adobe-flash-player": { "mime_types": [ "application/futuresplash", @@ -7,9 +7,9 @@ ], "versions": [ { - "version": "32.0.0.171", + "version": "32.0.0.192", "status": "requires_authorization", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-19.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-26.html" } ], "lang": "en-US",
diff --git a/chrome/browser/resources/plugin_metadata/plugins_win.json b/chrome/browser/resources/plugin_metadata/plugins_win.json index 0d449d1..9abad05 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_win.json +++ b/chrome/browser/resources/plugin_metadata/plugins_win.json
@@ -1,5 +1,5 @@ { - "x-version": 54, + "x-version": 55, "adobe-flash-player": { "mime_types": [ "application/futuresplash", @@ -7,9 +7,9 @@ ], "versions": [ { - "version": "32.0.0.171", + "version": "32.0.0.192", "status": "requires_authorization", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-19.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb19-26.html" } ], "lang": "en-US",
diff --git a/chrome/browser/resources/settings/device_page/device_page.html b/chrome/browser/resources/settings/device_page/device_page.html index 889d5d3..e0ab2a8 100644 --- a/chrome/browser/resources/settings/device_page/device_page.html +++ b/chrome/browser/resources/settings/device_page/device_page.html
@@ -9,6 +9,7 @@ <link rel="import" href="pointers.html"> <link rel="import" href="power.html"> <link rel="import" href="storage.html"> +<link rel="import" href="storage_external.html"> <link rel="import" href="stylus.html"> <link rel="import" href="../prefs/prefs.html"> <link rel="import" href="../route.html"> @@ -80,6 +81,16 @@ </settings-storage> </settings-subpage> </template> + <template is="dom-if" if="[[androidRunning_]]"> + <template is="dom-if" route-path="/storage/externalStoragePreferences"> + <settings-subpage + associated-control="[[$$('#externalStoragePreferencesRow')]]" + page-title="$i18n{storageExternal}"> + <settings-storage-external prefs="{{prefs}}"> + </settings-storage-external> + </settings-subpage> + </template> + </template> <template is="dom-if" route-path="/power" no-search="[[!enablePowerSettings_]]"> <settings-subpage
diff --git a/chrome/browser/resources/settings/device_page/device_page.js b/chrome/browser/resources/settings/device_page/device_page.js index b201a446..f009dad 100644 --- a/chrome/browser/resources/settings/device_page/device_page.js +++ b/chrome/browser/resources/settings/device_page/device_page.js
@@ -88,12 +88,23 @@ if (settings.routes.STORAGE) { map.set(settings.routes.STORAGE.path, '#storageRow'); } + if (settings.routes.EXTERNAL_STORAGE_PREFERENCES) { + map.set( + settings.routes.EXTERNAL_STORAGE_PREFERENCES.path, + '#externalStoragePreferencesRow'); + } if (settings.routes.POWER) { map.set(settings.routes.POWER.path, '#powerRow'); } return map; }, }, + + /** @private */ + androidRunning_: { + type: Boolean, + value: false, + }, }, observers: [ @@ -111,6 +122,10 @@ this.addWebUIListener( 'has-stylus-changed', this.set.bind(this, 'hasStylus_')); settings.DevicePageBrowserProxyImpl.getInstance().initializeStylus(); + + this.addWebUIListener( + 'storage-android-running-changed', + this.set.bind(this, 'androidRunning_')); }, /**
diff --git a/chrome/browser/resources/settings/device_page/storage.html b/chrome/browser/resources/settings/device_page/storage.html index 9e26641d..00881f1 100644 --- a/chrome/browser/resources/settings/device_page/storage.html +++ b/chrome/browser/resources/settings/device_page/storage.html
@@ -9,6 +9,7 @@ <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="drive_cache_dialog.html"> +<link rel="import" href="storage_external.html"> <link rel="import" href="../prefs/prefs.html"> <link rel="import" href="../route.html"> <link rel="import" href="../settings_shared_css.html"> @@ -232,6 +233,11 @@ label="$i18n{storageItemOtherUsers}" sub-label="$i18n{storageSizeComputing}"></cr-link-row> </template> + <template is="dom-if" if="[[androidRunning_]]"> + <cr-link-row id="externalStoragePreferences" class="hr" + on-click="onExternalStoragePreferencesTap_" + label="$i18n{storageExternal}"></cr-link-row> + </template> <settings-drive-cache-dialog id="storageDriveCache" on-close="onCloseDriveCacheDialog_">
diff --git a/chrome/browser/resources/settings/device_page/storage.js b/chrome/browser/resources/settings/device_page/storage.js index 9034714..2867765 100644 --- a/chrome/browser/resources/settings/device_page/storage.js +++ b/chrome/browser/resources/settings/device_page/storage.js
@@ -188,6 +188,14 @@ }, /** + * Handler for tapping the "External storage preferences" item. + * @private + */ + onExternalStoragePreferencesTap_: function() { + settings.navigateTo(settings.routes.EXTERNAL_STORAGE_PREFERENCES); + }, + + /** * @param {!settings.StorageSizeStat} sizeStat * @private */
diff --git a/chrome/browser/resources/settings/device_page/storage_external.html b/chrome/browser/resources/settings/device_page/storage_external.html new file mode 100644 index 0000000..e215e54 --- /dev/null +++ b/chrome/browser/resources/settings/device_page/storage_external.html
@@ -0,0 +1,21 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="../prefs/prefs.html"> +<link rel="import" href="../settings_shared_css.html"> + +<dom-module id="settings-storage-external"> + <template> + <style include="settings-shared"></style> + <div class="settings-box first"> + <span> + $i18n{storageAndroidAppsExternalDrivesNote} + </span> + </div> + <settings-toggle-button class="hr" + pref="{{prefs.arc.has_access_to_removable_media}}" + label="$i18n{storageAndroidAppsExternalDrives}"> + </settings-toggle-button> + </template> + <script src="storage_external.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/device_page/storage_external.js b/chrome/browser/resources/settings/device_page/storage_external.js new file mode 100644 index 0000000..61f54f6 --- /dev/null +++ b/chrome/browser/resources/settings/device_page/storage_external.js
@@ -0,0 +1,13 @@ +// Copyright 2019 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. + +/** + * @fileoverview + * 'settings-storage-external' is the settings subpage for external storage + * settings. + */ + +Polymer({ + is: 'settings-storage-external', +});
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index b324bb7..d8021a7 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -398,6 +398,12 @@ <structure name="IDR_OS_SETTINGS_DEVICE_STORAGE_JS" file="device_page/storage.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_HTML" + file="device_page/storage_external.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_JS" + file="device_page/storage_external.js" + type="chrome_html" /> <structure name="IDR_OS_SETTINGS_DEVICE_STYLUS_HTML" file="device_page/stylus.html" type="chrome_html" />
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js index b4c7da7..ca7e9875 100644 --- a/chrome/browser/resources/settings/route.js +++ b/chrome/browser/resources/settings/route.js
@@ -40,6 +40,7 @@ * DISPLAY: (undefined|!settings.Route), * DOWNLOADS: (undefined|!settings.Route), * EDIT_DICTIONARY: (undefined|!settings.Route), + * EXTERNAL_STORAGE_PREFERENCES: (undefined|!settings.Route), * FINGERPRINT: (undefined|!settings.Route), * FONTS: (undefined|!settings.Route), * GOOGLE_ASSISTANT: (undefined|!settings.Route), @@ -334,6 +335,8 @@ r.STYLUS = r.DEVICE.createChild('/stylus'); r.DISPLAY = r.DEVICE.createChild('/display'); r.STORAGE = r.DEVICE.createChild('/storage'); + r.EXTERNAL_STORAGE_PREFERENCES = + r.DEVICE.createChild('/storage/externalStoragePreferences'); r.POWER = r.DEVICE.createChild('/power'); // </if>
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index 49e1c0ea..56b7350f 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -543,6 +543,12 @@ <structure name="IDR_SETTINGS_DEVICE_STORAGE_JS" file="device_page/storage.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_HTML" + file="device_page/storage_external.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_DEVICE_STORAGE_EXTERNAL_JS" + file="device_page/storage_external.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_DEVICE_STYLUS_HTML" file="device_page/stylus.html" type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js index 3c0fa8a..02b96e43 100644 --- a/chrome/browser/resources/settings/settings_ui/settings_ui.js +++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -55,7 +55,10 @@ }, /** @private */ - narrow_: Boolean, + narrow_: { + type: Boolean, + observer: 'onNarrowChanged_', + }, /** * @private {!PageVisibility} @@ -344,4 +347,11 @@ this.advancedOpenedInMain_ = true; } }, + + /** @private */ + onNarrowChanged_: function() { + if (this.$.drawer.open && !this.narrow_) { + this.$.drawer.close(); + } + }, });
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc index dded19b..a4d2044 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc
@@ -76,10 +76,8 @@ case ash::SearchResultType::kUnknown: case ash::SearchResultType::kPlayStoreApp: case ash::SearchResultType::kInstantApp: - case ash::SearchResultType::kWebStoreApp: case ash::SearchResultType::kAnswerCard: case ash::SearchResultType::kPlayStoreReinstallApp: - case ash::SearchResultType::kWebStoreSearch: return RankingItemType::kIgnored; case ash::SearchResultType::kArcAppShortcut: return RankingItemType::kArcAppShortcut;
diff --git a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc index 73b420d..9e7bf56 100644 --- a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc +++ b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
@@ -35,7 +35,7 @@ // Maximum number of results to show in each mixer group. const size_t kMaxAppsGroupResults = 4; const size_t kMaxOmniboxResults = 4; -const size_t kMaxWebstoreResults = 2; +const size_t kMaxPlaystoreResults = 2; class TestSearchResult : public ChromeSearchResult { public: @@ -136,7 +136,7 @@ providers_.push_back( std::make_unique<TestSearchProvider>("omnibox", ResultType::kOmnibox)); providers_.push_back(std::make_unique<TestSearchProvider>( - "webstore", ResultType::kWebStoreApp)); + "playstore", ResultType::kPlayStoreApp)); } void CreateMixer() { @@ -146,11 +146,12 @@ // to test answer card/apps group having relevance boost. size_t apps_group_id = mixer_->AddGroup(kMaxAppsGroupResults, 1.0, 0.0); size_t omnibox_group_id = mixer_->AddGroup(kMaxOmniboxResults, 1.0, 0.0); - size_t webstore_group_id = mixer_->AddGroup(kMaxWebstoreResults, 0.5, 0.0); + size_t playstore_group_id = + mixer_->AddGroup(kMaxPlaystoreResults, 0.5, 0.0); mixer_->AddProviderToGroup(apps_group_id, providers_[0].get()); mixer_->AddProviderToGroup(omnibox_group_id, providers_[1].get()); - mixer_->AddProviderToGroup(webstore_group_id, providers_[2].get()); + mixer_->AddProviderToGroup(playstore_group_id, providers_[2].get()); } void RunQuery() { @@ -181,7 +182,7 @@ Mixer* mixer() { return mixer_.get(); } TestSearchProvider* app_provider() { return providers_[0].get(); } TestSearchProvider* omnibox_provider() { return providers_[1].get(); } - TestSearchProvider* webstore_provider() { return providers_[2].get(); } + TestSearchProvider* playstore_provider() { return providers_[2].get(); } private: base::test::ScopedTaskEnvironment scoped_task_environment_; @@ -206,43 +207,43 @@ struct TestCase { const size_t app_results; const size_t omnibox_results; - const size_t webstore_results; + const size_t playstore_results; const char* expected; } kTestCases[] = { {0, 0, 0, ""}, {10, 0, 0, "app0,app1,app2,app3,app4,app5,app6,app7,app8,app9"}, {0, 0, 10, - "webstore0,webstore1,webstore2,webstore3,webstore4,webstore5,webstore6," - "webstore7,webstore8,webstore9"}, + "playstore0,playstore1,playstore2,playstore3,playstore4,playstore5," + "playstore6,playstore7,playstore8,playstore9"}, {4, 6, 0, "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3"}, {4, 6, 2, - "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,webstore0," - "webstore1"}, + "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,playstore0," + "playstore1"}, {10, 10, 10, - "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,webstore0," - "webstore1"}, + "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,playstore0," + "playstore1"}, {0, 10, 0, "omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5,omnibox6," "omnibox7,omnibox8,omnibox9"}, {0, 10, 1, - "omnibox0,omnibox1,omnibox2,omnibox3,webstore0,omnibox4,omnibox5," + "omnibox0,omnibox1,omnibox2,omnibox3,playstore0,omnibox4,omnibox5," "omnibox6,omnibox7,omnibox8,omnibox9"}, - {0, 10, 2, "omnibox0,omnibox1,omnibox2,omnibox3,webstore0,webstore1"}, + {0, 10, 2, "omnibox0,omnibox1,omnibox2,omnibox3,playstore0,playstore1"}, {1, 10, 0, "app0,omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5,omnibox6," "omnibox7,omnibox8,omnibox9"}, {2, 10, 0, "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3"}, - {2, 10, 1, "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,webstore0"}, + {2, 10, 1, "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,playstore0"}, {2, 10, 2, - "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,webstore0,webstore1"}, - {2, 0, 2, "app0,app1,webstore0,webstore1"}, + "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,playstore0,playstore1"}, + {2, 0, 2, "app0,app1,playstore0,playstore1"}, {0, 0, 0, ""}, }; for (size_t i = 0; i < base::size(kTestCases); ++i) { app_provider()->set_count(kTestCases[i].app_results); omnibox_provider()->set_count(kTestCases[i].omnibox_results); - webstore_provider()->set_count(kTestCases[i].webstore_results); + playstore_provider()->set_count(kTestCases[i].playstore_results); RunQuery(); EXPECT_EQ(kTestCases[i].expected, GetResults()) << "Case " << i; @@ -263,8 +264,8 @@ omnibox_provider()->set_count(2); // This gives "dup0". - webstore_provider()->set_prefix(dup); - webstore_provider()->set_count(1); + playstore_provider()->set_prefix(dup); + playstore_provider()->set_count(1); RunQuery();
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc index e9e775c..a920c73 100644 --- a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc +++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -4,10 +4,8 @@ #include "ash/accelerators/accelerator_commands.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_properties.h" -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "base/command_line.h" #include "base/macros.h" #include "build/build_config.h" @@ -54,12 +52,7 @@ // Tells Ash to toggle fullscreen as if the user had pressed the hardware // fullscreen key. void ToggleFullscreen() { - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - ash::mojom::ShellTestApiAsyncWaiter waiter(shell_test_api.get()); - waiter.ToggleFullscreen(); + ash::ShellTestApi().ToggleFullscreen(); aura::test::WaitForAllChangesToComplete(); }
diff --git a/chrome/browser/ui/ash/ash_shell_init.cc b/chrome/browser/ui/ash/ash_shell_init.cc index d383c4d..b3b359d 100644 --- a/chrome/browser/ui/ash/ash_shell_init.cc +++ b/chrome/browser/ui/ash/ash_shell_init.cc
@@ -6,7 +6,6 @@ #include <utility> -#include "ash/display/display_prefs.h" #include "ash/shell.h" #include "ash/shell_init_params.h" #include "chrome/browser/browser_process.h" @@ -28,13 +27,7 @@ shell_init_params.connector = content::ServiceManagerConnection::GetForProcess()->GetConnector(); DCHECK(shell_init_params.connector); - // Pass the initial display prefs to ash::Shell as a Value dictionary. - // This is done this way to avoid complexities with registering the display - // prefs in multiple places (i.e. in g_browser_process->local_state() and - // ash::Shell::local_state_). See https://crbug.com/834775 for details. - shell_init_params.initial_display_prefs = - ash::DisplayPrefs::GetInitialDisplayPrefsFromPrefService( - g_browser_process->local_state()); + shell_init_params.local_state = g_browser_process->local_state(); shell_init_params.keyboard_ui_factory = std::make_unique<ChromeKeyboardUIFactory>(); shell_init_params.dbus_bus = @@ -45,13 +38,6 @@ } // namespace -// static -void AshShellInit::RegisterDisplayPrefs(PrefRegistrySimple* registry) { - // DisplayPrefs must be registered here so that the initial display prefs can - // be passed synchronously to ash::Shell. - ash::DisplayPrefs::RegisterLocalStatePrefs(registry); -} - AshShellInit::AshShellInit() { CreateShell(); ash::Shell::GetPrimaryRootWindow()->GetHost()->Show();
diff --git a/chrome/browser/ui/ash/ash_shell_init.h b/chrome/browser/ui/ash/ash_shell_init.h index ef4936e..8980039 100644 --- a/chrome/browser/ui/ash/ash_shell_init.h +++ b/chrome/browser/ui/ash/ash_shell_init.h
@@ -7,20 +7,12 @@ #include "base/macros.h" -class PrefRegistrySimple; - // Initializes and destroys the ash::Shell when Ash is running in process. class AshShellInit { public: AshShellInit(); ~AshShellInit(); - // Registers ash display prefs so that they can be provided synchronously - // to Shell from the local state (which is loaded asynchronously in Shell). - // |registry| should be the PrefRegistry for local state prefs. - // TODO(stevenjb): Improve how we do this. https://crbug.com/678949. - static void RegisterDisplayPrefs(PrefRegistrySimple* registry); - private: DISALLOW_COPY_AND_ASSIGN(AshShellInit); };
diff --git a/chrome/browser/ui/ash/ash_test_util.cc b/chrome/browser/ui/ash/ash_test_util.cc deleted file mode 100644 index 7b799d3..0000000 --- a/chrome/browser/ui/ash/ash_test_util.cc +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2019 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/ui/ash/ash_test_util.h" - -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" -#include "base/run_loop.h" -#include "content/public/common/service_manager_connection.h" -#include "services/service_manager/public/cpp/connector.h" -#include "ui/aura/test/mus/change_completion_waiter.h" - -namespace test { - -ash::mojom::ShellTestApiPtr GetShellTestApi() { - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - - return shell_test_api; -} - -void WaitForNoPointerHoldLock(bool wait_for_changes) { - ash::mojom::ShellTestApiPtr shell_test_api = GetShellTestApi(); - - // Allow nestable tasks because this is called within a move loop. - base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); - shell_test_api->WaitForNoPointerHoldLock(run_loop.QuitClosure()); - run_loop.Run(); - - if (wait_for_changes) - aura::test::WaitForAllChangesToComplete(); -} - -void WaitForOverviewAnimationState(ash::mojom::OverviewAnimationState state) { - ash::mojom::ShellTestApiPtr shell_test_api = GetShellTestApi(); - - base::RunLoop run_loop; - shell_test_api->WaitForOverviewAnimationState(state, run_loop.QuitClosure()); - run_loop.Run(); -} - -} // namespace test
diff --git a/chrome/browser/ui/ash/ash_test_util.h b/chrome/browser/ui/ash/ash_test_util.h deleted file mode 100644 index 5e918fd..0000000 --- a/chrome/browser/ui/ash/ash_test_util.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2019 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_UI_ASH_ASH_TEST_UTIL_H_ -#define CHROME_BROWSER_UI_ASH_ASH_TEST_UTIL_H_ - -#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" - -namespace test { - -// Binds to ash service and returns a ShellTestApiPtr. -ash::mojom::ShellTestApiPtr GetShellTestApi(); - -// Waits until WindowTreeHost no longer holding pointer events. -// If |wait_for_all_changes| is true, this also runs -// aura::test::WaitForAllChangesToComplete(). -void WaitForNoPointerHoldLock(bool wait_for_changes = true); - -// Waits until the overview animation finishes and its state becomes |state|. -void WaitForOverviewAnimationState(ash::mojom::OverviewAnimationState state); - -} // namespace test - -#endif // CHROME_BROWSER_UI_ASH_ASH_TEST_UTIL_H_
diff --git a/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc b/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc index 5d7ac7c..13b4335 100644 --- a/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc +++ b/chrome/browser/ui/ash/drag_to_overview_interactive_uitest.cc
@@ -3,12 +3,12 @@ // found in the LICENSE file. #include "ash/public/cpp/ash_switches.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "base/bind.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/task/post_task.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/ash/tablet_mode_client_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" @@ -30,14 +30,6 @@ namespace { -bool IsOverviewSelecting() { - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - ash::mojom::ShellTestApiAsyncWaiter waiter(shell_test_api.get()); - bool is_selecting = false; - waiter.IsOverviewSelecting(&is_selecting); - return is_selecting; -} - int GetDetachY(TabStrip* tab_strip) { return std::max(TabDragController::kTouchVerticalDetachMagnetism, TabDragController::kVerticalDetachMagnetism) + @@ -48,11 +40,9 @@ // constructed. class NextFrameWaiter { public: - NextFrameWaiter() : shell_test_api_(test::GetShellTestApi()) { - shell_test_api_->WaitForNextFrame(base::BindOnce( + NextFrameWaiter() { + ash::ShellTestApi().WaitForNextFrame(base::BindOnce( &NextFrameWaiter::OnFramePresented, base::Unretained(this))); - // Flush to ensure the call has gone through. - shell_test_api_.FlushForTesting(); } ~NextFrameWaiter() { EXPECT_TRUE(frame_presented_); } @@ -72,7 +62,6 @@ run_loop_->Quit(); } - ash::mojom::ShellTestApiPtr shell_test_api_; bool frame_presented_ = false; std::unique_ptr<base::RunLoop> run_loop_; @@ -121,7 +110,7 @@ for (int i = 0; i < count; ++i) { drag_position += delta; - test::WaitForNoPointerHoldLock(/*wait_for_changes=*/false); + ash::ShellTestApi().WaitForNoPointerHoldLock(); NextFrameWaiter waiter; ASSERT_TRUE( ui_controls::SendMouseMove(drag_position.x(), drag_position.y())); @@ -163,7 +152,7 @@ browser_screen_bounds.CenterPoint().x(), browser_screen_bounds.y() + browser_view->GetTabStripHeight() / 2); - test::WaitForNoPointerHoldLock(); + ash::ShellTestApi().WaitForNoPointerHoldLock(); ASSERT_TRUE( ui_test_utils::SendMouseMoveSync(start_position) && ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::DOWN)); @@ -180,7 +169,7 @@ constexpr int kSteps = 20; gfx::Vector2d delta(0, drag_length / kSteps); ContinueDrag(start_position, delta, kSteps); - EXPECT_TRUE(IsOverviewSelecting()); + EXPECT_TRUE(ash::ShellTestApi().IsOverviewSelecting()); } IN_PROC_BROWSER_TEST_F(DragToOverviewTest, DragTab) { @@ -195,7 +184,7 @@ gfx::Point drag_position(ui_test_utils::GetCenterInScreenCoordinates( browser_view->tabstrip()->tab_at(0))); - test::WaitForNoPointerHoldLock(); + ash::ShellTestApi().WaitForNoPointerHoldLock(); ASSERT_TRUE( ui_test_utils::SendMouseMoveSync(drag_position) && ui_test_utils::SendMouseEventsSync(ui_controls::LEFT, ui_controls::DOWN)); @@ -210,7 +199,7 @@ gfx::Vector2d delta(0, drag_length / kSteps); // Drag tab far enough to detach. - test::WaitForNoPointerHoldLock(); + ash::ShellTestApi().WaitForNoPointerHoldLock(); drag_position.Offset(0, GetDetachY(browser_view->tabstrip())); ui_controls::SendMouseMoveNotifyWhenDone( drag_position.x(), drag_position.y(),
diff --git a/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc b/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc index f171b2c..ad2ae58 100644 --- a/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc +++ b/chrome/browser/ui/ash/launcher_animations_interactive_uitest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/interfaces/app_list_view.mojom.h" #include "base/bind.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/task/post_task.h" #include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -59,30 +59,22 @@ // use the 1st browser window regardless of number of windows created. BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - { - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kFullscreenAllApps, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/true, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } - { - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kClosed, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/true, - /*alt=*/false, - /* command = */ false); + ash::ShellTestApi shell_test_api; + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/true, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kFullscreenAllApps); - waiter.Run(); - } + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/true, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kClosed); } IN_PROC_BROWSER_TEST_F(LauncherAnimationsTest, Peeking) { @@ -91,29 +83,22 @@ // use the 1st browser window regardless of number of windows created. BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - { - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kPeeking, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } - { - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kClosed, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } + ash::ShellTestApi shell_test_api; + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kPeeking); + + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kClosed); } IN_PROC_BROWSER_TEST_F(LauncherAnimationsTest, Half) { @@ -122,44 +107,34 @@ // use the 1st browser window regardless of number of windows created. BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - { - // Hit the search key; it should switch to kPeeking state. - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kPeeking, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } - { - // Type some query in the launcher; it should show search results in kHalf - // state. - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kHalf, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_A, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } - { - // Search key to close the launcher. - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kClosed, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } + ash::ShellTestApi shell_test_api; + // Hit the search key; it should switch to kPeeking state. + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kPeeking); + + // Type some query in the launcher; it should show search results in kHalf + // state. + ui_controls::SendKeyPress(browser_window, ui::VKEY_A, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kHalf); + + // Search key to close the launcher. + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kClosed); } IN_PROC_BROWSER_TEST_F(LauncherAnimationsTest, FullscreenSearch) { @@ -168,54 +143,41 @@ // use the 1st browser window regardless of number of windows created. BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - { - // Hit the search key; it should switch to the kPeeking state. - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kPeeking, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } - { - // Type some query; it should show the search results in the kHalf state. - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kHalf, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_A, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } - { - // Shift+search key; it should expand to fullscreen with search results - // (i.e. kFullscreenSearch state). - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kFullscreenSearch, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/true, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } - { - // Search key to close the launcher. - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kClosed, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/false, - /*alt=*/false, - /* command = */ false); - waiter.Run(); - } + ash::ShellTestApi shell_test_api; + // Hit the search key; it should switch to the kPeeking state. + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kPeeking); + + // Type some query; it should show the search results in the kHalf state. + ui_controls::SendKeyPress(browser_window, ui::VKEY_A, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kHalf); + + // Shift+search key; it should expand to fullscreen with search results + // (i.e. kFullscreenSearch state). + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/true, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kFullscreenSearch); + + // Search key to close the launcher. + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/false, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kClosed); }
diff --git a/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc b/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc index e2fec830..601add7 100644 --- a/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc +++ b/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/public/cpp/app_list/app_list_config.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/interfaces/app_list_view.mojom.h" #include "ash/shelf/shelf_constants.h" #include "base/macros.h" @@ -10,7 +11,6 @@ #include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/test/base/perf/drag_event_generator.h" @@ -60,11 +60,7 @@ IN_PROC_BROWSER_TEST_F(LauncherDragTest, Open) { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kFullscreenAllApps, waiter.QuitClosure()); + ash::ShellTestApi shell_test_api; gfx::Rect display_bounds = GetDisplayBounds(browser_window); gfx::Point start_point = @@ -78,29 +74,22 @@ /*touch=*/true); generator.Wait(); - waiter.Run(); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kFullscreenAllApps); } // Drag to close the launcher. IN_PROC_BROWSER_TEST_F(LauncherDragTest, Close) { BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - { - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kFullscreenAllApps, waiter.QuitClosure()); - ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, - /*control=*/false, - /*shift=*/true, - /*alt=*/false, - /*command=*/false); - waiter.Run(); - } - - base::RunLoop waiter; - shell_test_api->WaitForLauncherAnimationState( - ash::mojom::AppListViewState::kClosed, waiter.QuitClosure()); + ash::ShellTestApi shell_test_api; + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/true, + /*alt=*/false, + /*command=*/false); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kFullscreenAllApps); gfx::Rect display_bounds = GetDisplayBounds(browser_window); gfx::Point start_point = gfx::Point(display_bounds.width() / 4, 10); @@ -112,5 +101,6 @@ /*touch=*/true); generator.Wait(); - waiter.Run(); + shell_test_api.WaitForLauncherAnimationState( + ash::mojom::AppListViewState::kClosed); }
diff --git a/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc index bcc65ce..afc0924 100644 --- a/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc +++ b/chrome/browser/ui/ash/network/networking_config_chromeos_browsertest.cc
@@ -7,6 +7,7 @@ #include "ash/public/interfaces/system_tray_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/system_tray_test_api.test-mojom.h" #include "base/macros.h" +#include "base/run_loop.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/extension_browsertest.h" @@ -38,8 +39,9 @@ // Show the network detail view. ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api.get()); wait_for.ShowDetailedView(ash::mojom::TrayItem::kNetwork); + base::RunLoop().RunUntilIdle(); - // Expect that the extension-controlled VPN item appears. + // Expect that the extension-controlled item appears. base::string16 expected_tooltip = base::UTF8ToUTF16( "The extension \"NetworkingConfig test extension\" can help connect to " "this network.");
diff --git a/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc b/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc index f07e045..404bc617 100644 --- a/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc +++ b/chrome/browser/ui/ash/overview_animations_interactive_uitest.cc
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/public/cpp/test/shell_test_api.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/task/post_task.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/ash/tablet_mode_client_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" @@ -83,15 +83,15 @@ /*shift=*/false, /*alt=*/false, /*command=*/false); - test::WaitForOverviewAnimationState( - ash::mojom::OverviewAnimationState::kEnterAnimationComplete); + ash::ShellTestApi().WaitForOverviewAnimationState( + ash::OverviewAnimationState::kEnterAnimationComplete); ui_controls::SendKeyPress(browser_window, ui::VKEY_MEDIA_LAUNCH_APP1, /*control=*/false, /*shift=*/false, /*alt=*/false, /*command=*/false); - test::WaitForOverviewAnimationState( - ash::mojom::OverviewAnimationState::kExitAnimationComplete); + ash::ShellTestApi().WaitForOverviewAnimationState( + ash::OverviewAnimationState::kExitAnimationComplete); } INSTANTIATE_TEST_SUITE_P(,
diff --git a/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc b/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc index 4f56217..05b009e3 100644 --- a/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc +++ b/chrome/browser/ui/ash/overview_window_drag_interactive_uitest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/cpp/window_state_type.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/task/post_task.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/ash/tablet_mode_client_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" @@ -132,8 +132,8 @@ /*shift=*/false, /*alt=*/false, /*command=*/false); - test::WaitForOverviewAnimationState( - ash::mojom::OverviewAnimationState::kEnterAnimationComplete); + ash::ShellTestApi().WaitForOverviewAnimationState( + ash::OverviewAnimationState::kEnterAnimationComplete); gfx::Size display_size = GetDisplaySize(browser_window); gfx::Point start_point = GetStartLocation(display_size); gfx::Point end_point(start_point); @@ -155,8 +155,8 @@ /*shift=*/false, /*alt=*/false, /*command=*/false); - test::WaitForOverviewAnimationState( - ash::mojom::OverviewAnimationState::kEnterAnimationComplete); + ash::ShellTestApi().WaitForOverviewAnimationState( + ash::OverviewAnimationState::kEnterAnimationComplete); content::WindowedNotificationObserver waiter( chrome::NOTIFICATION_BROWSER_CLOSED, @@ -185,8 +185,8 @@ /*shift=*/false, /*alt=*/false, /*command=*/false); - test::WaitForOverviewAnimationState( - ash::mojom::OverviewAnimationState::kEnterAnimationComplete); + ash::ShellTestApi().WaitForOverviewAnimationState( + ash::OverviewAnimationState::kEnterAnimationComplete); gfx::Point start_point = GetStartLocation(GetDisplaySize(browser_window)); gfx::Point end_point(start_point);
diff --git a/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc b/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc index 87d9b02f..e12b763 100644 --- a/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc +++ b/chrome/browser/ui/ash/screen_rotation_interactive_uitest.cc
@@ -9,7 +9,6 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/task/post_task.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/ash/tablet_mode_client_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/ui/ash/split_view_interactive_uitest.cc b/chrome/browser/ui/ash/split_view_interactive_uitest.cc index 69e9791..d01c2e9 100644 --- a/chrome/browser/ui/ash/split_view_interactive_uitest.cc +++ b/chrome/browser/ui/ash/split_view_interactive_uitest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/public/cpp/ash_switches.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/shell.h" #include "ash/wm/splitview/split_view_controller.h" #include "base/macros.h" @@ -10,7 +11,6 @@ #include "base/system/sys_info.h" #include "base/task/post_task.h" #include "base/test/bind_test_util.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/ash/tablet_mode_client_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" @@ -66,7 +66,7 @@ run_loop_->Run(); EXPECT_FALSE(waiting_for_frame_); } - test::WaitForNoPointerHoldLock(); + ash::ShellTestApi().WaitForNoPointerHoldLock(); } while (waiting_for_frame_); } @@ -130,7 +130,7 @@ shell->split_view_controller()->SnapWindow(browser_widget->GetNativeWindow(), ash::SplitViewController::RIGHT); - test::WaitForNoPointerHoldLock(); + ash::ShellTestApi().WaitForNoPointerHoldLock(); const gfx::Size display_size = display::Screen::GetScreen()->GetPrimaryDisplay().bounds().size();
diff --git a/chrome/browser/ui/ash/tablet_mode_client_test_util.cc b/chrome/browser/ui/ash/tablet_mode_client_test_util.cc index 94f5945..be9ce68 100644 --- a/chrome/browser/ui/ash/tablet_mode_client_test_util.cc +++ b/chrome/browser/ui/ash/tablet_mode_client_test_util.cc
@@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "base/run_loop.h" #include "chrome/browser/ui/ash/tablet_mode_client.h" #include "chrome/browser/ui/ash/tablet_mode_client_observer.h" @@ -50,11 +49,7 @@ void SetAndWaitForTabletMode(bool enabled) { ASSERT_NE(enabled, TabletModeClient::Get()->tablet_mode_enabled()); - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - shell_test_api->EnableTabletModeWindowManager(enabled); + ash::ShellTestApi().EnableTabletModeWindowManager(enabled); TestTabletModeClientObserver observer(enabled); observer.run_loop()->Run();
diff --git a/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc b/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc index b0a90e0c..72e2e49d 100644 --- a/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc +++ b/chrome/browser/ui/ash/tablet_mode_transition_interactive_uitest.cc
@@ -6,7 +6,6 @@ #include "base/macros.h" #include "base/run_loop.h" #include "base/task/post_task.h" -#include "chrome/browser/ui/ash/ash_test_util.h" #include "chrome/browser/ui/ash/tablet_mode_client_test_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index bbfb1ce1..79d61d43 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -107,11 +107,18 @@ // Ensures that - if we have not popped up an infobar to prompt the user to e.g. // reload the current page - that the content pane of the browser is refocused. void AppInfoDialogClosedCallback(content::WebContents* web_contents, - views::Widget::ClosedReason /* unused */, + views::Widget::ClosedReason closed_reason, bool reload_prompt) { if (reload_prompt) return; + // If the user clicked on something specific or focus was changed, don't + // override the focus. + if (closed_reason != views::Widget::ClosedReason::kEscKeyPressed && + closed_reason != views::Widget::ClosedReason::kCloseButtonClicked) { + return; + } + // Ensure that the web contents handle we have is still valid. It's possible // (though unlikely) that either the browser or web contents has been pulled // out from underneath us.
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm index 79a9187..1be7698 100644 --- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm +++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm
@@ -71,13 +71,26 @@ - (void)populateMenu:(NSMenu*)menu withServiceEntries:(NSArray*)entries forDisplay:(BOOL)display { - // Create a new service entry array that does not include the redundant - // Services vended by Safari. NSMutableArray* remainingEntries = [NSMutableArray array]; [g_filtered_entries_array removeAllObjects]; + // Remove some services. + // - Remove the ones from Safari, as they are redundant to the ones provided + // by Chromium, and confusing to the user due to them switching apps + // upon their selection. + // - Remove the "Open URL" one provided by SystemUIServer, as it is + // redundant to the one provided by Chromium and has other serious issues. + // (https://crbug.com/960209) + for (_NSServiceEntry* nextEntry in entries) { - if (![[nextEntry bundleIdentifier] isEqualToString:@"com.apple.Safari"]) { + NSString* bundleIdentifier = [nextEntry bundleIdentifier]; + NSString* message = [nextEntry valueForKey:@"message"]; + bool shouldRemove = + ([bundleIdentifier isEqualToString:@"com.apple.Safari"]) || + ([bundleIdentifier isEqualToString:@"com.apple.systemuiserver"] && + [message isEqualToString:@"openURL"]); + + if (!shouldRemove) { [remainingEntries addObject:nextEntry]; } else { [g_filtered_entries_array addObject:nextEntry];
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm index cef4092..da9d31f 100644 --- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm +++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
@@ -24,10 +24,11 @@ storeFilteredEntriesForTestingInArray:filteredItems_]; // Add a textfield, which we'll use to present a contextual menu for - // testing. + // testing. Fill it with a URL, as the services that need to be filtered + // primarily appear for URLs. textField_.reset( [[NSTextField alloc] initWithFrame:NSMakeRect(20, 20, 100, 20)]); - [textField_ setStringValue:@"some text"]; + [textField_ setStringValue:@"http://someurl.com/"]; NSWindow* window = browser()->window()->GetNativeWindow().GetNativeNSWindow(); [[window contentView] addSubview:textField_]; @@ -93,9 +94,27 @@ withEvent:[NSApp currentEvent] forView:firstResponder]; - // Confirm that Services items were removed from the contextual menu. This - // check was failing on the 10.10 bot, for some reason. Most-important is - // making sure it continues to work as OS X evolves. - if (base::mac::IsAtLeastOS10_11()) - EXPECT_LT(0LU, [filteredItems_ count]); + // Confirm that Services items were removed from the contextual menu. + + // Note that in macOS 10.10, a subset of the services are added directly to + // the contextual menu, none of which are the removed ones, so this test isn't + // applicable to that version. + if (base::mac::IsOS10_10()) + return; + + bool was_safari_item_removed = false; + bool was_open_url_item_removed = false; + + for (id item in filteredItems_.get()) { + if ([[item valueForKey:@"bundleIdentifier"] + isEqualToString:@"com.apple.Safari"]) { + was_safari_item_removed = true; + } + if ([[item valueForKey:@"message"] isEqualToString:@"openURL"]) { + was_open_url_item_removed = true; + } + } + + EXPECT_TRUE(was_safari_item_removed); + EXPECT_TRUE(was_open_url_item_removed); }
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc index 8ddbbf8..c3649e9 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -32,10 +32,7 @@ #include "content/public/browser/web_contents.h" #include "extensions/common/extension.h" -#if defined(OS_MACOSX) -#include "base/feature_list.h" -#include "chrome/common/chrome_features.h" -#else +#if !defined(OS_MACOSX) #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #endif @@ -443,11 +440,7 @@ WebContents* web_contents, bool enter_fullscreen) { if (enter_fullscreen) { - if (web_contents->IsBeingCaptured() -#if defined(OS_MACOSX) - || base::FeatureList::IsEnabled(features::kContentFullscreen) -#endif - ) { + if (web_contents->IsBeingCaptured()) { FullscreenWithinTabHelper::CreateForWebContents(web_contents); FullscreenWithinTabHelper::FromWebContents(web_contents) ->SetIsFullscreenWithinTab(true);
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc index 39f4061..a39f3be 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.cc +++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -258,6 +258,9 @@ if (!action_runner) return false; + if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) + extensions_container_->CloseOverflowMenuIfOpen(); + if (action_runner->RunAction(extension(), grant_tab_permissions) == ExtensionAction::ACTION_SHOW_POPUP) { GURL popup_url = extension_action_->GetPopupUrl( @@ -355,10 +358,6 @@ ExtensionActionViewController* ExtensionActionViewController::GetPreferredPopupViewController() { - // TODO(pbos): Remove this guard when implementing GetActionForId() in - // ExtensionsToolbarContainer. - if (base::FeatureList::IsEnabled(features::kExtensionsToolbarMenu)) - return this; return static_cast<ExtensionActionViewController*>( extensions_container_->GetActionForId(GetId())); }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index a9605f92..d7cf0f3 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -329,14 +329,14 @@ foreground ? (ADD_INHERIT_OPENER | ADD_ACTIVE) : ADD_NONE); } -void TabStripModel::InsertWebContentsAt(int index, - std::unique_ptr<WebContents> contents, - int add_types, - base::Optional<int> group) { +int TabStripModel::InsertWebContentsAt(int index, + std::unique_ptr<WebContents> contents, + int add_types, + base::Optional<int> group) { DCHECK(!reentrancy_guard_); base::AutoReset<bool> resetter(&reentrancy_guard_, true); - InsertWebContentsAtImpl(index, std::move(contents), add_types, group); + return InsertWebContentsAtImpl(index, std::move(contents), add_types, group); } std::unique_ptr<content::WebContents> TabStripModel::ReplaceWebContentsAt( @@ -536,9 +536,9 @@ /*triggered_by_other_operation=*/false); } -void TabStripModel::MoveWebContentsAt(int index, - int to_position, - bool select_after_move) { +int TabStripModel::MoveWebContentsAt(int index, + int to_position, + bool select_after_move) { DCHECK(!reentrancy_guard_); base::AutoReset<bool> resetter(&reentrancy_guard_, true); @@ -549,10 +549,10 @@ to_position = IsTabPinned(index) ? std::min(first_non_pinned_tab - 1, to_position) : std::max(first_non_pinned_tab, to_position); - if (index == to_position) - return; - MoveWebContentsAtImpl(index, to_position, select_after_move); + if (index != to_position) + MoveWebContentsAtImpl(index, to_position, select_after_move); + return to_position; } void TabStripModel::MoveSelectedTabsTo(int index) { @@ -1424,7 +1424,7 @@ return items; } -void TabStripModel::InsertWebContentsAtImpl( +int TabStripModel::InsertWebContentsAtImpl( int index, std::unique_ptr<content::WebContents> contents, int add_types, @@ -1484,6 +1484,8 @@ TabStripModelChange change(std::move(insert)); for (auto& observer : observers_) observer.OnTabStripModelChanged(this, change, selection); + + return index; } bool TabStripModel::InternalCloseTabs(
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h index b3799df..0091333 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.h +++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -167,15 +167,15 @@ // All append/insert methods end up in this method. // // NOTE: adding a tab using this method does NOT query the order controller, - // as such the ADD_FORCE_INDEX AddTabTypes is meaningless here. The only time + // as such the ADD_FORCE_INDEX AddTabTypes is meaningless here. The only time // the |index| is changed is if using the index would result in breaking the - // constraint that all pinned tabs occur before non-pinned tabs. - // See also AddWebContents. - void InsertWebContentsAt(int index, - std::unique_ptr<content::WebContents> contents, - int add_types, - base::Optional<int> group = base::nullopt); - + // constraint that all pinned tabs occur before non-pinned tabs. It returns + // the index the web contents is actually inserted to. See also + // AddWebContents. + int InsertWebContentsAt(int index, + std::unique_ptr<content::WebContents> contents, + int add_types, + base::Optional<int> group = base::nullopt); // Closes the WebContents at the specified index. This causes the // WebContents to be destroyed, but it may not happen immediately. // |close_types| is a bitmask of CloseTypes. Returns true if the @@ -224,8 +224,8 @@ // WebContents inline and sends a Moved notification instead. // If |select_after_move| is false, whatever tab was selected before the move // will still be selected, but its index may have incremented or decremented - // one slot. - void MoveWebContentsAt(int index, int to_position, bool select_after_move); + // one slot. It returns the index the web contents is actually moved to. + int MoveWebContentsAt(int index, int to_position, bool select_after_move); // Moves the selected tabs to |index|. |index| is treated as if the tab strip // did not contain any of the selected tabs. For example, if the tabstrip @@ -529,14 +529,15 @@ // All append/insert methods end up in this method. // // NOTE: adding a tab using this method does NOT query the order controller, - // as such the ADD_FORCE_INDEX AddTabTypes is meaningless here. The only time + // as such the ADD_FORCE_INDEX AddTabTypes is meaningless here. The only time // the |index| is changed is if using the index would result in breaking the - // constraint that all pinned tabs occur before non-pinned tabs. - // See also AddWebContents. - void InsertWebContentsAtImpl(int index, - std::unique_ptr<content::WebContents> contents, - int add_types, - base::Optional<int> group); + // constraint that all pinned tabs occur before non-pinned tabs. It returns + // the index the web contents is actually inserted to. See also + // AddWebContents. + int InsertWebContentsAtImpl(int index, + std::unique_ptr<content::WebContents> contents, + int add_types, + base::Optional<int> group); // Closes the WebContentses at the specified indices. This causes the // WebContentses to be destroyed, but it may not happen immediately. If
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc index 3099718..6ea9df92 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/i18n/message_formatter.h" #include "base/macros.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/extension_install_prompt_show_params.h" @@ -270,13 +271,18 @@ void ExtensionInstallDialogView::VisibilityChanged(views::View* starting_from, bool is_visible) { - if (is_visible && !install_button_enabled_) { - // This base::Unretained is safe because the task is owned by the timer, - // which is in turn owned by this object. - timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(g_install_delay_in_ms), - base::Bind(&ExtensionInstallDialogView::EnableInstallButton, - base::Unretained(this))); + if (is_visible) { + DCHECK(!install_result_timer_); + install_result_timer_ = base::ElapsedTimer(); + + if (!install_button_enabled_) { + // This base::Unretained is safe because the task is owned by the timer, + // which is in turn owned by this object. + enable_install_timer_.Start( + FROM_HERE, base::TimeDelta::FromMilliseconds(g_install_delay_in_ms), + base::BindOnce(&ExtensionInstallDialogView::EnableInstallButton, + base::Unretained(this))); + } } } @@ -544,8 +550,18 @@ void ExtensionInstallDialogView::UpdateInstallResultHistogram(bool accepted) const { - if (prompt_->type() == ExtensionInstallPrompt::INSTALL_PROMPT) - UMA_HISTOGRAM_BOOLEAN("Extensions.InstallPrompt.Accepted", accepted); + // Only update histograms if |install_result_timer_| was initialized in + // |VisibilityChanged|. + if (prompt_->type() == ExtensionInstallPrompt::INSTALL_PROMPT && + install_result_timer_) { + if (accepted) { + UmaHistogramMediumTimes("Extensions.InstallPrompt.TimeToInstall", + install_result_timer_->Elapsed()); + } else { + UmaHistogramMediumTimes("Extensions.InstallPrompt.TimeToCancel", + install_result_timer_->Elapsed()); + } + } }
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h index cc6e11a..b3826e1 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h
@@ -8,6 +8,8 @@ #include <vector> #include "base/macros.h" +#include "base/optional.h" +#include "base/timer/elapsed_timer.h" #include "base/timer/timer.h" #include "chrome/browser/extensions/extension_install_prompt.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" @@ -101,8 +103,12 @@ // has been run. bool handled_result_; + // Used to record time between dialog creation and acceptance, cancellation, + // or dismissal. + base::Optional<base::ElapsedTimer> install_result_timer_; + // Used to delay the activation of the install button. - base::OneShotTimer timer_; + base::OneShotTimer enable_install_timer_; // Used to determine whether the install button should be enabled. bool install_button_enabled_;
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc index 6971bd3..6d9b1cb 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/ui/views/extensions/extensions_menu_view.h" +#include <algorithm> + #include "base/path_service.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/extensions/chrome_test_extension_loader.h" @@ -11,11 +13,13 @@ #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/extensions/extensions_menu_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" +#include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/webui_url_constants.h" #include "ui/views/test/button_test_api.h" +#include "ui/views/test/widget_test.h" class ExtensionsMenuViewBrowserTest : public DialogBrowserTest { protected: @@ -45,13 +49,40 @@ std::vector<ExtensionsMenuButton*> buttons; for (auto* view : ExtensionsMenuView::GetExtensionsMenuViewForTesting() ->extension_menu_button_container_for_testing() - ->GetChildrenInZOrder()) { + ->children()) { if (view->GetClassName() == ExtensionsMenuButton::kClassName) buttons.push_back(static_cast<ExtensionsMenuButton*>(view)); } return buttons; } + std::vector<ToolbarActionView*> GetToolbarActionViews() const { + std::vector<ToolbarActionView*> views; + for (auto* view : BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->extensions_container() + ->children()) { + if (view->GetClassName() == ToolbarActionView::kClassName) + views.push_back(static_cast<ToolbarActionView*>(view)); + } + return views; + } + + std::vector<ToolbarActionView*> GetVisibleToolbarActionViews() const { + auto views = GetToolbarActionViews(); + base::EraseIf(views, [](views::View* view) { return !view->visible(); }); + return views; + } + + void TriggerSingleExtensionButton() { + auto buttons = GetExtensionMenuButtons(); + ASSERT_EQ(1u, buttons.size()); + ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0); + views::test::ButtonTestApi test_api(buttons[0]); + test_api.NotifyClick(click_event); + } + base::test::ScopedFeatureList scoped_feature_list_; std::vector<scoped_refptr<const extensions::Extension>> extensions_; }; @@ -67,6 +98,63 @@ ShowAndVerifyUi(); } +IN_PROC_BROWSER_TEST_F(ExtensionsMenuViewBrowserTest, TriggerPopup) { + LoadTestExtension("extensions/simple_with_popup"); + ShowUi(""); + VerifyUi(); + + ExtensionsContainer* const extensions_container = + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->extensions_container(); + + EXPECT_EQ(nullptr, extensions_container->GetPoppedOutAction()); + EXPECT_TRUE(GetVisibleToolbarActionViews().empty()); + + TriggerSingleExtensionButton(); + + // After triggering an extension with a popup, there should a popped-out + // action and show the view. + auto visible_icons = GetVisibleToolbarActionViews(); + EXPECT_NE(nullptr, extensions_container->GetPoppedOutAction()); + ASSERT_EQ(1u, visible_icons.size()); + EXPECT_EQ(extensions_container->GetPoppedOutAction(), + visible_icons[0]->view_controller()); + + extensions_container->HideActivePopup(); + + // After dismissing the popup there should no longer be a popped-out action + // and the icon should no longer be visible in the extensions container. + EXPECT_EQ(nullptr, extensions_container->GetPoppedOutAction()); + EXPECT_TRUE(GetVisibleToolbarActionViews().empty()); +} + +IN_PROC_BROWSER_TEST_F(ExtensionsMenuViewBrowserTest, + TriggeringExtensionClosesMenu) { + LoadTestExtension("extensions/trigger_actions/browser_action"); + ShowUi(""); + VerifyUi(); + + EXPECT_TRUE(ExtensionsMenuView::IsShowing()); + + views::test::WidgetDestroyedWaiter destroyed_waiter( + ExtensionsMenuView::GetExtensionsMenuViewForTesting()->GetWidget()); + TriggerSingleExtensionButton(); + + destroyed_waiter.Wait(); + + ExtensionsContainer* const extensions_container = + BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->extensions_container(); + + // This test should not use a popped-out action, as we want to make sure that + // the menu closes on its own and not because a popup dialog replaces it. + EXPECT_EQ(nullptr, extensions_container->GetPoppedOutAction()); + + EXPECT_FALSE(ExtensionsMenuView::IsShowing()); +} + IN_PROC_BROWSER_TEST_F(ExtensionsMenuViewBrowserTest, CreatesOneButtonPerExtension) { LoadTestExtension("extensions/uitest/long_name"); @@ -97,3 +185,6 @@ chrome::kChromeUIExtensionsURL, browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL()); } + +// TODO(pbos): Add test coverage that makes sure removing popped-out extensions +// properly disposes of the popup.
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc index 2945ac44..7a1e16e2 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -4,12 +4,20 @@ #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/layout_constants.h" +#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" +#include "chrome/browser/ui/views/extensions/extensions_menu_view.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" ExtensionsToolbarContainer::ExtensionsToolbarContainer(Browser* browser) : browser_(browser), + model_(ToolbarActionsModel::Get(browser_->profile())), + model_observer_(this), extensions_button_(new ExtensionsToolbarButton(browser_, this)) { + model_observer_.Add(model_); AddMainView(extensions_button_); + CreateActions(); } ExtensionsToolbarContainer::~ExtensionsToolbarContainer() = default; @@ -20,12 +28,16 @@ ToolbarActionViewController* ExtensionsToolbarContainer::GetActionForId( const std::string& action_id) { + for (const auto& action : actions_) { + if (action->GetId() == action_id) + return action.get(); + } return nullptr; } ToolbarActionViewController* ExtensionsToolbarContainer::GetPoppedOutAction() const { - return nullptr; + return popped_out_action_; } bool ExtensionsToolbarContainer::IsActionVisibleOnToolbar( @@ -33,18 +45,166 @@ return false; } -void ExtensionsToolbarContainer::UndoPopOut() {} +void ExtensionsToolbarContainer::UndoPopOut() { + DCHECK(popped_out_action_); + ToolbarActionViewController* const popped_out_action = popped_out_action_; + popped_out_action_ = nullptr; + // Note that we only hide this view if it was not pinned while being popped + // out. + icons_[popped_out_action->GetId()]->SetVisible( + IsActionVisibleOnToolbar(popped_out_action)); +} void ExtensionsToolbarContainer::SetPopupOwner( - ToolbarActionViewController* popup_owner) {} + ToolbarActionViewController* popup_owner) { + // We should never be setting a popup owner when one already exists, and + // never unsetting one when one wasn't set. + DCHECK((popup_owner_ != nullptr) ^ (popup_owner != nullptr)); + popup_owner_ = popup_owner; +} -void ExtensionsToolbarContainer::HideActivePopup() {} +void ExtensionsToolbarContainer::HideActivePopup() { + if (popup_owner_) + popup_owner_->HidePopup(); + DCHECK(!popup_owner_); +} bool ExtensionsToolbarContainer::CloseOverflowMenuIfOpen() { + if (ExtensionsMenuView::IsShowing()) { + ExtensionsMenuView::Hide(); + return true; + } return false; } void ExtensionsToolbarContainer::PopOutAction( ToolbarActionViewController* action, bool is_sticky, - const base::Closure& closure) {} + const base::Closure& closure) { + // TODO(pbos): Animate popout. + // TODO(pbos): Highlight popout differently. + DCHECK(!popped_out_action_); + popped_out_action_ = action; + icons_[popped_out_action_->GetId()]->SetVisible(true); + ReorderViews(); + closure.Run(); +} + +void ExtensionsToolbarContainer::OnToolbarActionAdded( + const ToolbarActionsModel::ActionId& action_id, + int index) { + CreateActionForId(action_id); + ReorderViews(); +} + +void ExtensionsToolbarContainer::OnToolbarActionRemoved( + const ToolbarActionsModel::ActionId& action_id) { + // TODO(pbos): Handle extension upgrades, see ToolbarActionsBar. Arguably this + // could be handled inside the model and be invisible to the container when + // permissions are unchanged. + + // Delete the icon first so it unregisters it from the action. + icons_.erase(action_id); + base::EraseIf( + actions_, + [action_id](const std::unique_ptr<ToolbarActionViewController>& item) { + return item->GetId() == action_id; + }); +} + +void ExtensionsToolbarContainer::OnToolbarActionMoved( + const ToolbarActionsModel::ActionId& action_id, + int index) {} + +void ExtensionsToolbarContainer::OnToolbarActionLoadFailed() {} + +void ExtensionsToolbarContainer::OnToolbarActionUpdated( + const ToolbarActionsModel::ActionId& action_id) { + ToolbarActionViewController* action = GetActionForId(action_id); + if (action) + action->UpdateState(); +} + +void ExtensionsToolbarContainer::OnToolbarVisibleCountChanged() {} + +void ExtensionsToolbarContainer::OnToolbarHighlightModeChanged( + bool is_highlighting) {} + +void ExtensionsToolbarContainer::OnToolbarModelInitialized() { + CreateActions(); +} + +void ExtensionsToolbarContainer::ReorderViews() { + // TODO(pbos): Reorder pinned actions here once they exist. + + // Popped out actions should be at the end. + if (popped_out_action_) + ReorderChildView(icons_[popped_out_action_->GetId()].get(), -1); + + // The extension button is always last. + ReorderChildView(extensions_button_, -1); +} + +void ExtensionsToolbarContainer::CreateActions() { + DCHECK(icons_.empty()); + DCHECK(actions_.empty()); + + // If the model isn't initialized, wait for it. + if (!model_->actions_initialized()) + return; + + for (auto& action_id : model_->action_ids()) + CreateActionForId(action_id); + + ReorderViews(); +} + +void ExtensionsToolbarContainer::CreateActionForId( + const ToolbarActionsModel::ActionId& action_id) { + actions_.push_back( + model_->CreateActionForId(browser_, this, false, action_id)); + + auto icon = std::make_unique<ToolbarActionView>(actions_.back().get(), this); + icon->set_owned_by_client(); + icon->SetVisible(IsActionVisibleOnToolbar(actions_.back().get())); + AddChildView(icon.get()); + + icons_[action_id] = std::move(icon); +} + +content::WebContents* ExtensionsToolbarContainer::GetCurrentWebContents() { + return browser_->tab_strip_model()->GetActiveWebContents(); +} + +bool ExtensionsToolbarContainer::ShownInsideMenu() const { + return false; +} + +void ExtensionsToolbarContainer::OnToolbarActionViewDragDone() {} + +views::LabelButton* ExtensionsToolbarContainer::GetOverflowReferenceView() { + return extensions_button_; +} + +gfx::Size ExtensionsToolbarContainer::GetToolbarActionSize() { + gfx::Rect rect(gfx::Size(28, 28)); + rect.Inset(-GetLayoutInsets(TOOLBAR_ACTION_VIEW)); + return rect.size(); +} + +void ExtensionsToolbarContainer::WriteDragDataForView( + View* sender, + const gfx::Point& press_pt, + ui::OSExchangeData* data) {} + +int ExtensionsToolbarContainer::GetDragOperationsForView(View* sender, + const gfx::Point& p) { + return ui::DragDropTypes::DRAG_MOVE; +} + +bool ExtensionsToolbarContainer::CanStartDragForView(View* sender, + const gfx::Point& press_pt, + const gfx::Point& p) { + // TODO(pbos): Implement + return false; +}
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h index 73024ca..2b8e229 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
@@ -5,11 +5,18 @@ #ifndef CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_H_ #define CHROME_BROWSER_UI_VIEWS_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_H_ +#include <map> +#include <memory> +#include <vector> + #include "chrome/browser/ui/extensions/extensions_container.h" +#include "chrome/browser/ui/toolbar/toolbar_actions_model.h" +#include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h" class Browser; class ExtensionsToolbarButton; +class ToolbarActionViewController; // Container for extensions shown in the toolbar. These include pinned // extensions and extensions that are 'popped out' transitively to show dialogs @@ -20,7 +27,9 @@ // TODO(crbug.com/943702): Remove note related to extensions menu when cleaning // up after the experiment. class ExtensionsToolbarContainer : public ToolbarIconContainerView, - public ExtensionsContainer { + public ExtensionsContainer, + public ToolbarActionsModel::Observer, + public ToolbarActionView::Delegate { public: explicit ExtensionsToolbarContainer(Browser* browser); ~ExtensionsToolbarContainer() override; @@ -33,6 +42,18 @@ void UpdateAllIcons() override; private: + // Creates toolbar actions and icons corresponding to the model. This is only + // called in the constructor or when the model initializes and should not be + // called for subsequent changes to the model. + void CreateActions(); + + // Creates an action and toolbar button for the corresponding ID. + void CreateActionForId(const ToolbarActionsModel::ActionId& action_id); + + // Sorts child views to display them in the correct order (pinned actions, + // popped out actions, extensions button). + void ReorderViews(); + // ExtensionsContainer: ToolbarActionViewController* GetActionForId( const std::string& action_id) override; @@ -47,9 +68,53 @@ bool is_sticky, const base::Closure& closure) override; + // ToolbarActionsModel::Observer: + void OnToolbarActionAdded(const ToolbarActionsModel::ActionId& action_id, + int index) override; + void OnToolbarActionRemoved( + const ToolbarActionsModel::ActionId& action_id) override; + void OnToolbarActionMoved(const ToolbarActionsModel::ActionId& action_id, + int index) override; + void OnToolbarActionLoadFailed() override; + void OnToolbarActionUpdated( + const ToolbarActionsModel::ActionId& action_id) override; + void OnToolbarVisibleCountChanged() override; + void OnToolbarHighlightModeChanged(bool is_highlighting) override; + void OnToolbarModelInitialized() override; + + // ToolbarActionView::Delegate: + content::WebContents* GetCurrentWebContents() override; + bool ShownInsideMenu() const override; + void OnToolbarActionViewDragDone() override; + views::LabelButton* GetOverflowReferenceView() override; + gfx::Size GetToolbarActionSize() override; + void WriteDragDataForView(View* sender, + const gfx::Point& press_pt, + ui::OSExchangeData* data) override; + int GetDragOperationsForView(View* sender, const gfx::Point& p) override; + bool CanStartDragForView(View* sender, + const gfx::Point& press_pt, + const gfx::Point& p) override; + Browser* const browser_; + ToolbarActionsModel* const model_; + ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer> + model_observer_; ExtensionsToolbarButton* const extensions_button_; + // TODO(pbos): Create actions and icons only for pinned pinned / popped out + // actions (lazily). Currently code expects GetActionForId() to return + // actions for extensions that aren't visible. + // Actions for all extensions. + std::vector<std::unique_ptr<ToolbarActionViewController>> actions_; + // View for every action, does not imply pinned or currently shown. + std::map<ToolbarActionsModel::ActionId, std::unique_ptr<ToolbarActionView>> + icons_; + // Popped-out extension, if any. + ToolbarActionViewController* popped_out_action_ = nullptr; + // The action that triggered the current popup, if any. + ToolbarActionViewController* popup_owner_ = nullptr; + DISALLOW_COPY_AND_ASSIGN(ExtensionsToolbarContainer); };
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc index 6583755..e433ab9 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -14,8 +14,6 @@ #include "ash/public/cpp/window_properties.h" #include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/shelf_test_api.test-mojom-test-utils.h" -#include "ash/public/interfaces/shelf_test_api.test-mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" #include "ash/public/interfaces/window_pin_type.mojom.h" #include "ash/shell.h" // mash-ok #include "ash/wm/overview/overview_controller.h" // mash-ok
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc index 3ff1c3cc..454eabd 100644 --- a/chrome/browser/ui/views/frame/browser_view_layout.cc +++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -340,9 +340,9 @@ int top_inset = delegate_->GetTopInsetInBrowserView(); int top = LayoutTabStripRegion(top_inset); if (delegate_->IsTabStripVisible()) { - tab_strip_->SetBackgroundOffset( - tab_strip_->GetMirroredX() + browser_view_->GetMirroredX() + - delegate_->GetThemeBackgroundXInset()); + tab_strip_->SetBackgroundOffset(tab_strip_region_view_->GetMirroredX() + + browser_view_->GetMirroredX() + + delegate_->GetThemeBackgroundXInset()); } top = LayoutToolbar(top);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc index 7f025a7..6566b65 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc
@@ -4,8 +4,6 @@ #include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "base/macros.h" #include "base/test/test_mock_time_task_runner.h" #include "chrome/browser/extensions/extension_browsertest.h"
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc index a5e45cb..0e6a3fe1 100644 --- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc +++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -476,6 +476,8 @@ const int side_margin = margins().left(); DCHECK_EQ(margins().left(), margins().right()); + EnableUpDownKeyboardAccelerators(); + ChromeLayoutProvider* layout_provider = ChromeLayoutProvider::Get(); // In Harmony, the last view is a HoverButton, which overrides the bottom
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc index b83b14c..0539e0f0 100644 --- a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc +++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc
@@ -62,7 +62,8 @@ } PluginVmLauncherView::PluginVmLauncherView(Profile* profile) - : plugin_vm_image_manager_( + : profile_(profile), + plugin_vm_image_manager_( plugin_vm::PluginVmImageManagerFactory::GetForProfile(profile)) { // Layout constants from the spec. gfx::Insets kDialogInsets(60, 64, 0, 64); @@ -180,6 +181,8 @@ return ui::DIALOG_BUTTON_OK; case State::ERROR: return ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK; + case State::NOT_ALLOWED: + return ui::DIALOG_BUTTON_CANCEL; } } @@ -202,6 +205,10 @@ ? IDS_PLUGIN_VM_LAUNCHER_RETRY_BUTTON : IDS_APP_CANCEL); } + case State::NOT_ALLOWED: { + DCHECK_EQ(button, ui::DIALOG_BUTTON_CANCEL); + return l10n_util::GetStringUTF16(IDS_APP_CANCEL); + } } } @@ -340,7 +347,7 @@ OnStateUpdated(); } -base::string16 PluginVmLauncherView::GetBigMessage() { +base::string16 PluginVmLauncherView::GetBigMessage() const { switch (state_) { case State::START_DOWNLOADING: case State::DOWNLOADING: @@ -351,17 +358,52 @@ case State::FINISHED: return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_FINISHED_TITLE); case State::ERROR: + case State::NOT_ALLOWED: return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_TITLE); } } +base::string16 PluginVmLauncherView::GetMessage() const { + switch (state_) { + case State::START_DOWNLOADING: + return l10n_util::GetStringUTF16( + IDS_PLUGIN_VM_LAUNCHER_START_DOWNLOADING_MESSAGE); + case State::DOWNLOADING: + return l10n_util::GetStringUTF16( + IDS_PLUGIN_VM_LAUNCHER_DOWNLOADING_MESSAGE); + case State::UNZIPPING: + return l10n_util::GetStringUTF16( + IDS_PLUGIN_VM_LAUNCHER_UNZIPPING_MESSAGE); + case State::REGISTERING: + return l10n_util::GetStringUTF16( + IDS_PLUGIN_VM_LAUNCHER_REGISTERING_MESSAGE); + case State::FINISHED: + return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_FINISHED_MESSAGE); + case State::ERROR: + return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_MESSAGE); + case State::NOT_ALLOWED: + return l10n_util::GetStringUTF16( + IDS_PLUGIN_VM_LAUNCHER_NOT_ALLOWED_MESSAGE); + } +} + PluginVmLauncherView::~PluginVmLauncherView() { plugin_vm_image_manager_->RemoveObserver(); g_plugin_vm_launcher_view = nullptr; } void PluginVmLauncherView::AddedToWidget() { - StartPluginVmImageDownload(); + // Defensive check that ensures an error message is shown if this + // dialogue is reached somehow although PluginVm has been disabled. + if (!plugin_vm::IsPluginVmAllowedForProfile(profile_)) { + LOG(ERROR) << "PluginVm is disallowed by policy. Showing error screen."; + state_ = State::NOT_ALLOWED; + } + + if (state_ == State::START_DOWNLOADING) + StartPluginVmImageDownload(); + else + OnStateUpdated(); } void PluginVmLauncherView::OnStateUpdated() { @@ -389,27 +431,6 @@ GetWidget()->GetRootView()->Layout(); } -base::string16 PluginVmLauncherView::GetMessage() const { - switch (state_) { - case State::START_DOWNLOADING: - return l10n_util::GetStringUTF16( - IDS_PLUGIN_VM_LAUNCHER_START_DOWNLOADING_MESSAGE); - case State::DOWNLOADING: - return l10n_util::GetStringUTF16( - IDS_PLUGIN_VM_LAUNCHER_DOWNLOADING_MESSAGE); - case State::UNZIPPING: - return l10n_util::GetStringUTF16( - IDS_PLUGIN_VM_LAUNCHER_UNZIPPING_MESSAGE); - case State::REGISTERING: - return l10n_util::GetStringUTF16( - IDS_PLUGIN_VM_LAUNCHER_REGISTERING_MESSAGE); - case State::FINISHED: - return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_FINISHED_MESSAGE); - case State::ERROR: - return l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_MESSAGE); - } -} - base::string16 PluginVmLauncherView::GetDownloadProgressMessage( uint64_t bytes_downloaded, int64_t content_length) const { @@ -465,7 +486,7 @@ } void PluginVmLauncherView::SetBigImage() { - if (state_ == State::ERROR) { + if (state_ == State::ERROR || state_ == State::NOT_ALLOWED) { big_image_->SetImage( ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_PLUGIN_VM_LAUNCHER_ERROR));
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h index a2b198f..a6bc7323 100644 --- a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h +++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h
@@ -51,7 +51,8 @@ void OnRegistrationFailed() override; // Public for testing purposes. - base::string16 GetBigMessage(); + base::string16 GetBigMessage() const; + base::string16 GetMessage() const; protected: enum class State { @@ -61,6 +62,7 @@ REGISTERING, // PluginVm image registering is in progress. FINISHED, // PluginVm environment setting has been finished. ERROR, // Something unexpected happened. + NOT_ALLOWED, // PluginVm is disallowed on the device. }; State state_ = State::START_DOWNLOADING; @@ -71,7 +73,6 @@ void AddedToWidget() override; private: - base::string16 GetMessage() const; base::string16 GetDownloadProgressMessage(uint64_t downlaoded_bytes, int64_t content_length) const; // Returns empty string in case time left cannot be estimated. @@ -84,6 +85,7 @@ void StartPluginVmImageDownload(); + Profile* profile_ = nullptr; plugin_vm::PluginVmImageManager* plugin_vm_image_manager_ = nullptr; views::Label* big_message_label_ = nullptr; views::Label* message_label_ = nullptr;
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc index 267a9f5..1d7ba97 100644 --- a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc +++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc
@@ -7,11 +7,17 @@ #include "base/bind.h" #include "base/files/file_util.h" #include "base/threading/thread_restrictions.h" +#include "chrome/browser/chromeos/login/users/mock_user_manager.h" #include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h" +#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/test/test_browser_dialog.h" #include "chrome/grit/generated_resources.h" +#include "components/account_id/account_id.h" #include "components/download/public/background_service/download_metadata.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" @@ -49,7 +55,8 @@ void OnStateUpdated() override { PluginVmLauncherView::OnStateUpdated(); - if (state_ == State::FINISHED || state_ == State::ERROR) { + if (state_ == State::FINISHED || state_ == State::ERROR || + state_ == State::NOT_ALLOWED) { if (setup_is_finished_callback_for_testing_) setup_is_finished_callback_for_testing_.Run(); } @@ -97,7 +104,9 @@ } protected: + chromeos::MockUserManager user_manager_; PluginVmLauncherViewForTesting* view_; + chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_; SetupObserver* setup_observer_; bool HasAcceptButton() { @@ -108,6 +117,17 @@ return view_->GetDialogClientView()->cancel_button() != nullptr; } + void CheckSetupNotAllowed() { + EXPECT_FALSE(HasAcceptButton()); + EXPECT_TRUE(HasCancelButton()); + EXPECT_EQ(view_->GetBigMessage(), + l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_TITLE)); + EXPECT_EQ( + view_->GetMessage(), + l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_NOT_ALLOWED_MESSAGE)); + CheckNoPluginVmImageDirExists(); + } + void CheckSetupFailed() { EXPECT_TRUE(HasAcceptButton()); EXPECT_TRUE(HasCancelButton()); @@ -115,7 +135,12 @@ l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_RETRY_BUTTON)); EXPECT_EQ(view_->GetBigMessage(), l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_TITLE)); + EXPECT_EQ(view_->GetMessage(), + l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_MESSAGE)); + CheckNoPluginVmImageDirExists(); + } + void CheckNoPluginVmImageDirExists() { base::FilePath plugin_vm_image_dir = browser() ->profile() @@ -147,6 +172,22 @@ EXPECT_TRUE(base::PathExists(plugin_vm_image_dir.AppendASCII(kZippedFile))); } + void SetPluginVmDevicePolicies() { + scoped_testing_cros_settings_.device_settings()->Set( + chromeos::kPluginVmAllowed, base::Value(true)); + scoped_testing_cros_settings_.device_settings()->Set( + chromeos::kPluginVmLicenseKey, base::Value("LICENSE_KEY")); + } + + void SetUserWithAffiliation() { + const AccountId account_id(AccountId::FromUserEmailGaiaId( + browser()->profile()->GetProfileUserName(), "id")); + user_manager_.AddUserWithAffiliationAndType( + account_id, true, user_manager::USER_TYPE_REGULAR); + chromeos::ProfileHelper::Get()->SetProfileToUserMappingForTesting( + user_manager_.GetActiveUser()); + } + void SetPluginVmImagePref(std::string url, std::string hash) { DictionaryPrefUpdate update(browser()->profile()->GetPrefs(), plugin_vm::prefs::kPluginVmImage); @@ -166,6 +207,8 @@ IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, SetupShouldFinishSuccessfully) { + SetPluginVmDevicePolicies(); + SetUserWithAffiliation(); SetPluginVmImagePref(embedded_test_server()->GetURL(kZipFile).spec(), kZipFileHash); @@ -179,6 +222,8 @@ IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, SetupShouldFailAsHashesDoNotMatch) { + SetPluginVmDevicePolicies(); + SetUserWithAffiliation(); SetPluginVmImagePref(embedded_test_server()->GetURL(kZipFile).spec(), kNonMatchingHash); @@ -192,6 +237,8 @@ IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, SetupShouldFailAsUnzippingFails) { + SetPluginVmDevicePolicies(); + SetUserWithAffiliation(); SetPluginVmImagePref(embedded_test_server()->GetURL(kJpgFile).spec(), kJpgFileHash); @@ -205,6 +252,8 @@ IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, CouldRetryAfterFailedSetup) { + SetPluginVmDevicePolicies(); + SetUserWithAffiliation(); SetPluginVmImagePref(embedded_test_server()->GetURL(kZipFile).spec(), kNonMatchingHash); @@ -225,3 +274,14 @@ CheckSetupIsFinishedSuccessfully(); } + +IN_PROC_BROWSER_TEST_F( + PluginVmLauncherViewBrowserTest, + SetupShouldShowDisallowedMessageIfPluginVmIsNotAllowedToRun) { + ShowUi("default"); + EXPECT_NE(nullptr, view_); + + // We do not have to wait for setup to finish since the NOT_ALLOWED state + // is set during dialogue construction. + CheckSetupNotAllowed(); +}
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc index a85863b..03bfe52 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
@@ -7,9 +7,7 @@ #include <memory> #include "ash/keyboard/ui/public/keyboard_switches.h" -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "base/bind_helpers.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" @@ -464,12 +462,7 @@ test::SetAndWaitForTabletMode(true); // Enable the virtual keyboard. - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - ash::mojom::ShellTestApiAsyncWaiter waiter(shell_test_api.get()); - waiter.EnableVirtualKeyboard(); + ash::ShellTestApi().EnableVirtualKeyboard(); auto* client = ChromeKeyboardControllerClient::Get(); EXPECT_FALSE(client->is_keyboard_visible());
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index d6af447..8134079ebe9 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -70,10 +70,8 @@ #if defined(OS_CHROMEOS) #include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_properties.h" -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" #include "ash/shell.h" #include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/window_state.h" @@ -425,7 +423,8 @@ root_ = browser()->window()->GetNativeWindow()->GetRootWindow(); // Disable flings which might otherwise inadvertently be generated from // tests' touch events. - SetMinFlingVelocity(std::numeric_limits<float>::max()); + ui::GestureConfiguration::GetInstance()->set_min_fling_velocity( + std::numeric_limits<float>::max()); aura::test::WaitForAllChangesToComplete(); #endif #if defined(OS_MACOSX) @@ -442,18 +441,6 @@ } #if defined(OS_CHROMEOS) - void SetMinFlingVelocity(float velocity) { - ui::GestureConfiguration::GetInstance()->set_min_fling_velocity(velocity); - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - shell_test_api->SetMinFlingVelocity(velocity); - shell_test_api.FlushForTesting(); - } -#endif - -#if defined(OS_CHROMEOS) bool SendTouchEventsSync(int action, int id, const gfx::Point& location) { base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); if (!ui_controls::SendTouchEventsNotifyWhenDone( @@ -2795,11 +2782,7 @@ ASSERT_EQ(2u, browser_list->size()); // Switching display mode should cancel the drag operation. - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - shell_test_api->AddRemoveDisplay(); + ash::ShellTestApi().AddRemoveDisplay(); } // Invoked from the nested run loop. @@ -3075,7 +3058,7 @@ // Reduce the minimum fling velocity for this specific test case to cause the // fling-down gesture in the middle of tab-dragging. This should end up with // minimizing the window. See https://crbug.com/902897 for the details. - SetMinFlingVelocity(1); + ui::GestureConfiguration::GetInstance()->set_min_fling_velocity(1); TabStrip* tab_strip = GetTabStripForBrowser(browser()); const gfx::Point tab_0_center = @@ -3107,7 +3090,7 @@ IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTestTouch, FlingOnStartingDrag) { - SetMinFlingVelocity(1); + ui::GestureConfiguration::GetInstance()->set_min_fling_velocity(1); AddTabAndResetBrowser(browser()); TabStrip* tab_strip = GetTabStripForBrowser(browser()); const gfx::Point tab_0_center =
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc index 0f8ec8b..8a8c22b 100644 --- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc +++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -319,6 +319,7 @@ GetBubbleFrameView()->set_preferred_arrow_adjustment( views::BubbleFrameView::PreferredArrowAdjustment::kOffset); + GetBubbleFrameView()->set_hit_test_transparent(true); if (CustomShadowsSupported()) { GetBubbleFrameView()->SetCornerRadius(
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc index d73875a3..18ed7af 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -48,6 +48,8 @@ //////////////////////////////////////////////////////////////////////////////// // ToolbarActionView +const char ToolbarActionView::kClassName[] = "ToolbarActionView"; + ToolbarActionView::ToolbarActionView( ToolbarActionViewController* view_controller, ToolbarActionView::Delegate* delegate) @@ -77,6 +79,10 @@ view_controller_->SetDelegate(nullptr); } +const char* ToolbarActionView::GetClassName() const { + return kClassName; +} + void ToolbarActionView::OnBoundsChanged(const gfx::Rect& previous_bounds) { // TODO(pbos): Consolidate with ToolbarButton::OnBoundsChanged. SetToolbarButtonHighlightPath(this, gfx::Insets());
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_view.h index 6dfa4b5..c1d474a8e 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
@@ -97,8 +97,11 @@ views::MenuItemView* menu_for_testing() { return menu_; } + static const char kClassName[]; + private: // views::MenuButton: + const char* GetClassName() const override; gfx::Size CalculatePreferredSize() const override; bool OnMousePressed(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override;
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc index 4069512d..4ba517b 100644 --- a/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc +++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_browsertest.cc
@@ -4,9 +4,7 @@ #include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h" -#include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h" -#include "ash/public/interfaces/shell_test_api.test-mojom.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/chromeos/login/login_manager_test.h" #include "chrome/browser/chromeos/login/startup_utils.h" @@ -42,15 +40,7 @@ // Wait for window visibility to stabilize. aura::test::WaitForAllChangesToComplete(); - // Connect to the ash test interface. - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - ash::mojom::ShellTestApiAsyncWaiter waiter(shell_test_api.get()); - bool modal_open = false; - waiter.IsSystemModalWindowOpen(&modal_open); - return modal_open; + return ash::ShellTestApi().IsSystemModalWindowOpen(); } class MockSystemWebDialog : public SystemWebDialogDelegate {
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 21858f4..8b738391 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -932,7 +932,12 @@ {"storageClearDriveCacheDialogDescription", IDS_SETTINGS_STORAGE_CLEAR_DRIVE_CACHE_DESCRIPTION}, {"storageDeleteAllButtonTitle", - IDS_SETTINGS_STORAGE_DELETE_ALL_BUTTON_TITLE}}; + IDS_SETTINGS_STORAGE_DELETE_ALL_BUTTON_TITLE}, + {"storageExternal", IDS_SETTINGS_STORAGE_EXTERNAL}, + {"storageAndroidAppsExternalDrives", + IDS_SETTINGS_STORAGE_ANDROID_APPS_ACCESS_EXTERNAL_DRIVES}, + {"storageAndroidAppsExternalDrivesNote", + IDS_SETTINGS_STORAGE_ANDROID_APPS_ACCESS_EXTERNAL_DRIVES_NOTE}}; AddLocalizedStringsBulk(html_source, kStorageStrings, base::size(kStorageStrings));
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc index 583ccd7..dbe54d2b 100644 --- a/chrome/browser/vr/webxr_vr_input_browser_test.cc +++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -148,7 +148,30 @@ return ConnectController(controller); } + void UpdateControllerSupport( + unsigned int controller_index, + const std::map<vr::EVRButtonId, unsigned int>& axis_types, + uint64_t supported_buttons) { + auto controller_data = GetCurrentControllerData(controller_index); + + for (unsigned int i = 0; i < device::kMaxNumAxes; i++) { + auto button_id = GetAxisId(i); + auto it = axis_types.find(button_id); + unsigned int new_axis_type = k_eControllerAxis_None; + if (it != axis_types.end()) + new_axis_type = it->second; + controller_data.axis_data[i].axis_type = new_axis_type; + } + + controller_data.supported_buttons = supported_buttons; + + UpdateControllerAndWait(controller_index, controller_data); + } + private: + vr::EVRButtonId GetAxisId(unsigned int offset) { + return static_cast<vr::EVRButtonId>(vr::k_EButton_Axis0 + offset); + } unsigned int GetAxisOffset(vr::EVRButtonId button_id) { DCHECK(vr::k_EButton_Axis0 <= button_id && button_id < (vr::k_EButton_Axis0 + device::kMaxNumAxes)); @@ -177,6 +200,80 @@ std::move(callback).Run(); } +// Ensure that changes to a gamepad object respect that it is the same object +// and that if whether or not an input source has a gamepad changes that the +// input source change event is fired and a new input source is created. +IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestStandard, TestInputGamepadSameObject) { + WebXrControllerInputMock my_mock; + + // Create a set of buttons and axes that don't have enough data to be made + // into an xr-standard gamepad (which we expect the runtimes to not report). + // Note that we need to set the trigger axis because of how OpenVR handles + // selects. + uint64_t insufficient_buttons = + vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger); + std::map<vr::EVRButtonId, unsigned int> insufficient_axis_types = { + {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger}, + }; + + // Create a set of buttons and axes that we expect to have enough data to be + // made into an xr-standard gamepad (which we expect the runtimes to report). + uint64_t sufficient_buttons = + vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger) | + vr::ButtonMaskFromId(vr::k_EButton_Axis0); + std::map<vr::EVRButtonId, unsigned int> sufficient_axis_types = { + {vr::k_EButton_Axis0, vr::k_eControllerAxis_TrackPad}, + {vr::k_EButton_SteamVR_Trigger, vr::k_eControllerAxis_Trigger}, + }; + + // Start off without a gamepad. + unsigned int controller_index = my_mock.CreateAndConnectController( + device::ControllerRole::kControllerRoleRight, insufficient_axis_types, + insufficient_buttons); + + LoadUrlAndAwaitInitialization( + GetFileUrlForHtmlTestFile("test_webxr_input_same_object")); + EnterSessionWithUserGestureOrFail(); + + RunJavaScriptOrFail("setupListeners()"); + + // We should only have seen the first change indicating we have input sources. + PollJavaScriptBooleanOrFail("inputChangeEvents === 1", kPollTimeoutShort); + + // We only expect one input source, cache it. + RunJavaScriptOrFail("validateInputSourceLength(1)"); + RunJavaScriptOrFail("updateCachedInputSource(0)"); + + // Toggle a button and confirm that the controller is still the same. + my_mock.PressReleasePrimaryTrigger(controller_index); + RunJavaScriptOrFail("validateCachedSourcePresence(true)"); + RunJavaScriptOrFail("validateCurrentAndCachedGamepadMatch()"); + + // Update the controller to now support a gamepad and verify that we get a + // change event and that the old controller isn't present. Then cache the new + // one. + my_mock.UpdateControllerSupport(controller_index, sufficient_axis_types, + sufficient_buttons); + PollJavaScriptBooleanOrFail("inputChangeEvents === 2", kPollTimeoutShort); + RunJavaScriptOrFail("validateCachedSourcePresence(false)"); + RunJavaScriptOrFail("validateInputSourceLength(1)"); + RunJavaScriptOrFail("updateCachedInputSource(0)"); + + // Toggle a button and confirm that the controller is still the same. + my_mock.PressReleasePrimaryTrigger(controller_index); + RunJavaScriptOrFail("validateCachedSourcePresence(true)"); + RunJavaScriptOrFail("validateCurrentAndCachedGamepadMatch()"); + + // Switch back to the insufficient gamepad and confirm that we get the change. + my_mock.UpdateControllerSupport(controller_index, insufficient_axis_types, + insufficient_buttons); + PollJavaScriptBooleanOrFail("inputChangeEvents === 3", kPollTimeoutShort); + RunJavaScriptOrFail("validateCachedSourcePresence(false)"); + RunJavaScriptOrFail("validateInputSourceLength(1)"); + RunJavaScriptOrFail("done()"); + EndTest(); +} + // Ensure that if the controller lacks enough data to be considered a Gamepad // that the input source that it is associated with does not have a Gamepad. IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestStandard, TestGamepadIncompleteData) { @@ -189,12 +286,12 @@ my_mock.CreateAndConnectController( device::ControllerRole::kControllerRoleRight, {}, supported_buttons); - this->LoadUrlAndAwaitInitialization( - this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); - this->EnterSessionWithUserGestureOrFail(); - this->ExecuteStepAndWait("validateInputSourceHasNoGamepad()"); - this->RunJavaScriptOrFail("done()"); - this->EndTest(); + LoadUrlAndAwaitInitialization( + GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); + EnterSessionWithUserGestureOrFail(); + ExecuteStepAndWait("validateInputSourceHasNoGamepad()"); + RunJavaScriptOrFail("done()"); + EndTest(); } // Ensure that if a Gamepad has the minimum required number of axes/buttons to @@ -204,9 +301,9 @@ WebXrControllerInputMock my_mock; unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad(); - this->LoadUrlAndAwaitInitialization( - this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); - this->EnterSessionWithUserGestureOrFail(); + LoadUrlAndAwaitInitialization( + GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); + EnterSessionWithUserGestureOrFail(); // Press the trigger and set the axis to a non-zero amount, so we can ensure // we aren't getting just default gamepad data. @@ -215,10 +312,10 @@ // The trigger should be button 0, and the first set of axes should have it's // value set. - this->ExecuteStepAndWait("validateButtonPressed(0)"); - this->ExecuteStepAndWait("validateAxesValues(0, 0.5, -0.5)"); - this->RunJavaScriptOrFail("done()"); - this->EndTest(); + ExecuteStepAndWait("validateButtonPressed(0)"); + ExecuteStepAndWait("validateAxesValues(0, 0.5, -0.5)"); + RunJavaScriptOrFail("done()"); + EndTest(); } // Ensure that if a Gamepad has all of the required and optional buttons as @@ -245,9 +342,9 @@ device::ControllerRole::kControllerRoleRight, axis_types, supported_buttons); - this->LoadUrlAndAwaitInitialization( - this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); - this->EnterSessionWithUserGestureOrFail(); + LoadUrlAndAwaitInitialization( + GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); + EnterSessionWithUserGestureOrFail(); // Setup some state on the optional buttons (as TestGamepadMinimumData should // ensure proper state on the required buttons). @@ -263,18 +360,18 @@ vr::ButtonMaskFromId(vr::k_EButton_Grip)); // The secondary set of axes should be set appropriately. - this->ExecuteStepAndWait("validateAxesValues(1, 0.25, -0.25)"); + ExecuteStepAndWait("validateAxesValues(1, 0.25, -0.25)"); // Button 2 is reserved for the Grip, and should be pressed. - this->ExecuteStepAndWait("validateButtonPressed(2)"); + ExecuteStepAndWait("validateButtonPressed(2)"); // Button 3 is reserved for the secondary trackpad/joystick and should be // touched but not pressed. - this->ExecuteStepAndWait("validateButtonNotPressed(3)"); - this->ExecuteStepAndWait("validateButtonTouched(3)"); + ExecuteStepAndWait("validateButtonNotPressed(3)"); + ExecuteStepAndWait("validateButtonTouched(3)"); - this->RunJavaScriptOrFail("done()"); - this->EndTest(); + RunJavaScriptOrFail("done()"); + EndTest(); } // Ensure that if a Gamepad has all required buttons, an extra button not @@ -300,9 +397,9 @@ device::ControllerRole::kControllerRoleRight, axis_types, supported_buttons); - this->LoadUrlAndAwaitInitialization( - this->GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); - this->EnterSessionWithUserGestureOrFail(); + LoadUrlAndAwaitInitialization( + GetFileUrlForHtmlTestFile("test_webxr_gamepad_support")); + EnterSessionWithUserGestureOrFail(); // Claim that all buttons are pressed, note that any non-supported buttons // should be ignored. @@ -311,14 +408,14 @@ // Index 2 and 3 are reserved for the grip and secondary joystick. // As our controller doesn't support them, they should be present but not // pressed, and our "extra" button should be index 4 and should be pressed. - this->ExecuteStepAndWait("validateButtonPressed(0)"); - this->ExecuteStepAndWait("validateButtonPressed(1)"); - this->ExecuteStepAndWait("validateButtonNotPressed(2)"); - this->ExecuteStepAndWait("validateButtonNotPressed(3)"); - this->ExecuteStepAndWait("validateButtonPressed(4)"); + ExecuteStepAndWait("validateButtonPressed(0)"); + ExecuteStepAndWait("validateButtonPressed(1)"); + ExecuteStepAndWait("validateButtonNotPressed(2)"); + ExecuteStepAndWait("validateButtonNotPressed(3)"); + ExecuteStepAndWait("validateButtonPressed(4)"); - this->RunJavaScriptOrFail("done()"); - this->EndTest(); + RunJavaScriptOrFail("done()"); + EndTest(); } // Test that OpenVR controller input is registered via WebXR's input method. @@ -331,13 +428,12 @@ unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad(); // Load the test page and enter presentation. - this->LoadUrlAndAwaitInitialization( - this->GetFileUrlForHtmlTestFile("test_webxr_input")); - this->EnterSessionWithUserGestureOrFail(); + LoadUrlAndAwaitInitialization(GetFileUrlForHtmlTestFile("test_webxr_input")); + EnterSessionWithUserGestureOrFail(); unsigned int num_iterations = 10; - this->RunJavaScriptOrFail("stepSetupListeners(" + - std::to_string(num_iterations) + ")"); + RunJavaScriptOrFail("stepSetupListeners(" + + base::NumberToString(num_iterations) + ")"); // Press and unpress the controller's trigger a bunch of times and make sure // they're all registered. @@ -345,9 +441,9 @@ my_mock.PressReleasePrimaryTrigger(controller_index); // After each trigger release, wait for the JavaScript to receive the // "select" event. - this->WaitOnJavaScriptStep(); + WaitOnJavaScriptStep(); } - this->EndTest(); + EndTest(); } // Test that OpenVR controller input is registered via the Gamepad API. @@ -370,9 +466,9 @@ unsigned int controller_index = my_mock.ConnectController(controller_data); // Load the test page and enter presentation. - this->LoadUrlAndAwaitInitialization( - this->GetFileUrlForHtmlTestFile("test_gamepad_button")); - this->EnterSessionWithUserGestureOrFail(); + LoadUrlAndAwaitInitialization( + GetFileUrlForHtmlTestFile("test_gamepad_button")); + EnterSessionWithUserGestureOrFail(); // We need to have this, otherwise the JavaScript side of the Gamepad API // doesn't seem to pick up the correct button state? I.e. if we don't have @@ -385,13 +481,13 @@ // flakiness workaround. Coincidentally, it's also helpful for the different // issue solved by the above PressReleasePrimaryTrigger, so make sure to set // it here so that the above press/release isn't caught by the test code. - this->RunJavaScriptOrFail("canStartTest = true"); + RunJavaScriptOrFail("canStartTest = true"); // Press and release the trigger, ensuring the Gamepad API detects both. my_mock.TogglePrimaryTrigger(controller_index); - this->WaitOnJavaScriptStep(); + WaitOnJavaScriptStep(); my_mock.TogglePrimaryTrigger(controller_index); - this->WaitOnJavaScriptStep(); - this->EndTest(); + WaitOnJavaScriptStep(); + EndTest(); } class WebXrHeadPoseMock : public MockXRDeviceHookBase {
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 70807207..5464f22 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -172,8 +172,6 @@ "ClickToOpenPDFPlaceholder", base::FEATURE_ENABLED_BY_DEFAULT}; #if defined(OS_MACOSX) -const base::Feature kContentFullscreen{"ContentFullscreen", - base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kImmersiveFullscreen{"ImmersiveFullscreen", base::FEATURE_DISABLED_BY_DEFAULT}; #endif @@ -464,14 +462,6 @@ base::FEATURE_ENABLED_BY_DEFAULT}; #endif -#if defined(OS_CHROMEOS) -// Enables the Recommend Apps screen in OOBE. -// TODO(https://crbug.com/862774): Remove this after the feature is fully -// launched. -const base::Feature kOobeRecommendAppsScreen{"OobeRecommendAppsScreen", - base::FEATURE_ENABLED_BY_DEFAULT}; -#endif - // Adds the base language code to the Language-Accept headers if at least one // corresponding language+region code is present in the user preferences. // For example: "en-US, fr-FR" --> "en-US, en, fr-FR, fr".
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 171a701..f261755 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -101,7 +101,6 @@ extern const base::Feature kClickToOpenPDFPlaceholder; #if defined(OS_MACOSX) -COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kContentFullscreen; COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kImmersiveFullscreen; #endif @@ -298,11 +297,6 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kOomIntervention; #endif -#if defined(OS_CHROMEOS) -COMPONENT_EXPORT(CHROME_FEATURES) -extern const base::Feature kOobeRecommendAppsScreen; -#endif - COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUseNewAcceptLanguageHeader;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 991f3cf9..ffab7a9 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2232,11 +2232,7 @@ ] if (is_chrome_branded) { - sources += [ - "../browser/conflicts/incompatible_applications_browsertest.cc", - "../browser/conflicts/third_party_blocking_browsertest.cc", - ] - deps += [ ":conflicts_dll" ] + deps += [ "//chrome/browser/conflicts:browser_tests" ] } } else { # Not Windows. sources -= [ "../app/chrome_version.rc.version" ] @@ -2661,14 +2657,6 @@ "../browser/component_updater/subresource_filter_component_installer_unittest.cc", "../browser/component_updater/supervised_user_whitelist_installer_unittest.cc", "../browser/component_updater/sw_reporter_installer_win_unittest.cc", - "../browser/conflicts/enumerate_input_method_editors_win_unittest.cc", - "../browser/conflicts/enumerate_shell_extensions_win_unittest.cc", - "../browser/conflicts/inspection_results_cache_win_unittest.cc", - "../browser/conflicts/module_database_win_unittest.cc", - "../browser/conflicts/module_event_sink_impl_win_unittest.cc", - "../browser/conflicts/module_info_util_win_unittest.cc", - "../browser/conflicts/module_info_win_unittest.cc", - "../browser/conflicts/module_inspector_win_unittest.cc", "../browser/content_settings/content_settings_default_provider_unittest.cc", "../browser/content_settings/content_settings_mock_observer.cc", "../browser/content_settings/content_settings_mock_observer.h", @@ -3248,7 +3236,10 @@ if (is_win) { assert(toolkit_views) sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ] - deps += [ "//chrome/test:credential_provider_test_utils" ] + deps += [ + "//chrome/browser/conflicts:unit_tests", + "//chrome/test:credential_provider_test_utils", + ] } if (enable_dice_support) { @@ -4575,7 +4566,6 @@ data_deps += [ "//chrome/browser/safe_browsing/incident_reporting/verifier_test:verifier_test_dll_1", "//chrome/browser/safe_browsing/incident_reporting/verifier_test:verifier_test_dll_2", - ":conflicts_dll", ] libs = [ @@ -4594,17 +4584,7 @@ ] if (is_chrome_branded) { - sources += [ - "../browser/conflicts/incompatible_applications_updater_win_unittest.cc", - "../browser/conflicts/installed_applications_win_unittest.cc", - "../browser/conflicts/module_blacklist_cache_updater_win_unittest.cc", - "../browser/conflicts/module_blacklist_cache_util_win_unittest.cc", - "../browser/conflicts/module_list_filter_win_unittest.cc", - "../browser/conflicts/module_load_attempt_log_listener_win_unittest.cc", - "../browser/conflicts/registry_key_watcher_win_unittest.cc", - "../browser/conflicts/third_party_conflicts_manager_win_unittest.cc", - "../browser/google/google_update_win_unittest.cc", - ] + sources += [ "../browser/google/google_update_win_unittest.cc" ] } } if (is_android) { @@ -4870,15 +4850,6 @@ } } -if (is_win) { - loadable_module("conflicts_dll") { - testonly = true - sources = [ - "conflicts/conflicts_dll.cc", - ] - } -} - if (!is_android) { static_library("test_support_ui") { defines = []
diff --git a/chrome/test/base/interactive_test_utils_win.cc b/chrome/test/base/interactive_test_utils_win.cc index 69fdb90..8329f145 100644 --- a/chrome/test/base/interactive_test_utils_win.cc +++ b/chrome/test/base/interactive_test_utils_win.cc
@@ -6,11 +6,19 @@ #include <Psapi.h> +#include <memory> + +#include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/location.h" #include "base/logging.h" +#include "base/process/process_handle.h" #include "base/stl_util.h" +#include "base/test/test_timeouts.h" +#include "base/threading/platform_thread.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "chrome/test/base/interactive_test_utils_aura.h" #include "chrome/test/base/process_lineage_win.h" #include "chrome/test/base/save_desktop_snapshot_win.h" @@ -41,48 +49,103 @@ ::ShowWindow(hwnd, SW_SHOW); - if (GetForegroundWindow() != hwnd) { + int attempts_left = 5; + bool have_snapshot = false; + while (true) { + if (::GetForegroundWindow() == hwnd) + return true; + VLOG(1) << "Forcefully refocusing front window"; ui::ForegroundHelper::SetForeground(hwnd); - } - // ShowWindow does not necessarily activate the window. In particular if a - // window from another app is the foreground window then the request to - // activate the window fails. See SetForegroundWindow for details. - HWND foreground_window = GetForegroundWindow(); - if (foreground_window == hwnd) - return true; + // ShowWindow does not necessarily activate the window. In particular if a + // window from another app is the foreground window then the request to + // activate the window fails. See SetForegroundWindow for details. + HWND foreground_window = ::GetForegroundWindow(); + if (foreground_window == hwnd) + return true; - wchar_t window_title[256]; - GetWindowText(foreground_window, window_title, base::size(window_title)); + // Emit some diagnostic information about the foreground window and its + // owning process. + wchar_t window_title[256]; + GetWindowText(foreground_window, window_title, base::size(window_title)); - base::string16 lineage_str; - base::string16 window_contents; - if (foreground_window) { - DWORD process_id = 0; - GetWindowThreadProcessId(foreground_window, &process_id); - ProcessLineage lineage = ProcessLineage::Create(process_id); - if (!lineage.IsEmpty()) { - lineage_str = STRING16_LITERAL(", process lineage: "); - lineage_str.append(lineage.ToString()); + base::string16 lineage_str; + base::string16 window_contents; + DWORD foreground_process_id = 0; + if (foreground_window) { + GetWindowThreadProcessId(foreground_window, &foreground_process_id); + ProcessLineage lineage = ProcessLineage::Create(foreground_process_id); + if (!lineage.IsEmpty()) { + lineage_str = STRING16_LITERAL(", process lineage: "); + lineage_str.append(lineage.ToString()); + } + + window_contents = WindowContentsAsString(foreground_window); + } + LOG(ERROR) << "ShowAndFocusNativeWindow found a foreground window: " + << foreground_window << ", title: " << window_title + << lineage_str << ", contents:" << std::endl + << window_contents; + + // Take a snapshot of the screen. + const base::FilePath output_dir = + base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( + kSnapshotOutputDir); + if (!have_snapshot && !output_dir.empty()) { + base::FilePath snapshot_file = SaveDesktopSnapshot(output_dir); + if (!snapshot_file.empty()) { + have_snapshot = true; + LOG(ERROR) << "Screenshot saved to file: \"" << snapshot_file.value() + << "\""; + } } - window_contents = WindowContentsAsString(foreground_window); - } - LOG(ERROR) << "ShowAndFocusNativeWindow failed. foreground window: " - << foreground_window << ", title: " << window_title << lineage_str - << ", contents:" << std::endl - << window_contents; - - const base::FilePath output_dir = - base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( - kSnapshotOutputDir); - if (!output_dir.empty()) { - base::FilePath snapshot_file = SaveDesktopSnapshot(output_dir); - if (!snapshot_file.empty()) { - LOG(ERROR) << "Screenshot saved to file: \"" << snapshot_file.value() - << "\""; + if (!attempts_left--) { + LOG(ERROR) << "ShowAndFocusNativeWindow failed after too many attempts."; + break; } + + // Give up if there is no foreground window or if it's mysteriously from + // this process. + if (!foreground_window) { + LOG(ERROR) << "ShowAndFocusNativeWindow failed to focus any window."; + break; + } + + if (foreground_process_id == base::GetCurrentProcId()) { + LOG(ERROR) << "ShowAndFocusNativeWindow failed because another window in" + " the test process will not give up focus."; + break; + } + + // Attempt to close the offending window. + ::PostMessageW(foreground_window, WM_CLOSE, 0, 0); + // Poll to wait for the window to be destroyed. While it is possible to + // avoid polling via use of UI Automation to observe the closing of the + // window, the code to do so is non-trivial and requires use of another + // thread in the MTA. + base::RunLoop run_loop; + base::RepeatingTimer timer( + FROM_HERE, TestTimeouts::tiny_timeout(), + base::BindRepeating( + [](HWND foreground_window, + const base::RepeatingClosure& quit_closure, int* polls) { + if (!*polls-- || ::GetForegroundWindow() != foreground_window) + quit_closure.Run(); + }, + foreground_window, run_loop.QuitClosure(), + base::Owned(std::make_unique<int>( + TestTimeouts::action_timeout().InMicroseconds() / + TestTimeouts::tiny_timeout().InMicroseconds())))); + timer.Reset(); + run_loop.Run(); + if (::GetForegroundWindow() == foreground_window) { + LOG(ERROR) << "ShowAndFocusNativeWindow timed out closing the " + "foreground window."; + break; + } + // Otherwise, loop around and try focusing the desired window again. } return false;
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index ef2c0153..c391376 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -319,7 +319,7 @@ user_cloud_policy_manager_(std::move(policy_manager)), delegate_(delegate), profile_name_(profile_name), - policy_service_(policy_service.release()) { + policy_service_(std::move(policy_service)) { if (parent) parent->SetOffTheRecordProfile(std::unique_ptr<Profile>(this));
diff --git a/chrome/test/chromedriver/key_converter_unittest.cc b/chrome/test/chromedriver/key_converter_unittest.cc index 2e0908e..e733936 100644 --- a/chrome/test/chromedriver/key_converter_unittest.cc +++ b/chrome/test/chromedriver/key_converter_unittest.cc
@@ -261,14 +261,7 @@ CheckEventsReleaseModifiers(keys, key_events); } -#if defined(OS_WIN) -// https://code.google.com/p/chromedriver/issues/detail?id=546 -#define MAYBE_AllShorthandKeys DISABLED_AllShorthandKeys -#else -#define MAYBE_AllShorthandKeys AllShorthandKeys -#endif - -TEST(KeyConverter, MAYBE_AllShorthandKeys) { +TEST(KeyConverter, AllShorthandKeys) { KeyEventBuilder builder; std::list<KeyEvent> key_events; builder.SetKeyCode(ui::VKEY_RETURN) @@ -276,7 +269,7 @@ ->Generate(&key_events); builder.Generate(&key_events); builder.SetKeyCode(ui::VKEY_TAB); -#if defined(USE_AURA) || defined(OS_LINUX) +#if defined(OS_LINUX) builder.SetText("\t", "\t")->Generate(&key_events); #else builder.SetText(std::string(), std::string()); @@ -284,7 +277,7 @@ key_events.push_back(builder.SetType(kKeyUpEventType)->Build()); #endif builder.SetKeyCode(ui::VKEY_BACK); -#if defined(USE_AURA) || defined(OS_LINUX) +#if defined(OS_LINUX) builder.SetText("\b", "\b")->Generate(&key_events); #else builder.SetText(std::string(), std::string()); @@ -348,25 +341,14 @@ } } -#if defined(OS_LINUX) || defined(OS_WIN) -// https://code.google.com/p/chromedriver/issues/detail?id=240 -// https://code.google.com/p/chromedriver/issues/detail?id=546 -#define MAYBE_AllSpecialWebDriverKeysOnEnglishKeyboard \ - DISABLED_AllSpecialWebDriverKeysOnEnglishKeyboard -#else -#define MAYBE_AllSpecialWebDriverKeysOnEnglishKeyboard \ - AllSpecialWebDriverKeysOnEnglishKeyboard -#endif - -TEST(KeyConverter, MAYBE_AllSpecialWebDriverKeysOnEnglishKeyboard) { +TEST(KeyConverter, AllSpecialWebDriverKeysOnEnglishKeyboard) { const char kTextForKeys[] = { -#if defined(USE_AURA) || defined(OS_LINUX) - 0, 0, 0, '\b', '\t', 0, '\r', '\r', 0, 0, 0, 0, 0x1B, - ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7F, ';', '=', +#if defined(OS_LINUX) + 0, 0, 0, 0, '\t', 0, '\r', '\r', 0, 0, 0, 0, 0, #else 0, 0, 0, 0, 0, 0, '\r', '\r', 0, 0, 0, 0, 0, - ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ';', '=', #endif + ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ';', '=', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', ',', '-', '.', '/'}; for (size_t i = 0; i <= 0x3D; ++i) {
diff --git a/chrome/test/conflicts/OWNERS b/chrome/test/conflicts/OWNERS deleted file mode 100644 index 186b2df..0000000 --- a/chrome/test/conflicts/OWNERS +++ /dev/null
@@ -1,4 +0,0 @@ -chrisha@chromium.org -pmonette@chromium.org - -# COMPONENT: Internals>Core
diff --git a/chrome/test/data/extensions/api_test/tabs/basics/move.js b/chrome/test/data/extensions/api_test/tabs/basics/move.js index 4a0e944..5c7d9d9 100644 --- a/chrome/test/data/extensions/api_test/tabs/basics/move.js +++ b/chrome/test/data/extensions/api_test/tabs/basics/move.js
@@ -13,6 +13,36 @@ 'chrome-search://local-ntp/local-ntp.html', ]; +// Check if callback object is same as the expected/actual behaviour. +function checkMoveResult(movedTab, expectedResult) { + const { tabId, windowId, index, pinned } = expectedResult; + assertEq(index, movedTab.index); + assertEq(windowId, movedTab.windowId); + assertEq(tabId, movedTab.id); + assertEq(pinned, movedTab.pinned); +}; + +function pinTab(tabId) { + return new Promise((resolve) => { + chrome.tabs.update(tabId, { pinned: true }, (tab) => { + chrome.test.assertNoLastError(); + resolve(tab); + }); + }); +}; + +function moveTab(tabId, toWindowId, toIndex) { + return new Promise(resolve => { + chrome.tabs.move( + tabId, + { windowId: toWindowId, index: toIndex }, + tab => { + chrome.test.assertNoLastError(); + resolve(tab); + }); + }); +} + chrome.test.runTests([ // Do a series of moves and removes so that we get the following // @@ -191,5 +221,197 @@ })); })); })); + }, + + // Test that the correct tab index is returned for cases where extensions + // try to move tabs across the pinned, not-pinned boundary in the + // same window. + function moveTabWithConstrainedIndexToSameWindow() { + // Create and pin tabs + function prepareTest(callback) { + const pageNames = ['tab-a', 'tab-b', 'tab-c', 'tab-d']; + setupWindow(pageNames).then(([winId, tabIds]) => { + Promise.all([ + pinTab(tabIds['tab-a']), + pinTab(tabIds['tab-b']) + ]).then(() => { + callback(winId, tabIds); + }); + }); + }; + + prepareTest((winId, tabIds) => { + // pinned -> non-pinned(desired index adjusted to the end of + // pinned tabs) + // Initial state: [tab-a(pinned), tab-b(pinned), tab-c, tab-d] + moveTab(tabIds['tab-a'], winId, 3).then((movedTab) => { + // After state: [tab-b(pinned), tab-a(pinned), tab-c, tab-d] + checkMoveResult(movedTab, { + tabId: tabIds['tab-a'], + windowId: winId, + index: 1, + pinned: true + }); + + // non-pinned -> pinned(desired index adjusted to the start of + // non-pinned tabs) + return moveTab(tabIds['tab-d'], winId, 0); + }).then((movedTab) => { + // After state: [tab-b(pinned), tab-a(pinned), tab-d, tab-c] + checkMoveResult(movedTab, { + tabId: tabIds['tab-d'], + windowId: winId, + index: 2, + pinned: false + }); + + // pinned -> -1 index(desired index adjusted to the end of + // pinned tabs) + return moveTab(tabIds['tab-b'], winId, -1); + }).then((movedTab) => { + // After state: [tab-a(pinned), tab-b(pinned), tab-d, tab-c] + checkMoveResult(movedTab, { + tabId: tabIds['tab-b'], + windowId: winId, + index: 1, + pinned: true + }); + }) + .then(chrome.test.succeed) + .catch((error) => { + // If the test has failed, ignore the exception and return. + if (error === 'chrome.test.failure') + return; + + // We received an unexpected exception, fail the test. + // This will re-throw. + chrome.test.fail(error.stack || error); + }).catch(() => {}); + }); + }, + // Test that the correct tab index is returned for cases where extensions + // try to move tabs across the pinned, not-pinned boundary in the + // different window. + function moveTabWithConstrainedIndexToDifferentWindow() { + // Create and pin tabs + async function prepareTest(callback) { + const firstWindowPageNames = [ + 'tab-a', + 'tab-b', + 'tab-c', + 'tab-d', + 'tab-e' + ]; + const secondWindowPageNames = [ + 'tab-aa', + 'tab-bb', + 'tab-cc', + 'tab-dd', + 'tab-ee' + ]; + const [firstWindow, secondWindow] = await Promise.all([ + setupWindow(firstWindowPageNames), + setupWindow(secondWindowPageNames) + ]); + const [firstWindowId, firstWindowTabIds] = firstWindow; + const [secondWindowId, secondWindowTabIds] = secondWindow; + await Promise.all([ + pinTab(firstWindowTabIds['tab-a']), + pinTab(firstWindowTabIds['tab-b']), + pinTab(secondWindowTabIds['tab-aa']), + pinTab(secondWindowTabIds['tab-bb']) + ]); + callback( + firstWindowId, + firstWindowTabIds, + secondWindowId, + secondWindowTabIds + ); + }; + + prepareTest(( + firstWindowId, + firstWindowTabIds, + secondWindowId, + secondWindowTabIds + ) => { + // pinned -> pinned(unpinned and desired index adjusted + // to the start of non-pinned tabs) + // Initial firstWindow state: + // [tab-a(pinned), tab-b(pinned), tab-c, tab-d, tab-e] + // secondWindow state: + // [tab-aa(pinned), tab-bb(pinned), tab-cc, tab-dd, tab-ee] + moveTab(firstWindowTabIds['tab-a'], secondWindowId, 0) + .then((movedTab) => { + // After firstWindow state: + // [tab-b(pinned), tab-c, tab-d, tab-e] + // secondWindow state: + // [tab-aa(pinned), tab-bb(pinned), tab-a(NOW non-pinned), + // tab-cc, tab-dd, tab-ee] + checkMoveResult(movedTab, { + tabId: firstWindowTabIds['tab-a'], + windowId: secondWindowId, + index: 2, + pinned: false + }); + + // pinned -> non-pinned(unpinned and moved to desired index) + return moveTab(firstWindowTabIds['tab-b'], secondWindowId, 4); + }).then((movedTab) => { + // After firstWindow state: + // [tab-c, tab-d, tab-e] + // secondWindow state: + // [tab-aa(pinned), tab-bb(pinned), tab-a, tab-cc, + // tab-b(NOW non-pinned), tab-dd, tab-ee] + checkMoveResult(movedTab, { + tabId: firstWindowTabIds['tab-b'], + windowId: secondWindowId, + index: 4, + pinned: false + }); + + // non-pinned -> pinned(desired index adjusted to the start of + // non-pinned tabs) + return moveTab(firstWindowTabIds['tab-c'], secondWindowId, 0); + }).then((movedTab) => { + // After firstWindow state: + // [tab-d, tab-e] + // secondWindow state: + // [tab-aa(pinned), tab-bb(pinned), tab-c, + // tab-a, tab-cc, tab-b, tab-dd, tab-ee] + checkMoveResult(movedTab, { + tabId: firstWindowTabIds['tab-c'], + windowId: secondWindowId, + index: 2, + pinned: false + }); + + // pinned -> -1 index(unpinned and desired index adjusted to + // the end of non-pinned tabs) + return moveTab(secondWindowTabIds['tab-aa'], firstWindowId, -1); + }).then((movedTab) => { + // After firstWindow state: + // [tab-d, tab-e, tab-aa(Now non-pinned)] + // secondWindow state: + // [tab-bb(pinned), tab-c, tab-a, tab-cc, tab-b, + // tab-dd, tab-ee] + checkMoveResult(movedTab, { + tabId: secondWindowTabIds['tab-aa'], + windowId: firstWindowId, + index: 2, + pinned: false + }); + }) + .then(chrome.test.succeed) + .catch((error) => { + // If the test has failed, ignore the exception and return. + if (error === 'chrome.test.failure') + return; + + // We received an unexpected exception, fail the test. + // This will re-throw. + chrome.test.fail(error.stack || error); + }).catch(() => {}); + }); } -]); +]); \ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/tabs/basics/tabs_util.js b/chrome/test/data/extensions/api_test/tabs/basics/tabs_util.js index 2ee8b07..e99b988 100644 --- a/chrome/test/data/extensions/api_test/tabs/basics/tabs_util.js +++ b/chrome/test/data/extensions/api_test/tabs/basics/tabs_util.js
@@ -109,3 +109,18 @@ } ); } + +// Create one window with names. It returns created windowId and tabIdsTable +// that can be used to find tab's id by page name. +function setupWindow(pageNames) { + const pages = pageNames.map(pageName => pageUrl(pageName)); + return new Promise(resolve => { + createWindow(pages, {}, function(winId, tabIds) { + const tabIdsTable = {}; + for (let i = 0; i < tabIds.length; i++) { + tabIdsTable[pageNames[i]] = tabIds[i]; + }; + resolve([winId, tabIdsTable]); + }); + }); +}; \ No newline at end of file
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html index 13c869f..57b5aa3 100644 --- a/chrome/test/data/local_ntp/local_ntp_browsertest.html +++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -196,6 +196,38 @@ </div> </div> <div id="backgrounds-image-menu" class="menu-panel"></div> + <div id="shortcuts-menu" class="menu-panel"> + <div id="sh-options"> + <div id="sh-option-cl" class="sh-option"> + <div class="sh-option-image"> + <div class="sh-option-icon"></div> + <div class="sh-option-mini"></div> + <div class="sh-option-select"></div> + </div> + <div class="sh-title">My shortcuts</div> + Your personalized shortcuts + </div> + <div id="sh-option-mv" class="sh-option"> + <div class="sh-option-image"> + <div class="sh-option-icon"></div> + <div class="sh-option-mini"></div> + <div class="sh-option-select"></div> + </div> + <div class="sh-title">Most visited sites</div> + Link suggestions from Chrome based on your browsing activity + </div> + </div> + <div id="sh-hide"> + <div id="sh-hide-icon"></div> + <div> + <div id="sh-hide-title">Hide shortcuts</div> + Do not show shortcuts on the new tab page. + </div> + <div id="sh-hide-toggle"> + <input type="checkbox"></input> + </div> + </div> + </div> </div> <div id="menu-footer"> <button id="menu-cancel" class="bg-sel-footer-button paper secondary
diff --git a/chrome/test/data/webui/settings/settings_ui_browsertest.js b/chrome/test/data/webui/settings/settings_ui_browsertest.js index 3ac151b..016e899dc 100644 --- a/chrome/test/data/webui/settings/settings_ui_browsertest.js +++ b/chrome/test/data/webui/settings/settings_ui_browsertest.js
@@ -84,6 +84,22 @@ }); }); + test('app drawer closes when exiting narrow mode', async () => { + const drawer = ui.$.drawer; + const toolbar = ui.$$('cr-toolbar'); + + // Mimic narrow mode and open the drawer + toolbar.narrow = true; + drawer.openDrawer(); + Polymer.dom.flush(); + await test_util.eventToPromise('cr-drawer-opened', drawer); + + toolbar.narrow = false; + Polymer.dom.flush(); + await test_util.eventToPromise('close', drawer); + assertFalse(drawer.open); + }); + test('advanced UIs stay in sync', function() { const main = ui.$$('settings-main'); const floatingMenu = ui.$$('#left settings-menu');
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_input_same_object.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_input_same_object.html new file mode 100644 index 0000000..6758434 --- /dev/null +++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_input_same_object.html
@@ -0,0 +1,58 @@ +<!doctype html> +<!-- +A collection of helper functions and listeners to confirm the state of input +sources for the same object tests. +--> +<html> + <head> + <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css"> + </head> + <body> + <canvas id="webgl-canvas"></canvas> + <script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script> + <script src="../resources/webxr_e2e.js"></script> + <script src="../resources/webxr_boilerplate.js"></script> + <script> + let inputChangeEvents = 0; + function onInputSourcesChange() { + inputChangeEvents++; + } + + function setupListeners() { + let currentSession = sessionInfos[sessionTypes.IMMERSIVE].currentSession; + currentSession.addEventListener('inputsourceschange', onInputSourcesChange, false); + } + + function getCurrentInputSources() { + let currentSession = sessionInfos[sessionTypes.IMMERSIVE].currentSession; + return currentSession.getInputSources(); + } + + let cached_input_source = null; + function updateCachedInputSource(id) { + let input_sources = getCurrentInputSources(); + assert_less_than(id, input_sources.length); + cached_input_source = input_sources[id]; + } + + function validateCachedSourcePresence(present) { + assert_not_equals(cached_input_source, null); + assert_not_equals(present, undefined); + let current_sources = getCurrentInputSources(); + assert_equals(current_sources.includes(cached_input_source), present); + } + + function validateInputSourceLength(length) { + assert_equals(getCurrentInputSources().length, length); + } + + function validateCurrentAndCachedGamepadMatch() { + assert_not_equals(cached_input_source, null); + let current_sources = getCurrentInputSources(); + let index = current_sources.indexOf(cached_input_source); + assert_not_equals(index, -1); + assert_equals(cached_input_source.gamepad, current_sources[index].gamepad); + } + </script> + </body> +</html>
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc index ac7c6fd6..3795bc2 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc +++ b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
@@ -63,7 +63,7 @@ {AudioContentType::kCommunication, 1.0f}, {AudioContentType::kOther, 1.0f}}, base::KEEP_FIRST_OF_DUPES), - active_backend_wrapper_(nullptr), + backend_wrapper_using_video_decoder_(nullptr), buffer_delegate_(nullptr), weak_factory_(this) { DCHECK(media_task_runner_); @@ -85,28 +85,30 @@ std::unique_ptr<CmaBackend> MediaPipelineBackendManager::CreateCmaBackend( const media::MediaPipelineDeviceParams& params) { DCHECK(media_task_runner_->BelongsToCurrentThread()); - - // TODO(guohuideng): Because we now allow multiple CmaBackends to exist, - // we can no longer revoke |active_backend_wrapper_| here unconditionally. - // We will need to only revoke the old |backend_wrapper| if it has active - // video decoder and it has a different |session_id| within its - // MediaPipelineDeviceParams. - - std::unique_ptr<MediaPipelineBackendWrapper> backend_wrapper = - std::make_unique<MediaPipelineBackendWrapper>(params, this); - - active_backend_wrapper_ = backend_wrapper.get(); - return backend_wrapper; + return std::make_unique<MediaPipelineBackendWrapper>(params, this); } void MediaPipelineBackendManager::BackendDestroyed( MediaPipelineBackendWrapper* backend_wrapper) { DCHECK(media_task_runner_->BelongsToCurrentThread()); - if (active_backend_wrapper_ == backend_wrapper) { - active_backend_wrapper_ = nullptr; + if (backend_wrapper_using_video_decoder_ == backend_wrapper) { + backend_wrapper_using_video_decoder_ = nullptr; } } +void MediaPipelineBackendManager::BackendUseVideoDecoder( + MediaPipelineBackendWrapper* backend_wrapper) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(backend_wrapper); + if (backend_wrapper_using_video_decoder_ && + backend_wrapper_using_video_decoder_ != backend_wrapper) { + LOG(INFO) << __func__ << " revoke old backend : " + << backend_wrapper_using_video_decoder_; + backend_wrapper_using_video_decoder_->Revoke(); + } + backend_wrapper_using_video_decoder_ = backend_wrapper; +} + bool MediaPipelineBackendManager::IncrementDecoderCount(DecoderType type) { DCHECK(media_task_runner_->BelongsToCurrentThread()); DCHECK(type < NUM_DECODER_TYPES);
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_manager.h b/chromecast/media/cma/backend/media_pipeline_backend_manager.h index a641222..26bbdb1 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_manager.h +++ b/chromecast/media/cma/backend/media_pipeline_backend_manager.h
@@ -95,6 +95,12 @@ // Inform that a backend previously created is destroyed. // Must be called on the same thread as |media_task_runner_|. void BackendDestroyed(MediaPipelineBackendWrapper* backend_wrapper); + // |backend_wrapper| will use a VideoDecoder. + // MediaPipelineBackendManager needs to record the backend that uses the + // VideoDecoder; and if there is an active backend using VideoDecoder, that + // backend needs to be revoked. + // Must be called on the same thread as |media_task_runner_|. + void BackendUseVideoDecoder(MediaPipelineBackendWrapper* backend_wrapper); base::SingleThreadTaskRunner* task_runner() const { return media_task_runner_.get(); @@ -169,9 +175,8 @@ base::flat_set<ActiveAudioDecoderWrapper*> audio_decoders_; base::flat_map<AudioContentType, float> global_volume_multipliers_; - // Previously issued MediaPipelineBackendWraper that is still alive - // and not revoked. - MediaPipelineBackendWrapper* active_backend_wrapper_; + // Previously issued MediaPipelineBackendWrapper that uses a video decoder. + MediaPipelineBackendWrapper* backend_wrapper_using_video_decoder_; BufferDelegate* buffer_delegate_;
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc b/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc index 9b77e2df..5907af6 100644 --- a/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc +++ b/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc
@@ -77,6 +77,7 @@ public: ActiveMediaPipelineBackendWrapper( const media::MediaPipelineDeviceParams& params, + MediaPipelineBackendWrapper* wrapping_backend, MediaPipelineBackendManager* backend_manager); ~ActiveMediaPipelineBackendWrapper() override; @@ -109,6 +110,7 @@ AudioDecoderWrapper* audio_decoder_ptr_; bool video_decoder_created_; const std::unique_ptr<MediaPipelineBackend> backend_; + MediaPipelineBackendWrapper* const wrapping_backend_; MediaPipelineBackendManager* const backend_manager_; const MediaPipelineDeviceParams::AudioStreamType audio_stream_type_; const AudioContentType content_type_; @@ -120,11 +122,13 @@ ActiveMediaPipelineBackendWrapper::ActiveMediaPipelineBackendWrapper( const media::MediaPipelineDeviceParams& params, + MediaPipelineBackendWrapper* wrapping_backend, MediaPipelineBackendManager* backend_manager) : audio_decoder_ptr_(nullptr), video_decoder_created_(false), backend_(base::WrapUnique( media::CastMediaShlib::CreateMediaPipelineBackend(params))), + wrapping_backend_(wrapping_backend), backend_manager_(backend_manager), audio_stream_type_(params.audio_type), content_type_(params.content_type), @@ -199,9 +203,11 @@ std::unique_ptr<VideoDecoderWrapper> ActiveMediaPipelineBackendWrapper::CreateVideoDecoderWrapper() { DCHECK(!video_decoder_created_); + backend_manager_->BackendUseVideoDecoder(wrapping_backend_); if (!backend_manager_->IncrementDecoderCount(DecoderType::VIDEO_DECODER)) return nullptr; + MediaPipelineBackend::VideoDecoder* real_decoder = backend_->CreateVideoDecoder(); if (!real_decoder) { @@ -276,7 +282,7 @@ backend_manager_(backend_manager), content_type_(params.content_type) { backend_ = std::make_unique<ActiveMediaPipelineBackendWrapper>( - params, backend_manager); + params, this, backend_manager); } MediaPipelineBackendWrapper::~MediaPipelineBackendWrapper() {
diff --git a/chromeos/components/drivefs/drivefs_auth_unittest.cc b/chromeos/components/drivefs/drivefs_auth_unittest.cc index 52265ec..a0af470 100644 --- a/chromeos/components/drivefs/drivefs_auth_unittest.cc +++ b/chromeos/components/drivefs/drivefs_auth_unittest.cc
@@ -108,7 +108,7 @@ std::move(callback).Run(account_info, {}); } - void GetAccessToken(const std::string& account_id, + void GetAccessToken(const CoreAccountId& account_id, const ::identity::ScopeSet& scopes, const std::string& consumer_id, GetAccessTokenCallback callback) override {
diff --git a/chromeos/components/drivefs/drivefs_host_unittest.cc b/chromeos/components/drivefs/drivefs_host_unittest.cc index b356920..607fe65 100644 --- a/chromeos/components/drivefs/drivefs_host_unittest.cc +++ b/chromeos/components/drivefs/drivefs_host_unittest.cc
@@ -227,7 +227,7 @@ std::move(callback).Run(account_info, {}); } - void GetAccessToken(const std::string& account_id, + void GetAccessToken(const CoreAccountId& account_id, const ::identity::ScopeSet& scopes, const std::string& consumer_id, GetAccessTokenCallback callback) override {
diff --git a/chromeos/components/proximity_auth/remote_status_update.cc b/chromeos/components/proximity_auth/remote_status_update.cc index 05116e8..c7d630c 100644 --- a/chromeos/components/proximity_auth/remote_status_update.cc +++ b/chromeos/components/proximity_auth/remote_status_update.cc
@@ -4,8 +4,8 @@ #include "chromeos/components/proximity_auth/remote_status_update.h" -#include "base/logging.h" #include "base/values.h" +#include "chromeos/components/multidevice/logging/logging.h" namespace { @@ -40,9 +40,9 @@ const base::DictionaryValue& serialized_value) { std::string type; if (!serialized_value.GetString(kType, &type) || type != kStatusUpdateType) { - VLOG(1) << "Unable to parse remote status update: unexpected type. " - << "Expected: '" << kStatusUpdateType << "', " - << "Saw: '" << type << "'."; + PA_LOG(ERROR) << "Unable to parse remote status update: unexpected type. " + << "Expected: '" << kStatusUpdateType << "', " + << "Saw: '" << type << "'."; return nullptr; } @@ -51,9 +51,9 @@ !serialized_value.GetString(kSecureScreenLock, &secure_screen_lock_state) || !serialized_value.GetString(kTrustAgent, &trust_agent_state)) { - VLOG(1) << "Unable to parse remote status update: missing data value. " - << "Status update:\n" - << serialized_value; + PA_LOG(ERROR) << "Unable to parse remote status update: missing data value." + << " Status update:\n" + << serialized_value; return nullptr; } @@ -65,8 +65,9 @@ } else if (user_presence == kUserPresenceUnknown) { parsed_update->user_presence = USER_PRESENCE_UNKNOWN; } else { - VLOG(1) << "Unable to parse remote status update: invalid user presence: '" - << user_presence << "'."; + PA_LOG(ERROR) + << "Unable to parse remote status update: invalid user presence: '" + << user_presence << "'."; return nullptr; } @@ -77,8 +78,8 @@ } else if (secure_screen_lock_state == kSecureScreenLockStateUnknown) { parsed_update->secure_screen_lock_state = SECURE_SCREEN_LOCK_STATE_UNKNOWN; } else { - VLOG(1) << "Unable to parse remote status update: invalid secure screen " - << "lock state: '" << secure_screen_lock_state << "'."; + PA_LOG(ERROR) << "Unable to parse remote status update: invalid secure " + << "screen lock state: '" << secure_screen_lock_state << "'."; return nullptr; } @@ -89,8 +90,8 @@ } else if (trust_agent_state == kTrustAgentUnsupported) { parsed_update->trust_agent_state = TRUST_AGENT_UNSUPPORTED; } else { - VLOG(1) << "Unable to parse remote status update: invalid trust agent " - << "state: '" << trust_agent_state << "'."; + PA_LOG(ERROR) << "Unable to parse remote status update: invalid trust " + << "agent state: '" << trust_agent_state << "'."; return nullptr; }
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc index c264672..2163810 100644 --- a/chromeos/network/network_state.cc +++ b/chromeos/network/network_state.cc
@@ -527,6 +527,8 @@ network_config::mojom::ActivationStateType NetworkState::GetMojoActivationState() const { using network_config::mojom::ActivationStateType; + if (IsDefaultCellular()) + return ActivationStateType::kNoService; if (activation_state_.empty()) return ActivationStateType::kUnknown; if (activation_state_ == shill::kActivationStateActivated)
diff --git a/chromeos/network/network_type_pattern.h b/chromeos/network/network_type_pattern.h index 01479b3..6479a89 100644 --- a/chromeos/network/network_type_pattern.h +++ b/chromeos/network/network_type_pattern.h
@@ -12,6 +12,9 @@ namespace chromeos { +// Class to convert Shill network type names to explicit types and do pattern +// matching for grouped types (e.g. Wireless). Grouped type matching is also +// implemented for mojo types in cros_network_config_util.cc. class COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkTypePattern { public: // Matches any network.
diff --git a/chromeos/services/assistant/service_unittest.cc b/chromeos/services/assistant/service_unittest.cc index 6768df3..0014cd7 100644 --- a/chromeos/services/assistant/service_unittest.cc +++ b/chromeos/services/assistant/service_unittest.cc
@@ -71,7 +71,7 @@ void GetPrimaryAccountWhenAvailable( GetPrimaryAccountWhenAvailableCallback callback) override {} - void GetAccessToken(const std::string& account_id, + void GetAccessToken(const CoreAccountId& account_id, const ::identity::ScopeSet& scopes, const std::string& consumer_id, GetAccessTokenCallback callback) override {
diff --git a/chromeos/services/network_config/cros_network_config.cc b/chromeos/services/network_config/cros_network_config.cc index 0d908c5..4401128 100644 --- a/chromeos/services/network_config/cros_network_config.cc +++ b/chromeos/services/network_config/cros_network_config.cc
@@ -53,6 +53,8 @@ return NetworkTypePattern::Cellular(); case mojom::NetworkType::kEthernet: return NetworkTypePattern::Ethernet(); + case mojom::NetworkType::kMobile: + return NetworkTypePattern::Mobile(); case mojom::NetworkType::kTether: return NetworkTypePattern::Tether(); case mojom::NetworkType::kVPN: @@ -95,9 +97,11 @@ return mojom::VPNType::kOpenVPN; } -base::Optional<mojom::DeviceStateType> GetMojoDeviceStateType( +mojom::DeviceStateType GetMojoDeviceStateType( NetworkStateHandler::TechnologyState technology_state) { switch (technology_state) { + case NetworkStateHandler::TECHNOLOGY_UNAVAILABLE: + return mojom::DeviceStateType::kUnavailable; case NetworkStateHandler::TECHNOLOGY_UNINITIALIZED: return mojom::DeviceStateType::kUninitialized; case NetworkStateHandler::TECHNOLOGY_AVAILABLE: @@ -108,11 +112,9 @@ return mojom::DeviceStateType::kEnabled; case NetworkStateHandler::TECHNOLOGY_PROHIBITED: return mojom::DeviceStateType::kProhibited; - case NetworkStateHandler::TECHNOLOGY_UNAVAILABLE: - return base::nullopt; } NOTREACHED(); - return base::nullopt; + return mojom::DeviceStateType::kUnavailable; } mojom::NetworkStatePropertiesPtr NetworkStateToMojo( @@ -135,8 +137,18 @@ result->guid = network->guid(); result->name = network->name(); result->priority = network->priority(); + result->prohibited_by_policy = network->blocked_by_policy(); result->source = mojom::ONCSource(network->onc_source()); + const NetworkState::CaptivePortalProviderInfo* captive_portal_provider = + network->captive_portal_provider(); + if (captive_portal_provider) { + auto mojo_captive_portal_provider = mojom::CaptivePortalProvider::New(); + mojo_captive_portal_provider->id = captive_portal_provider->id; + mojo_captive_portal_provider->name = captive_portal_provider->name; + result->captive_portal_provider = std::move(mojo_captive_portal_provider); + } + switch (type) { case mojom::NetworkType::kCellular: { auto cellular = mojom::CellularStateProperties::New(); @@ -177,15 +189,11 @@ network->vpn_provider(); if (vpn_provider) { vpn->type = ShillVpnTypeToMojo(vpn_provider->type); - if (vpn->type == mojom::VPNType::kThirdPartyVPN) { - auto third_party_vpn = mojom::ThirdPartyVPNProperties::New(); - third_party_vpn->extension_id = vpn_provider->id; - // TODO(stevenjb): Set the provider name in network state. - // third_party_vpn->provider_name = vpn_provider->name; - vpn->third_party_vpn = std::move(third_party_vpn); - } - result->vpn = std::move(vpn); + vpn->provider_id = vpn_provider->id; + // TODO(stevenjb): Set the provider name in network state. + // vpn->provider_name = vpn_provider->name; } + result->vpn = std::move(vpn); break; } case mojom::NetworkType::kWiFi: { @@ -206,6 +214,7 @@ break; } case mojom::NetworkType::kAll: + case mojom::NetworkType::kMobile: case mojom::NetworkType::kWireless: NOTREACHED() << "NetworkStateProperties can not be of type: " << type; break; @@ -223,17 +232,17 @@ return nullptr; } - base::Optional<mojom::DeviceStateType> state = + mojom::DeviceStateType state = GetMojoDeviceStateType(network_state_handler->GetTechnologyState( NetworkTypePattern::Primitive(device->type()))); - if (!state) { + if (state == mojom::DeviceStateType::kUnavailable) { NET_LOG(ERROR) << "Device state unavailable"; return nullptr; } auto result = mojom::DeviceStateProperties::New(); result->type = type; result->scanning = device->scanning(); - result->state = *state; + result->state = state; result->managed_network_available = !device->available_managed_network_path().empty();
diff --git a/chromeos/services/network_config/public/cpp/cros_network_config_util.cc b/chromeos/services/network_config/public/cpp/cros_network_config_util.cc index b7c97c5..b7b19437b 100644 --- a/chromeos/services/network_config/public/cpp/cros_network_config_util.cc +++ b/chromeos/services/network_config/public/cpp/cros_network_config_util.cc
@@ -7,28 +7,38 @@ namespace chromeos { namespace network_config { -bool NetworkStateMatchesType(const mojom::NetworkStateProperties* network, - mojom::NetworkType type) { - switch (type) { +// This matches logic in NetworkTypePattern and should be kept in sync. +bool NetworkTypeMatchesType(mojom::NetworkType network_type, + mojom::NetworkType match_type) { + switch (match_type) { case mojom::NetworkType::kAll: return true; + case mojom::NetworkType::kMobile: + return network_type == mojom::NetworkType::kCellular || + network_type == mojom::NetworkType::kTether || + network_type == mojom::NetworkType::kWiMAX; + case mojom::NetworkType::kWireless: + return network_type == mojom::NetworkType::kCellular || + network_type == mojom::NetworkType::kTether || + network_type == mojom::NetworkType::kWiFi || + network_type == mojom::NetworkType::kWiMAX; case mojom::NetworkType::kCellular: case mojom::NetworkType::kEthernet: case mojom::NetworkType::kTether: case mojom::NetworkType::kVPN: case mojom::NetworkType::kWiFi: case mojom::NetworkType::kWiMAX: - return network->type == type; - case mojom::NetworkType::kWireless: - return network->type == mojom::NetworkType::kCellular || - network->type == mojom::NetworkType::kTether || - network->type == mojom::NetworkType::kWiFi || - network->type == mojom::NetworkType::kWiMAX; + return network_type == match_type; } NOTREACHED(); return false; } +bool NetworkStateMatchesType(const mojom::NetworkStateProperties* network, + mojom::NetworkType type) { + return NetworkTypeMatchesType(network->type, type); +} + bool StateIsConnected(mojom::ConnectionStateType connection_state) { switch (connection_state) { case mojom::ConnectionStateType::kOnline:
diff --git a/chromeos/services/network_config/public/cpp/cros_network_config_util.h b/chromeos/services/network_config/public/cpp/cros_network_config_util.h index 0a4ef77..9ba0659 100644 --- a/chromeos/services/network_config/public/cpp/cros_network_config_util.h +++ b/chromeos/services/network_config/public/cpp/cros_network_config_util.h
@@ -10,8 +10,12 @@ namespace chromeos { namespace network_config { -// Returns true if network->type matches |type|, which may include kAll or -// kWireless. +// Returns true if |network_type| matches |match_type|, which may include kAll +// or kWireless. +bool NetworkTypeMatchesType(mojom::NetworkType network_type, + mojom::NetworkType match_type); + +// Calls NetworkTypeMatchesType with |network_type| = |network|->type. bool NetworkStateMatchesType(const mojom::NetworkStateProperties* network, mojom::NetworkType type);
diff --git a/chromeos/services/network_config/public/mojom/cros_network_config.mojom b/chromeos/services/network_config/public/mojom/cros_network_config.mojom index 8ccb1c47..c5ebf36 100644 --- a/chromeos/services/network_config/public/mojom/cros_network_config.mojom +++ b/chromeos/services/network_config/public/mojom/cros_network_config.mojom
@@ -12,10 +12,12 @@ // Activation state for Cellular networks. enum ActivationStateType { kUnknown, - kActivated, - kActivating, kNotActivated, + kActivating, kPartiallyActivated, + kActivated, + // A cellular modem exists, but no network service is available. + kNoService, }; // The authentication type for Ethernet networks. @@ -33,13 +35,15 @@ kNotConnected, }; -// Device / Technology state for available devices. +// Device / Technology state for devices. enum DeviceStateType { kUninitialized, kDisabled, kEnabling, kEnabled, kProhibited, + // Not used in DeviceStateProperties, but useful when querying by type. + kUnavailable, }; // The ONC source for policy or imported networks. @@ -57,6 +61,8 @@ kAll, kCellular, kEthernet, + // Mobile includes Cellular, Tether, and WiMAX. + kMobile, kTether, kVPN, // Wireles includes Cellular, Tether, WiFi, and WiMAX. @@ -95,6 +101,13 @@ kAll, }; +struct CaptivePortalProvider { + // Id used to identify the captive portal provider (i.e. an extension id). + string id; + // Display name for the captive portal provider (i.e. extension name). + string name; +}; + // The SIM card lock status for Cellular networks. struct SIMLockStatus { // The status of SIM lock. Possible values are 'sim-pin', 'sim-puk' or empty. @@ -105,14 +118,6 @@ int32 retries_left; }; -// Additional properties for third party VPNs. -struct ThirdPartyVPNProperties { - // ID of the third-party VPN provider extension. - string extension_id; - // The VPN provider name. - string provider_name; -}; - struct CellularStateProperties { // Enumerated ONC activation state. ActivationStateType activation_state; @@ -145,7 +150,8 @@ struct VPNStateProperties { VPNType type; - ThirdPartyVPNProperties? third_party_vpn; + string provider_id; + string provider_name; }; struct WiFiStateProperties { @@ -168,6 +174,7 @@ }; struct NetworkStateProperties { + CaptivePortalProvider? captive_portal_provider; CellularStateProperties? cellular; // True if the network is configured and may be connectable. bool connectable = false; @@ -184,6 +191,8 @@ string name; // The relative priority of the network. Larger values have higher priority. int32 priority; + // True for visible networks that are blocked / disallowed by policy. + bool prohibited_by_policy = false; ONCSource source; TetherStateProperties? tether; NetworkType type;
diff --git a/components/arc/volume_mounter/arc_volume_mounter_bridge.cc b/components/arc/volume_mounter/arc_volume_mounter_bridge.cc index 7346202..f8a2befdf 100644 --- a/components/arc/volume_mounter/arc_volume_mounter_bridge.cc +++ b/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
@@ -120,10 +120,7 @@ bool ArcVolumeMounterBridge::HasAccessToRemovableMedia() const { DCHECK(pref_service_); - return pref_service_->GetBoolean(prefs::kArcHasAccessToRemovableMedia) - // TODO(yusukes): Once the UI for controlling the pref is ready, remove - // the condition below. - || true; + return pref_service_->GetBoolean(prefs::kArcHasAccessToRemovableMedia); } void ArcVolumeMounterBridge::OnPrefChanged() {
diff --git a/components/autofill/core/browser/autofill_profile_validation_util.cc b/components/autofill/core/browser/autofill_profile_validation_util.cc index 8adf74309..abec17f 100644 --- a/components/autofill/core/browser/autofill_profile_validation_util.cc +++ b/components/autofill/core/browser/autofill_profile_validation_util.cc
@@ -31,10 +31,10 @@ using ::i18n::addressinput::STREET_ADDRESS; using ::i18n::addressinput::RECIPIENT; -using ::i18n::addressinput::AddressData; -using ::i18n::addressinput::AddressField; -using ::i18n::addressinput::AddressProblem; -using ::i18n::addressinput::FieldProblemMap; +using i18nAddressData = ::i18n::addressinput::AddressData; +using i18nAddressField = ::i18n::addressinput::AddressField; +using i18nAddressProblem = ::i18n::addressinput::AddressProblem; +using i18nFieldProblemMap = ::i18n::addressinput::FieldProblemMap; using ::i18n::addressinput::INVALID_FORMAT; using ::i18n::addressinput::MISMATCHING_VALUE; @@ -45,17 +45,17 @@ using ::i18n::phonenumbers::PhoneNumberUtil; -const AddressField kFields[] = {COUNTRY, ADMIN_AREA, LOCALITY, - DEPENDENT_LOCALITY, POSTAL_CODE}; -const AddressProblem kProblems[] = {UNEXPECTED_FIELD, MISSING_REQUIRED_FIELD, - UNKNOWN_VALUE, INVALID_FORMAT, - MISMATCHING_VALUE, UNSUPPORTED_FIELD}; +const i18nAddressField kFields[] = {COUNTRY, ADMIN_AREA, LOCALITY, + DEPENDENT_LOCALITY, POSTAL_CODE}; +const i18nAddressProblem kProblems[] = { + UNEXPECTED_FIELD, MISSING_REQUIRED_FIELD, UNKNOWN_VALUE, + INVALID_FORMAT, MISMATCHING_VALUE, UNSUPPORTED_FIELD}; // If the |address_field| is valid, set the validity state of the // |address_field| in the |profile| to the |state| and return true. // Otherwise, return false. bool SetValidityStateForAddressField(const AutofillProfile* profile, - AddressField address_field, + i18nAddressField address_field, AutofillDataModel::ValidityState state) { ServerFieldType server_field = i18n::TypeForField(address_field, /*billing=*/false); @@ -76,8 +76,8 @@ // Returns all relevant pairs of (field, problem), where field is in // |kFields|, and problem is in |kProblems|. -FieldProblemMap* CreateFieldProblemMap() { - FieldProblemMap* filter = new FieldProblemMap(); +i18nFieldProblemMap* CreateFieldProblemMap() { + i18nFieldProblemMap* filter = new i18nFieldProblemMap(); for (auto field : kFields) { for (auto problem : kProblems) { filter->insert(std::make_pair(field, problem)); @@ -88,14 +88,14 @@ // GetFilter() will make sure that the validation only returns problems that // are relevant. -const FieldProblemMap* GetFilter() { - static const FieldProblemMap* const filter = CreateFieldProblemMap(); +const i18nFieldProblemMap* GetFilter() { + static const i18nFieldProblemMap* const filter = CreateFieldProblemMap(); return filter; } // Initializes |address| data from the address info in the |profile|. void InitializeAddressFromProfile(const AutofillProfile& profile, - AddressData* address) { + i18nAddressData* address) { address->region_code = base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)); address->administrative_area = @@ -263,9 +263,9 @@ // The COUNTRY was already listed in the CountryDataMap, therefore it's valid. SetValidityStateForAddressField(profile, COUNTRY, AutofillDataModel::VALID); - AddressData address; + i18nAddressData address; InitializeAddressFromProfile(*profile, &address); - FieldProblemMap problems; + i18nFieldProblemMap problems; // status denotes if the rule was successfully loaded before validation. AddressValidator::Status status = address_validator->ValidateAddress(address, GetFilter(), &problems);
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index 2f338db..f10d190 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -10,10 +10,10 @@ #include "ash/frame/wide_frame_view.h" #include "ash/public/cpp/caption_buttons/caption_button_model.h" #include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/interfaces/window_pin_type.mojom.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/system/unified/unified_system_tray.h" #include "ash/wm/drag_window_resizer.h" #include "ash/wm/overview/overview_controller.h" @@ -65,8 +65,7 @@ using ClientControlledShellSurfaceTest = test::ExoTestBase; bool HasBackdrop() { - ash::WorkspaceController* wc = - ash::ShellTestApi(ash::Shell::Get()).workspace_controller(); + ash::WorkspaceController* wc = ash::ShellTestApi().workspace_controller(); return !!ash::WorkspaceControllerTestApi(wc).GetBackdropWindow(); }
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index df5f52a..43df35f1 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -7,8 +7,8 @@ #include "ash/accessibility/accessibility_delegate.h" #include "ash/frame/non_client_frame_view_ash.h" #include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/test/shell_test_api.h" #include "ash/shell.h" -#include "ash/shell_test_api.h" #include "ash/wm/window_state.h" #include "ash/wm/wm_event.h" #include "ash/wm/workspace/workspace_window_resizer.h" @@ -46,8 +46,7 @@ using ShellSurfaceTest = test::ExoTestBase; bool HasBackdrop() { - ash::WorkspaceController* wc = - ash::ShellTestApi(ash::Shell::Get()).workspace_controller(); + ash::WorkspaceController* wc = ash::ShellTestApi().workspace_controller(); return !!ash::WorkspaceControllerTestApi(wc).GetBackdropWindow(); }
diff --git a/components/exo/wayland/zcr_gaming_input.cc b/components/exo/wayland/zcr_gaming_input.cc index dac7e76..5d5ba65f 100644 --- a/components/exo/wayland/zcr_gaming_input.cc +++ b/components/exo/wayland/zcr_gaming_input.cc
@@ -144,13 +144,10 @@ &WaylandGamepadDelegate::ResetGamepadResource); if (base::FeatureList::IsEnabled(kRawGamepadInfoFeature)) { - // The version is temporarily set to 0 because the information is not - // available in ui::InputDevice. - // TODO(tetsui): Add version field to ui::InputDevice zcr_gaming_seat_v2_send_gamepad_added_with_device_info( gaming_seat_resource_, gamepad_resource, device.name.c_str(), GetGamepadBusType(device.type), device.vendor_id, device.product_id, - /*version=*/0); + device.version); // TODO(tetsui): Send joystick motion range. } else {
diff --git a/components/password_manager/core/browser/sync/password_model_worker.cc b/components/password_manager/core/browser/sync/password_model_worker.cc index d69b0cd9..9314d1c6 100644 --- a/components/password_manager/core/browser/sync/password_model_worker.cc +++ b/components/password_manager/core/browser/sync/password_model_worker.cc
@@ -33,9 +33,7 @@ void PasswordModelWorker::ScheduleWork(base::OnceClosure work) { base::AutoLock lock(password_store_lock_); if (password_store_) { - password_store_->ScheduleTask( - base::BindOnce([](base::OnceClosure work) { std::move(work).Run(); }, - base::Passed(std::move(work)))); + password_store_->ScheduleTask(std::move(work)); } }
diff --git a/components/policy/core/common/policy_map_unittest.cc b/components/policy/core/common/policy_map_unittest.cc index 1dc34a11..d95bfc2 100644 --- a/components/policy/core/common/policy_map_unittest.cc +++ b/components/policy/core/common/policy_map_unittest.cc
@@ -342,145 +342,143 @@ // Case 1 - kTestPolicyName1 // Enterprise default policies should not be merged with other sources. - PolicyMap::Entry platform_user_mandatory( - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM, - std::make_unique<base::Value>(abc), nullptr); + PolicyMap::Entry case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, + std::make_unique<base::Value>(abc), nullptr); - platform_user_mandatory.AddConflictingPolicy(PolicyMap::Entry( + case1.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_ACTIVE_DIRECTORY, std::make_unique<base::Value>(cd), nullptr)); - platform_user_mandatory.AddConflictingPolicy( + case1.AddConflictingPolicy( PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_ENTERPRISE_DEFAULT, std::make_unique<base::Value>(ef), nullptr)); - platform_user_mandatory.AddConflictingPolicy( + case1.AddConflictingPolicy( PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, POLICY_SOURCE_ENTERPRISE_DEFAULT, std::make_unique<base::Value>(ef), nullptr)); - PolicyMap::Entry merged_user_mandatory( - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_MERGED, - std::make_unique<base::Value>(abcd), nullptr); - merged_user_mandatory.AddConflictingPolicy(platform_user_mandatory); + PolicyMap::Entry expected_case1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_MERGED, + std::make_unique<base::Value>(abcd), nullptr); + expected_case1.AddConflictingPolicy(case1); // Case 2 - kTestPolicyName2 // Policies should only be merged with other policies with the same target, // level and scope. - PolicyMap::Entry cloud_machine_recommended( - POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, - POLICY_SOURCE_PRIORITY_CLOUD, std::make_unique<base::Value>(int12), - nullptr); + PolicyMap::Entry case2(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PRIORITY_CLOUD, + std::make_unique<base::Value>(int12), nullptr); - cloud_machine_recommended.AddConflictingPolicy(PolicyMap::Entry( + case2.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, std::make_unique<base::Value>(int34), nullptr)); - cloud_machine_recommended.AddConflictingPolicy(PolicyMap::Entry( + case2.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM, std::make_unique<base::Value>(int56), nullptr)); - PolicyMap::Entry merged_machine_recommended( + PolicyMap::Entry expected_case2( POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED, std::make_unique<base::Value>(int1234), nullptr); - merged_machine_recommended.AddConflictingPolicy(cloud_machine_recommended); + expected_case2.AddConflictingPolicy(case2); // Case 3 - kTestPolicyName3 // Trivial case with 2 sources. - PolicyMap::Entry cloud_machine_mandatory( - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, - POLICY_SOURCE_PRIORITY_CLOUD, std::make_unique<base::Value>(ab), nullptr); + PolicyMap::Entry case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_PRIORITY_CLOUD, + std::make_unique<base::Value>(ab), nullptr); - cloud_machine_mandatory.AddConflictingPolicy(PolicyMap::Entry( + case3.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM, std::make_unique<base::Value>(cd), nullptr)); - PolicyMap::Entry merged_cloud_machine_mandatory( - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED, - std::make_unique<base::Value>(abcd), nullptr); - auto merged_cloud_machine_mandatory_blocked_by_group = - merged_cloud_machine_mandatory.DeepCopy(); - merged_cloud_machine_mandatory_blocked_by_group - .SetIgnoredByPolicyAtomicGroup(); - merged_cloud_machine_mandatory.AddConflictingPolicy(cloud_machine_mandatory); + PolicyMap::Entry expected_case3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, + std::make_unique<base::Value>(abcd), nullptr); + auto case3_blocked_by_group = expected_case3.DeepCopy(); + case3_blocked_by_group.SetIgnoredByPolicyAtomicGroup(); + expected_case3.AddConflictingPolicy(case3); // Case 4 - kTestPolicyName4 // Policies with a single source should stay the same. - PolicyMap::Entry ad_machine_mandatory( - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, - POLICY_SOURCE_ACTIVE_DIRECTORY, std::make_unique<base::Value>(ef), - nullptr); + PolicyMap::Entry case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ACTIVE_DIRECTORY, + std::make_unique<base::Value>(ef), nullptr); + PolicyMap::Entry expected_case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_MERGED, + std::make_unique<base::Value>(ef), nullptr); + expected_case4.AddConflictingPolicy(case4); // Case 5 - kTestPolicyName5 // Policies that are not lists should not be merged. // If such a policy is explicitly in the list of policies to merge, an error // is added to the entry and the policy stays intact. - PolicyMap::Entry bad_stuff(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, - POLICY_SOURCE_ACTIVE_DIRECTORY, - std::make_unique<base::Value>("bad stuff"), - nullptr); + PolicyMap::Entry case5(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ACTIVE_DIRECTORY, + std::make_unique<base::Value>("bad stuff"), nullptr); - PolicyMap::Entry expected_bad_stuff( - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, - POLICY_SOURCE_ACTIVE_DIRECTORY, - std::make_unique<base::Value>("bad stuff"), nullptr); - expected_bad_stuff.AddError( - IDS_POLICY_LIST_MERGING_WRONG_POLICY_TYPE_SPECIFIED); + PolicyMap::Entry expected_case5(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, + POLICY_SOURCE_ACTIVE_DIRECTORY, + std::make_unique<base::Value>("bad stuff"), + nullptr); + expected_case5.AddError(IDS_POLICY_LIST_MERGING_WRONG_POLICY_TYPE_SPECIFIED); // Case 6 - kTestPolicyName6 // User cloud policies should not be merged with other sources. - PolicyMap::Entry user_not_merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, - POLICY_SOURCE_PLATFORM, - std::make_unique<base::Value>(ab), nullptr); - user_not_merged.AddConflictingPolicy(PolicyMap::Entry( + PolicyMap::Entry case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, + std::make_unique<base::Value>(ab), nullptr); + case6.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(cd), nullptr)); - user_not_merged.AddConflictingPolicy(PolicyMap::Entry( + case6.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PRIORITY_CLOUD, std::make_unique<base::Value>(ef), nullptr)); + PolicyMap::Entry expected_case6(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_MERGED, + std::make_unique<base::Value>(ab), nullptr); + expected_case6.AddConflictingPolicy(case6); // Case 7 - kTestPolicyName7 // Lists of dictionaries should not have duplicates. - PolicyMap::Entry platform_user_mandatory_dict( - POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM, - std::make_unique<base::Value>(list_dict_abd), nullptr); + PolicyMap::Entry case7(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, + POLICY_SOURCE_PLATFORM, + std::make_unique<base::Value>(list_dict_abd), nullptr); - platform_user_mandatory_dict.AddConflictingPolicy(PolicyMap::Entry( + case7.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_ACTIVE_DIRECTORY, std::make_unique<base::Value>(list_dict_abd), nullptr)); - platform_user_mandatory_dict.AddConflictingPolicy( + case7.AddConflictingPolicy( PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_DEVICE_LOCAL_ACCOUNT_OVERRIDE, std::make_unique<base::Value>(list_dict_c), nullptr)); - PolicyMap::Entry merged_user_mandatory_dict( + PolicyMap::Entry expected_case7( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_MERGED, std::make_unique<base::Value>(list_dict_abcd), nullptr); - merged_user_mandatory_dict.AddConflictingPolicy(platform_user_mandatory_dict); + expected_case7.AddConflictingPolicy(case7); PolicyMap policy_not_merged; - policy_not_merged.Set(kTestPolicyName1, platform_user_mandatory.DeepCopy()); - policy_not_merged.Set(kTestPolicyName2, cloud_machine_recommended.DeepCopy()); - policy_not_merged.Set(kTestPolicyName3, cloud_machine_mandatory.DeepCopy()); - policy_not_merged.Set(kTestPolicyName4, ad_machine_mandatory.DeepCopy()); - policy_not_merged.Set(kTestPolicyName5, bad_stuff.DeepCopy()); - policy_not_merged.Set(kTestPolicyName6, user_not_merged.DeepCopy()); - policy_not_merged.Set(kTestPolicyName7, - platform_user_mandatory_dict.DeepCopy()); + policy_not_merged.Set(kTestPolicyName1, case1.DeepCopy()); + policy_not_merged.Set(kTestPolicyName2, case2.DeepCopy()); + policy_not_merged.Set(kTestPolicyName3, case3.DeepCopy()); + policy_not_merged.Set(kTestPolicyName4, case4.DeepCopy()); + policy_not_merged.Set(kTestPolicyName5, case5.DeepCopy()); + policy_not_merged.Set(kTestPolicyName6, case6.DeepCopy()); + policy_not_merged.Set(kTestPolicyName7, case7.DeepCopy()); PolicyMap expected_list_merged; - expected_list_merged.Set(kTestPolicyName1, merged_user_mandatory.DeepCopy()); - expected_list_merged.Set(kTestPolicyName2, - merged_machine_recommended.DeepCopy()); - expected_list_merged.Set(kTestPolicyName3, - merged_cloud_machine_mandatory.DeepCopy()); - expected_list_merged.Set(kTestPolicyName4, ad_machine_mandatory.DeepCopy()); - expected_list_merged.Set(kTestPolicyName5, expected_bad_stuff.DeepCopy()); - expected_list_merged.Set(kTestPolicyName6, user_not_merged.DeepCopy()); - expected_list_merged.Set(kTestPolicyName7, - merged_user_mandatory_dict.DeepCopy()); + expected_list_merged.Set(kTestPolicyName1, expected_case1.DeepCopy()); + expected_list_merged.Set(kTestPolicyName2, expected_case2.DeepCopy()); + expected_list_merged.Set(kTestPolicyName3, expected_case3.DeepCopy()); + expected_list_merged.Set(kTestPolicyName4, expected_case4.DeepCopy()); + expected_list_merged.Set(kTestPolicyName5, expected_case5.DeepCopy()); + expected_list_merged.Set(kTestPolicyName6, expected_case6.DeepCopy()); + expected_list_merged.Set(kTestPolicyName7, expected_case7.DeepCopy()); PolicyMap list_merged; list_merged.CopyFrom(policy_not_merged); @@ -508,7 +506,7 @@ PolicyMap expected_list_merged_wildcard; expected_list_merged_wildcard.CopyFrom(expected_list_merged); - expected_list_merged_wildcard.Set(kTestPolicyName5, bad_stuff.DeepCopy()); + expected_list_merged_wildcard.Set(kTestPolicyName5, case5.DeepCopy()); list_merged_wildcard.MergeValues({&wildcard_policy_list}); EXPECT_TRUE(list_merged_wildcard.Equals(expected_list_merged_wildcard)); } @@ -569,10 +567,10 @@ merged_dict_case1.MergeDictionary(&dict_b); merged_dict_case1.MergeDictionary(&dict_a); - PolicyMap::Entry case1_merged( + PolicyMap::Entry expected_case1( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED, base::Value::ToUniquePtrValue(merged_dict_case1.Clone()), nullptr); - case1_merged.AddConflictingPolicy(case1); + expected_case1.AddConflictingPolicy(case1); // Case - kTestPolicyName2 // Policies should only be merged with other policies with the same target, @@ -594,10 +592,10 @@ merged_dict_case2.MergeDictionary(&dict_f); merged_dict_case2.MergeDictionary(&dict_e); - PolicyMap::Entry case2_merged( + PolicyMap::Entry expected_case2( POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED, base::Value::ToUniquePtrValue(merged_dict_case2.Clone()), nullptr); - case2_merged.AddConflictingPolicy(case2); + expected_case2.AddConflictingPolicy(case2); // Case 3 - kTestPolicyName3 // Enterprise default policies should not be merged with other sources. @@ -623,17 +621,21 @@ merged_dict_case3.MergeDictionary(&dict_b); merged_dict_case3.MergeDictionary(&dict_a); - PolicyMap::Entry case3_merged( + PolicyMap::Entry expected_case3( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_MERGED, base::Value::ToUniquePtrValue(merged_dict_case3.Clone()), nullptr); - case3_merged.AddConflictingPolicy(case3); + expected_case3.AddConflictingPolicy(case3); // Case 4 - kTestPolicyName4 - // Policies with a single source should stay the same. + // Policies with a single source should be merged. PolicyMap::Entry case4(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_ACTIVE_DIRECTORY, base::Value::ToUniquePtrValue(dict_a.Clone()), nullptr); + PolicyMap::Entry expected_case4( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED, + base::Value::ToUniquePtrValue(dict_a.Clone()), nullptr); + expected_case4.AddConflictingPolicy(case4); // Case 5 - kTestPolicyName5 // Policies that are not dictionaries should not be merged. @@ -661,6 +663,10 @@ case6.AddConflictingPolicy(PolicyMap::Entry( POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PRIORITY_CLOUD, base::Value::ToUniquePtrValue(dict_f.Clone()), nullptr)); + PolicyMap::Entry expected_case6( + POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_MERGED, + base::Value::ToUniquePtrValue(dict_a.Clone()), nullptr); + expected_case6.AddConflictingPolicy(case6); // Case 7 - kTestPolicyName7 // Policies that are not dictionaries should not be merged. @@ -685,12 +691,12 @@ policy_not_merged.Set(kTestPolicyName7, case7.DeepCopy()); PolicyMap expected_list_merged; - expected_list_merged.Set(kTestPolicyName1, case1_merged.DeepCopy()); - expected_list_merged.Set(kTestPolicyName2, case2_merged.DeepCopy()); - expected_list_merged.Set(kTestPolicyName3, case3_merged.DeepCopy()); - expected_list_merged.Set(kTestPolicyName4, case4.DeepCopy()); + expected_list_merged.Set(kTestPolicyName1, expected_case1.DeepCopy()); + expected_list_merged.Set(kTestPolicyName2, expected_case2.DeepCopy()); + expected_list_merged.Set(kTestPolicyName3, expected_case3.DeepCopy()); + expected_list_merged.Set(kTestPolicyName4, expected_case4.DeepCopy()); expected_list_merged.Set(kTestPolicyName5, expected_case5.DeepCopy()); - expected_list_merged.Set(kTestPolicyName6, case6.DeepCopy()); + expected_list_merged.Set(kTestPolicyName6, expected_case6.DeepCopy()); expected_list_merged.Set(kTestPolicyName7, expected_case7.DeepCopy()); PolicyMap list_merged;
diff --git a/components/policy/core/common/policy_merger.cc b/components/policy/core/common/policy_merger.cc index 4c85c09c..89ef8fd 100644 --- a/components/policy/core/common/policy_merger.cc +++ b/components/policy/core/common/policy_merger.cc
@@ -73,16 +73,13 @@ } void PolicyListMerger::DoMerge(PolicyMap::Entry* policy) const { - if (policy->conflicts.empty()) - return; - std::vector<const base::Value*> merged_values; auto compare_value_ptr = [](const base::Value* a, const base::Value* b) { return *a < *b; }; std::set<const base::Value*, decltype(compare_value_ptr)> duplicates( compare_value_ptr); - bool merged = false; + bool value_changed = false; for (const base::Value& val : policy->value->GetList()) { if (duplicates.find(&val) != duplicates.end()) @@ -105,21 +102,20 @@ merged_values.push_back(&val); } - merged = true; + value_changed = true; } - if (merged) { - auto new_conflict = policy->DeepCopy(); - + auto new_conflict = policy->DeepCopy(); + if (value_changed) { base::ListValue* new_value = new base::ListValue(); for (const base::Value* it : merged_values) new_value->GetList().emplace_back(it->Clone()); policy->value.reset(new_value); - policy->ClearConflicts(); - policy->AddConflictingPolicy(new_conflict); - policy->source = POLICY_SOURCE_MERGED; } + policy->ClearConflicts(); + policy->AddConflictingPolicy(new_conflict); + policy->source = POLICY_SOURCE_MERGED; } PolicyDictionaryMerger::PolicyDictionaryMerger( @@ -170,10 +166,7 @@ } void PolicyDictionaryMerger::DoMerge(PolicyMap::Entry* policy) const { - if (policy->conflicts.empty()) - return; - - bool merged = false; + // Keep priority sorted list of potential merge targets. std::vector<const PolicyMap::Entry*> policies; policies.push_back(policy); for (const auto& it : policy->conflicts) @@ -185,11 +178,12 @@ }); base::DictionaryValue merged_dictionary; + bool value_changed = false; + // Merges all the keys from the policies from different sources. for (const auto* it : policies) { - if (!UseConflictValueInMerging(*it, *policy)) { + if (it != policy && !UseConflictValueInMerging(*it, *policy)) continue; - } base::DictionaryValue* dict = nullptr; @@ -202,16 +196,16 @@ merged_dictionary.SetKey(key, val->Clone()); } - merged |= it != policy; + value_changed |= it != policy; } - if (merged) { - auto new_conflict = policy->DeepCopy(); - policy->ClearConflicts(); - policy->AddConflictingPolicy(new_conflict); - policy->source = POLICY_SOURCE_MERGED; + auto new_conflict = policy->DeepCopy(); + if (value_changed) policy->value = base::Value::ToUniquePtrValue(std::move(merged_dictionary)); - } + + policy->ClearConflicts(); + policy->AddConflictingPolicy(new_conflict); + policy->source = POLICY_SOURCE_MERGED; } void PolicyGroupMerger::Merge(PolicyMap::PolicyMapType* policies) const {
diff --git a/components/send_tab_to_self/features.cc b/components/send_tab_to_self/features.cc index 5c2ead8..9ac7562 100644 --- a/components/send_tab_to_self/features.cc +++ b/components/send_tab_to_self/features.cc
@@ -16,6 +16,9 @@ const base::Feature kSendTabToSelfBroadcast{"SendTabToSelfBroadcast", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSendTabToSelfHistory{"SendTabToSelfHistory", + base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kSendTabToSelfWhenSignedIn{ "SendTabToSelfWhenSignedIn", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -30,4 +33,9 @@ base::FeatureList::IsEnabled(kSendTabToSelfWhenSignedIn); } +bool HistoryViewEnabled() { + return base::FeatureList::IsEnabled(switches::kSyncSendTabToSelf) && + base::FeatureList::IsEnabled(kSendTabToSelfHistory); +} + } // namespace send_tab_to_self
diff --git a/components/send_tab_to_self/features.h b/components/send_tab_to_self/features.h index cfd6ce5..6e3b42b 100644 --- a/components/send_tab_to_self/features.h +++ b/components/send_tab_to_self/features.h
@@ -19,6 +19,11 @@ // targeted to a specific device. This only affects the receiving side. extern const base::Feature kSendTabToSelfBroadcast; +// If this feature is enabled, the tabs will be accessible after they are shared +// in the history tab on desktop devices or in the recent tab page on mobile +// devices. +extern const base::Feature kSendTabToSelfHistory; + // If this feature is enabled, we will use signed-in, ephemeral data rather than // persistent sync data. Users who are signed in can use the feature regardless // of whether they have the sync feature enabled. @@ -35,6 +40,9 @@ // regardless of whether they have full sync enabled. bool EnabledOnSignIn(); +// Returns whether we should show the send tab to self history ui on desktop or +// the recent tab UI on mobile, in order to access previously sent tabs. +bool HistoryViewEnabled(); } // namespace send_tab_to_self #endif // COMPONENTS_SEND_TAB_TO_SELF_FEATURES_H_
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc index 8f108992..0988ac0 100644 --- a/components/signin/core/browser/account_tracker_service.cc +++ b/components/signin/core/browser/account_tracker_service.cc
@@ -46,28 +46,12 @@ const char kAdvancedProtectionAccountStatusPath[] = "is_under_advanced_protection"; -// TODO(knn): Remove once deprecated service flags have been migrated from -// preferences. -const char kChildAccountServiceFlag[] = "uca"; - // Account folders used for storing account related data at disk. const base::FilePath::CharType kAccountsFolder[] = FILE_PATH_LITERAL("Accounts"); const base::FilePath::CharType kAvatarImagesFolder[] = FILE_PATH_LITERAL("Avatar Images"); -// TODO(M48): Remove deprecated preference migration. -const char kAccountServiceFlagsPath[] = "service_flags"; - -void RemoveDeprecatedServiceFlags(PrefService* pref_service) { - ListPrefUpdate update(pref_service, prefs::kAccountInfo); - for (size_t i = 0; i < update->GetSize(); ++i) { - base::DictionaryValue* dict = nullptr; - if (update->GetDictionary(i, &dict)) - dict->RemoveWithoutPathExpansion(kAccountServiceFlagsPath, nullptr); - } -} - // Reads a PNG image from disk and decodes it. If the reading/decoding attempt // was unsuccessful, an empty image is returned. gfx::Image ReadImage(const base::FilePath& image_path) { @@ -464,7 +448,6 @@ void AccountTrackerService::LoadFromPrefs() { const base::ListValue* list = pref_service_->GetList(prefs::kAccountInfo); std::set<std::string> to_remove; - bool contains_deprecated_service_flags = false; for (size_t i = 0; i < list->GetSize(); ++i) { const base::DictionaryValue* dict; if (list->GetDictionary(i, &dict)) { @@ -498,20 +481,6 @@ account_info.picture_url = base::UTF16ToUTF8(value); bool is_child_account = false; - // Migrate deprecated service flag preference. - const base::ListValue* service_flags_list; - if (dict->GetList(kAccountServiceFlagsPath, &service_flags_list)) { - contains_deprecated_service_flags = true; - std::string flag_string; - for (const auto& flag : *service_flags_list) { - if (flag.GetAsString(&flag_string) && - flag_string == kChildAccountServiceFlag) { - is_child_account = true; - break; - } - } - account_info.is_child_account = is_child_account; - } if (dict->GetBoolean(kAccountChildAccountStatusPath, &is_child_account)) account_info.is_child_account = is_child_account; @@ -528,12 +497,6 @@ } } - UMA_HISTOGRAM_BOOLEAN("Signin.AccountTracker.DeprecatedServiceFlagDeleted", - contains_deprecated_service_flags); - - if (contains_deprecated_service_flags) - RemoveDeprecatedServiceFlags(pref_service_); - // Remove any obsolete prefs. for (auto account_id : to_remove) { AccountInfo account_info;
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc index a9367943..3bb9cdb 100644 --- a/components/signin/core/browser/account_tracker_service_unittest.cc +++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -962,48 +962,6 @@ EXPECT_EQ(AccountKeyToEmail(kAccountKeyFooBar), infos[0].email); } -TEST_F(AccountTrackerServiceTest, NoDeprecatedServiceFlags) { - const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha); - const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha); - - ListPrefUpdate update(prefs(), prefs::kAccountInfo); - - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("account_id", email_alpha); - dict->SetString("email", email_alpha); - dict->SetString("gaia", gaia_alpha); - update->Append(std::move(dict)); - - base::HistogramTester tester; - - ResetAccountTracker(); - tester.ExpectBucketCount("Signin.AccountTracker.DeprecatedServiceFlagDeleted", - false, 1); -} - -TEST_F(AccountTrackerServiceTest, MigrateDeprecatedServiceFlags) { - const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha); - const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha); - - ListPrefUpdate update(prefs(), prefs::kAccountInfo); - - std::unique_ptr<base::ListValue> service_flags(new base::ListValue()); - service_flags->Append(std::make_unique<base::Value>("uca")); - - std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetString("account_id", email_alpha); - dict->SetString("email", email_alpha); - dict->SetString("gaia", gaia_alpha); - dict->SetList("service_flags", std::move(service_flags)); - update->Append(std::move(dict)); - - base::HistogramTester tester; - - ResetAccountTracker(); - tester.ExpectBucketCount("Signin.AccountTracker.DeprecatedServiceFlagDeleted", - true, 1); -} - TEST_F(AccountTrackerServiceTest, MigrateAccountIdToGaiaId) { if (!AccountTrackerService::IsMigrationSupported()) return;
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-25.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-25.png.sha1 index f46fb206..9335464 100644 --- a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-25.png.sha1 +++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-25.png.sha1
@@ -1 +1 @@ -9ef5447ea3d00d9978e8389ab1f25eb12d012396 \ No newline at end of file +94d51539dee684b7ed109c145f738e5b03c972f5 \ No newline at end of file
diff --git a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-26.png.sha1 b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-26.png.sha1 index 63d588f5..f40d33b 100644 --- a/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-26.png.sha1 +++ b/components/test/data/vr_browser_video/render_tests/VrBrowserWebInputEditingTest.fullscreen_video_paused_browser_content.Pixel_XL-26.png.sha1
@@ -1 +1 @@ -3a6e79cb8d4e001ebb370274022286eff523dee9 \ No newline at end of file +834d01dbb54a5f90ac36adbe0fe878cf147cd90a \ No newline at end of file
diff --git a/components/viz/common/quads/render_pass.cc b/components/viz/common/quads/render_pass.cc index 00cbb78..09151a9b 100644 --- a/components/viz/common/quads/render_pass.cc +++ b/components/viz/common/quads/render_pass.cc
@@ -184,18 +184,19 @@ DCHECK(shared_quad_state_list.empty()); } -void RenderPass::SetAll(uint64_t id, - const gfx::Rect& output_rect, - const gfx::Rect& damage_rect, - const gfx::Transform& transform_to_root_target, - const cc::FilterOperations& filters, - const cc::FilterOperations& backdrop_filters, - const gfx::RRectF& backdrop_filter_bounds, - const gfx::ColorSpace& color_space, - bool has_transparent_background, - bool cache_render_pass, - bool has_damage_from_contributing_content, - bool generate_mipmap) { +void RenderPass::SetAll( + uint64_t id, + const gfx::Rect& output_rect, + const gfx::Rect& damage_rect, + const gfx::Transform& transform_to_root_target, + const cc::FilterOperations& filters, + const cc::FilterOperations& backdrop_filters, + const base::Optional<gfx::RRectF>& backdrop_filter_bounds, + const gfx::ColorSpace& color_space, + bool has_transparent_background, + bool cache_render_pass, + bool has_damage_from_contributing_content, + bool generate_mipmap) { DCHECK(id); this->id = id; @@ -237,8 +238,10 @@ backdrop_filters.AsValueInto(value); value->EndArray(); - cc::MathUtil::AddToTracedValue("backdrop_filter_bounds", - backdrop_filter_bounds, value); + if (backdrop_filter_bounds.has_value()) { + cc::MathUtil::AddToTracedValue("backdrop_filter_bounds", + backdrop_filter_bounds.value(), value); + } value->BeginArray("shared_quad_state_list"); for (auto* shared_quad_state : shared_quad_state_list) {
diff --git a/components/viz/common/quads/render_pass.h b/components/viz/common/quads/render_pass.h index ced1e18..f705948c 100644 --- a/components/viz/common/quads/render_pass.h +++ b/components/viz/common/quads/render_pass.h
@@ -91,7 +91,7 @@ const gfx::Transform& transform_to_root_target, const cc::FilterOperations& filters, const cc::FilterOperations& backdrop_filters, - const gfx::RRectF& backdrop_filter_bounds, + const base::Optional<gfx::RRectF>& backdrop_filter_bounds, const gfx::ColorSpace& color_space, bool has_transparent_background, bool cache_render_pass, @@ -131,7 +131,7 @@ cc::FilterOperations backdrop_filters; // Clipping bounds for backdrop filter. - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; // The color space into which content will be rendered for this render pass. gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
diff --git a/components/viz/common/quads/render_pass_unittest.cc b/components/viz/common/quads/render_pass_unittest.cc index c0daf9f..48a39eac 100644 --- a/components/viz/common/quads/render_pass_unittest.cc +++ b/components/viz/common/quads/render_pass_unittest.cc
@@ -29,7 +29,7 @@ gfx::Transform transform_to_root_target; cc::FilterOperations filters; cc::FilterOperations backdrop_filters; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; gfx::ColorSpace color_space; bool has_transparent_background; bool generate_mipmap; @@ -81,7 +81,8 @@ filters.Append(cc::FilterOperation::CreateOpacityFilter(0.5)); cc::FilterOperations backdrop_filters; backdrop_filters.Append(cc::FilterOperation::CreateInvertFilter(1.0)); - gfx::RRectF backdrop_filter_bounds(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8); + base::Optional<gfx::RRectF> backdrop_filter_bounds( + {10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8}); gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB(); bool has_transparent_background = true; bool cache_render_pass = false; @@ -114,8 +115,8 @@ EXPECT_EQ(pass->damage_rect, copy->damage_rect); EXPECT_EQ(pass->filters, copy->filters); EXPECT_EQ(pass->backdrop_filters, copy->backdrop_filters); - EXPECT_TRUE(pass->backdrop_filter_bounds.ApproximatelyEqual( - copy->backdrop_filter_bounds, 0.001)); + EXPECT_TRUE(pass->backdrop_filter_bounds->ApproximatelyEqual( + copy->backdrop_filter_bounds.value(), 0.001)); EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background); EXPECT_EQ(pass->generate_mipmap, copy->generate_mipmap); EXPECT_EQ(0u, copy->quad_list.size()); @@ -139,7 +140,8 @@ filters.Append(cc::FilterOperation::CreateOpacityFilter(0.5)); cc::FilterOperations backdrop_filters; backdrop_filters.Append(cc::FilterOperation::CreateInvertFilter(1.0)); - gfx::RRectF backdrop_filter_bounds(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8); + base::Optional<gfx::RRectF> backdrop_filter_bounds( + {10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8}); gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); bool has_transparent_background = true; bool cache_render_pass = false; @@ -194,8 +196,8 @@ contrib_filters.Append(cc::FilterOperation::CreateSepiaFilter(0.5)); cc::FilterOperations contrib_backdrop_filters; contrib_backdrop_filters.Append(cc::FilterOperation::CreateSaturateFilter(1)); - gfx::RRectF contrib_backdrop_filter_bounds(20, 30, 140, 150, 1, 2, 3, 4, 5, 6, - 7, 8); + base::Optional<gfx::RRectF> contrib_backdrop_filter_bounds( + {20, 30, 140, 150, 1, 2, 3, 4, 5, 6, 7, 8}); gfx::ColorSpace contrib_color_space = gfx::ColorSpace::CreateSCRGBLinear(); bool contrib_has_transparent_background = true; bool contrib_cache_render_pass = false; @@ -250,7 +252,8 @@ filters.Append(cc::FilterOperation::CreateOpacityFilter(0.5)); cc::FilterOperations backdrop_filters; backdrop_filters.Append(cc::FilterOperation::CreateInvertFilter(1.0)); - gfx::RRectF backdrop_filter_bounds(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8); + base::Optional<gfx::RRectF> backdrop_filter_bounds( + {10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8}); gfx::ColorSpace color_space = gfx::ColorSpace::CreateSCRGBLinear(); bool has_transparent_background = true; bool cache_render_pass = false;
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index d91f7f8..7f52d505 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -351,12 +351,8 @@ render_pass_filters_[pass->id] = &pass->filters; if (!pass->backdrop_filters.IsEmpty()) { render_pass_backdrop_filters_[pass->id] = &pass->backdrop_filters; - // |backdrop_filter_bounds| only apply if there is a non-empty - // backdrop-filter to apply. - if (!pass->backdrop_filters.IsEmpty()) { - render_pass_backdrop_filter_bounds_[pass->id] = - &pass->backdrop_filter_bounds; - } + render_pass_backdrop_filter_bounds_[pass->id] = + pass->backdrop_filter_bounds; } } @@ -533,10 +529,12 @@ return it == render_pass_backdrop_filters_.end() ? nullptr : it->second; } -const gfx::RRectF* DirectRenderer::BackdropFilterBoundsForPass( +const base::Optional<gfx::RRectF> DirectRenderer::BackdropFilterBoundsForPass( RenderPassId render_pass_id) const { auto it = render_pass_backdrop_filter_bounds_.find(render_pass_id); - return it == render_pass_backdrop_filter_bounds_.end() ? nullptr : it->second; + return it == render_pass_backdrop_filter_bounds_.end() + ? base::Optional<gfx::RRectF>() + : it->second; } void DirectRenderer::FlushPolygons(
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h index 8ab7952..e35a0f3a 100644 --- a/components/viz/service/display/direct_renderer.h +++ b/components/viz/service/display/direct_renderer.h
@@ -159,7 +159,7 @@ const cc::FilterOperations* FiltersForPass(RenderPassId render_pass_id) const; const cc::FilterOperations* BackdropFiltersForPass( RenderPassId render_pass_id) const; - const gfx::RRectF* BackdropFilterBoundsForPass( + const base::Optional<gfx::RRectF> BackdropFilterBoundsForPass( RenderPassId render_pass_id) const; // Private interface implemented by subclasses for use by DirectRenderer. @@ -242,7 +242,7 @@ base::flat_map<RenderPassId, cc::FilterOperations*> render_pass_filters_; base::flat_map<RenderPassId, cc::FilterOperations*> render_pass_backdrop_filters_; - base::flat_map<RenderPassId, gfx::RRectF*> + base::flat_map<RenderPassId, base::Optional<gfx::RRectF>> render_pass_backdrop_filter_bounds_; bool visible_ = false;
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc index 55c5f6e..a70fb43 100644 --- a/components/viz/service/display/gl_renderer.cc +++ b/components/viz/service/display/gl_renderer.cc
@@ -222,7 +222,7 @@ gfx::Transform quad_to_target_transform; const cc::FilterOperations* filters = nullptr; const cc::FilterOperations* backdrop_filters = nullptr; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; // Whether the texture to be sampled from needs to be flipped. bool source_needs_flip = false; @@ -758,7 +758,7 @@ gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad( DrawRenderPassDrawQuadParams* params, gfx::Transform* backdrop_filter_bounds_transform, - gfx::RRectF* backdrop_filter_bounds, + base::Optional<gfx::RRectF>* backdrop_filter_bounds, gfx::Rect* unclipped_rect) { DCHECK(backdrop_filter_bounds_transform); DCHECK(backdrop_filter_bounds); @@ -774,10 +774,12 @@ } // |backdrop_filter_bounds| is a rounded rect in [-0.5,0.5] space that // represents |params->backdrop_filter_bounds| as a fraction of the space - // defined by |quad->rect|. - if (!GetScaledRRectF(quad->rect, params->backdrop_filter_bounds, - backdrop_filter_bounds)) { - *backdrop_filter_bounds = gfx::RRectF(SharedGeometryQuad().BoundingBox()); + // defined by |quad->rect|, not including its offset. + *backdrop_filter_bounds = gfx::RRectF(); + if (!params->backdrop_filter_bounds.has_value() || + !GetScaledRRectF(quad->rect, params->backdrop_filter_bounds.value(), + &backdrop_filter_bounds->value())) { + backdrop_filter_bounds->reset(); } // |backdrop_rect| is now the bounding box of clip_region, in window pixel @@ -897,7 +899,7 @@ sk_sp<SkImage> GLRenderer::ApplyBackdropFilters( DrawRenderPassDrawQuadParams* params, const gfx::Rect& unclipped_rect, - const gfx::RRectF& backdrop_filter_bounds, + const base::Optional<gfx::RRectF>& backdrop_filter_bounds, const gfx::Transform& backdrop_filter_bounds_transform) { DCHECK(ShouldApplyBackdropFilters(params->backdrop_filters)); DCHECK(params->backdrop_filter_quality); @@ -984,9 +986,9 @@ quad->filters_origin, true); // Clip the filtered image to the (rounded) bounding box of the element. - if (!backdrop_filter_bounds.IsEmpty()) { + if (backdrop_filter_bounds.has_value()) { surface->getCanvas()->save(); - gfx::RRectF clip_rect(backdrop_filter_bounds); + gfx::RRectF clip_rect(backdrop_filter_bounds.value()); clip_rect.Scale(params->backdrop_filter_quality); surface->getCanvas()->setMatrix(backdrop_filter_bounds_transform.matrix()); surface->getCanvas()->clipRRect(SkRRect(clip_rect), SkClipOp::kIntersect, @@ -998,7 +1000,7 @@ surface->getCanvas()->drawImageRect(filtered_image, subset, dest_rect, nullptr); - if (!backdrop_filter_bounds.IsEmpty()) { + if (backdrop_filter_bounds.has_value()) { surface->getCanvas()->restore(); } @@ -1091,11 +1093,13 @@ params->backdrop_filters = BackdropFiltersForPass(quad->render_pass_id); if (ShouldApplyBackdropFilters(params->backdrop_filters)) { params->backdrop_filter_bounds = - *BackdropFilterBoundsForPass(quad->render_pass_id); - params->backdrop_filter_bounds.Scale(quad->filters_scale.x(), - quad->filters_scale.y()); + BackdropFilterBoundsForPass(quad->render_pass_id); + if (params->backdrop_filter_bounds.has_value()) { + params->backdrop_filter_bounds->Scale(quad->filters_scale.x(), + quad->filters_scale.y()); + } } else { - params->backdrop_filter_bounds = gfx::RRectF(); + params->backdrop_filter_bounds.reset(); } params->backdrop_filter_quality = quad->backdrop_filter_quality; gfx::Rect dst_rect = params->filters @@ -1166,11 +1170,11 @@ if (params->use_shaders_for_blending) { // Compute a bounding box around the pixels that will be visible through // the quad. - gfx::RRectF backdrop_filter_bounds_rect; + base::Optional<gfx::RRectF> backdrop_filter_bounds; gfx::Transform backdrop_filter_bounds_transform; gfx::Rect unclipped_rect; params->background_rect = GetBackdropBoundingBoxForRenderPassQuad( - params, &backdrop_filter_bounds_transform, &backdrop_filter_bounds_rect, + params, &backdrop_filter_bounds_transform, &backdrop_filter_bounds, &unclipped_rect); if (!params->background_rect.IsEmpty()) { @@ -1188,9 +1192,9 @@ if (ShouldApplyBackdropFilters(params->backdrop_filters)) { // Apply the background filters to R, so that it is applied in the // pixels' coordinate space. - params->background_image = ApplyBackdropFilters( - params, unclipped_rect, backdrop_filter_bounds_rect, - backdrop_filter_bounds_transform); + params->background_image = + ApplyBackdropFilters(params, unclipped_rect, backdrop_filter_bounds, + backdrop_filter_bounds_transform); if (params->background_image) { params->background_image_id = GetGLTextureIDFromSkImage(params->background_image.get());
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h index 7b5ed49..49293c4 100644 --- a/components/viz/service/display/gl_renderer.h +++ b/components/viz/service/display/gl_renderer.h
@@ -204,7 +204,7 @@ gfx::Rect GetBackdropBoundingBoxForRenderPassQuad( DrawRenderPassDrawQuadParams* params, gfx::Transform* backdrop_filter_bounds_transform, - gfx::RRectF* backdrop_filter_bounds, + base::Optional<gfx::RRectF>* backdrop_filter_bounds, gfx::Rect* unclipped_rect); // Allocates and returns a texture id that contains a copy of the contents @@ -224,7 +224,7 @@ sk_sp<SkImage> ApplyBackdropFilters( DrawRenderPassDrawQuadParams* params, const gfx::Rect& unclipped_rect, - const gfx::RRectF& backdrop_filter_bounds, + const base::Optional<gfx::RRectF>& backdrop_filter_bounds, const gfx::Transform& backdrop_filter_bounds_transform); const TileDrawQuad* CanPassBeDrawnDirectly(const RenderPass* pass) override;
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc index 007b064..5927942 100644 --- a/components/viz/service/display/renderer_pixeltest.cc +++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -2906,7 +2906,7 @@ RenderPassList pass_list_; cc::FilterOperations backdrop_filters_; - gfx::RRectF backdrop_filter_bounds_; + base::Optional<gfx::RRectF> backdrop_filter_bounds_; gfx::Transform filter_pass_to_target_transform_; gfx::Rect filter_pass_layer_rect_; };
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 58aab45..3c6769fb 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc
@@ -1634,7 +1634,7 @@ // Determine if the backdrop filter has its own clip (which only needs to be // checked when we have a backdrop filter to apply) if (rpdq_params.backdrop_filter) { - const gfx::RRectF* backdrop_filter_bounds = + const base::Optional<gfx::RRectF> backdrop_filter_bounds = BackdropFilterBoundsForPass(quad->render_pass_id); if (backdrop_filter_bounds) { // Map this into the same coordinate system as the quad.
diff --git a/components/viz/test/data/backdrop_filter_rotated_gl.png b/components/viz/test/data/backdrop_filter_rotated_gl.png index 746b7d7..0a8ddab 100644 --- a/components/viz/test/data/backdrop_filter_rotated_gl.png +++ b/components/viz/test/data/backdrop_filter_rotated_gl.png Binary files differ
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc index ed0d2cc..17db74e 100644 --- a/content/browser/accessibility/browser_accessibility_manager_android.cc +++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -223,6 +223,7 @@ case ui::AXEventGenerator::Event::LAYOUT_INVALIDATED: case ui::AXEventGenerator::Event::LIVE_REGION_CHANGED: case ui::AXEventGenerator::Event::LIVE_REGION_CREATED: + case ui::AXEventGenerator::Event::LIVE_RELEVANT_CHANGED: case ui::AXEventGenerator::Event::LIVE_STATUS_CHANGED: case ui::AXEventGenerator::Event::LOAD_START: case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm index 6ddc3e4e..e44929e 100644 --- a/content/browser/accessibility/browser_accessibility_manager_mac.mm +++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
@@ -392,6 +392,7 @@ case ui::AXEventGenerator::Event::LANGUAGE_CHANGED: case ui::AXEventGenerator::Event::LAYOUT_INVALIDATED: case ui::AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED: + case ui::AXEventGenerator::Event::LIVE_RELEVANT_CHANGED: case ui::AXEventGenerator::Event::LIVE_STATUS_CHANGED: case ui::AXEventGenerator::Event::LOAD_START: case ui::AXEventGenerator::Event::MULTILINE_STATE_CHANGED:
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc index 5ccd856..f801491d 100644 --- a/content/browser/accessibility/browser_accessibility_manager_win.cc +++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -281,6 +281,7 @@ case ui::AXEventGenerator::Event::LAYOUT_INVALIDATED: FireUiaAccessibilityEvent(UIA_LayoutInvalidatedEventId, node); break; + case ui::AXEventGenerator::Event::LIVE_RELEVANT_CHANGED: case ui::AXEventGenerator::Event::MULTILINE_STATE_CHANGED: aria_properties_events_.insert(node); break; @@ -297,12 +298,14 @@ break; case ui::AXEventGenerator::Event::POSITION_IN_SET_CHANGED: FireUiaPropertyChangedEvent(UIA_PositionInSetPropertyId, node); + aria_properties_events_.insert(node); break; case ui::AXEventGenerator::Event::READONLY_CHANGED: if (ui::IsRangeValueSupported(node->GetData())) FireUiaPropertyChangedEvent(UIA_RangeValueIsReadOnlyPropertyId, node); else if (ui::IsValuePatternSupported(node)) FireUiaPropertyChangedEvent(UIA_ValueIsReadOnlyPropertyId, node); + aria_properties_events_.insert(node); break; case ui::AXEventGenerator::Event::REQUIRED_STATE_CHANGED: FireUiaPropertyChangedEvent(UIA_IsRequiredForFormPropertyId, node);
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc index ed628db..73dc997 100644 --- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -286,6 +286,21 @@ } IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, + AccessibilityEventsAriaPosinsetChanged) { + RunEventTest(FILE_PATH_LITERAL("aria-posinset-changed.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, + AccessibilityEventsAriaReadonlyChanged) { + RunEventTest(FILE_PATH_LITERAL("aria-readonly-changed.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, + AccessibilityEventsAriaRelevantChanged) { + RunEventTest(FILE_PATH_LITERAL("aria-relevant-changed.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, AccessibilityEventsAriaTreeCollapse) { RunEventTest(FILE_PATH_LITERAL("aria-tree-collapse.html")); } @@ -535,6 +550,11 @@ } IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, + AccessibilityEventsMultipleAriaPropertiesChanged) { + RunEventTest(FILE_PATH_LITERAL("multiple-aria-properties-changed.html")); +} + +IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest, AccessibilityEventsNameChange) { RunEventTest(FILE_PATH_LITERAL("name-change.html")); }
diff --git a/content/browser/background_fetch/background_fetch_test_data_manager.cc b/content/browser/background_fetch/background_fetch_test_data_manager.cc index ec30477..27f5de6 100644 --- a/content/browser/background_fetch/background_fetch_test_data_manager.cc +++ b/content/browser/background_fetch/background_fetch_test_data_manager.cc
@@ -71,7 +71,7 @@ cache_manager_ = CacheStorageManager::Create( storage_partition_->GetPath(), base::ThreadTaskRunnerHandle::Get(), - quota_manager_proxy_); + base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_); DCHECK(cache_manager_); cache_manager_->SetBlobParametersForCache(
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc index 915520b..e57d69a 100644 --- a/content/browser/background_sync/background_sync_manager.cc +++ b/content/browser/background_sync/background_sync_manager.cc
@@ -454,7 +454,8 @@ BackgroundSyncManager::BackgroundSyncManager( scoped_refptr<ServiceWorkerContextWrapper> service_worker_context, scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context) - : op_scheduler_(CacheStorageSchedulerClient::kBackgroundSync), + : op_scheduler_(CacheStorageSchedulerClient::kBackgroundSync, + base::ThreadTaskRunnerHandle::Get()), service_worker_context_(std::move(service_worker_context)), devtools_context_(std::move(devtools_context)), parameters_(std::make_unique<BackgroundSyncParameters>()),
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc index 4e500b0c..c2134af 100644 --- a/content/browser/cache_storage/cache_storage_cache_unittest.cc +++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -341,6 +341,7 @@ cache_name, path, cache_storage, + base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy, blob_context, 0 /* cache_size */, @@ -401,6 +402,7 @@ const base::FilePath& origin_path, bool memory_only, base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, CacheStorageManager* cache_storage_manager, @@ -409,6 +411,7 @@ : LegacyCacheStorage(origin_path, memory_only, cache_task_runner, + std::move(scheduler_task_runner), std::move(quota_manager_proxy), std::move(blob_context), cache_storage_manager, @@ -475,7 +478,8 @@ // must be present to be notified when a cache becomes unreferenced. mock_cache_storage_ = std::make_unique<MockLegacyCacheStorage>( temp_dir_path_, MemoryOnly(), base::ThreadTaskRunnerHandle::Get().get(), - quota_manager_proxy_, blob_storage_context_->AsWeakPtr(), + base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_, + blob_storage_context_->AsWeakPtr(), /* cache_storage_manager = */ nullptr, kOrigin, CacheStorageOwner::kCacheAPI);
diff --git a/content/browser/cache_storage/cache_storage_context_impl.cc b/content/browser/cache_storage/cache_storage_context_impl.cc index 01cbfcf..eb3dec6 100644 --- a/content/browser/cache_storage/cache_storage_context_impl.cc +++ b/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -8,6 +8,7 @@ #include "base/files/file_path.h" #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" +#include "base/threading/thread_task_runner_handle.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/cache_storage/cache_storage_manager.h" #include "content/public/browser/browser_context.h" @@ -47,7 +48,7 @@ // posted task can register the quota client. // TODO: Fix the tests to let the quota manager initialize normally. if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { - CreateCacheStorageManager(user_data_directory, cache_task_runner, + CreateCacheStorageManager(user_data_directory, std::move(cache_task_runner), std::move(quota_manager_proxy)); return; } @@ -55,7 +56,7 @@ base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&CacheStorageContextImpl::CreateCacheStorageManager, this, - user_data_directory, cache_task_runner, + user_data_directory, std::move(cache_task_runner), std::move(quota_manager_proxy))); } @@ -124,9 +125,13 @@ scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner = + base::ThreadTaskRunnerHandle::Get(); + DCHECK(!cache_manager_); cache_manager_ = CacheStorageManager::Create( - user_data_directory, cache_task_runner, std::move(quota_manager_proxy)); + user_data_directory, std::move(cache_task_runner), + std::move(scheduler_task_runner), std::move(quota_manager_proxy)); } void CacheStorageContextImpl::ShutdownOnIO() {
diff --git a/content/browser/cache_storage/cache_storage_manager.cc b/content/browser/cache_storage/cache_storage_manager.cc index eab6ea0..9440a4a 100644 --- a/content/browser/cache_storage/cache_storage_manager.cc +++ b/content/browser/cache_storage/cache_storage_manager.cc
@@ -158,6 +158,7 @@ scoped_refptr<CacheStorageManager> CacheStorageManager::Create( const base::FilePath& path, scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) { base::FilePath root_path = path; if (!path.empty()) { @@ -166,7 +167,8 @@ } return base::WrapRefCounted(new CacheStorageManager( - root_path, std::move(cache_task_runner), std::move(quota_manager_proxy))); + root_path, std::move(cache_task_runner), std::move(scheduler_task_runner), + std::move(quota_manager_proxy))); } // static @@ -174,6 +176,7 @@ CacheStorageManager* old_manager) { scoped_refptr<CacheStorageManager> manager(new CacheStorageManager( old_manager->root_path(), old_manager->cache_task_runner(), + old_manager->scheduler_task_runner(), old_manager->quota_manager_proxy_.get())); // These values may be NULL, in which case this will be called again later by // the dispatcher host per usual. @@ -201,8 +204,8 @@ if (it == cache_storage_map_.end()) { LegacyCacheStorage* cache_storage = new LegacyCacheStorage( ConstructOriginPath(root_path_, origin, owner), IsMemoryBacked(), - cache_task_runner_.get(), quota_manager_proxy_, blob_context_, this, - origin, owner); + cache_task_runner_.get(), scheduler_task_runner_, quota_manager_proxy_, + blob_context_, this, origin, owner); cache_storage_map_[{origin, owner}] = base::WrapUnique(cache_storage); return cache_storage->CreateHandle(); } @@ -444,9 +447,11 @@ CacheStorageManager::CacheStorageManager( const base::FilePath& path, scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) : root_path_(path), cache_task_runner_(std::move(cache_task_runner)), + scheduler_task_runner_(std::move(scheduler_task_runner)), quota_manager_proxy_(std::move(quota_manager_proxy)), weak_ptr_factory_(this) { if (quota_manager_proxy_.get()) {
diff --git a/content/browser/cache_storage/cache_storage_manager.h b/content/browser/cache_storage/cache_storage_manager.h index c8ab8e63..ad29f617 100644 --- a/content/browser/cache_storage/cache_storage_manager.h +++ b/content/browser/cache_storage/cache_storage_manager.h
@@ -64,6 +64,7 @@ static scoped_refptr<CacheStorageManager> Create( const base::FilePath& path, scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy); static scoped_refptr<CacheStorageManager> Create( @@ -120,6 +121,7 @@ CacheStorageManager( const base::FilePath& path, scoped_refptr<base::SequencedTaskRunner> cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy); virtual ~CacheStorageManager(); @@ -157,6 +159,10 @@ return cache_task_runner_; } + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner() const { + return scheduler_task_runner_; + } + bool IsMemoryBacked() const { return root_path_.empty(); } // MemoryPressureListener callback @@ -165,6 +171,7 @@ base::FilePath root_path_; scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc index 3d2ef71f..1ee61943 100644 --- a/content/browser/cache_storage/cache_storage_manager_unittest.cc +++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -163,14 +163,8 @@ file_path = enumerator.Next()) { if (!GetFileInfo(file_path, &info)) return false; - if (index_last_modified < info.last_modified) { -#if defined(OS_FUCHSIA) - // TODO(crbug.com/760687): Extra logging for bot debugging. - LOG(ERROR) << "index_last_modified: " << index_last_modified - << " info.last_modified: " << info.last_modified; -#endif // OS_FUCHSIA + if (index_last_modified < info.last_modified) return false; - } } return true; @@ -318,7 +312,7 @@ cache_manager_ = CacheStorageManager::Create( temp_dir_path, base::ThreadTaskRunnerHandle::Get(), - quota_manager_proxy_); + base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_); cache_manager_->SetBlobParametersForCache( blob_storage_context->context()->AsWeakPtr()); @@ -1576,9 +1570,13 @@ } } -// TODO(crbug.com/760687): Flaky on Fuchsia. Temporarily enabled with extra -// logging to help debug. -TEST_F(CacheStorageManagerTest, GetAllOriginsUsageWithOldIndex) { +// TODO(crbug.com/760687): Flaky on Fuchsia. +#if defined(OS_FUCHSIA) +#define MAYBE_GetAllOriginsUsageWithOldIndex DISABLED_GetAllOriginsUsageWithOldIndex +#else +#define MAYBE_GetAllOriginsUsageWithOldIndex GetAllOriginsUsageWithOldIndex +#endif +TEST_F(CacheStorageManagerTest, MAYBE_GetAllOriginsUsageWithOldIndex) { // Write a single value (V1) to the cache. const GURL kFooURL = origin1_.GetURL().Resolve("foo"); const std::string kCacheName = "foo";
diff --git a/content/browser/cache_storage/cache_storage_operation.cc b/content/browser/cache_storage/cache_storage_operation.cc index 98362a7..01bde84 100644 --- a/content/browser/cache_storage/cache_storage_operation.cc +++ b/content/browser/cache_storage/cache_storage_operation.cc
@@ -16,7 +16,7 @@ base::OnceClosure closure, CacheStorageSchedulerClient client_type, CacheStorageSchedulerOp op_type, - scoped_refptr<base::SingleThreadTaskRunner> task_runner) + scoped_refptr<base::SequencedTaskRunner> task_runner) : closure_(std::move(closure)), creation_ticks_(base::TimeTicks::Now()), client_type_(client_type),
diff --git a/content/browser/cache_storage/cache_storage_operation.h b/content/browser/cache_storage/cache_storage_operation.h index 0c893251..cf101328 100644 --- a/content/browser/cache_storage/cache_storage_operation.h +++ b/content/browser/cache_storage/cache_storage_operation.h
@@ -9,7 +9,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" +#include "base/sequenced_task_runner.h" #include "base/time/time.h" #include "content/browser/cache_storage/cache_storage_scheduler_types.h" #include "content/common/content_export.h" @@ -20,11 +20,10 @@ // to run plus a bunch of metrics data. class CONTENT_EXPORT CacheStorageOperation { public: - CacheStorageOperation( - base::OnceClosure closure, - CacheStorageSchedulerClient client_type, - CacheStorageSchedulerOp op_type, - scoped_refptr<base::SingleThreadTaskRunner> task_runner); + CacheStorageOperation(base::OnceClosure closure, + CacheStorageSchedulerClient client_type, + CacheStorageSchedulerOp op_type, + scoped_refptr<base::SequencedTaskRunner> task_runner); ~CacheStorageOperation(); @@ -54,7 +53,7 @@ const CacheStorageSchedulerClient client_type_; const CacheStorageSchedulerOp op_type_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; base::WeakPtrFactory<CacheStorageOperation> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(CacheStorageOperation);
diff --git a/content/browser/cache_storage/cache_storage_scheduler.cc b/content/browser/cache_storage/cache_storage_scheduler.cc index c6486756..3532bf01 100644 --- a/content/browser/cache_storage/cache_storage_scheduler.cc +++ b/content/browser/cache_storage/cache_storage_scheduler.cc
@@ -11,15 +11,18 @@ #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "content/browser/cache_storage/cache_storage_histogram_utils.h" #include "content/browser/cache_storage/cache_storage_operation.h" namespace content { CacheStorageScheduler::CacheStorageScheduler( - CacheStorageSchedulerClient client_type) - : client_type_(client_type), weak_ptr_factory_(this) {} + CacheStorageSchedulerClient client_type, + scoped_refptr<base::SequencedTaskRunner> task_runner) + : task_runner_(std::move(task_runner)), + client_type_(client_type), + weak_ptr_factory_(this) {} CacheStorageScheduler::~CacheStorageScheduler() {} @@ -31,7 +34,7 @@ pending_operations_.push_back(std::make_unique<CacheStorageOperation>( std::move(closure), client_type_, op_type, - base::ThreadTaskRunnerHandle::Get())); + base::SequencedTaskRunnerHandle::Get())); RunOperationIfIdle(); }
diff --git a/content/browser/cache_storage/cache_storage_scheduler.h b/content/browser/cache_storage/cache_storage_scheduler.h index 416d160c..eda2a8f 100644 --- a/content/browser/cache_storage/cache_storage_scheduler.h +++ b/content/browser/cache_storage/cache_storage_scheduler.h
@@ -29,7 +29,8 @@ // the next operation. class CONTENT_EXPORT CacheStorageScheduler { public: - explicit CacheStorageScheduler(CacheStorageSchedulerClient client_type); + CacheStorageScheduler(CacheStorageSchedulerClient client_type, + scoped_refptr<base::SequencedTaskRunner> task_runner); virtual ~CacheStorageScheduler(); // Adds the operation to the tail of the queue and starts it if the scheduler @@ -68,9 +69,10 @@ CompleteOperationAndRunNext(); } + scoped_refptr<base::SequencedTaskRunner> task_runner_; std::list<std::unique_ptr<CacheStorageOperation>> pending_operations_; std::unique_ptr<CacheStorageOperation> running_operation_; - CacheStorageSchedulerClient client_type_; + const CacheStorageSchedulerClient client_type_; base::WeakPtrFactory<CacheStorageScheduler> weak_ptr_factory_;
diff --git a/content/browser/cache_storage/cache_storage_scheduler_unittest.cc b/content/browser/cache_storage/cache_storage_scheduler_unittest.cc index 50918cfb..3afaf4c9 100644 --- a/content/browser/cache_storage/cache_storage_scheduler_unittest.cc +++ b/content/browser/cache_storage/cache_storage_scheduler_unittest.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/run_loop.h" +#include "base/threading/thread_task_runner_handle.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -32,7 +33,8 @@ protected: CacheStorageSchedulerTest() : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), - scheduler_(CacheStorageSchedulerClient::kStorage), + scheduler_(CacheStorageSchedulerClient::kStorage, + base::ThreadTaskRunnerHandle::Get()), task1_(TestTask(&scheduler_)), task2_(TestTask(&scheduler_)) {}
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.cc b/content/browser/cache_storage/legacy/legacy_cache_storage.cc index 75ba7c3f..6250b9e 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage.cc
@@ -93,12 +93,14 @@ base::OnceCallback<void(std::unique_ptr<CacheStorageIndex>)>; CacheLoader(base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, storage::QuotaManagerProxy* quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, LegacyCacheStorage* cache_storage, const url::Origin& origin, CacheStorageOwner owner) : cache_task_runner_(cache_task_runner), + scheduler_task_runner_(std::move(scheduler_task_runner)), quota_manager_proxy_(quota_manager_proxy), blob_context_(blob_context), cache_storage_(cache_storage), @@ -142,7 +144,8 @@ virtual void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) {} protected: - scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; + const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; + const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_; // Owned by CacheStorage which owns this. storage::QuotaManagerProxy* quota_manager_proxy_; @@ -164,12 +167,14 @@ : public LegacyCacheStorage::CacheLoader { public: MemoryLoader(base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, storage::QuotaManagerProxy* quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, LegacyCacheStorage* cache_storage, const url::Origin& origin, CacheStorageOwner owner) : CacheLoader(cache_task_runner, + std::move(scheduler_task_runner), quota_manager_proxy, blob_context, cache_storage, @@ -182,8 +187,8 @@ int64_t cache_padding, std::unique_ptr<SymmetricKey> cache_padding_key) override { return LegacyCacheStorageCache::CreateMemoryCache( - origin_, owner_, cache_name, cache_storage_, quota_manager_proxy_, - blob_context_, storage::CopyDefaultPaddingKey()); + origin_, owner_, cache_name, cache_storage_, scheduler_task_runner_, + quota_manager_proxy_, blob_context_, storage::CopyDefaultPaddingKey()); } void PrepareNewCacheDestination(const std::string& cache_name, @@ -230,14 +235,17 @@ class LegacyCacheStorage::SimpleCacheLoader : public LegacyCacheStorage::CacheLoader { public: - SimpleCacheLoader(const base::FilePath& origin_path, - base::SequencedTaskRunner* cache_task_runner, - storage::QuotaManagerProxy* quota_manager_proxy, - base::WeakPtr<storage::BlobStorageContext> blob_context, - LegacyCacheStorage* cache_storage, - const url::Origin& origin, - CacheStorageOwner owner) + SimpleCacheLoader( + const base::FilePath& origin_path, + base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, + storage::QuotaManagerProxy* quota_manager_proxy, + base::WeakPtr<storage::BlobStorageContext> blob_context, + LegacyCacheStorage* cache_storage, + const url::Origin& origin, + CacheStorageOwner owner) : CacheLoader(cache_task_runner, + std::move(scheduler_task_runner), quota_manager_proxy, blob_context, cache_storage, @@ -258,8 +266,8 @@ base::FilePath cache_path = origin_path_.AppendASCII(cache_dir); return LegacyCacheStorageCache::CreatePersistentCache( origin_, owner_, cache_name, cache_storage_, cache_path, - quota_manager_proxy_, blob_context_, cache_size, cache_padding, - std::move(cache_padding_key)); + scheduler_task_runner_, quota_manager_proxy_, blob_context_, cache_size, + cache_padding, std::move(cache_padding_key)); } void PrepareNewCacheDestination(const std::string& cache_name, @@ -548,6 +556,7 @@ const base::FilePath& path, bool memory_only, base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, CacheStorageManager* cache_storage_manager, @@ -558,7 +567,8 @@ initializing_(false), memory_only_(memory_only), scheduler_( - new CacheStorageScheduler(CacheStorageSchedulerClient::kStorage)), + new CacheStorageScheduler(CacheStorageSchedulerClient::kStorage, + scheduler_task_runner)), origin_path_(path), cache_task_runner_(cache_task_runner), quota_manager_proxy_(quota_manager_proxy), @@ -566,12 +576,13 @@ cache_storage_manager_(cache_storage_manager), weak_factory_(this) { if (memory_only) - cache_loader_.reset(new MemoryLoader(cache_task_runner_.get(), - quota_manager_proxy.get(), - blob_context, this, origin, owner)); + cache_loader_.reset(new MemoryLoader( + cache_task_runner_.get(), std::move(scheduler_task_runner), + quota_manager_proxy.get(), blob_context, this, origin, owner)); else cache_loader_.reset(new SimpleCacheLoader( - origin_path_, cache_task_runner_.get(), quota_manager_proxy.get(), + origin_path_, cache_task_runner_.get(), + std::move(scheduler_task_runner), quota_manager_proxy.get(), blob_context, this, origin, owner)); }
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.h b/content/browser/cache_storage/legacy/legacy_cache_storage.h index fdb21f7..ff71a2a5 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage.h +++ b/content/browser/cache_storage/legacy/legacy_cache_storage.h
@@ -54,6 +54,7 @@ const base::FilePath& origin_path, bool memory_only, base::SequencedTaskRunner* cache_task_runner, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, CacheStorageManager* cache_storage_manager,
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc index e4568739..4bccc509 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -458,13 +458,15 @@ CacheStorageOwner owner, const std::string& cache_name, LegacyCacheStorage* cache_storage, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, std::unique_ptr<crypto::SymmetricKey> cache_padding_key) { LegacyCacheStorageCache* cache = new LegacyCacheStorageCache( origin, owner, cache_name, base::FilePath(), cache_storage, - std::move(quota_manager_proxy), blob_context, 0 /* cache_size */, - 0 /* cache_padding */, std::move(cache_padding_key)); + std::move(scheduler_task_runner), std::move(quota_manager_proxy), + blob_context, 0 /* cache_size */, 0 /* cache_padding */, + std::move(cache_padding_key)); cache->SetObserver(cache_storage); cache->InitBackend(); return base::WrapUnique(cache); @@ -478,6 +480,7 @@ const std::string& cache_name, LegacyCacheStorage* cache_storage, const base::FilePath& path, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, int64_t cache_size, @@ -485,8 +488,8 @@ std::unique_ptr<crypto::SymmetricKey> cache_padding_key) { LegacyCacheStorageCache* cache = new LegacyCacheStorageCache( origin, owner, cache_name, path, cache_storage, - std::move(quota_manager_proxy), blob_context, cache_size, cache_padding, - std::move(cache_padding_key)); + std::move(scheduler_task_runner), std::move(quota_manager_proxy), + blob_context, cache_size, cache_padding, std::move(cache_padding_key)); cache->SetObserver(cache_storage); cache->InitBackend(); return base::WrapUnique(cache); @@ -904,6 +907,7 @@ const std::string& cache_name, const base::FilePath& path, LegacyCacheStorage* cache_storage, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, int64_t cache_size, @@ -916,8 +920,8 @@ cache_storage_(cache_storage), quota_manager_proxy_(std::move(quota_manager_proxy)), blob_storage_context_(blob_context), - scheduler_( - new CacheStorageScheduler(CacheStorageSchedulerClient::kCache)), + scheduler_(new CacheStorageScheduler(CacheStorageSchedulerClient::kCache, + std::move(scheduler_task_runner))), cache_size_(cache_size), cache_padding_(cache_padding), cache_padding_key_(std::move(cache_padding_key)),
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h index bce6bad..6610ef46 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h +++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.h
@@ -68,6 +68,7 @@ CacheStorageOwner owner, const std::string& cache_name, LegacyCacheStorage* cache_storage, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, std::unique_ptr<crypto::SymmetricKey> cache_padding_key); @@ -77,6 +78,7 @@ const std::string& cache_name, LegacyCacheStorage* cache_storage, const base::FilePath& path, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, int64_t cache_size, @@ -240,6 +242,7 @@ const std::string& cache_name, const base::FilePath& path, LegacyCacheStorage* cache_storage, + scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner, scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext> blob_context, int64_t cache_size,
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 51ee832..c971d70 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -913,8 +913,7 @@ resource_request_->resource_type == static_cast<int>(ResourceType::kMainFrame), static_cast<ui::PageTransition>(resource_request_->transition_type), - resource_request_->has_user_gesture, resource_request_->method, - resource_request_->headers, &proxied_factory_request_, + resource_request_->has_user_gesture, &proxied_factory_request_, external_protocol_factory); if (external_protocol_factory) {
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 1c3acde..5d721ca 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -628,8 +628,7 @@ return GetContentClient()->browser()->HandleExternalProtocol( url, info->GetWebContentsGetterForRequest(), info->GetChildID(), info->GetNavigationUIData(), info->IsMainFrame(), - info->GetPageTransition(), info->HasUserGesture(), url_request->method(), - url_request->extra_request_headers(), nullptr, dummy); + info->GetPageTransition(), info->HasUserGesture(), nullptr, dummy); } void ResourceDispatcherHostImpl::DidStartRequest(ResourceLoader* loader) {
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index d8c1dcc..3897520 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -2182,8 +2182,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) override { return false;
diff --git a/content/browser/renderer_host/input/scroll_latency_browsertest.cc b/content/browser/renderer_host/input/scroll_latency_browsertest.cc index 91e82b07..79824eca 100644 --- a/content/browser/renderer_host/input/scroll_latency_browsertest.cc +++ b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
@@ -355,6 +355,12 @@ 0, "Event.Latency.ScrollBegin.Touch.TimeToScrollUpdateSwapBegin4")); } +IN_PROC_BROWSER_TEST_F(ScrollLatencyBrowserTest, ScrollbarButtonLatency) { + LoadURL(); + + RunScrollbarButtonLatencyTest(); +} + class ScrollLatencyCompositedScrollbarBrowserTest : public ScrollLatencyBrowserTest { public:
diff --git a/content/common/sandbox_init_mac.cc b/content/common/sandbox_init_mac.cc index 398a3454..64e1258 100644 --- a/content/common/sandbox_init_mac.cc +++ b/content/common/sandbox_init_mac.cc
@@ -34,7 +34,7 @@ if (sandbox_type != service_manager::SANDBOX_TYPE_GPU) return original; - return base::Bind( + return base::BindOnce( [](base::OnceClosure arg) { // We need to gather GPUInfo and compute GpuFeatureInfo here, so we can // decide if initializing core profile or compatibility profile GL, @@ -72,7 +72,7 @@ if (!arg.is_null()) std::move(arg).Run(); }, - base::Passed(std::move(original))); + std::move(original)); } // Fill in |sandbox_type| based on the command line. Returns false if the
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 9531bc9..74da3cc 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -898,8 +898,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) { return true;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 133a7b8..3545b14 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -120,7 +120,6 @@ using ClientCertIdentityList = std::vector<std::unique_ptr<ClientCertIdentity>>; class ClientCertStore; class CookieStore; -class HttpRequestHeaders; class NetLog; class SSLCertRequestInfo; class SSLInfo; @@ -1459,8 +1458,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory);
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 1ebc105..392e527b 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -88,11 +88,6 @@ const base::Feature kBlockCredentialedSubresources{ "BlockCredentialedSubresources", base::FEATURE_ENABLED_BY_DEFAULT}; -// Enables brotli "Accept-Encoding" advertising and "Content-Encoding" support. -// Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli -const base::Feature kBrotliEncoding{"brotli-encoding", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Enables code caching for inline scripts. const base::Feature kCacheInlineScriptCode{"CacheInlineScriptCode", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 320c6ff5..dff5ecccf 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -32,7 +32,6 @@ CONTENT_EXPORT extern const base::Feature kBlinkHeapIncrementalMarking; CONTENT_EXPORT extern const base::Feature kBloatedRendererDetection; CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources; -CONTENT_EXPORT extern const base::Feature kBrotliEncoding; CONTENT_EXPORT extern const base::Feature kCacheInlineScriptCode; CONTENT_EXPORT extern const base::Feature kCanvas2DImageChromium; CONTENT_EXPORT extern const base::Feature kCompositeOpaqueFixedPosition;
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc index ff1ec5f..2931db1 100644 --- a/content/renderer/input/render_widget_input_handler.cc +++ b/content/renderer/input/render_widget_input_handler.cc
@@ -216,7 +216,8 @@ handling_event_overscroll_(nullptr), handling_injected_scroll_params_(nullptr), handling_event_type_(WebInputEvent::kUndefined), - suppress_next_char_events_(false) { + suppress_next_char_events_(false), + last_injected_gesture_was_begin_(false) { DCHECK(delegate); DCHECK(widget); delegate->SetInputHandler(this); @@ -441,23 +442,9 @@ // scroll gestures back into blink, e.g., a mousedown on a scrollbar. We // do this here so that we can attribute lateny information from the mouse as // a scroll interaction, instead of just classifying as mouse input. - if (injected_scroll_params) { - // TODO(dlibby): Create a copy of latency_info with new type - // and set a new swap promise monitor. - WebFloatPoint position = ui::PositionInWidgetFromInputEvent(input_event); - for (const InjectScrollGestureParams& params : *injected_scroll_params) { - std::unique_ptr<WebGestureEvent> gesture_event = - ui::GenerateInjectedScrollGesture( - params.type, input_event.TimeStamp(), params.device, position, - params.scroll_delta, params.granularity); - if (params.type == WebInputEvent::Type::kGestureScrollBegin) { - gesture_event->data.scroll_begin.scrollable_area_element_id = - params.scrollable_area_element_id.GetInternalValue(); - } - - widget_->GetWebWidget()->HandleInputEvent( - blink::WebCoalescedInputEvent(*gesture_event.get())); - } + if (injected_scroll_params && injected_scroll_params->size()) { + HandleInjectedScrollGestures(*injected_scroll_params, input_event, + latency_info); } // Send gesture scroll events and their dispositions to the compositor thread, @@ -603,6 +590,69 @@ } } +void RenderWidgetInputHandler::HandleInjectedScrollGestures( + std::vector<InjectScrollGestureParams> injected_scroll_params, + const WebInputEvent& input_event, + const ui::LatencyInfo& original_latency_info) { + DCHECK(injected_scroll_params.size()); + + base::TimeTicks original_timestamp; + bool found_original_component = original_latency_info.FindLatency( + ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, &original_timestamp); + DCHECK(found_original_component); + + WebFloatPoint position = ui::PositionInWidgetFromInputEvent(input_event); + for (const InjectScrollGestureParams& params : injected_scroll_params) { + // Set up a new LatencyInfo for the injected scroll - this is the original + // LatencyInfo for the input event that was being handled when the scroll + // was injected. This new LatencyInfo will have a modified type, and an + // additional scroll update component. Also set up a SwapPromiseMonitor that + // will cause the LatencyInfo to be sent up with the compositor frame, if + // the GSU causes a commit. This allows end to end latency to be logged for + // the injected scroll, annotated with the correct type. + ui::LatencyInfo scrollbar_latency_info(original_latency_info); + + // Currently only scrollbar is supported - if this DCHECK hits due to a + // new type being injected, please modify the type passed to + // |set_source_event_type()|. + DCHECK(params.device == blink::WebGestureDevice::kScrollbar); + scrollbar_latency_info.set_source_event_type( + ui::SourceEventType::SCROLLBAR); + scrollbar_latency_info.AddLatencyNumber( + ui::LatencyComponentType::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT); + + if (params.type == WebInputEvent::Type::kGestureScrollUpdate) { + scrollbar_latency_info.AddLatencyNumberWithTimestamp( + last_injected_gesture_was_begin_ + ? ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT + : ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, + original_timestamp, 1); + } + + std::unique_ptr<cc::SwapPromiseMonitor> swap_promise_monitor; + if (widget_->layer_tree_view()) { + swap_promise_monitor = + widget_->layer_tree_view()->CreateLatencyInfoSwapPromiseMonitor( + &scrollbar_latency_info); + } + + std::unique_ptr<WebGestureEvent> gesture_event = + ui::GenerateInjectedScrollGesture( + params.type, input_event.TimeStamp(), params.device, position, + params.scroll_delta, params.granularity); + if (params.type == WebInputEvent::Type::kGestureScrollBegin) { + gesture_event->data.scroll_begin.scrollable_area_element_id = + params.scrollable_area_element_id.GetInternalValue(); + last_injected_gesture_was_begin_ = true; + } else { + last_injected_gesture_was_begin_ = false; + } + + widget_->GetWebWidget()->HandleInputEvent( + blink::WebCoalescedInputEvent(*gesture_event.get())); + } +} + bool RenderWidgetInputHandler::DidChangeCursor(const WebCursor& cursor) { if (current_cursor_.has_value() && current_cursor_.value() == cursor) return false;
diff --git a/content/renderer/input/render_widget_input_handler.h b/content/renderer/input/render_widget_input_handler.h index 8a8c5942..df13357 100644 --- a/content/renderer/input/render_widget_input_handler.h +++ b/content/renderer/input/render_widget_input_handler.h
@@ -97,6 +97,11 @@ blink::WebInputEventResult HandleTouchEvent( const blink::WebCoalescedInputEvent& coalesced_event); + void HandleInjectedScrollGestures( + std::vector<InjectScrollGestureParams> injected_scroll_params, + const WebInputEvent& input_event, + const ui::LatencyInfo& original_latency_info); + RenderWidgetInputHandlerDelegate* const delegate_; RenderWidget* const widget_; @@ -128,6 +133,11 @@ // Indicates if the next sequence of Char events should be suppressed or not. bool suppress_next_char_events_; + // Whether the last injected scroll gesture was a GestureScrollBegin. Used to + // determine which GestureScrollUpdate is the first in a gesture sequence for + // latency classification. + bool last_injected_gesture_was_begin_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetInputHandler); };
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 1981bdb..d13a90f 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1969,7 +1969,6 @@ : base::TimeDelta::FromMilliseconds( blink::mojom::kDefaultCaretBlinkIntervalInMilliseconds)); -#if BUILDFLAG(USE_DEFAULT_RENDER_THEME) if (renderer_prefs.use_custom_colors) { blink::SetFocusRingColor(renderer_prefs.focus_ring_color); blink::SetSelectionColors(renderer_prefs.active_selection_bg_color, @@ -1979,7 +1978,6 @@ if (webview()) webview()->MainFrameWidget()->ThemeChanged(); } -#endif // BUILDFLAG(USE_DEFAULT_RENDER_THEME) if (webview() && old_accept_languages != renderer_preferences_.accept_languages) {
diff --git a/content/test/data/accessibility/event/aria-atomic-changed.html b/content/test/data/accessibility/event/aria-atomic-changed.html index 318563f..1b230b77 100644 --- a/content/test/data/accessibility/event/aria-atomic-changed.html +++ b/content/test/data/accessibility/event/aria-atomic-changed.html
@@ -13,20 +13,20 @@ <button onclick="go()">go</button> <script> function go() { - // Set aria-atomic from default false->false; do not fire an event. + // Set aria-atomic from default false->false; should not fire an event. document.getElementById('d1').setAttribute('aria-atomic', false); - // Set aria-atomic from true->false; fire an event. + // Set aria-atomic from true->false; should fire an event. document.getElementById('d2').setAttribute('aria-atomic', false); - // Set aria-atomic from true->[removed]; fire an event. + // Set aria-atomic from true->[removed]; should fire an event. document.getElementById('d3').removeAttribute('aria-atomic'); - // Set aria-atomic from false->true; fire an event. + // Set aria-atomic from false->true; should fire an event. document.getElementById('d4').setAttribute('aria-atomic', true); - // Set aria-atomic from false->true on a non-live region; do not fire an - // event. + // Set aria-atomic from false->true on a non-live region; + // should not fire an event. document.getElementById('d5').setAttribute('aria-atomic', true); } </script>
diff --git a/content/test/data/accessibility/event/aria-haspopup-changed.html b/content/test/data/accessibility/event/aria-haspopup-changed.html index e5237de..a449886 100644 --- a/content/test/data/accessibility/event/aria-haspopup-changed.html +++ b/content/test/data/accessibility/event/aria-haspopup-changed.html
@@ -11,28 +11,36 @@ <input id="input7" aria-label="input7" role="combobox" aria-haspopup="true"> <script> function go() { - // Set aria-haspopup from combobox default(listbox)->listbox, do not fire an event. + // Set aria-haspopup from combobox default(listbox)->listbox; + // should not fire an event. document.getElementById('input0').setAttribute('aria-haspopup', 'listbox'); - // Set aria-haspopup from combobox default(listbox, false)->false; fire an event. + // Set aria-haspopup from combobox default(listbox, false)->false; + // should fire an event. document.getElementById('input1').setAttribute('aria-haspopup', 'false'); - // Set aria-haspopup from combobox default(listbox)->true(menu); fire an event. + // Set aria-haspopup from combobox default(listbox)->true(menu); + // should fire an event. document.getElementById('input2').setAttribute('aria-haspopup', 'true'); - // Set aria-haspopup from combobox default(listbox)->menu; fire an event. + // Set aria-haspopup from combobox default(listbox)->menu; + // should fire an event. document.getElementById('input3').setAttribute('aria-haspopup', 'menu'); - // Set aria-haspopup from combobox default(listbox)->tree; fire an event. + // Set aria-haspopup from combobox default(listbox)->tree; + // should fire an event. document.getElementById('input4').setAttribute('aria-haspopup', 'tree'); - // Set aria-haspopup from combobox default(listbox)->grid; fire an event. + // Set aria-haspopup from combobox default(listbox)->grid; + // should fire an event. document.getElementById('input5').setAttribute('aria-haspopup', 'grid'); - // Set aria-haspopup from combobox default(listbox)->dialog; fire an event. + // Set aria-haspopup from combobox default(listbox)->dialog; + // should fire an event. document.getElementById('input6').setAttribute('aria-haspopup', 'dialog'); - // Remove aria-haspopup. Set aria-haspopup from true(menu)->default(listbox); fire an event. + // Remove aria-haspopup. Set aria-haspopup from true(menu)->default(listbox); + // should fire an event. document.getElementById('input7').removeAttribute('aria-haspopup'); } </script>
diff --git a/content/test/data/accessibility/event/aria-invalid-changed.html b/content/test/data/accessibility/event/aria-invalid-changed.html index 5d9f3fc..4bf5df2 100644 --- a/content/test/data/accessibility/event/aria-invalid-changed.html +++ b/content/test/data/accessibility/event/aria-invalid-changed.html
@@ -7,16 +7,16 @@ <input id="field3" aria-label="field3"> <script> function go() { - // Set aria-invalid from default false->false, no event is fired. + // Set aria-invalid from default false->false; should not fire an event. document.getElementById('field0').setAttribute('aria-invalid', 'false'); - // Set aria-invalid from true->false; fire an event. + // Set aria-invalid from true->false; should fire an event. document.getElementById('field1').setAttribute('aria-invalid', 'false'); - // Set aria-invalid from true->[removed]; fire an event. + // Set aria-invalid from true->[removed]; should fire an event. document.getElementById('field2').removeAttribute('aria-invalid'); - // Set aria-invalid from false->true; fire an event. + // Set aria-invalid from false->true; should fire an event. document.getElementById('field3').setAttribute('aria-invalid', 'true'); } </script>
diff --git a/content/test/data/accessibility/event/aria-multiline-changed.html b/content/test/data/accessibility/event/aria-multiline-changed.html index f6c33e4..5fafa887 100644 --- a/content/test/data/accessibility/event/aria-multiline-changed.html +++ b/content/test/data/accessibility/event/aria-multiline-changed.html
@@ -7,16 +7,16 @@ <input id="input3" aria-label="input3" role="textbox"> <script> function go() { - // Set aria-multiline from default false->false, no event is fired. + // Set aria-multiline from default false->false; should not fire an event. document.getElementById('input0').setAttribute('aria-multiline', 'false'); - // Set aria-multiline from true->false; fire an event. + // Set aria-multiline from true->false; should fire an event. document.getElementById('input1').setAttribute('aria-multiline', 'false'); - // Set aria-multiline from true->[removed]; fire an event. + // Set aria-multiline from true->[removed]; should fire an event. document.getElementById('input2').removeAttribute('aria-multiline'); - // Set aria-multiline from false->true; fire an event. + // Set aria-multiline from false->true; should fire an event. document.getElementById('input3').setAttribute('aria-multiline', 'true'); } </script>
diff --git a/content/test/data/accessibility/event/aria-posinset-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-posinset-changed-expected-uia-win.txt new file mode 100644 index 0000000..92175ba --- /dev/null +++ b/content/test/data/accessibility/event/aria-posinset-changed-expected-uia-win.txt
@@ -0,0 +1,4 @@ +AriaProperties changed on role=option, name=Li1 +AriaProperties changed on role=option, name=Li2 +PositionInSet changed on role=option, name=Li1 +PositionInSet changed on role=option, name=Li2
diff --git a/content/test/data/accessibility/event/aria-posinset-changed-expected-uia-win7.txt b/content/test/data/accessibility/event/aria-posinset-changed-expected-uia-win7.txt new file mode 100644 index 0000000..8f1bdff4 --- /dev/null +++ b/content/test/data/accessibility/event/aria-posinset-changed-expected-uia-win7.txt
@@ -0,0 +1,2 @@ +AriaProperties changed on role=option, name=Li1 +AriaProperties changed on role=option, name=Li2
diff --git a/content/test/data/accessibility/event/aria-posinset-changed.html b/content/test/data/accessibility/event/aria-posinset-changed.html new file mode 100644 index 0000000..8d62b909 --- /dev/null +++ b/content/test/data/accessibility/event/aria-posinset-changed.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<body> +<ul role="listbox"> + <li id="li1" role="option">Li1</li> + <li id="li2" role="option" aria-posinset="2">Li2</li> + <li id="li3" role="option" aria-posinset="3">Li3</li> +</ul> +<script> + function go() { + // Set aria-posinset from default calculation '1'->'2'; should fire an event. + document.getElementById('li1').setAttribute('aria-posinset', '2'); + + // Set aria-posinset from '2'->[removed]; should fire an event. + document.getElementById('li2').removeAttribute('aria-posinset'); + + // Set aria-posinset from '3'->'3; should not fire an event. + document.getElementById('li3').setAttribute('aria-posinset', '3'); + } +</script> +</body> +</html>
diff --git a/content/test/data/accessibility/event/aria-pressed-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-pressed-changed-expected-uia-win.txt new file mode 100644 index 0000000..f666105 --- /dev/null +++ b/content/test/data/accessibility/event/aria-pressed-changed-expected-uia-win.txt
@@ -0,0 +1,4 @@ +AriaProperties changed on role=button, name=button1 +AriaProperties changed on role=button, name=button2 +ToggleToggleState changed on role=button, name=button1 +ToggleToggleState changed on role=button, name=button2
diff --git a/content/test/data/accessibility/event/aria-readonly-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-readonly-changed-expected-uia-win.txt new file mode 100644 index 0000000..b52748af --- /dev/null +++ b/content/test/data/accessibility/event/aria-readonly-changed-expected-uia-win.txt
@@ -0,0 +1,6 @@ +AriaProperties changed on role=textbox, name=textarea2 +AriaProperties changed on role=textbox, name=textarea3 +AriaProperties changed on role=textbox, name=textarea4 +ValueIsReadOnly changed on role=textbox, name=textarea2 +ValueIsReadOnly changed on role=textbox, name=textarea3 +ValueIsReadOnly changed on role=textbox, name=textarea4
diff --git a/content/test/data/accessibility/event/aria-readonly-changed.html b/content/test/data/accessibility/event/aria-readonly-changed.html new file mode 100644 index 0000000..e43c121 --- /dev/null +++ b/content/test/data/accessibility/event/aria-readonly-changed.html
@@ -0,0 +1,29 @@ +<!-- +@UIA-WIN-DENY:* +@UIA-WIN-ALLOW:AriaProperties* +@UIA-WIN-ALLOW:ValueIsReadOnly* +--> +<!DOCTYPE html> +<html> +<body> + <textarea id="textarea1" aria-label="textarea1">Textarea1</textarea> + <textarea id="textarea2" aria-label="textarea2">Textarea2</textarea> + <textarea id="textarea3" aria-label="textarea3" aria-readonly="true">Textarea3</textarea> + <textarea id="textarea4" aria-label="textarea4" aria-readonly="true">Textarea4</textarea> + <script> + function go() { + // Set aria-readonly default false->false; should not fire an event. + document.getElementById('textarea1').setAttribute('aria-readonly', false); + + // Set aria-readonly from false->true; should fire an event. + document.getElementById('textarea2').setAttribute('aria-readonly', true); + + // Set aria-readonly from true->false; should fire an event. + document.getElementById('textarea3').setAttribute('aria-readonly', false); + + // Set aria-readonly from true->[removed]; should fire an event. + document.getElementById('textarea4').removeAttribute('aria-readonly'); + } + </script> +</body> +</html>
diff --git a/content/test/data/accessibility/event/aria-relevant-changed-expected-uia-win.txt b/content/test/data/accessibility/event/aria-relevant-changed-expected-uia-win.txt new file mode 100644 index 0000000..4670f83 --- /dev/null +++ b/content/test/data/accessibility/event/aria-relevant-changed-expected-uia-win.txt
@@ -0,0 +1,6 @@ +AriaProperties changed on role=group, name=Div3 +AriaProperties changed on role=group, name=Div4 +AriaProperties changed on role=group, name=Div5 +AriaProperties changed on role=group, name=Div6 +AriaProperties changed on role=group, name=Div7 +AriaProperties changed on role=group, name=Div8
diff --git a/content/test/data/accessibility/event/aria-relevant-changed.html b/content/test/data/accessibility/event/aria-relevant-changed.html new file mode 100644 index 0000000..b1de155 --- /dev/null +++ b/content/test/data/accessibility/event/aria-relevant-changed.html
@@ -0,0 +1,52 @@ +<!-- +@UIA-WIN-DENY:* +@UIA-WIN-ALLOW:AriaProperties* +--> +<!DOCTYPE html> +<html> +<body> + <div id="d1" aria-label="Div1">Div1</div> + <div id="d2" aria-label="Div2" aria-live="polite">Div2</div> + <div id="d3" aria-label="Div3" aria-live="polite">Div3</div> + <div id="d4" aria-label="Div4" aria-live="polite">Div4</div> + <div id="d5" aria-label="Div5" aria-live="polite">Div5</div> + <div id="d6" aria-label="Div6" aria-live="polite">Div6</div> + <div id="d7" aria-label="Div7" aria-live="polite" aria-relevant="true">Div7</div> + <div id="d8" aria-label="Div8" aria-live="polite" aria-relevant="true">Div8</div> + <script> + function go() { + // Set aria-relevant from default 'additions text'->'all' on a non-live region; + // should not fire an event. + document.getElementById('d1').setAttribute('aria-relevant', 'all'); + + // Set aria-relevant from default 'additions text'->'additions text'; + // should not fire an event. + document.getElementById('d2').setAttribute('aria-relevant', 'additions text'); + + // Set aria-relevant from default 'additions text'->'additions'; + // should fire an event. + document.getElementById('d3').setAttribute('aria-relevant', 'additions'); + + // Set aria-relevant from default 'additions text'->'all'; + // should fire an event. + document.getElementById('d4').setAttribute('aria-relevant', 'all'); + + // Set aria-relevant from default 'additions text'->'removals'; + // should fire an event. + document.getElementById('d5').setAttribute('aria-relevant', 'removals'); + + // Set aria-relevant from default 'additions text'->'text'; + // should fire an event. + document.getElementById('d6').setAttribute('aria-relevant', 'text'); + + // Set aria-relevant from 'additions'->'additions text'; + // should fire an event. + document.getElementById('d7').setAttribute('aria-relevant', 'additions text'); + + // Set aria-relevant from 'additions'->[removed]; + // should fire an event. + document.getElementById('d8').removeAttribute('aria-relevant'); + } + </script> +</body> +</html>
diff --git a/content/test/data/accessibility/event/multiple-aria-properties-changed-expected-uia-win.txt b/content/test/data/accessibility/event/multiple-aria-properties-changed-expected-uia-win.txt new file mode 100644 index 0000000..7562547 --- /dev/null +++ b/content/test/data/accessibility/event/multiple-aria-properties-changed-expected-uia-win.txt
@@ -0,0 +1,3 @@ +AriaProperties changed on role=checkbox, name=checkbox2 +AriaProperties changed on role=checkbox, name=checkbox3 +AriaProperties changed on role=checkbox, name=checkbox4
diff --git a/content/test/data/accessibility/event/multiple-aria-properties-changed.html b/content/test/data/accessibility/event/multiple-aria-properties-changed.html new file mode 100644 index 0000000..d5f69c3 --- /dev/null +++ b/content/test/data/accessibility/event/multiple-aria-properties-changed.html
@@ -0,0 +1,42 @@ +<!-- +@UIA-WIN-DENY:* +@UIA-WIN-ALLOW:AriaProperties* +--> +<!DOCTYPE html> +<form> + <div aria-label="checkbox1" role="checkbox"></div> + <div aria-label="checkbox2" role="checkbox" aria-checked="false" aria-required="false" aria-readonly="false"></div> + <div aria-label="checkbox3" role="checkbox" aria-checked="true" aria-required="true" aria-readonly="true"></div> + <div aria-label="checkbox4" role="checkbox" aria-checked="true" aria-required="true" aria-readonly="true"></div> +</form> +<script> + function go() { + // Tests below modify multiple aria attributes on a single element at + // a time and the expected behavior is to fire UIA_AriaPropertiesPropertyId + // event once rather than multiple times. + + // Multiple aria attributes change, default[false]->false; + // should not fire any event. + document.querySelector('div[aria-label=checkbox1]').setAttribute('aria-checked', false); + document.querySelector('div[aria-label=checkbox1]').setAttribute('aria-required', false); + document.querySelector('div[aria-label=checkbox1]').setAttribute('aria-readonly', false); + + // Multiple aria attributes change, false->true; + // should fire only one event. + document.querySelector('div[aria-label=checkbox2]').setAttribute('aria-checked', true); + document.querySelector('div[aria-label=checkbox2]').setAttribute('aria-required', true); + document.querySelector('div[aria-label=checkbox2]').setAttribute('aria-readonly', true); + + // Multiple aria attributes change, true->false; + // should fire only one event. + document.querySelector('div[aria-label=checkbox3]').setAttribute('aria-checked', false); + document.querySelector('div[aria-label=checkbox3]').setAttribute('aria-required', false); + document.querySelector('div[aria-label=checkbox3]').setAttribute('aria-readonly', false); + + // Multiple aria attributes change, true->removed; + // should fire only one event. + document.querySelector('div[aria-label=checkbox4]').removeAttribute('aria-checked'); + document.querySelector('div[aria-label=checkbox4]').removeAttribute('aria-required'); + document.querySelector('div[aria-label=checkbox4]').removeAttribute('aria-readonly'); + } +</script>
diff --git a/content/test/data/accessibility/event/range-value-is-readonly-changed-expected-uia-win.txt b/content/test/data/accessibility/event/range-value-is-readonly-changed-expected-uia-win.txt index 3f2feb2..095aad32 100644 --- a/content/test/data/accessibility/event/range-value-is-readonly-changed-expected-uia-win.txt +++ b/content/test/data/accessibility/event/range-value-is-readonly-changed-expected-uia-win.txt
@@ -6,8 +6,10 @@ IsEnabled changed on role=slider RangeValueIsReadOnly changed on role=slider === Start Continuation === +AriaProperties changed on role=slider RangeValueIsReadOnly changed on role=slider === Start Continuation === +AriaProperties changed on role=slider RangeValueIsReadOnly changed on role=slider === Start Continuation === AriaProperties changed on role=slider
diff --git a/content/test/data/accessibility/event/value-is-readonly-changed-expected-uia-win.txt b/content/test/data/accessibility/event/value-is-readonly-changed-expected-uia-win.txt index 5e7b21e5..c6febd4b7 100644 --- a/content/test/data/accessibility/event/value-is-readonly-changed-expected-uia-win.txt +++ b/content/test/data/accessibility/event/value-is-readonly-changed-expected-uia-win.txt
@@ -6,12 +6,16 @@ IsEnabled changed on role=textbox ValueIsReadOnly changed on role=textbox === Start Continuation === +AriaProperties changed on role=textbox ValueIsReadOnly changed on role=textbox === Start Continuation === +AriaProperties changed on role=textbox ValueIsReadOnly changed on role=textbox === Start Continuation === +AriaProperties changed on role=textbox ValueIsReadOnly changed on role=textbox === Start Continuation === +AriaProperties changed on role=textbox ValueIsReadOnly changed on role=textbox === Start Continuation === AriaProperties changed on role=textbox
diff --git a/extensions/browser/api/web_request/OWNERS b/extensions/browser/api/web_request/OWNERS new file mode 100644 index 0000000..ec7ca22 --- /dev/null +++ b/extensions/browser/api/web_request/OWNERS
@@ -0,0 +1,4 @@ +karandeepb@chromium.org +battre@chromium.org + +# COMPONENT: Platform>Extensions>API
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc index a8075bc..c08e945 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.cc
@@ -160,10 +160,14 @@ ->AttachGuest(embedder_frame_process_id, element_instance_id_, guest_instance_id, base::DictionaryValue() /* unused attach_params */); + // Full page plugin refers to <iframe> or main frame navigations to a + // MimeHandlerView resource. In such cases MHVG does not have a frame + // container. + bool is_full_page = !guest_view->maybe_has_frame_container(); MimeHandlerViewAttachHelper::Get(embedder_frame_process_id) ->AttachToOuterWebContents(guest_view, embedder_frame_process_id, outer_contents_rfh, element_instance_id_, - true /* is_full_page_plugin */); + is_full_page /* is_full_page_plugin */); // MHVE is no longer required. GetMimeHandlerViewEmbeddersMap()->erase(frame_tree_node_id_); }
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h index 3506eb1..94e23fe 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
@@ -104,6 +104,11 @@ original_resource_url_ = url; } + // Returns true when the MHVG's embedder frame has a plugin element type of + // frame owner. In such a case there might be a MHVFC assigned to MHVG in the + // parent frame of the embedder frame (for post message). + bool maybe_has_frame_container() const { return maybe_has_frame_container_; } + protected: explicit MimeHandlerViewGuest(content::WebContents* owner_web_contents); ~MimeHandlerViewGuest() override;
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc index 5de6520..ffa0d80 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.cc +++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -271,6 +271,16 @@ if (!site.SchemeIs(content::kGuestScheme)) return false; + // The partition name is user supplied value, which we have encoded when the + // URL was created, so it needs to be decoded. Since it was created via + // EscapeQueryParamValue(), it should have no path separators or control codes + // when unescaped, but safest to check for that and fail if it does. + if (!net::UnescapeBinaryURLComponentSafe(site.query_piece(), + true /* fail_on_path_separators */, + partition_name)) { + return false; + } + // Since guest URLs are only used for packaged apps, there must be an app // id in the URL. CHECK(site.has_host()); @@ -278,10 +288,6 @@ // Since persistence is optional, the path must either be empty or the // literal string. *in_memory = (site.path() != "/persist"); - // The partition name is user supplied value, which we have encoded when the - // URL was created, so it needs to be decoded. - *partition_name = - net::UnescapeURLComponent(site.query(), net::UnescapeRule::NORMAL); return true; }
diff --git a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc index 0a4f855df..c733f4158 100644 --- a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc +++ b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
@@ -203,6 +203,7 @@ case ui::AXEventGenerator::Event::LABELED_BY_CHANGED: case ui::AXEventGenerator::Event::LANGUAGE_CHANGED: case ui::AXEventGenerator::Event::LAYOUT_INVALIDATED: + case ui::AXEventGenerator::Event::LIVE_RELEVANT_CHANGED: case ui::AXEventGenerator::Event::LIVE_STATUS_CHANGED: case ui::AXEventGenerator::Event::MULTILINE_STATE_CHANGED: case ui::AXEventGenerator::Event::MULTISELECTABLE_STATE_CHANGED:
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index 3b8edfc..b10dd2a 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -323,6 +323,30 @@ if (!match_about_blank || !document_url.SchemeIs(url::kAboutScheme)) return document_url; + blink::WebSecurityOrigin web_frame_origin = frame->GetSecurityOrigin(); + url::Origin frame_origin = web_frame_origin; + // Check the origin of the frame, including whether it is an opaque origin + // (like about:blank) that has a non-opaque opener. + // Unfortunately, we still have to traverse the frame tree, because match + // patterns are associated with paths as well, not just origins. For instance, + // if an extension wants to run on google.com/maps/* with match_about_blank + // true, then it should run on about:blank frames created by google.com/maps, + // but not about:blank frames created by google.com (which is what the + // precursor tuple origin would be). + const url::SchemeHostPort& tuple_or_precursor_tuple_origin = + frame_origin.GetTupleOrPrecursorTupleIfOpaque(); + + // There is no valid tuple origin (which can happen in the case of e.g. a + // browser-initiated navigation to an opaque URL). Bail. + if (tuple_or_precursor_tuple_origin.IsInvalid()) + return document_url; + + url::Origin precursor_origin = + url::Origin::Create(tuple_or_precursor_tuple_origin.GetURL()); + // The frame can't access its precursor. Bail. + if (!web_frame_origin.CanAccess(blink::WebSecurityOrigin(precursor_origin))) + return document_url; + // Non-sandboxed about:blank and about:srcdoc pages inherit their security // origin from their parent frame/window. So, traverse the frame/window // hierarchy to find the closest non-about:-page and return its URL. @@ -341,6 +365,31 @@ if (base::ContainsKey(already_visited_frames, parent)) return document_url; + url::SchemeHostPort parent_tuple_origin = + url::Origin(parent->GetSecurityOrigin()) + .GetTupleOrPrecursorTupleIfOpaque(); + if (parent_tuple_origin.IsInvalid() || + parent_tuple_origin != tuple_or_precursor_tuple_origin) { + // The parent has a different tuple origin than frame; this could happen + // in edge cases where a parent navigates an iframe or popup of a child + // frame at a different origin. [1] In this case, bail, since we can't + // find a full URL (i.e., one including the path) with the same security + // origin to use for the frame in question. + // [1] Consider a frame tree like: + // <html> <!--example.com--> + // <iframe id="a" src="a.com"> + // <iframe id="b" src="b.com"></iframe> + // </iframe> + // </html> + // Frame "a" is cross-origin from the top-level frame, and so the + // example.com top-level frame can't directly access frame "b". However, + // it can navigate it through + // window.frames[0].frames[0].location.href = 'about:blank'; + // In that case, the precursor origin tuple origin of frame "b" would be + // example.com, but the parent tuple origin is a.com. + return document_url; + } + parent_document = parent && parent->IsWebLocalFrame() ? parent->ToWebLocalFrame()->GetDocument() : blink::WebDocument(); @@ -348,11 +397,11 @@ GURL(parent_document.Url()).SchemeIs(url::kAboutScheme)); if (!parent_document.IsNull()) { - // Only return the parent URL if the frame can access it. - if (frame->GetDocument().GetSecurityOrigin().CanAccess( - parent_document.GetSecurityOrigin())) { - return parent_document.Url(); - } + // We should know that the frame can access the parent document, since it + // has the same tuple origin as the frame, and we checked the frame access + // above. + DCHECK(web_frame_origin.CanAccess(parent_document.GetSecurityOrigin())); + return parent_document.Url(); } return document_url; }
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc index 45cf0ea..a99a803 100644 --- a/extensions/shell/browser/shell_content_browser_client.cc +++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -317,8 +317,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) { return false;
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h index 29f0830..10d9fff 100644 --- a/extensions/shell/browser/shell_content_browser_client.h +++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -91,8 +91,6 @@ bool is_main_frame, ui::PageTransition page_transition, bool has_user_gesture, - const std::string& method, - const net::HttpRequestHeaders& headers, network::mojom::URLLoaderFactoryRequest* factory_request, network::mojom::URLLoaderFactory*& out_factory) override; network::mojom::URLLoaderFactoryPtrInfo
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index 7f399f6..f9f8d6f 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -589,6 +589,10 @@ {"identity-disc", flag_descriptions::kIdentityDiscName, flag_descriptions::kIdentityDiscDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(kIdentityDisc)}, + {"enable-send-tab-to-self-history", + flag_descriptions::kSendTabToSelfHistoryName, + flag_descriptions::kSendTabToSelfHistoryDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(send_tab_to_self::kSendTabToSelfHistory)}, }; // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/context_menu/context_menu_egtest.mm b/ios/chrome/browser/context_menu/context_menu_egtest.mm index 2c12612..702b7a70 100644 --- a/ios/chrome/browser/context_menu/context_menu_egtest.mm +++ b/ios/chrome/browser/context_menu/context_menu_egtest.mm
@@ -13,7 +13,6 @@ #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/app/chrome_test_util.h" #import "ios/chrome/test/app/histogram_test_util.h" -#import "ios/chrome/test/app/settings_test_util.h" #import "ios/chrome/test/app/tab_test_util.h" #import "ios/chrome/test/app/web_view_interaction_test_util.h" #import "ios/chrome/test/earl_grey/chrome_actions.h" @@ -169,11 +168,13 @@ + (void)setUp { [super setUp]; - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_ALLOW); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_ALLOW]); } + (void)tearDown { - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_DEFAULT); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_DEFAULT]); [super tearDown]; }
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc index b7fceb4..761dd90 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -380,15 +380,21 @@ const char kSearchIconToggleDescription[] = "Different icons for the search button."; +const char kSendTabToSelfName[] = "Send tab to self"; +const char kSendTabToSelfDescription[] = + "Allows users to receive tabs that were pushed from another of their " + "synced devices, in order to easily transition tabs between devices."; + const char kSendTabToSelfBroadcastName[] = "Send tab to self broadcast"; const char kSendTabToSelfBroadcastDescription[] = "Allows users to broadcast the tab they send to all of their devices " "instead of targetting only one device."; -const char kSendTabToSelfName[] = "Send tab to self"; -const char kSendTabToSelfDescription[] = - "Allows users to receive tabs that were pushed from another of their " - "synced devices, in order to easily transition tabs between devices."; +const char kSendTabToSelfHistoryName[] = "Send tab to self history"; +const char kSendTabToSelfHistoryDescription[] = + "Allows users to view tabs that were sent to other synced devices by " + "accessing these tabs through a landing page either in history or in " + "recent tabs. Requires Send tab to self to also be enabled"; const char kSendTabToSelfShowSendingUIName[] = "Send tab to self show sending UI";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h index 3e07954..cb5ed9b 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -317,15 +317,20 @@ extern const char kSearchIconToggleName[]; extern const char kSearchIconToggleDescription[]; +// Title and description for the flag to enable the send tab to self receiving +// feature. +extern const char kSendTabToSelfName[]; +extern const char kSendTabToSelfDescription[]; + // Title and description for the flag to enable the tab to be broadcasted to all // of the users devices. extern const char kSendTabToSelfBroadcastName[]; extern const char kSendTabToSelfBroadcastDescription[]; -// Title and description for the flag to enable the send tab to self receiving +// Title and description for the flag to enable the send tab to self history // feature. -extern const char kSendTabToSelfName[]; -extern const char kSendTabToSelfDescription[]; +extern const char kSendTabToSelfHistoryName[]; +extern const char kSendTabToSelfHistoryDescription[]; // Title and description for the flag to enable the send tab to self sending UI. extern const char kSendTabToSelfShowSendingUIName[];
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.h b/ios/chrome/browser/overlays/overlay_presenter_impl.h index 650b224..8f542ec 100644 --- a/ios/chrome/browser/overlays/overlay_presenter_impl.h +++ b/ios/chrome/browser/overlays/overlay_presenter_impl.h
@@ -81,10 +81,10 @@ // delegate is executed. void OverlayWasDismissed(UIDelegate* ui_delegate, OverlayRequest* request, - OverlayRequestQueueImpl* queue, + base::WeakPtr<OverlayRequestQueueImpl> queue, OverlayDismissalReason reason); - // Cancels all overlays for |queue|. + // Cancels all overlays for |request|. void CancelOverlayUIForRequest(OverlayRequest* request); // Cancels all overlays for the Browser. @@ -96,6 +96,8 @@ // OverlayRequestQueueImpl::Observer: void RequestAddedToQueue(OverlayRequestQueueImpl* queue, OverlayRequest* request) override; + void QueuedRequestCancelled(OverlayRequestQueueImpl* queue, + OverlayRequest* request) override; // WebStateListObserver: void WebStateInsertedAt(WebStateList* web_state_list, @@ -115,6 +117,13 @@ int active_index, int reason) override; + // Whether the UI delegate is presenting overlay UI for this presenter. Stays + // true from the beginning of the presentation until the end of the + // dismissal. + bool presenting_ = false; + // Whether the active WebState is being detached. + bool detaching_active_web_state_ = false; + OverlayModality modality_; WebStateList* web_state_list_ = nullptr; web::WebState* active_web_state_ = nullptr; @@ -122,8 +131,6 @@ base::ObserverList<OverlayPresenter::Observer, /* check_empty= */ true> observers_; - bool presenting_ = false; - bool detaching_active_web_state_ = false; base::WeakPtrFactory<OverlayPresenterImpl> weak_factory_; };
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.mm b/ios/chrome/browser/overlays/overlay_presenter_impl.mm index 0649b0b..ab199cb 100644 --- a/ios/chrome/browser/overlays/overlay_presenter_impl.mm +++ b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
@@ -184,14 +184,15 @@ OverlayDismissalCallback dismissal_callback = base::BindOnce( &OverlayPresenterImpl::OverlayWasDismissed, weak_factory_.GetWeakPtr(), - ui_delegate_, request, GetActiveQueue()); + ui_delegate_, request, GetActiveQueue()->GetWeakPtr()); ui_delegate_->ShowOverlayUI(this, request, std::move(dismissal_callback)); } -void OverlayPresenterImpl::OverlayWasDismissed(UIDelegate* ui_delegate, - OverlayRequest* request, - OverlayRequestQueueImpl* queue, - OverlayDismissalReason reason) { +void OverlayPresenterImpl::OverlayWasDismissed( + UIDelegate* ui_delegate, + OverlayRequest* request, + base::WeakPtr<OverlayRequestQueueImpl> queue, + OverlayDismissalReason reason) { // If the UI delegate is reset while presenting an overlay, that overlay will // be cancelled and dismissed. The presenter is now using the new UI // delegate's presentation context, so this dismissal should not trigger @@ -199,13 +200,14 @@ if (ui_delegate_ != ui_delegate) return; - // If the overlay was dismissed for user interaction, pop it from the queue - // since it will never be shown again. - // TODO(crbug.com/941745): Prevent the queue from being accessed if deleted. - // This is possible if a WebState is closed during an overlay dismissal - // animation triggered by user interaction. - if (reason == OverlayDismissalReason::kUserInteraction) + // Pop the request for overlays dismissed by the user. The check against the + // queue's front request prevents popping the request twice in the event that + // the front request was cancelled by the queue during a user-triggered + // dismissal. + if (reason == OverlayDismissalReason::kUserInteraction && queue && + queue->front_request() == request) { queue->PopFrontRequest(); + } presenting_ = false; @@ -257,7 +259,13 @@ PresentOverlayForActiveRequest(); } -#pragma mark WebStateListObserver +void OverlayPresenterImpl::QueuedRequestCancelled( + OverlayRequestQueueImpl* queue, + OverlayRequest* request) { + CancelOverlayUIForRequest(request); +} + +#pragma mark - WebStateListObserver void OverlayPresenterImpl::WebStateInsertedAt(WebStateList* web_state_list, web::WebState* web_state,
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm b/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm index bdf16ca3..12f01b7 100644 --- a/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm +++ b/ios/chrome/browser/overlays/overlay_presenter_impl_unittest.mm
@@ -272,3 +272,25 @@ EXPECT_EQ(second_request, queue->front_request()); EXPECT_EQ(1U, queue->size()); } + +// Tests cancelling the requests. +TEST_F(OverlayPresenterImplTest, CancelRequests) { + // Add a WebState to the list and a request to that WebState's queue. + presenter().SetUIDelegate(&ui_delegate()); + web_state_list().InsertWebState(0, std::make_unique<web::TestWebState>(), + WebStateList::InsertionFlags::INSERT_ACTIVATE, + WebStateOpener()); + OverlayRequestQueueImpl* queue = GetQueueForWebState(active_web_state()); + OverlayRequest* active_request = AddRequest(active_web_state()); + OverlayRequest* queued_request = AddRequest(active_web_state()); + + EXPECT_EQ(FakeOverlayPresenterUIDelegate::PresentationState::kPresented, + ui_delegate().GetPresentationState(active_request)); + + // Cancel the queue's requests and verify that the UI is also cancelled. + queue->CancelAllRequests(); + EXPECT_EQ(FakeOverlayPresenterUIDelegate::PresentationState::kCancelled, + ui_delegate().GetPresentationState(active_request)); + EXPECT_EQ(FakeOverlayPresenterUIDelegate::PresentationState::kCancelled, + ui_delegate().GetPresentationState(queued_request)); +}
diff --git a/ios/chrome/browser/overlays/overlay_request_queue_impl.h b/ios/chrome/browser/overlays/overlay_request_queue_impl.h index 82e6ba3f..83bb2b4c 100644 --- a/ios/chrome/browser/overlays/overlay_request_queue_impl.h +++ b/ios/chrome/browser/overlays/overlay_request_queue_impl.h
@@ -9,10 +9,12 @@ #include <memory> #include "base/containers/circular_deque.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/observer_list_types.h" #include "ios/chrome/browser/overlays/public/overlay_modality.h" #import "ios/chrome/browser/overlays/public/overlay_request_queue.h" +#import "ios/web/public/web_state/web_state_observer.h" #import "ios/web/public/web_state/web_state_user_data.h" // Mutable implementation of OverlayRequestQueue. @@ -35,6 +37,7 @@ WEB_STATE_USER_DATA_KEY_DECL(); Container(web::WebState* web_state); + web::WebState* web_state_ = nullptr; std::map<OverlayModality, std::unique_ptr<OverlayRequestQueueImpl>> queues_; }; @@ -44,12 +47,22 @@ // Called after |request| has been added to |queue|. virtual void RequestAddedToQueue(OverlayRequestQueueImpl* queue, OverlayRequest* request) {} + + // Called when |request| is cancelled before it is removed from |queue|. + // All requests in a queue are cancelled before the queue is destroyed. + virtual void QueuedRequestCancelled(OverlayRequestQueueImpl* queue, + OverlayRequest* request) {} }; // Adds and removes observers. void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); + // Returns a weak pointer to the queue. + base::WeakPtr<OverlayRequestQueueImpl> GetWeakPtr(); + + // Whether the queue is empty. + bool empty() const { return requests_.empty(); } // The number of requests in the queue. size_t size() const { return requests_.size(); } @@ -58,18 +71,40 @@ void PopFrontRequest(); void PopBackRequest(); + // Cancels the UI for all requests in the queue then empties the queue. + void CancelAllRequests(); + // OverlayRequestQueue: void AddRequest(std::unique_ptr<OverlayRequest> request) override; OverlayRequest* front_request() const override; private: // Private constructor called by container. - OverlayRequestQueueImpl(); + explicit OverlayRequestQueueImpl(web::WebState* web_state); + // Helper object that cancels requests for navigation events. + class RequestCancellationHelper : public web::WebStateObserver { + public: + RequestCancellationHelper(OverlayRequestQueueImpl* queue, + web::WebState* web_state); + + private: + // web::WebStateObserver: + void DidFinishNavigation( + web::WebState* web_state, + web::NavigationContext* navigation_context) override; + void RenderProcessGone(web::WebState* web_state) override; + void WebStateDestroyed(web::WebState* web_state) override; + + OverlayRequestQueueImpl* queue_ = nullptr; + }; + + RequestCancellationHelper cancellation_helper_; base::ObserverList<Observer, /* check_empty= */ true> observers_; // The queue used to hold the received requests. Stored as a circular dequeue // to allow performant pop events from the front of the queue. base::circular_deque<std::unique_ptr<OverlayRequest>> requests_; + base::WeakPtrFactory<OverlayRequestQueueImpl> weak_factory_; }; #endif // IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_REQUEST_QUEUE_IMPL_H_
diff --git a/ios/chrome/browser/overlays/overlay_request_queue_impl.mm b/ios/chrome/browser/overlays/overlay_request_queue_impl.mm index 7264835..86c2ec23 100644 --- a/ios/chrome/browser/overlays/overlay_request_queue_impl.mm +++ b/ios/chrome/browser/overlays/overlay_request_queue_impl.mm
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "ios/chrome/browser/overlays/public/overlay_request.h" +#import "ios/web/public/web_state/navigation_context.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -28,20 +29,22 @@ WEB_STATE_USER_DATA_KEY_IMPL(OverlayRequestQueueImpl::Container) -OverlayRequestQueueImpl::Container::Container(web::WebState* web_state) {} +OverlayRequestQueueImpl::Container::Container(web::WebState* web_state) + : web_state_(web_state) {} OverlayRequestQueueImpl::Container::~Container() = default; OverlayRequestQueueImpl* OverlayRequestQueueImpl::Container::QueueForModality( OverlayModality modality) { auto& queue = queues_[modality]; if (!queue) - queue = base::WrapUnique(new OverlayRequestQueueImpl()); + queue = base::WrapUnique(new OverlayRequestQueueImpl(web_state_)); return queue.get(); } #pragma mark - OverlayRequestQueueImpl -OverlayRequestQueueImpl::OverlayRequestQueueImpl() = default; +OverlayRequestQueueImpl::OverlayRequestQueueImpl(web::WebState* web_state) + : cancellation_helper_(this, web_state), weak_factory_(this) {} OverlayRequestQueueImpl::~OverlayRequestQueueImpl() = default; #pragma mark Public @@ -54,6 +57,10 @@ observers_.RemoveObserver(observer); } +base::WeakPtr<OverlayRequestQueueImpl> OverlayRequestQueueImpl::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + void OverlayRequestQueueImpl::PopFrontRequest() { DCHECK(!requests_.empty()); requests_.pop_front(); @@ -64,6 +71,17 @@ requests_.pop_back(); } +void OverlayRequestQueueImpl::CancelAllRequests() { + while (!empty()) { + // Requests are cancelled in reverse order to prevent attempting to present + // subsequent requests after the dismissal of the front request's UI. + for (auto& observer : observers_) { + observer.QueuedRequestCancelled(this, requests_.back().get()); + } + PopBackRequest(); + } +} + #pragma mark OverlayRequestQueue void OverlayRequestQueueImpl::AddRequest( @@ -77,3 +95,31 @@ OverlayRequest* OverlayRequestQueueImpl::front_request() const { return requests_.empty() ? nullptr : requests_.front().get(); } + +#pragma mark RequestCancellationHelper + +OverlayRequestQueueImpl::RequestCancellationHelper::RequestCancellationHelper( + OverlayRequestQueueImpl* queue, + web::WebState* web_state) + : queue_(queue) { + web_state->AddObserver(this); +} + +void OverlayRequestQueueImpl::RequestCancellationHelper::DidFinishNavigation( + web::WebState* web_state, + web::NavigationContext* navigation_context) { + if (navigation_context->HasCommitted() && + !navigation_context->IsSameDocument()) { + queue_->CancelAllRequests(); + } +} + +void OverlayRequestQueueImpl::RequestCancellationHelper::RenderProcessGone( + web::WebState* web_state) { + queue_->CancelAllRequests(); +} + +void OverlayRequestQueueImpl::RequestCancellationHelper::WebStateDestroyed( + web::WebState* web_state) { + web_state->RemoveObserver(this); +}
diff --git a/ios/chrome/browser/overlays/overlay_request_queue_impl_unittest.mm b/ios/chrome/browser/overlays/overlay_request_queue_impl_unittest.mm index 6745bb7..ad14f05 100644 --- a/ios/chrome/browser/overlays/overlay_request_queue_impl_unittest.mm +++ b/ios/chrome/browser/overlays/overlay_request_queue_impl_unittest.mm
@@ -24,6 +24,8 @@ MOCK_METHOD2(RequestAddedToQueue, void(OverlayRequestQueueImpl*, OverlayRequest*)); + MOCK_METHOD2(QueuedRequestCancelled, + void(OverlayRequestQueueImpl*, OverlayRequest*)); }; } // namespace @@ -45,6 +47,15 @@ } MockOverlayRequestQueueImplObserver& observer() { return observer_; } + OverlayRequest* AddRequest() { + std::unique_ptr<OverlayRequest> passed_request = + OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr); + OverlayRequest* request = passed_request.get(); + EXPECT_CALL(observer(), RequestAddedToQueue(queue(), request)); + queue()->AddRequest(std::move(passed_request)); + return request; + } + private: web::TestWebState web_state_; MockOverlayRequestQueueImplObserver observer_; @@ -53,22 +64,10 @@ // Tests that state is updated correctly and observer callbacks are received // when adding requests to the back of the queue. TEST_F(OverlayRequestQueueImplTest, AddRequest) { - std::unique_ptr<OverlayRequest> first_request = - OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr); - OverlayRequest* first_request_ptr = first_request.get(); - std::unique_ptr<OverlayRequest> second_request = - OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr); - OverlayRequest* second_request_ptr = second_request.get(); + OverlayRequest* first_request = AddRequest(); + AddRequest(); - // Add two requests and pop the first, verifying that the size and front - // requests are updated. - EXPECT_CALL(observer(), RequestAddedToQueue(queue(), first_request_ptr)); - queue()->AddRequest(std::move(first_request)); - - EXPECT_CALL(observer(), RequestAddedToQueue(queue(), second_request_ptr)); - queue()->AddRequest(std::move(second_request)); - - EXPECT_EQ(first_request_ptr, queue()->front_request()); + EXPECT_EQ(first_request, queue()->front_request()); EXPECT_EQ(2U, queue()->size()); } @@ -76,23 +75,9 @@ // when popping the requests. TEST_F(OverlayRequestQueueImplTest, PopRequests) { // Add three requests to the queue. - std::unique_ptr<OverlayRequest> passed_request = - OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr); - OverlayRequest* first_request = passed_request.get(); - EXPECT_CALL(observer(), RequestAddedToQueue(queue(), first_request)); - queue()->AddRequest(std::move(passed_request)); - - passed_request = - OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr); - OverlayRequest* second_request = passed_request.get(); - EXPECT_CALL(observer(), RequestAddedToQueue(queue(), second_request)); - queue()->AddRequest(std::move(passed_request)); - - passed_request = - OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr); - OverlayRequest* third_request = passed_request.get(); - EXPECT_CALL(observer(), RequestAddedToQueue(queue(), third_request)); - queue()->AddRequest(std::move(passed_request)); + OverlayRequest* first_request = AddRequest(); + OverlayRequest* second_request = AddRequest(); + AddRequest(); ASSERT_EQ(first_request, queue()->front_request()); ASSERT_EQ(3U, queue()->size()); @@ -109,3 +94,19 @@ EXPECT_EQ(second_request, queue()->front_request()); EXPECT_EQ(1U, queue()->size()); } + +// Tests that state is updated correctly and observer callbacks are received +// when popping the requests. +TEST_F(OverlayRequestQueueImplTest, CancelAllRequests) { + // Add two requests to the queue then cancel all requests, verifying that + // the observer callback is received for each. + OverlayRequest* first_request = AddRequest(); + OverlayRequest* second_request = AddRequest(); + + EXPECT_CALL(observer(), QueuedRequestCancelled(queue(), first_request)); + EXPECT_CALL(observer(), QueuedRequestCancelled(queue(), second_request)); + queue()->CancelAllRequests(); + + EXPECT_EQ(0U, queue()->size()); + EXPECT_TRUE(queue()->empty()); +}
diff --git a/ios/chrome/browser/overlays/test/fake_overlay_presenter_ui_delegate.cc b/ios/chrome/browser/overlays/test/fake_overlay_presenter_ui_delegate.cc index b7e75f9..f2e7ead 100644 --- a/ios/chrome/browser/overlays/test/fake_overlay_presenter_ui_delegate.cc +++ b/ios/chrome/browser/overlays/test/fake_overlay_presenter_ui_delegate.cc
@@ -54,6 +54,6 @@ if (state == PresentationState::kPresented) { SimulateDismissalForRequest(request, OverlayDismissalReason::kCancellation); } else { - state = PresentationState::kNotPresented; + state = PresentationState::kCancelled; } }
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm index 4a12f9a..7ebee1d 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm
@@ -15,7 +15,6 @@ #import "base/test/ios/wait_util.h" #include "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/test/app/chrome_test_util.h" -#import "ios/chrome/test/app/settings_test_util.h" #import "ios/chrome/test/app/web_view_interaction_test_util.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" @@ -310,7 +309,8 @@ kPageHeightEM, javaScript.c_str()); web::test::SetUpSimpleHttpServer(responses); - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_ALLOW); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_ALLOW]); CHROME_EG_ASSERT_NO_ERROR([ChromeEarlGrey loadURL:URL]); CHROME_EG_ASSERT_NO_ERROR(
diff --git a/ios/chrome/browser/ui/infobars/BUILD.gn b/ios/chrome/browser/ui/infobars/BUILD.gn index f279795c..0ac49f8 100644 --- a/ios/chrome/browser/ui/infobars/BUILD.gn +++ b/ios/chrome/browser/ui/infobars/BUILD.gn
@@ -62,8 +62,10 @@ deps = [ ":public", "resources:infobar_downloading", + "resources:infobar_hide_password_icon", "resources:infobar_passwords_icon", "resources:infobar_popup_blocker", + "resources:infobar_reveal_password_icon", "resources:infobar_settings_icon", "resources:infobar_warning", "//base",
diff --git a/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm b/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm index 0a014471..ea02651 100644 --- a/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm +++ b/ios/chrome/browser/ui/infobars/modals/infobar_password_table_view_controller.mm
@@ -59,6 +59,8 @@ // Used to build and record metrics specific to passwords. @property(nonatomic, strong) IOSChromePasswordInfobarMetricsRecorder* passwordMetricsRecorder; +// Whether the current password being shown is masked or not. +@property(nonatomic, assign) BOOL passwordMasked; @end @implementation InfobarPasswordTableViewController @@ -169,9 +171,14 @@ self.passwordItem.textFieldName = l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD); self.passwordItem.textFieldValue = self.maskedPassword; + self.passwordItem.identifyingIcon = + [UIImage imageNamed:@"infobar_reveal_password_icon"]; + self.passwordItem.identifyingIconEnabled = YES; [model addItem:self.passwordItem toSectionWithIdentifier:SectionIdentifierContent]; + self.passwordMasked = YES; + self.saveCredentialsItem = [[TableViewTextButtonItem alloc] initWithType:ItemTypeSaveCredentials]; self.saveCredentialsItem.textAlignment = NSTextAlignmentNatural; @@ -231,18 +238,24 @@ [editCell.textField addTarget:self action:@selector(updateSaveCredentialsButtonState) forControlEvents:UIControlEventEditingChanged]; + editCell.selectionStyle = UITableViewCellSelectionStyleNone; + editCell.textField.delegate = self; break; } case ItemTypePassword: { TableViewTextEditCell* editCell = base::mac::ObjCCast<TableViewTextEditCell>(cell); - editCell.textField.delegate = self; [editCell.textField addTarget:self action:@selector(updateSaveCredentialsButtonState) forControlEvents:UIControlEventEditingChanged]; + [editCell.identifyingIconButton addTarget:self + action:@selector(togglePasswordMasking) + forControlEvents:UIControlEventTouchUpInside]; + editCell.selectionStyle = UITableViewCellSelectionStyleNone; break; } case ItemTypeURL: + cell.selectionStyle = UITableViewCellSelectionStyleNone; break; } @@ -322,4 +335,18 @@ recordModalEvent:MobileMessagesPasswordsModalEvent::EditedUserName]; } +- (void)togglePasswordMasking { + self.passwordMasked = !self.passwordMasked; + if (self.passwordMasked) { + self.passwordItem.identifyingIcon = + [UIImage imageNamed:@"infobar_reveal_password_icon"]; + self.passwordItem.textFieldValue = self.maskedPassword; + } else { + self.passwordItem.identifyingIcon = + [UIImage imageNamed:@"infobar_hide_password_icon"]; + self.passwordItem.textFieldValue = self.unmaskedPassword; + } + [self reconfigureCellsForItems:@[ self.passwordItem ]]; +} + @end
diff --git a/ios/chrome/browser/ui/infobars/resources/BUILD.gn b/ios/chrome/browser/ui/infobars/resources/BUILD.gn index 1da4e819..87bd745f 100644 --- a/ios/chrome/browser/ui/infobars/resources/BUILD.gn +++ b/ios/chrome/browser/ui/infobars/resources/BUILD.gn
@@ -40,6 +40,22 @@ ] } +imageset("infobar_reveal_password_icon") { + sources = [ + "infobar_reveal_password_icon.imageset/Contents.json", + "infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png", + "infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png", + ] +} + +imageset("infobar_hide_password_icon") { + sources = [ + "infobar_hide_password_icon.imageset/Contents.json", + "infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png", + "infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png", + ] +} + imageset("infobar_settings_icon") { sources = [ "infobar_settings_icon.imageset/Contents.json",
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/Contents.json b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/Contents.json new file mode 100644 index 0000000..acbff6c5 --- /dev/null +++ b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/Contents.json
@@ -0,0 +1,18 @@ +{ + "images": [ + { + "idiom": "universal", + "scale": "2x", + "filename": "infobar_hide_password_icon@2x.png" + }, + { + "idiom": "universal", + "scale": "3x", + "filename": "infobar_hide_password_icon@3x.png" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +}
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png new file mode 100644 index 0000000..4827898 --- /dev/null +++ b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png new file mode 100644 index 0000000..8863188a --- /dev/null +++ b/ios/chrome/browser/ui/infobars/resources/infobar_hide_password_icon.imageset/infobar_hide_password_icon@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/Contents.json b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/Contents.json new file mode 100644 index 0000000..7d8697c --- /dev/null +++ b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/Contents.json
@@ -0,0 +1,18 @@ +{ + "images": [ + { + "idiom": "universal", + "scale": "2x", + "filename": "infobar_reveal_password_icon@2x.png" + }, + { + "idiom": "universal", + "scale": "3x", + "filename": "infobar_reveal_password_icon@3x.png" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +}
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png new file mode 100644 index 0000000..d421f539 --- /dev/null +++ b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png new file mode 100644 index 0000000..63cea42 --- /dev/null +++ b/ios/chrome/browser/ui/infobars/resources/infobar_reveal_password_icon.imageset/infobar_reveal_password_icon@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm index e6b9cde..c31909f 100644 --- a/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm +++ b/ios/chrome/browser/ui/settings/table_cell_catalog_view_controller.mm
@@ -266,6 +266,17 @@ [model addItem:textEditItemBothIcons toSectionWithIdentifier:SectionIdentifierText]; + TableViewTextEditItem* textEditItemIconButton = + [[TableViewTextEditItem alloc] initWithType:ItemTypeTextEditItem]; + textEditItemIconButton.textFieldName = @"Edit Text Item"; + textEditItemIconButton.textFieldValue = @" icon is a button."; + textEditItemIconButton.identifyingIcon = + [UIImage imageNamed:@"table_view_cell_check_mark"]; + textEditItemIconButton.identifyingIconEnabled = YES; + textEditItemIconButton.textFieldEnabled = NO; + [model addItem:textEditItemIconButton + toSectionWithIdentifier:SectionIdentifierText]; + TableViewMultiDetailTextItem* tableViewMultiDetailTextItem = [[TableViewMultiDetailTextItem alloc] initWithType:ItemTypeMultiDetailText];
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm index 42332be..6473b42c1 100644 --- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm +++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
@@ -14,7 +14,6 @@ #import "ios/chrome/browser/snapshots/snapshot_cache_factory.h" #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" #import "ios/chrome/browser/tabs/tab.h" -#import "ios/chrome/browser/tabs/tab_model_observer.h" #import "ios/chrome/browser/ui/fullscreen/animated_scoped_fullscreen_disabler.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h" #import "ios/chrome/browser/ui/fullscreen/scoped_fullscreen_disabler.h" @@ -59,7 +58,6 @@ } @interface SideSwipeController () <CRWWebStateObserver, - TabModelObserver, UIGestureRecognizerDelegate, WebStateListObserving> { @private @@ -134,6 +132,10 @@ // Removes the |curtain_| and calls |completionHandler| when the curtain is // removed. - (void)dismissCurtainWithCompletionHandler:(ProceduralBlock)completionHandler; + +// Removes the |curtain_| if there was an active swipe, and resets +// |inSwipe_| value. +- (void)dismissCurtain; @end @implementation SideSwipeController @@ -153,7 +155,6 @@ self = [super init]; if (self) { model_ = model; - [model_ addObserver:self]; webStateListObserver_ = std::make_unique<WebStateListObserverBridge>(self); model_.webStateList->AddObserver(webStateListObserver_.get()); webStateObserverBridge_ = @@ -161,6 +162,8 @@ scopedWebStateObserver_ = std::make_unique<ScopedObserver<web::WebState, web::WebStateObserver>>( webStateObserverBridge_.get()); + if (self.activeWebState) + scopedWebStateObserver_->Add(self.activeWebState); browserState_ = browserState; } @@ -173,7 +176,6 @@ // |model_| is still alive before accessing |webStateList|. model_.webStateList->RemoveObserver(webStateListObserver_.get()); } - [model_ removeObserver:self]; scopedWebStateObserver_.reset(); webStateObserverBridge_.reset(); @@ -497,8 +499,6 @@ if (webState && (web::GetWebClient()->IsSlimNavigationManagerEnabled() || webState->IsLoading())) { - scopedWebStateObserver_->RemoveAll(); - scopedWebStateObserver_->Add(webState); [self addCurtainWithCompletionHandler:^{ inSwipe_ = NO; }]; @@ -593,12 +593,19 @@ - (void)dismissCurtainWithCompletionHandler:(ProceduralBlock)completionHandler { [NSObject cancelPreviousPerformRequestsWithTarget:self]; - scopedWebStateObserver_->RemoveAll(); [curtain_ removeFromSuperview]; curtain_ = nil; completionHandler(); } +- (void)dismissCurtain { + if (!inSwipe_) + return; + [self dismissCurtainWithCompletionHandler:^{ + inSwipe_ = NO; + }]; +} + - (void)updateNavigationEdgeSwipeForWebState:(web::WebState*)webState { // With slim nav disabled, always use SideSwipeController's edge swipe for // navigation. @@ -645,27 +652,18 @@ - (void)webStateDidStopLoading:(web::WebState*)webState { if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) return; - [self dismissCurtainWithCompletionHandler:^{ - inSwipe_ = NO; - }]; + [self dismissCurtain]; } - (void)webState:(web::WebState*)webState didLoadPageWithSuccess:(BOOL)success { if (!web::GetWebClient()->IsSlimNavigationManagerEnabled()) return; - [self dismissCurtainWithCompletionHandler:^{ - inSwipe_ = NO; - }]; + [self dismissCurtain]; } -- (void)webStateDestroyed:(web::WebState*)webState { - scopedWebStateObserver_->Remove(webState); -} - -#pragma mark - TabModelObserver Methods - -- (void)tabModel:(TabModel*)model didChangeTab:(Tab*)tab { - [self updateNavigationEdgeSwipeForWebState:tab.webState]; +- (void)webState:(web::WebState*)webState + didFinishNavigation:(web::NavigationContext*)navigation { + [self updateNavigationEdgeSwipeForWebState:webState]; } #pragma mark - WebStateListObserving Methods @@ -675,10 +673,19 @@ oldWebState:(web::WebState*)oldWebState atIndex:(int)atIndex reason:(int)reason { + // If there is any an ongoing swipe for the old webState, cancel it and + // dismiss the curtain. + [self dismissCurtain]; // Toggling the gesture's enabled state off and on will effectively cancel // the gesture recognizer. [swipeGestureRecognizer_ setEnabled:NO]; [swipeGestureRecognizer_ setEnabled:YES]; + // Track the new active WebState for navigation events. Also remove the old if + // there was one. + if (oldWebState) + scopedWebStateObserver_->Remove(oldWebState); + if (newWebState) + scopedWebStateObserver_->Add(newWebState); [self updateNavigationEdgeSwipeForWebState:newWebState]; }
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm index b5786b0..e46ade9 100644 --- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm +++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller_unittest.mm
@@ -11,6 +11,7 @@ #import "ios/chrome/browser/web_state_list/web_state_opener.h" #include "ios/web/common/features.h" #import "ios/web/public/navigation_item.h" +#import "ios/web/public/test/fakes/fake_navigation_context.h" #import "ios/web/public/test/fakes/test_navigation_manager.h" #import "ios/web/public/test/fakes/test_web_state.h" #include "ios/web/public/test/test_web_thread_bundle.h" @@ -145,4 +146,40 @@ EXPECT_TRUE(side_swipe_controller_.trailingEdgeNavigationEnabled); } +// Tests that when the active webState is changed or when the active webState +// finishes navigation, the edge state will be updated accordingly. +TEST_F(SideSwipeControllerTest, ObserversTriggerStateUpdate) { + feature_list_.InitAndEnableFeature(web::features::kSlimNavigationManager); + + ASSERT_FALSE(side_swipe_controller_.leadingEdgeNavigationEnabled); + ASSERT_FALSE(side_swipe_controller_.trailingEdgeNavigationEnabled); + + auto testWebState = std::make_unique<web::TestWebState>(); + web::TestWebState* testWebStatePtr = testWebState.get(); + auto testNavigationManager = std::make_unique<web::TestNavigationManager>(); + std::unique_ptr<web::NavigationItem> item = web::NavigationItem::Create(); + testNavigationManager->SetVisibleItem(item.get()); + testNavigationManager->SetLastCommittedItem(item.get()); + testWebState->SetNavigationManager(std::move(testNavigationManager)); + + // The NTP and chrome://crash should use native swipe. + item->SetURL(GURL(kChromeUINewTabURL)); + // Insert the WebState and make sure it's active. This should trigger + // didChangeActiveWebState and update edge navigation state. + web_state_list_->InsertWebState(1, std::move(testWebState), + WebStateList::INSERT_ACTIVATE, + WebStateOpener()); + EXPECT_TRUE(side_swipe_controller_.leadingEdgeNavigationEnabled); + EXPECT_TRUE(side_swipe_controller_.trailingEdgeNavigationEnabled); + + // Non native URL should have shouldn't be handled by SideSwipeController. + item->SetURL(GURL("http://wwww.test.test")); + web::FakeNavigationContext context; + context.SetHasCommitted(true); + // Navigation finish should also update the edge navigation state. + testWebStatePtr->OnNavigationFinished(&context); + EXPECT_FALSE(side_swipe_controller_.leadingEdgeNavigationEnabled); + EXPECT_FALSE(side_swipe_controller_.trailingEdgeNavigationEnabled); +} + } // anonymous namespace
diff --git a/ios/chrome/browser/ui/table_view/cells/BUILD.gn b/ios/chrome/browser/ui/table_view/cells/BUILD.gn index 024e579..e64a21e 100644 --- a/ios/chrome/browser/ui/table_view/cells/BUILD.gn +++ b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
@@ -50,6 +50,7 @@ "//base:i18n", "//ios/chrome/app/strings", "//ios/chrome/browser/ui/colors:colors", + "//ios/chrome/browser/ui/elements", "//ios/chrome/browser/ui/list_model", "//ios/chrome/browser/ui/settings/cells:public", "//ios/chrome/browser/ui/table_view:styler",
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h b/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h index c4a06e5..60a358c 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h
@@ -22,6 +22,9 @@ // An icon identifying the text field or its current value, if any. @property(nonatomic, copy) UIImage* identifyingIcon; +// If YES the identifyingIcon will be enabled as a button. Disabled by default. +@property(nonatomic, assign) BOOL identifyingIconEnabled; + // Whether to hide or display the trailing edit icon. @property(nonatomic, assign) BOOL hideEditIcon; @@ -59,6 +62,12 @@ // Whether the icon showing that the cell is editable should be displayed. @property(nonatomic, assign) BOOL editIconDisplayed; +// Identifying button. UIButton containing the icon +// identifying |textField| or its current value. It is located at the most +// trailing position of the Cell. +@property(nonatomic, readonly, strong) UIButton* identifyingIconButton; + +// Sets |self.identifyingIconButton| icon. - (void)setIdentifyingIcon:(UIImage*)icon; @end
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.mm index 3259c03..cf8e748 100644 --- a/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.mm +++ b/ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.mm
@@ -4,6 +4,7 @@ #import "ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h" +#import "ios/chrome/browser/ui/elements/extended_touch_target_button.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" #import "ios/chrome/browser/ui/util/rtl_geometry.h" @@ -78,6 +79,7 @@ cell.textField.keyboardType = self.keyboardType; cell.textField.autocapitalizationType = self.autoCapitalizationType; [cell setIdentifyingIcon:self.identifyingIcon]; + cell.identifyingIconButton.enabled = self.identifyingIconEnabled; } #pragma mark Actions @@ -96,7 +98,6 @@ @property(nonatomic, strong) NSLayoutConstraint* iconWidthConstraint; @property(nonatomic, strong) NSLayoutConstraint* textFieldTrailingConstraint; @property(nonatomic, strong) NSLayoutConstraint* textLabelTrailingConstraint; - @property(nonatomic, strong) NSLayoutConstraint* editIconHeightConstraint; @property(nonatomic, strong) NSLayoutConstraint* iconTrailingConstraint; @@ -107,10 +108,6 @@ // another line. They conflict with the |standardConstraints|. @property(nonatomic, strong) NSArray<NSLayoutConstraint*>* accessibilityConstraints; - -// UIImageView containing the icon identifying |textField| or its current value. -@property(nonatomic, readonly, strong) UIImageView* identifyingIconView; - // UIImageView containing the icon indicating that |textField| is editable. @property(nonatomic, strong) UIImageView* editIconView; @@ -150,10 +147,11 @@ _textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; - // Trailing con. - _identifyingIconView = [[UIImageView alloc] initWithFrame:CGRectZero]; - _identifyingIconView.translatesAutoresizingMaskIntoConstraints = NO; - [contentView addSubview:_identifyingIconView]; + // Trailing icon button. + _identifyingIconButton = + [ExtendedTouchTargetButton buttonWithType:UIButtonTypeCustom]; + _identifyingIconButton.translatesAutoresizingMaskIntoConstraints = NO; + [contentView addSubview:_identifyingIconButton]; // Edit icon. UIImage* editImage = [[UIImage imageNamed:@"table_view_cell_edit_icon"] @@ -167,9 +165,9 @@ // Set up the icons size constraints. They are activated here and updated in // layoutSubviews. _iconHeightConstraint = - [_identifyingIconView.heightAnchor constraintEqualToConstant:0]; + [_identifyingIconButton.heightAnchor constraintEqualToConstant:0]; _iconWidthConstraint = - [_identifyingIconView.widthAnchor constraintEqualToConstant:0]; + [_identifyingIconButton.widthAnchor constraintEqualToConstant:0]; _editIconHeightConstraint = [_editIconView.heightAnchor constraintEqualToConstant:0]; @@ -178,7 +176,7 @@ _textLabelTrailingConstraint = [_textLabel.trailingAnchor constraintEqualToAnchor:_editIconView.leadingAnchor]; _iconTrailingConstraint = [_editIconView.trailingAnchor - constraintEqualToAnchor:_identifyingIconView.leadingAnchor]; + constraintEqualToAnchor:_identifyingIconButton.leadingAnchor]; _standardConstraints = @[ [_textField.firstBaselineAnchor @@ -203,10 +201,10 @@ constraintEqualToAnchor:contentView.leadingAnchor constant:kTableViewHorizontalSpacing], _textFieldTrailingConstraint, - [_identifyingIconView.trailingAnchor + [_identifyingIconButton.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor constant:-kTableViewHorizontalSpacing], - [_identifyingIconView.centerYAnchor + [_identifyingIconButton.centerYAnchor constraintEqualToAnchor:contentView.centerYAnchor], [_editIconView.centerYAnchor constraintEqualToAnchor:contentView.centerYAnchor], @@ -251,7 +249,14 @@ } - (void)setIdentifyingIcon:(UIImage*)icon { - self.identifyingIconView.image = icon; + // Set Image as UIImageRenderingModeAlwaysTemplate to allow the Button tint + // color to propagate. + [self.identifyingIconButton + setImage:[icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] + forState:UIControlStateNormal]; + // Set the same image for the button's disable state so it's not grayed out + // when disabled. + [self.identifyingIconButton setImage:icon forState:UIControlStateDisabled]; if (icon) { self.iconTrailingConstraint.constant = -kLabelAndFieldGap; @@ -296,7 +301,8 @@ [self.textField removeTarget:nil action:nil forControlEvents:UIControlEventAllEvents]; - self.identifyingIconView.image = nil; + [self setIdentifyingIcon:nil]; + self.identifyingIconButton.enabled = NO; } #pragma mark Accessibility
diff --git a/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm b/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm index 58b005a..9137375f 100644 --- a/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm +++ b/ios/chrome/browser/web/child_window_open_by_dom_egtest.mm
@@ -5,7 +5,6 @@ #import <EarlGrey/EarlGrey.h> #include "components/content_settings/core/common/content_settings.h" -#include "ios/chrome/test/app/settings_test_util.h" #import "ios/chrome/test/app/tab_test_util.h" #import "ios/chrome/test/app/web_view_interaction_test_util.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -44,12 +43,14 @@ + (void)setUp { [super setUp]; - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_ALLOW); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_ALLOW]); web::test::SetUpFileBasedHttpServer(); } + (void)tearDown { - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_DEFAULT); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_DEFAULT]); [super tearDown]; }
diff --git a/ios/chrome/browser/web/window_open_by_dom_egtest.mm b/ios/chrome/browser/web/window_open_by_dom_egtest.mm index fc73c76..d10075d0 100644 --- a/ios/chrome/browser/web/window_open_by_dom_egtest.mm +++ b/ios/chrome/browser/web/window_open_by_dom_egtest.mm
@@ -12,7 +12,6 @@ #include "components/content_settings/core/common/content_settings.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/app/chrome_test_util.h" -#include "ios/chrome/test/app/settings_test_util.h" #import "ios/chrome/test/app/tab_test_util.h" #import "ios/chrome/test/app/web_view_interaction_test_util.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" @@ -60,12 +59,14 @@ + (void)setUp { [super setUp]; - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_ALLOW); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_ALLOW]); web::test::SetUpFileBasedHttpServer(); } + (void)tearDown { - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_DEFAULT); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_DEFAULT]); [super tearDown]; } @@ -122,7 +123,8 @@ // Tests executing script that clicks a link with target="_blank". - (void)testLinkWithBlankTargetWithoutUserGesture { - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_BLOCK); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_BLOCK]); NSError* error = nil; ExecuteJavaScript( @"document.getElementById('webScenarioWindowOpenRegularLink').click()", @@ -286,7 +288,8 @@ // Tests that popup blocking works when a popup is injected into a window before // its initial load is committed. - (void)testBlockPopupInjectedIntoOpenedWindow { - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_BLOCK); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_BLOCK]); GREYAssert(TapWebViewElementWithId("webScenarioOpenWindowAndInjectPopup"), @"Failed to tap \"webScenarioOpenWindowAndInjectPopup\""); [[EarlGrey selectElementWithMatcher:PopupBlocker()]
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn index fb9ec841..edec0f596 100644 --- a/ios/chrome/test/earl_grey/BUILD.gn +++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -386,6 +386,7 @@ deps = [ "//base", "//base/test:test_support", + "//components/content_settings/core/common:common", "//ios/testing:nserror_support", "//ios/testing/earl_grey:eg_test_support+eg2", "//ios/third_party/earl_grey2:test_lib",
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h index b19c87a..b7b58a5c 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey.h +++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -10,6 +10,7 @@ #include <string> #include "base/compiler_specific.h" +#import "components/content_settings/core/common/content_settings.h" #include "url/gurl.h" @class ElementSelector; @@ -153,6 +154,11 @@ + (NSError*)waitForElementWithMatcherSufficientlyVisible: (id<GREYMatcher>)matcher WARN_UNUSED_RESULT; +#pragma mark - Settings Utilities + +// Sets value for content setting. ++ (NSError*)setContentSettings:(ContentSetting)setting WARN_UNUSED_RESULT; + @end #endif // IOS_CHROME_TEST_EARL_GREY_CHROME_EARL_GREY_H_
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm index 4c20e25f..09c3a8b 100644 --- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm +++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -25,6 +25,7 @@ #import "ios/chrome/test/app/chrome_test_util.h" // nogncheck #import "ios/chrome/test/app/history_test_util.h" // nogncheck #include "ios/chrome/test/app/navigation_test_util.h" // nogncheck +#import "ios/chrome/test/app/settings_test_util.h" // nogncheck #import "ios/chrome/test/app/static_html_view_test_util.h" // nogncheck #import "ios/chrome/test/app/tab_test_util.h" // nogncheck #import "ios/web/public/test/earl_grey/js_test_util.h" // nogncheck @@ -419,6 +420,12 @@ return nil; } +#pragma mark - Settings Utilities ++ (NSError*)setContentSettings:(ContentSetting)setting { + chrome_test_util::SetContentSettingsBlockPopups(setting); + return nil; +} + @end #endif // defined(CHROME_EARL_GREY_1)
diff --git a/ios/chrome/test/earl_grey/chrome_test_case.mm b/ios/chrome/test/earl_grey/chrome_test_case.mm index 34345d6..81ce81c 100644 --- a/ios/chrome/test/earl_grey/chrome_test_case.mm +++ b/ios/chrome/test/earl_grey/chrome_test_case.mm
@@ -16,7 +16,6 @@ #include "base/strings/sys_string_conversions.h" #include "components/signin/core/browser/signin_switches.h" #import "ios/chrome/test/app/chrome_test_util.h" -#include "ios/chrome/test/app/settings_test_util.h" #include "ios/chrome/test/app/signin_test_util.h" #import "ios/chrome/test/app/sync_test_util.h" #import "ios/chrome/test/app/tab_test_util.h" @@ -168,7 +167,8 @@ // ensure the UI is in a clean state. [self removeAnyOpenMenusAndInfoBars]; [self closeAllTabs]; - chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_DEFAULT); + CHROME_EG_ASSERT_NO_ERROR( + [ChromeEarlGrey setContentSettings:CONTENT_SETTING_DEFAULT]); [CoverageUtils configureCoverageReportPath]; }
diff --git a/ios/testing/earl_grey/BUILD.gn b/ios/testing/earl_grey/BUILD.gn index 946bc04..e3d7ade 100644 --- a/ios/testing/earl_grey/BUILD.gn +++ b/ios/testing/earl_grey/BUILD.gn
@@ -17,6 +17,8 @@ sources = [ "base_earl_grey_test_case.h", "base_earl_grey_test_case.mm", + "base_eg_test_helper_impl.h", + "base_eg_test_helper_impl.mm", "coverage_utils.h", "coverage_utils.mm", "disabled_test_macros.h", @@ -58,6 +60,8 @@ sources = [ "base_earl_grey_test_case.h", "base_earl_grey_test_case.mm", + "base_eg_test_helper_impl.h", + "base_eg_test_helper_impl.mm", "coverage_utils.h", "coverage_utils_stub.mm", "disabled_test_macros.h",
diff --git a/ios/testing/earl_grey/base_eg_test_helper_impl.h b/ios/testing/earl_grey/base_eg_test_helper_impl.h new file mode 100644 index 0000000..9b9f331d --- /dev/null +++ b/ios/testing/earl_grey/base_eg_test_helper_impl.h
@@ -0,0 +1,72 @@ +// Copyright 2019 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_TESTING_EARL_GREY_BASE_EG_TEST_HELPER_IMPL_H_ +#define IOS_TESTING_EARL_GREY_BASE_EG_TEST_HELPER_IMPL_H_ + +#import <Foundation/Foundation.h> + +// Public macro to use in test helpers methods. Usage example: +// +// @interface MyEarlGreyImpl : BaseEGTestHelperImpl +// @end +// @implementation MyEarlGreyImpl +// + (void)loadURL:(const GURL&)URL { +// NSString* spec = base::SysUTF8ToNSString(URL.spec()); +// EG_TEST_HELPER_ASSERT_NO_ERROR(LoadUrl(spec)); +// } +// @end +// +// In this example LoadUrl() must return NSError* on failure and nil on success +// and MyEarlGreyImpl has to be a subclass of BaseEGTestHelperImpl. +// +#define EG_TEST_HELPER_ASSERT_NO_ERROR(__expression) \ + [self failWithError:__expression expression:@"" #__expression]; + +// Public macro to use in test helpers methods. Usage example: +// +// @interface MyEarlGreyImpl : TestHelperImpl +// @end +// @implementation MyEarlGreyImpl +// - (void)waitForLoadCompletion { +// EG_TEST_HELPER_ASSERT_TRUE(WaitForLoadCompletion(), +// @"Waiting for load completion"); +// } +// @end +// +// In this example WaitForLoadCompletion() must return bool indicating success +// and MyEarlGreyImpl has to be a subclass of TestHelperImpl. +// +#define EG_TEST_HELPER_ASSERT_TRUE(__expression, __description) \ + [self fail:!__expression \ + expression:@"" #__expression \ + description:__description]; + +// Base class used for logging the failure. Compiled in Test Process for EG2 and +// EG1. Must not be instantiated directly. +@interface BaseEGTestHelperImpl : NSObject + +// Creates BaseEGTestHelperImpl object with preset file name and line number for +// failure. Must be invoked by helper macro and not called directly. ++ (instancetype)invokedFromFile:(NSString*)fileName lineNumber:(int)lineNumber; + +- (instancetype)init NS_UNAVAILABLE; + +// Raises EarlGrey exception if |error| argument is not nil. +// |error.localizedDescription| is used as exception reason. +// Invoked by EG_TEST_HELPER_ASSERT_NO_ERROR macro and must not be called +// directly. +- (void)failWithError:(NSError*)error expression:(NSString*)expression; + +// Raises EarlGrey exception if |fail| argument is YES. +// |description| is used as exception reason. +// Invoked by EG_TEST_HELPER_ASSERT_TRUE macro and must not be called +// directly. +- (void)fail:(BOOL)fail + expression:(NSString*)expression + description:(NSString*)description; + +@end + +#endif // IOS_TESTING_EARL_GREY_BASE_EG_TEST_HELPER_IMPL_H_
diff --git a/ios/testing/earl_grey/base_eg_test_helper_impl.mm b/ios/testing/earl_grey/base_eg_test_helper_impl.mm new file mode 100644 index 0000000..a48d550 --- /dev/null +++ b/ios/testing/earl_grey/base_eg_test_helper_impl.mm
@@ -0,0 +1,64 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/testing/earl_grey/base_eg_test_helper_impl.h" + +#include "ios/testing/earl_grey/earl_grey_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation BaseEGTestHelperImpl { + // Used to raise EarlGrey exception with specific file name and line number. + EarlGreyImpl* _impl; +} + ++ (instancetype)invokedFromFile:(NSString*)fileName lineNumber:(int)lineNumber { + EarlGreyImpl* impl = [EarlGreyImpl invokedFromFile:fileName + lineNumber:lineNumber]; + return [[[self class] alloc] initWithImpl:impl]; +} + +- (instancetype)initWithImpl:(EarlGreyImpl*)impl { + self = [super init]; + if (self) { + _impl = impl; + } + return self; +} + +- (void)failWithError:(NSError*)error expression:(NSString*)expression { + if (!error) + return; + + NSString* name = [NSString stringWithFormat:@"%@ helper error", [self class]]; + NSString* reason = + [NSString stringWithFormat:@"%@ expression returned error: '%@'", + expression, error.localizedDescription]; + [self failWithExceptionName:name reason:reason]; +} + +#pragma mark - Private + +- (void)fail:(BOOL)fail + expression:(NSString*)expression + description:(NSString*)description { + if (!fail) + return; + + NSString* reason = + [NSString stringWithFormat:@"%@ is false: %@", expression, description]; + [self failWithExceptionName:@"expression error" reason:reason]; +} + +#pragma mark - Private + +- (void)failWithExceptionName:(NSString*)name reason:(NSString*)reason { + GREYFrameworkException* exception = + [GREYFrameworkException exceptionWithName:name reason:reason]; + [_impl handleException:exception details:@""]; +} + +@end
diff --git a/ios/web/find_in_page/find_in_page_constants.h b/ios/web/find_in_page/find_in_page_constants.h index 541a208..51e8928 100644 --- a/ios/web/find_in_page/find_in_page_constants.h +++ b/ios/web/find_in_page/find_in_page_constants.h
@@ -13,6 +13,12 @@ extern const char kFindInPagePump[]; // The name of JavaScript function which selects and scrolls to a match. extern const char kFindInPageSelectAndScrollToMatch[]; +// Dictionary key that holds value of updated match count in +// kFindInPageSelectAndScrollToMatch response. +extern const char kSelectAndScrollResultMatches[]; +// Dictionary key that holds value of currently selected index in +// kFindInPageSelectAndScrollToMatch resoonse. +extern const char kSelectAndScrollResultIndex[]; // The name of JavaScript function which stops Find in Page. extern const char kFindInPageStop[];
diff --git a/ios/web/find_in_page/find_in_page_constants.mm b/ios/web/find_in_page/find_in_page_constants.mm index 3b5d6fdd..98bb4228 100644 --- a/ios/web/find_in_page/find_in_page_constants.mm +++ b/ios/web/find_in_page/find_in_page_constants.mm
@@ -17,6 +17,10 @@ const char kFindInPageSelectAndScrollToMatch[] = "findInPage.selectAndScrollToMatch"; +const char kSelectAndScrollResultMatches[] = "matches"; + +const char kSelectAndScrollResultIndex[] = "index"; + const char kFindInPageStop[] = "findInPage.stop"; } // namespace web
diff --git a/ios/web/find_in_page/find_in_page_manager_impl.h b/ios/web/find_in_page/find_in_page_manager_impl.h index 9265b1e..4db0d99 100644 --- a/ios/web/find_in_page/find_in_page_manager_impl.h +++ b/ios/web/find_in_page/find_in_page_manager_impl.h
@@ -47,6 +47,8 @@ // Returns the index of the currently selected match for all matches on the // page. If no match is selected, then returns -1. int GetCurrentSelectedMatchIndex(); + // Gets the number of matches in |selected_frame_id|. + int GetMatchCountForSelectedFrame(); // Sets |selected_frame_id| and |selected_match_index_in_selected_frame| to // the first match on the page. No-op if no known matches exist. Returns // true if selected a match, false otherwise. @@ -64,6 +66,8 @@ // |web_frame| contains currently selected match. |web_frame| must not be // null. void RemoveFrame(WebFrame* web_frame); + // Sets |match_count| for |selected_frame_id|. + void SetMatchCountForSelectedFrame(int match_count); // Unique identifier for each find used to check that it is the most recent // find. This ensures that an old find doesn't decrement // |pending_frame_calls_count| after it has been reset by the new find. @@ -113,7 +117,7 @@ // Calls delegate DidSelectMatch() method to pass back index selected if // |delegate_| is set. |result| is a byproduct of using base::BindOnce() to // call this method after making a web_frame->CallJavaScriptFunction() call. - void NotifyDelegateDidSelectMatch(const base::Value* result); + void SelectDidFinish(const base::Value* result); // Executes highlightResult() JavaScript function in frame which contains the // currently selected match. void SelectCurrentMatch();
diff --git a/ios/web/find_in_page/find_in_page_manager_impl.mm b/ios/web/find_in_page/find_in_page_manager_impl.mm index 2345760..962072b 100644 --- a/ios/web/find_in_page/find_in_page_manager_impl.mm +++ b/ios/web/find_in_page/find_in_page_manager_impl.mm
@@ -19,8 +19,7 @@ #error "This file requires ARC support." #endif -namespace web { - +namespace { // Timeout for the find within JavaScript in milliseconds. const double kFindInPageFindTimeout = 100.0; @@ -32,6 +31,9 @@ // restart again. If this timeout hits, then something went wrong with the find // and find in page should not continue. const double kJavaScriptFunctionCallTimeout = 200.0; +} // namespace + +namespace web { // static FindInPageManagerImpl::FindInPageManagerImpl(WebState* web_state) @@ -99,6 +101,10 @@ return total_match_index; } +int FindInPageManagerImpl::FindRequest::GetMatchCountForSelectedFrame() { + return frame_match_count[*selected_frame_id]; +} + bool FindInPageManagerImpl::FindRequest::GoToFirstMatch() { for (auto frame_id = frame_order.begin(); frame_id != frame_order.end(); ++frame_id) { @@ -187,6 +193,11 @@ frame_match_count.erase(web_frame->GetFrameId()); } +void FindInPageManagerImpl::FindRequest::SetMatchCountForSelectedFrame( + int match_count) { + frame_match_count[*selected_frame_id] = match_count; +} + bool FindInPageManagerImpl::FindRequest::IsSelectedFrame(WebFrame* web_frame) { if (selected_frame_id == frame_order.end()) { return false; @@ -360,8 +371,28 @@ } } -void FindInPageManagerImpl::NotifyDelegateDidSelectMatch( - const base::Value* result) { +void FindInPageManagerImpl::SelectDidFinish(const base::Value* result) { + if (result && result->is_dict()) { + // Get updated match count. + const base::Value* matches = result->FindKey(kSelectAndScrollResultMatches); + if (matches && matches->is_double()) { + int match_count = static_cast<int>(matches->GetDouble()); + if (match_count != last_find_request_.GetMatchCountForSelectedFrame()) { + last_find_request_.SetMatchCountForSelectedFrame(match_count); + if (delegate_) { + delegate_->DidHighlightMatches( + web_state_, last_find_request_.GetTotalMatchCount(), + last_find_request_.query); + } + } + } + // Get updated currently selected index. + const base::Value* index = result->FindKey(kSelectAndScrollResultIndex); + if (index && index->is_double()) { + int current_index = static_cast<int>(index->GetDouble()); + last_find_request_.selected_match_index_in_selected_frame = current_index; + } + } if (delegate_) { delegate_->DidSelectMatch( web_state_, last_find_request_.GetCurrentSelectedMatchIndex()); @@ -389,7 +420,7 @@ base::Value(last_find_request_.selected_match_index_in_selected_frame)); frame->CallJavaScriptFunction( kFindInPageSelectAndScrollToMatch, params, - base::BindOnce(&FindInPageManagerImpl::NotifyDelegateDidSelectMatch, + base::BindOnce(&FindInPageManagerImpl::SelectDidFinish, weak_factory_.GetWeakPtr()), base::TimeDelta::FromMilliseconds(kJavaScriptFunctionCallTimeout)); }
diff --git a/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm b/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm index 179c9f06..f3c20ae13 100644 --- a/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm +++ b/ios/web/find_in_page/find_in_page_manger_impl_unittest.mm
@@ -647,4 +647,33 @@ EXPECT_FALSE(fake_delegate_.state()->query); } +// Tests that Find in Page responds with an updated match count when calling +// FindInPageNext after the visible match count in a frame changes following a +// FindInPageSearch. This simulates a once hidden match becoming visible between +// a FindInPageSearch and a FindInPageNext. +TEST_F(FindInPageManagerImplTest, FindInPageNextUpdatesMatchCount) { + auto frame_with_hidden_match = CreateMainWebFrameWithJsResultForFind( + std::make_unique<base::Value>(2.0), "frame_with_hidden_match"); + FakeWebFrame* frame_with_hidden_match_ptr = frame_with_hidden_match.get(); + test_web_state_->AddWebFrame(std::move(frame_with_hidden_match)); + + GetFindInPageManager()->Find(@"foo", FindInPageOptions::FindInPageSearch); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^bool { + base::RunLoop().RunUntilIdle(); + return fake_delegate_.state() && fake_delegate_.state()->match_count == 2; + })); + auto select_and_scroll_result = std::make_unique<base::DictionaryValue>(); + select_and_scroll_result->SetDouble("matches", 3.0); + select_and_scroll_result->SetDouble("index", 1.0); + frame_with_hidden_match_ptr->AddJsResultForFunctionCall( + std::move(select_and_scroll_result), kFindInPageSelectAndScrollToMatch); + + GetFindInPageManager()->Find(@"foo", FindInPageOptions::FindInPageNext); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^bool { + base::RunLoop().RunUntilIdle(); + return fake_delegate_.state() && fake_delegate_.state()->match_count == 3; + })); + EXPECT_EQ(1, fake_delegate_.state()->index); +} + } // namespace web
diff --git a/ios/web/navigation/error_retry_state_machine.h b/ios/web/navigation/error_retry_state_machine.h index cb1dad8..3e7d6d3 100644 --- a/ios/web/navigation/error_retry_state_machine.h +++ b/ios/web/navigation/error_retry_state_machine.h
@@ -62,7 +62,10 @@ kReload, // WebView should rewrite its URL (assumed to be a placeholder URL) to the // navigation item's URL to prepare for reload. - kRewriteWebViewURL, + kRewriteToWebViewURL, + // WebView should rewrite its URL to a placeholder URL to prepare for loading + // the error view. + kRewriteToPlaceholderURL, // WebView doesn't need to do anything. kDoNothing, };
diff --git a/ios/web/navigation/error_retry_state_machine.mm b/ios/web/navigation/error_retry_state_machine.mm index 4f48bba90..d711df2 100644 --- a/ios/web/navigation/error_retry_state_machine.mm +++ b/ios/web/navigation/error_retry_state_machine.mm
@@ -80,8 +80,13 @@ // Retry of a previous failure still fails. case ErrorRetryState::kDisplayingWebErrorForFailedNavigation: if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { + // In this case, a back/forward item already exists. Rewriting the + // WebView's URL to the placeholder URL before loading the error page + // ensures that WebKit doesn't associate the (empty) contents of an + // immediately-preceding kRewriteToWebViewURL step with the actual URL + // in its page cache. See http://crbug.com/950489. state_ = ErrorRetryState::kLoadingPlaceholder; - return ErrorRetryCommand::kLoadPlaceholder; + return ErrorRetryCommand::kRewriteToPlaceholderURL; } else { return BackForwardOrReloadFailed(web_view_url, error_url); } @@ -140,9 +145,9 @@ DCHECK_EQ(web_view_url, wk_navigation_util::CreatePlaceholderUrlForUrl(url_)); state_ = ErrorRetryState::kRetryPlaceholderNavigation; - return ErrorRetryCommand::kRewriteWebViewURL; + return ErrorRetryCommand::kRewriteToWebViewURL; } else { - // The url was written by kRewriteWebViewURL in the if block, so on + // The url was written by kRewriteToWebViewURL in the if block, so on // this navigation load an error view. state_ = ErrorRetryState::kReadyToDisplayErrorForFailedNavigation; return ErrorRetryCommand::kLoadErrorView; @@ -170,7 +175,7 @@ // (4) Back/forward to or reload of placeholder URL. Rewrite WebView URL // to prepare for retry. state_ = ErrorRetryState::kNavigatingToFailedNavigationItem; - return ErrorRetryCommand::kRewriteWebViewURL; + return ErrorRetryCommand::kRewriteToWebViewURL; } if (wk_navigation_util::IsRestoreSessionUrl(web_view_url)) {
diff --git a/ios/web/navigation/error_retry_state_machine_unittest.mm b/ios/web/navigation/error_retry_state_machine_unittest.mm index e08e16c..c58016f7 100644 --- a/ios/web/navigation/error_retry_state_machine_unittest.mm +++ b/ios/web/navigation/error_retry_state_machine_unittest.mm
@@ -48,7 +48,7 @@ machine.state()); // Reload the failed navigation. - ASSERT_EQ(ErrorRetryCommand::kRewriteWebViewURL, + ASSERT_EQ(ErrorRetryCommand::kRewriteToWebViewURL, machine.DidFinishNavigation(placeholder_url)); ASSERT_EQ(ErrorRetryState::kNavigatingToFailedNavigationItem, machine.state()); @@ -69,7 +69,7 @@ { ErrorRetryStateMachine clone(machine); if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { - ASSERT_EQ(ErrorRetryCommand::kLoadPlaceholder, + ASSERT_EQ(ErrorRetryCommand::kRewriteToPlaceholderURL, clone.DidFailProvisionalNavigation(test_url, test_url)); ASSERT_EQ(ErrorRetryState::kLoadingPlaceholder, clone.state()); } else { @@ -128,7 +128,7 @@ // Back-forward navigation to failed navigation rewrites Web View URL. { ErrorRetryStateMachine clone(machine); - ASSERT_EQ(ErrorRetryCommand::kRewriteWebViewURL, + ASSERT_EQ(ErrorRetryCommand::kRewriteToWebViewURL, clone.DidFinishNavigation(placeholder_url)); ASSERT_EQ(ErrorRetryState::kNavigatingToFailedNavigationItem, clone.state()); @@ -138,7 +138,7 @@ { ErrorRetryStateMachine clone(machine); if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { - ASSERT_EQ(ErrorRetryCommand::kLoadPlaceholder, + ASSERT_EQ(ErrorRetryCommand::kRewriteToPlaceholderURL, clone.DidFailProvisionalNavigation(test_url, test_url)); ASSERT_EQ(ErrorRetryState::kLoadingPlaceholder, clone.state()); } else { @@ -207,7 +207,7 @@ { ErrorRetryStateMachine clone(machine); if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { - ASSERT_EQ(ErrorRetryCommand::kLoadPlaceholder, + ASSERT_EQ(ErrorRetryCommand::kRewriteToPlaceholderURL, clone.DidFailProvisionalNavigation(test_url, test_url)); ASSERT_EQ(ErrorRetryState::kLoadingPlaceholder, clone.state()); } else { @@ -264,7 +264,7 @@ // Then trigger a retry. machine.SetRetryPlaceholderNavigation(); - ASSERT_EQ(ErrorRetryCommand::kRewriteWebViewURL, + ASSERT_EQ(ErrorRetryCommand::kRewriteToWebViewURL, machine.DidFinishNavigation(placeholder_url)); ASSERT_EQ(ErrorRetryState::kRetryPlaceholderNavigation, machine.state());
diff --git a/ios/web/shell/test/BUILD.gn b/ios/web/shell/test/BUILD.gn index c39e898..6e4dc2d 100644 --- a/ios/web/shell/test/BUILD.gn +++ b/ios/web/shell/test/BUILD.gn
@@ -56,6 +56,7 @@ deps = [ "//base", "//base/test:test_support", + "//ios/testing:nserror_support", "//ios/testing/earl_grey:earl_grey_support", "//ios/third_party/earl_grey:earl_grey+link", "//ios/web", @@ -126,6 +127,7 @@ deps = [ "//base", "//base/test:test_support", + "//ios/testing:nserror_support", "//ios/testing/earl_grey:eg_app_support+eg2", "//ios/third_party/earl_grey2:app_framework+link", "//ios/web", @@ -162,6 +164,7 @@ deps = [ "//base", "//base/test:test_support", + "//ios/testing:nserror_support", "//ios/testing/earl_grey:eg_test_support+eg2", "//ios/third_party/earl_grey2:test_lib", "//ios/web/public/test:element_selector",
diff --git a/ios/web/shell/test/context_menu_egtest.mm b/ios/web/shell/test/context_menu_egtest.mm index 747845e..3f69c568 100644 --- a/ios/web/shell/test/context_menu_egtest.mm +++ b/ios/web/shell/test/context_menu_egtest.mm
@@ -47,14 +47,11 @@ // Tests context menu appears on a regular link. - (void)testContextMenu { const char linkID[] = "normal-link"; - const char linkText[] = "normal-link-text"; + NSString* const linkText = @"normal-link-text"; const GURL pageURL = _server.GetURL(kHtmlFile); - bool success = shell_test_util::LoadUrl(pageURL); - GREYAssert(success, @"Page did not complete loading."); - - success = shell_test_util::WaitForWebViewContainingText(linkText); - GREYAssert(success, @"Failed waiting for web view containing '%s'", linkText); + [ShellEarlGrey loadURL:pageURL]; + [ShellEarlGrey waitForWebStateContainingText:linkText]; [[EarlGrey selectElementWithMatcher:web::WebView()] performAction:web::LongPressElementForContextMenu( @@ -78,13 +75,11 @@ // ancestor and overridden. - (void)testContextMenuWebkitTouchCalloutOverride { const char linkID[] = "no-webkit-link"; - const char linkText[] = "no-webkit-link-text"; + NSString* const linkText = @"no-webkit-link-text"; const GURL pageURL = _server.GetURL(kHtmlFile); - bool success = shell_test_util::LoadUrl(pageURL); - GREYAssert(success, @"Page did not complete loading."); - success = shell_test_util::WaitForWebViewContainingText(linkText); - GREYAssert(success, @"Failed waiting for web view containing '%s'", linkText); + [ShellEarlGrey loadURL:pageURL]; + [ShellEarlGrey waitForWebStateContainingText:linkText]; [[EarlGrey selectElementWithMatcher:web::WebView()] performAction:web::LongPressElementForContextMenu(
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey.h b/ios/web/shell/test/earl_grey/shell_earl_grey.h index b19ae4f..0a7fba55 100644 --- a/ios/web/shell/test/earl_grey/shell_earl_grey.h +++ b/ios/web/shell/test/earl_grey/shell_earl_grey.h
@@ -7,24 +7,38 @@ #import <Foundation/Foundation.h> -#include "ios/web/public/test/element_selector.h" +#import "ios/testing/earl_grey/base_eg_test_helper_impl.h" #include "url/gurl.h" -// Test methods that perform actions on Web Shell. These methods may read or -// alter Web Shell's internal state programmatically or via the UI, but in both -// cases will properly synchronize the UI for Earl Grey tests. -namespace shell_test_util { +// Public macro to invoke helper methods in test methods (Test Process). Usage +// example: +// +// @interface PageLoadTestCase : XCTestCase +// @end +// @implementation PageLoadTestCase +// - (void)testPageload { +// [ShellEarlGrey loadURL:GURL("https://chromium.org")]; +// } +// +// In this example ShellEarlGreyImpl must implement -loadURL:. +// +#define ShellEarlGrey \ + [ShellEarlGreyImpl invokedFromFile:@"" __FILE__ lineNumber:__LINE__] + +// Used for logging the failure. Compiled in Test Process for EG2 and EG1. Can +// be extended with category methods to provide additional test helpers. +// Category method names must be unique. +@interface ShellEarlGreyImpl : BaseEGTestHelperImpl // Loads |URL| in the current WebState with transition of type -// ui::PAGE_TRANSITION_TYPED, and waits for the page to complete loading, or -// a timeout. Returns false if the page doesn't finish loading, true if it -// does. -bool LoadUrl(const GURL& url) WARN_UNUSED_RESULT; +// ui::PAGE_TRANSITION_TYPED and waits for the loading to complete. Raises +// EarlGrey exception if load does not complete within a timeout. +- (void)loadURL:(const GURL&)URL; -// Waits for the current web view to contain |text|. If the condition is not met -// within a timeout, it returns false, otherwise, true. -bool WaitForWebViewContainingText(const std::string& text) WARN_UNUSED_RESULT; +// Waits for the current web view to contain |text|. Raises EarlGrey exception +// if the content does not show up within a timeout. +- (void)waitForWebStateContainingText:(NSString*)text; -} // namespace shell_test_util +@end #endif // IOS_WEB_SHELL_TEST_EARL_GREY_SHELL_EARL_GREY_H_
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey.mm b/ios/web/shell/test/earl_grey/shell_earl_grey.mm index f511bd3..dc22b34 100644 --- a/ios/web/shell/test/earl_grey/shell_earl_grey.mm +++ b/ios/web/shell/test/earl_grey/shell_earl_grey.mm
@@ -21,35 +21,43 @@ GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(ShellEarlGreyAppInterface) #endif -namespace shell_test_util { +@implementation ShellEarlGreyImpl -bool LoadUrl(const GURL& url) { - [ShellEarlGreyAppInterface loadURL:base::SysUTF8ToNSString(url.spec())]; +- (void)loadURL:(const GURL&)URL { + NSString* spec = base::SysUTF8ToNSString(URL.spec()); + [ShellEarlGreyAppInterface loadURL:spec]; - bool load_success = WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ - return ![ShellEarlGreyAppInterface isCurrentWebStateLoading]; - }); - if (!load_success) { - return false; - } + NSString* loadingErrorDescription = [NSString + stringWithFormat:@"Current WebState did not finish loading %@ URL", spec]; + GREYCondition* condition = [GREYCondition + conditionWithName:loadingErrorDescription + block:^{ + return ! + [ShellEarlGreyAppInterface isCurrentWebStateLoading]; + }]; + BOOL pageLoaded = [condition waitWithTimeout:kWaitForPageLoadTimeout]; + EG_TEST_HELPER_ASSERT_TRUE(pageLoaded, loadingErrorDescription); - bool injection_success = - [ShellEarlGreyAppInterface waitForWindowIDInjectedInCurrentWebState]; - if (!injection_success) { - return false; - } + EG_TEST_HELPER_ASSERT_NO_ERROR( + [ShellEarlGreyAppInterface waitForWindowIDInjectedInCurrentWebState]); // Ensure any UI elements handled by EarlGrey become idle for any subsequent // EarlGrey steps. [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; - return true; } -bool WaitForWebViewContainingText(const std::string& text) { - return WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^bool { - return [ShellEarlGreyAppInterface - currentWebStateContainsText:base::SysUTF8ToNSString(text)]; - }); +- (void)waitForWebStateContainingText:(NSString*)text { + NSString* description = [NSString + stringWithFormat:@"Current WebState does not contain: '%@'", text]; + GREYCondition* condition = + [GREYCondition conditionWithName:description + block:^{ + return [ShellEarlGreyAppInterface + currentWebStateContainsText:text]; + }]; + + BOOL containsText = [condition waitWithTimeout:kWaitForPageLoadTimeout]; + EG_TEST_HELPER_ASSERT_TRUE(containsText, description); } -} // namespace shell_test_util +@end
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h index 03eb265..91fa7e5 100644 --- a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h +++ b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h
@@ -21,10 +21,11 @@ // Returns YES if the current WebState is loading. + (BOOL)isCurrentWebStateLoading WARN_UNUSED_RESULT; -// Returns YES if the windowID has been injected into the current web state. If -// the WebState contains content that does not require windowID injection, -// returns YES immediately. -+ (BOOL)waitForWindowIDInjectedInCurrentWebState WARN_UNUSED_RESULT; +// Waits until the windowID is injected into the current web state. Returns nil +// on success, or else an NSError indicating why the operation failed. +// Immediately returns if the WebState contains content that does not require +// windowID injection. ++ (NSError*)waitForWindowIDInjectedInCurrentWebState WARN_UNUSED_RESULT; // Returns YES if the current WebState contains the given |text|. + (BOOL)currentWebStateContainsText:(NSString*)text WARN_UNUSED_RESULT;
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm index 66c37e0..8c914536 100644 --- a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm +++ b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm
@@ -7,6 +7,7 @@ #import "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" #import "ios/testing/earl_grey/earl_grey_app.h" +#import "ios/testing/nserror_util.h" #import "ios/web/public/test/earl_grey/js_test_util.h" #import "ios/web/public/test/navigation_test_util.h" #import "ios/web/public/test/web_view_content_test_util.h" @@ -29,8 +30,16 @@ return GetCurrentWebState()->IsLoading(); } -+ (BOOL)waitForWindowIDInjectedInCurrentWebState { - return web::WaitUntilWindowIdInjected(GetCurrentWebState()); ++ (NSError*)waitForWindowIDInjectedInCurrentWebState { + web::WebState* webState = GetCurrentWebState(); + if (web::WaitUntilWindowIdInjected(webState)) + return nil; + + NSString* description = [NSString + stringWithFormat:@"WindowID failed to inject into the page with URL: %s", + webState->GetLastCommittedURL().spec().c_str()]; + + return testing::NSErrorWithLocalizedDescription(description); } + (BOOL)currentWebStateContainsText:(NSString*)text {
diff --git a/ios/web/shell/test/page_state_egtest.mm b/ios/web/shell/test/page_state_egtest.mm index 76e73b0..ac860c9 100644 --- a/ios/web/shell/test/page_state_egtest.mm +++ b/ios/web/shell/test/page_state_egtest.mm
@@ -54,8 +54,7 @@ // be {0, 0} before returning. void ScrollLongPageToTop(const GURL& url) { // Load the page and swipe down. - bool success = shell_test_util::LoadUrl(url); - GREYAssert(success, @"Page did not complete loading."); + [ShellEarlGrey loadURL:url]; [[EarlGrey selectElementWithMatcher:web::WebViewScrollView()] performAction:grey_scrollToContentEdge(kGREYContentEdgeTop)]; // Waits for the {0, 0} offset. @@ -112,8 +111,7 @@ - (void)testZeroContentOffsetAfterLoad { // Set up the file-based server to load the tall page. const GURL baseURL = _server.GetURL(kLongPage1); - bool success = shell_test_util::LoadUrl(baseURL); - GREYAssert(success, @"Page did not complete loading."); + [ShellEarlGrey loadURL:baseURL]; // Scroll the page and load again to verify that the new page's scroll offset // is reset to {0, 0}. @@ -126,9 +124,7 @@ // Add a query parameter so the next load creates another NavigationItem. GURL::Replacements replacements; replacements.SetQueryStr(base::NumberToString(i)); - bool success = - shell_test_util::LoadUrl(baseURL.ReplaceComponents(replacements)); - GREYAssert(success, @"Page did not complete loading."); + [ShellEarlGrey loadURL:baseURL.ReplaceComponents(replacements)]; // Wait for the content offset to be set to {0, 0}. WaitForOffset(0.0); }
diff --git a/ios/web/web_state/error_page_inttest.mm b/ios/web/web_state/error_page_inttest.mm index bb21184..bd60808 100644 --- a/ios/web/web_state/error_page_inttest.mm +++ b/ios/web/web_state/error_page_inttest.mm
@@ -161,6 +161,33 @@ ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "Echo")); } +// Tests that reloading a page that is no longer accessible doesn't destroy +// forward history. +TEST_P(ErrorPageTest, ReloadOfflinePage) { + server_responds_with_content_ = true; + + test::LoadUrl(web_state(), server_.GetURL("/echo-query?foo")); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "foo")); + + test::LoadUrl(web_state(), server_.GetURL("/echoall?bar")); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "bar")); + + web_state()->GetNavigationManager()->GoBack(); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "foo")); + + server_responds_with_content_ = false; + web_state()->GetNavigationManager()->Reload(ReloadType::NORMAL, + /*check_for_repost=*/false); + + ASSERT_TRUE(WaitForErrorText(web_state(), server_.GetURL("/echo-query?foo"))); + server_responds_with_content_ = true; + + // Make sure that forward history hasn't been destroyed. + ASSERT_TRUE(web_state()->GetNavigationManager()->CanGoForward()); + web_state()->GetNavigationManager()->GoForward(); + ASSERT_TRUE(test::WaitForWebViewContainingText(web_state(), "bar")); +} + // Loads the URL which fails to load, then sucessfully reloads the page. TEST_P(ErrorPageTest, ReloadErrorPage) { // No response leads to -1005 error code.
diff --git a/ios/web/web_state/js/find_in_page_js_unittest.mm b/ios/web/web_state/js/find_in_page_js_unittest.mm index 0e87195..6263add 100644 --- a/ios/web/web_state/js/find_in_page_js_unittest.mm +++ b/ios/web/web_state/js/find_in_page_js_unittest.mm
@@ -492,4 +492,108 @@ EXPECT_FALSE([inner_html containsString:@"chrome_find"]); } +// Tests that FindInPage only selects the visible match when there is also a +// hidden match. +TEST_F(FindInPageJsTest, HiddenMatch) { + ASSERT_TRUE( + LoadHtml("<span style='display:none'>foo</span><span>foo bar</span>")); + const base::TimeDelta kCallJavascriptFunctionTimeout = + base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ + return frames_manager()->GetAllWebFrames().size() == 1; + })); + __block bool message_received = false; + std::vector<base::Value> params; + params.push_back(base::Value(kFindStringFoo)); + params.push_back(base::Value(kPumpSearchTimeout)); + main_web_frame()->CallJavaScriptFunction( + kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) { + ASSERT_TRUE(result); + ASSERT_TRUE(result->is_double()); + double count = result->GetDouble(); + ASSERT_EQ(1.0, count); + message_received = true; + }), + kCallJavascriptFunctionTimeout); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ + return message_received; + })); + + message_received = false; + std::vector<base::Value> highlight_params; + highlight_params.push_back(base::Value(0)); + main_web_frame()->CallJavaScriptFunction( + kFindInPageSelectAndScrollToMatch, highlight_params, + base::BindOnce(^(const base::Value* result) { + message_received = true; + }), + kCallJavascriptFunctionTimeout); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ + base::RunLoop().RunUntilIdle(); + return message_received; + })); + + id inner_html = ExecuteJavaScript(@"document.body.innerHTML"); + ASSERT_TRUE([inner_html isKindOfClass:[NSString class]]); + NSRange visible_match = + [inner_html rangeOfString:@"find_in_page find_selected"]; + NSRange hidden_match = [inner_html rangeOfString:@"find_in_page"]; + // Assert that the selected match comes after the first match in the DOM since + // it is expected the hidden match is skipped. + EXPECT_GT(visible_match.location, hidden_match.location); +} + +// Tests that FindInPage is responds with an updated match count when a once +// hidden match becomes visible after a search finishes. +TEST_F(FindInPageJsTest, HiddenMatchBecomesVisible) { + ASSERT_TRUE( + LoadHtml("<span id=\"hidden_match\" style='display:none'>foo</span>")); + const base::TimeDelta kCallJavascriptFunctionTimeout = + base::TimeDelta::FromSeconds(kWaitForJSCompletionTimeout); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ + return frames_manager()->GetAllWebFrames().size() == 1; + })); + __block bool message_received = false; + std::vector<base::Value> params; + params.push_back(base::Value(kFindStringFoo)); + params.push_back(base::Value(kPumpSearchTimeout)); + main_web_frame()->CallJavaScriptFunction( + kFindInPageSearch, params, base::BindOnce(^(const base::Value* result) { + ASSERT_TRUE(result); + ASSERT_TRUE(result->is_double()); + double count = result->GetDouble(); + ASSERT_EQ(0.0, count); + message_received = true; + }), + kCallJavascriptFunctionTimeout); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ + return message_received; + })); + + ExecuteJavaScript( + @"document.getElementById('hidden_match').removeAttribute('style')"); + message_received = false; + std::vector<base::Value> highlight_params; + highlight_params.push_back(base::Value(0)); + main_web_frame()->CallJavaScriptFunction( + kFindInPageSelectAndScrollToMatch, highlight_params, + base::BindOnce(^(const base::Value* result) { + ASSERT_TRUE(result); + ASSERT_TRUE(result->is_dict()); + const base::Value* count = + result->FindKey(kSelectAndScrollResultMatches); + ASSERT_TRUE(count->is_double()); + ASSERT_EQ(1.0, count->GetDouble()); + const base::Value* index = result->FindKey(kSelectAndScrollResultIndex); + ASSERT_TRUE(index->is_double()); + ASSERT_EQ(0.0, index->GetDouble()); + message_received = true; + }), + kCallJavascriptFunctionTimeout); + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ + base::RunLoop().RunUntilIdle(); + return message_received; + })); +} + } // namespace web
diff --git a/ios/web/web_state/js/resources/find_in_page.js b/ios/web/web_state/js/resources/find_in_page.js index ae916b5..703d3c3c 100644 --- a/ios/web/web_state/js/resources/find_in_page.js +++ b/ios/web/web_state/js/resources/find_in_page.js
@@ -534,31 +534,41 @@ replacements_[i].doSwap(); } - // Count visible elements. + let visibleMatchCount = countVisibleMatches_(timer); + + searchInProgress_ = false; + + return visibleMatchCount; +}; + +/** + * Counts the total number of visible matches. + * @param {Timer} used to pause the counting if overall search + * has taken too long. + * @return {Number} of visible matches. + */ +function countVisibleMatches_(timer) { let max = __gCrWeb.findInPage.matches.length; let maxVisible = MAX_VISIBLE_ELEMENTS; + var currentlyVisibleMatchCount = 0; for (let index = visibleIndex_; index < max; index++) { let match = __gCrWeb.findInPage.matches[index]; - if (timer.overtime()) { + if (timer && timer.overtime()) { visibleIndex_ = index; return TIMEOUT; } // Stop after |maxVisible| elements. - if (visibleFound_ > maxVisible) { - match.visibleIndex = maxVisible; + if (currentlyVisibleMatchCount > maxVisible) { continue; } if (match.visible()) { - visibleFound_++; - match.visibleIndex = visibleFound_; + currentlyVisibleMatchCount++; } } - - searchInProgress_ = false; - - return visibleFound_; + visibleFound_ = currentlyVisibleMatchCount; + return currentlyVisibleMatchCount; }; /** @@ -584,14 +594,19 @@ }; /** - * Highlights the match at |index| and scrolls to that match. Clears currently - * highlighted match if one exists. - * @param {Number} index of match to highlight. + * Selects the match at |index| and scrolls to that match. If the match at + * |index| is hidden, the next visible match will be selected. Clears + * currently selected match if one exists. + * @param {Number} index of visible match to highlight. + * @return {Dictionary} of currently visible matches and currently selected + * match index. */ __gCrWeb.findInPage.selectAndScrollToMatch = function(index) { - if (index >= __gCrWeb.findInPage.matches.length || index < 0) { - // Do nothing if invalid index is passed. - return; + let totalMatches = __gCrWeb.findInPage.matches.length; + if (index >= totalMatches || index < 0 || index == selectedMatchIndex_) { + // Do nothing if invalid index is passed, if there are no matches, or + // if |index| is the currently selected match. + return {matches: visibleFound_, index: selectedMatchIndex_}; } // Remove previous highlight. @@ -600,10 +615,30 @@ match.removeSelectHighlight(); } + let previouslySelectedMatchIndex = selectedMatchIndex_; selectedMatchIndex_ = index; + while (!getCurrentSelectedMatch_().visible()) { + // Match at |index| is not visible. Find next visible match. + if (previouslySelectedMatchIndex == selectedMatchIndex_) { + // Checked all matches but didn't find anything else visible. + break; + } + if (previouslySelectedMatchIndex < selectedMatchIndex_) { + if (++selectedMatchIndex_ == totalMatches) { + selectedMatchIndex_ = 0; + } + } else { + if (--selectedMatchIndex_ < 0) { + selectedMatchIndex_ = totalMatches - 1; + } + } + } + // Recalculate total visible matches. + let visibleMatchCount = countVisibleMatches_(null); getCurrentSelectedMatch_().addSelectHighlight(); scrollToCurrentlySelectedMatch_(); + return {matches: visibleMatchCount, index: selectedMatchIndex_}; }; /**
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 1c1baeb..e4c4494 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2390,7 +2390,7 @@ [self.webView reload]; break; - case web::ErrorRetryCommand::kRewriteWebViewURL: { + case web::ErrorRetryCommand::kRewriteToWebViewURL: { std::unique_ptr<web::NavigationContextImpl> navigationContext = [self registerLoadRequestForURL:item->GetURL() sameDocumentNavigation:NO @@ -2407,6 +2407,21 @@ forNavigation:navigation]; } break; + case web::ErrorRetryCommand::kRewriteToPlaceholderURL: { + std::unique_ptr<web::NavigationContextImpl> originalContext = + [self.navigationHandler.navigationStates + removeNavigation:originalNavigation]; + originalContext->SetPlaceholderNavigation(YES); + GURL placeholderURL = CreatePlaceholderUrlForUrl(item->GetURL()); + + WKNavigation* navigation = + [self.webView loadHTMLString:@"" + baseURL:net::NSURLWithGURL(placeholderURL)]; + [self.navigationHandler.navigationStates + setContext:std::move(originalContext) + forNavigation:navigation]; + } break; + case web::ErrorRetryCommand::kDoNothing: NOTREACHED(); }
diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc index 4a3fa16..e17cf794 100644 --- a/media/audio/win/audio_low_latency_output_win.cc +++ b/media/audio/win/audio_low_latency_output_win.cc
@@ -12,6 +12,7 @@ #include "base/command_line.h" #include "base/logging.h" #include "base/metrics/histogram.h" +#include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" @@ -286,6 +287,8 @@ source_ = callback; num_written_frames_ = endpoint_buffer_size_frames_; + last_position_ = 0; + last_qpc_position_ = 0; // Create and start the thread that will drive the rendering by waiting for // render events. @@ -333,6 +336,8 @@ callback->OnError(); } + ReportAndResetStats(); + // Extra safety check to ensure that the buffers are cleared. // If the buffers are not cleared correctly, the next call to Start() // would fail with AUDCLNT_E_BUFFER_ERROR at IAudioRenderClient::GetBuffer(). @@ -527,6 +532,43 @@ const uint64_t played_out_frames = format_.Format.nSamplesPerSec * position / device_frequency; + // Check for glitches. Records a glitch whenever the stream's position has + // moved forward significantly less than the performance counter has. The + // threshold is set to half the buffer size, to limit false positives. + if (last_qpc_position_ != 0) { + const int64_t buffer_duration_us = packet_size_frames_ * + base::Time::kMicrosecondsPerSecond / + format_.Format.nSamplesPerSec; + + const int64_t position_us = + position * base::Time::kMicrosecondsPerSecond / device_frequency; + const int64_t last_position_us = last_position_ * + base::Time::kMicrosecondsPerSecond / + device_frequency; + // The QPC values are in 100 ns units. + const int64_t qpc_position_us = qpc_position / 10; + const int64_t last_qpc_position_us = last_qpc_position_ / 10; + + const int64_t position_diff_us = position_us - last_position_us; + const int64_t qpc_position_diff_us = + qpc_position_us - last_qpc_position_us; + + if (qpc_position_diff_us - position_diff_us > buffer_duration_us / 2) { + ++num_glitches_detected_; + + base::TimeDelta glitch_duration = base::TimeDelta::FromMicroseconds( + qpc_position_diff_us - position_diff_us); + + if (glitch_duration > largest_glitch_) + largest_glitch_ = glitch_duration; + + cumulative_audio_lost_ += glitch_duration; + } + } + + last_position_ = position; + last_qpc_position_ = qpc_position; + // Number of frames that have been written to the buffer but not yet // played out. const uint64_t delay_frames = num_written_frames_ - played_out_frames; @@ -667,4 +709,21 @@ source_ = NULL; } +void WASAPIAudioOutputStream::ReportAndResetStats() { + // Even if there aren't any glitches, we want to record it to get a feel for + // how often we get no glitches vs the alternative. + UMA_HISTOGRAM_CUSTOM_COUNTS("Media.Audio.Render.Glitches", + num_glitches_detected_, 1, 999999, 100); + // Don't record these unless there actually was a glitch, though. + if (num_glitches_detected_ != 0) { + UMA_HISTOGRAM_COUNTS_1M("Media.Audio.Render.LostFramesInMs", + cumulative_audio_lost_.InMilliseconds()); + UMA_HISTOGRAM_COUNTS_1M("Media.Audio.Render.LargestGlitchMs", + largest_glitch_.InMilliseconds()); + } + num_glitches_detected_ = 0; + cumulative_audio_lost_ = base::TimeDelta(); + largest_glitch_ = base::TimeDelta(); +} + } // namespace media
diff --git a/media/audio/win/audio_low_latency_output_win.h b/media/audio/win/audio_low_latency_output_win.h index ad70b39..4865a9d6 100644 --- a/media/audio/win/audio_low_latency_output_win.h +++ b/media/audio/win/audio_low_latency_output_win.h
@@ -170,6 +170,9 @@ // |source_| is set to NULL. void StopThread(); + // Reports audio stream glitch stats and resets them to their initial values. + void ReportAndResetStats(); + // Contains the thread ID of the creating thread. const base::PlatformThreadId creating_thread_id_; @@ -220,6 +223,21 @@ // Counts the number of audio frames written to the endpoint buffer. UINT64 num_written_frames_; + // The position read during the last call to RenderAudioFromSource + UINT64 last_position_ = 0; + + // The performance counter read during the last call to RenderAudioFromSource + UINT64 last_qpc_position_ = 0; + + // The number of glitches detected while this stream was active. + int num_glitches_detected_ = 0; + + // The approximate amount of audio lost due to glitches. + base::TimeDelta cumulative_audio_lost_; + + // The largest single glitch recorded. + base::TimeDelta largest_glitch_; + // Pointer to the client that will deliver audio samples to be played out. AudioSourceCallback* source_;
diff --git a/media/capture/video/video_frame_receiver_on_task_runner.cc b/media/capture/video/video_frame_receiver_on_task_runner.cc index 7f6bb4b..fc761bcb 100644 --- a/media/capture/video/video_frame_receiver_on_task_runner.cc +++ b/media/capture/video/video_frame_receiver_on_task_runner.cc
@@ -20,9 +20,8 @@ int buffer_id, media::mojom::VideoBufferHandlePtr buffer_handle) { task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&VideoFrameReceiver::OnNewBuffer, receiver_, buffer_id, - base::Passed(std::move(buffer_handle)))); + FROM_HERE, base::BindOnce(&VideoFrameReceiver::OnNewBuffer, receiver_, + buffer_id, std::move(buffer_handle))); } void VideoFrameReceiverOnTaskRunner::OnFrameReadyInBuffer(
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl index 3f9e8ab5..007e89e 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl
@@ -67,7 +67,7 @@ #include "mojo/public/cpp/bindings/lib/native_struct_serialization.h" {%- endif %} -{%- if export_header %} +{%- if export_header and module.constants|length %} #include "{{export_header}}" {%- endif %}
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 73f36b5..f6f25ecf 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -601,22 +601,15 @@ // Generate a key that can be used inside the cache. std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) { - // Strip out the reference, username, and password sections of the URL. - std::string url; + // TODO(crbug.com/950069): Sending an empty initiator origin now. + // This call will eventually be removed and ComputeCacheKey will be invoked at + // a higher layer before we start using the initiator. + std::string cache_key = HttpUtil::ComputeCacheKey( + request->top_frame_origin, base::Optional<url::Origin>()); - // If we're splitting the cache by top frame origin, then prefix the key with - // the origin. - if (request->top_frame_origin && - base::FeatureList::IsEnabled(features::kSplitCacheByTopFrameOrigin)) { - // Prepend the key with "_dk_" to mark it as double keyed (and makes it an - // invalid url so that it doesn't get confused with a single-keyed - // entry). Separate the origin and url with invalid whitespace and control - // characters. - url = base::StrCat({"_dk_", request->top_frame_origin->Serialize(), " \n", - HttpUtil::SpecForRequest(request->url)}); - } else { - url = HttpUtil::SpecForRequest(request->url); - } + // Strip out the reference, username, and password sections of the URL and + // concatenate with the cache_key if we are splitting the cache. + std::string url = cache_key + HttpUtil::SpecForRequest(request->url); DCHECK_NE(DISABLE, mode_); // No valid URL can begin with numerals, so we should not have to worry
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index edfd15f0..010c62a 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -709,11 +709,7 @@ rv = DoCreateStream(); break; case STATE_CREATE_STREAM_COMPLETE: - // TODO(zhongyi): remove liveness checks when crbug.com/652868 is - // solved. - net_log_.CrashIfInvalid(); rv = DoCreateStreamComplete(rv); - net_log_.CrashIfInvalid(); break; case STATE_INIT_STREAM: DCHECK_EQ(OK, rv);
diff --git a/net/http/http_request_info.h b/net/http/http_request_info.h index 3ebd61b..aa3066c 100644 --- a/net/http/http_request_info.h +++ b/net/http/http_request_info.h
@@ -60,6 +60,9 @@ // If the request is a Reporting upload, the depth is the max of the depth // of the requests reported within it plus 1. int reporting_upload_depth; + + // Key to be used for partitioning the HTTP cache. + std::string cache_key; }; } // namespace net
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h index 3b3247a..067b6e5 100644 --- a/net/http/http_stream_factory.h +++ b/net/http/http_stream_factory.h
@@ -26,7 +26,6 @@ #include "net/base/request_priority.h" #include "net/http/http_request_info.h" #include "net/http/http_server_properties.h" -#include "net/http/http_stream_factory.h" #include "net/http/http_stream_request.h" #include "net/log/net_log_source.h" #include "net/log/net_log_with_source.h"
diff --git a/net/http/http_util.cc b/net/http/http_util.cc index 1d2251e..db5611f 100644 --- a/net/http/http_util.cc +++ b/net/http/http_util.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/stl_util.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" @@ -18,6 +19,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" +#include "net/base/features.h" #include "net/base/url_util.h" namespace net { @@ -1220,4 +1222,25 @@ return true; } +std::string HttpUtil::ComputeCacheKey( + const base::Optional<url::Origin>& top_frame_origin, + const base::Optional<url::Origin>& initiator) { + std::string cache_key; + + if (!base::FeatureList::IsEnabled(features::kSplitCacheByTopFrameOrigin)) + return cache_key; + + if (top_frame_origin) { + // Prepend the key with "_dk_" to mark it as double keyed (and makes it an + // invalid url so that it doesn't get confused with a single-keyed + // entry). Separate the origin and url with invalid whitespace and control + // characters. + cache_key = base::StrCat({"_dk_", top_frame_origin->Serialize(), " \n"}); + } + + // TODO(crbug.com/950069): Use initiator for experimenting the split cache + // using both top frame and initiator origins. + return cache_key; +} + } // namespace net
diff --git a/net/http/http_util.h b/net/http/http_util.h index 1880257..a37d458 100644 --- a/net/http/http_util.h +++ b/net/http/http_util.h
@@ -21,6 +21,7 @@ #include "net/http/http_byte_range.h" #include "net/http/http_version.h" #include "url/gurl.h" +#include "url/origin.h" // This is a macro to support extending this string literal at compile time. // Please excuse me polluting your global namespace! @@ -251,6 +252,12 @@ static bool ParseContentEncoding(const std::string& content_encoding, std::set<std::string>* used_encodings); + // Computes the partitioning http cache key given the top frame and initiator + // origins. Returns empty string if split cache is not enabled. + static std::string ComputeCacheKey( + const base::Optional<url::Origin>& top_frame_origin, + const base::Optional<url::Origin>& initiator_origin); + // Used to iterate over the name/value pairs of HTTP headers. To iterate // over the values in a multi-value header, use ValuesIterator. // See AssembleRawHeaders for joining line continuations (this iterator
diff --git a/net/log/net_log_with_source.cc b/net/log/net_log_with_source.cc index bdaa42e..020c340 100644 --- a/net/log/net_log_with_source.cc +++ b/net/log/net_log_with_source.cc
@@ -35,14 +35,10 @@ } // namespace -NetLogWithSource::~NetLogWithSource() { - liveness_ = DEAD; -} +NetLogWithSource::~NetLogWithSource() {} void NetLogWithSource::AddEntry(NetLogEventType type, NetLogEventPhase phase) const { - CrashIfInvalid(); - if (!net_log_) return; net_log_->AddEntry(type, source_, phase, nullptr); @@ -52,8 +48,6 @@ NetLogEventType type, NetLogEventPhase phase, const NetLogParametersCallback& get_parameters) const { - CrashIfInvalid(); - if (!net_log_) return; net_log_->AddEntry(type, source_, phase, &get_parameters); @@ -116,7 +110,6 @@ } bool NetLogWithSource::IsCapturing() const { - CrashIfInvalid(); return net_log_ && net_log_->IsCapturing(); } @@ -130,14 +123,4 @@ return NetLogWithSource(source, net_log); } -void NetLogWithSource::CrashIfInvalid() const { - Liveness liveness = liveness_; - - if (liveness == ALIVE) - return; - - base::debug::Alias(&liveness); - CHECK_EQ(ALIVE, liveness); -} - } // namespace net
diff --git a/net/log/net_log_with_source.h b/net/log/net_log_with_source.h index 820160b..e15d0ba 100644 --- a/net/log/net_log_with_source.h +++ b/net/log/net_log_with_source.h
@@ -69,27 +69,15 @@ // the case of NULL net_log. static NetLogWithSource Make(NetLog* net_log, NetLogSourceType source_type); - // TODO(eroman): Temporary until crbug.com/467797 is solved. - void CrashIfInvalid() const; - const NetLogSource& source() const { return source_; } NetLog* net_log() const { return net_log_; } private: - // TODO(eroman): Temporary until crbug.com/467797 is solved. - enum Liveness { - ALIVE = 0xCA11AB13, - DEAD = 0xDEADBEEF, - }; - NetLogWithSource(const NetLogSource& source, NetLog* net_log) : source_(source), net_log_(net_log) {} NetLogSource source_; NetLog* net_log_; - - // TODO(eroman): Temporary until crbug.com/467797 is solved. - Liveness liveness_ = ALIVE; }; } // namespace net
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc index 0fd1b90..3a1fb846 100644 --- a/net/socket/transport_client_socket_pool.cc +++ b/net/socket/transport_client_socket_pool.cc
@@ -117,9 +117,7 @@ DCHECK_EQ(priority_, MAXIMUM_PRIORITY); } -TransportClientSocketPool::Request::~Request() { - liveness_ = DEAD; -} +TransportClientSocketPool::Request::~Request() {} void TransportClientSocketPool::Request::AssignJob(ConnectJob* job) { DCHECK(job); @@ -136,10 +134,6 @@ return job; } -void TransportClientSocketPool::Request::CrashIfInvalid() const { - CHECK_EQ(liveness_, ALIVE); -} - TransportClientSocketPool::TransportClientSocketPool( int max_sockets, int max_sockets_per_group, @@ -1842,7 +1836,6 @@ if (unbound_requests_.empty()) backup_job_timer_.Stop(); - request->CrashIfInvalid(); SanityCheck(); return request; }
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h index 52eb2a9..2f611482 100644 --- a/net/socket/transport_client_socket_pool.h +++ b/net/socket/transport_client_socket_pool.h
@@ -126,16 +126,7 @@ // request with a job. ConnectJob* ReleaseJob(); - // TODO(eroman): Temporary until crbug.com/467797 is solved. - void CrashIfInvalid() const; - private: - // TODO(eroman): Temporary until crbug.com/467797 is solved. - enum Liveness { - ALIVE = 0xCA11AB13, - DEAD = 0xDEADBEEF, - }; - ClientSocketHandle* const handle_; CompletionOnceCallback callback_; const ProxyAuthCallback proxy_auth_callback_; @@ -148,9 +139,6 @@ const SocketTag socket_tag_; ConnectJob* job_; - // TODO(eroman): Temporary until crbug.com/467797 is solved. - Liveness liveness_ = ALIVE; - DISALLOW_COPY_AND_ASSIGN(Request); };
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index de71c64..14aafab2 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -484,6 +484,10 @@ initiator_ = initiator; } +void URLRequest::set_cache_key(const std::string& cache_key) { + cache_key_ = cache_key; +} + void URLRequest::set_method(const std::string& method) { DCHECK(!is_pending_); method_ = method;
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 166b76f..18dfc33 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h
@@ -335,6 +335,10 @@ // This method may only be called before Start(). void set_initiator(const base::Optional<url::Origin>& initiator); + // The key used to partition resources in the HTTP cache. + const std::string& cache_key() const { return cache_key_; } + void set_cache_key(const std::string& cache_key); + // The request method, as an uppercase string. "GET" is the default value. // The request method may only be changed before Start() is called and // should only be assigned an uppercase value. @@ -868,6 +872,7 @@ bool attach_same_site_cookies_; base::Optional<url::Origin> initiator_; + std::string cache_key_; GURL delegate_redirect_url_; std::string method_; // "GET", "POST", etc. Should be all uppercase. std::string referrer_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index fc50628..d0a7f2b 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -362,6 +362,8 @@ AddExtraHeaders(); AddCookieHeaderAndStart(); + + request_info_.cache_key = request_->cache_key(); } void URLRequestHttpJob::Kill() {
diff --git a/remoting/host/linux/BUILD.gn b/remoting/host/linux/BUILD.gn index a07f8b0..bbfd2825 100644 --- a/remoting/host/linux/BUILD.gn +++ b/remoting/host/linux/BUILD.gn
@@ -60,7 +60,10 @@ ":remoting_user_session", ] if (is_component_build) { - sources += [ "$root_build_dir/libbase.so" ] + sources += [ + "$root_build_dir/libbase.so", + "$root_build_dir/libboringssl.so", + ] deps += [ "//base:base" ] if (use_custom_libcxx) { sources += [ "$root_build_dir/libc++.so" ]
diff --git a/remoting/protocol/fake_message_pipe.cc b/remoting/protocol/fake_message_pipe.cc index 2479b74..8f1e1062 100644 --- a/remoting/protocol/fake_message_pipe.cc +++ b/remoting/protocol/fake_message_pipe.cc
@@ -57,7 +57,7 @@ [](FakeMessagePipe* me, std::unique_ptr<CompoundBuffer> message) { me->ReceiveImpl(std::move(message)); }, - base::Unretained(this), base::Passed(std::move(message)))); + base::Unretained(this), std::move(message))); return; }
diff --git a/services/identity/DEPS b/services/identity/DEPS index 76399cc..f763191e 100644 --- a/services/identity/DEPS +++ b/services/identity/DEPS
@@ -12,5 +12,6 @@ "+components/signin/core/browser/test_signin_client.h", "+components/signin/public", "+components/sync_preferences/testing_pref_service_syncable.h", + "+google_apis/gaia/core_account_id.h", "+google_apis/gaia/google_service_auth_error.h", ]
diff --git a/services/identity/identity_accessor_impl.cc b/services/identity/identity_accessor_impl.cc index feff8bd9..287c698 100644 --- a/services/identity/identity_accessor_impl.cc +++ b/services/identity/identity_accessor_impl.cc
@@ -64,7 +64,7 @@ std::move(callback).Run(account_info, account_state); } -void IdentityAccessorImpl::GetAccessToken(const std::string& account_id, +void IdentityAccessorImpl::GetAccessToken(const CoreAccountId& account_id, const ScopeSet& scopes, const std::string& consumer_id, GetAccessTokenCallback callback) {
diff --git a/services/identity/identity_accessor_impl.h b/services/identity/identity_accessor_impl.h index 9af3fa4a..c0eb010 100644 --- a/services/identity/identity_accessor_impl.h +++ b/services/identity/identity_accessor_impl.h
@@ -11,6 +11,7 @@ #include "base/callback_list.h" #include "components/signin/core/browser/account_info.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" +#include "google_apis/gaia/core_account_id.h" #include "services/identity/public/cpp/account_state.h" #include "services/identity/public/cpp/identity_manager.h" #include "services/identity/public/cpp/scope_set.h" @@ -42,7 +43,7 @@ void GetPrimaryAccountInfo(GetPrimaryAccountInfoCallback callback) override; void GetPrimaryAccountWhenAvailable( GetPrimaryAccountWhenAvailableCallback callback) override; - void GetAccessToken(const std::string& account_id, + void GetAccessToken(const CoreAccountId& account_id, const ScopeSet& scopes, const std::string& consumer_id, GetAccessTokenCallback callback) override;
diff --git a/services/identity/public/cpp/core_account_id.typemap b/services/identity/public/cpp/core_account_id.typemap new file mode 100644 index 0000000..93416db --- /dev/null +++ b/services/identity/public/cpp/core_account_id.typemap
@@ -0,0 +1,16 @@ +# Copyright 2019 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. + +mojom = "//services/identity/public/mojom/core_account_id.mojom" +public_headers = [ "//google_apis/gaia/core_account_id.h" ] +traits_headers = + [ "//services/identity/public/cpp/core_account_id_mojom_traits.h" ] +sources = [ + "//services/identity/public/cpp/core_account_id_mojom_traits.cc", +] +public_deps = [ + "//google_apis", +] + +type_mappings = [ "identity.mojom.CoreAccountId=::CoreAccountId" ]
diff --git a/services/identity/public/cpp/core_account_id_mojom_traits.cc b/services/identity/public/cpp/core_account_id_mojom_traits.cc new file mode 100644 index 0000000..833d0c0 --- /dev/null +++ b/services/identity/public/cpp/core_account_id_mojom_traits.cc
@@ -0,0 +1,29 @@ +// Copyright 2019 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 "services/identity/public/cpp/core_account_id_mojom_traits.h" + +namespace mojo { + +// static +bool StructTraits<identity::mojom::CoreAccountId::DataView, ::CoreAccountId>:: + Read(identity::mojom::CoreAccountId::DataView data, ::CoreAccountId* out) { + std::string id; + + if (!data.ReadId(&id)) { + return false; + } + + out->id = id; + + return true; +} + +// static +bool StructTraits<identity::mojom::CoreAccountId::DataView, + ::CoreAccountId>::IsNull(const ::CoreAccountId& input) { + return input.empty(); +} + +} // namespace mojo \ No newline at end of file
diff --git a/services/identity/public/cpp/core_account_id_mojom_traits.h b/services/identity/public/cpp/core_account_id_mojom_traits.h new file mode 100644 index 0000000..7af3673 --- /dev/null +++ b/services/identity/public/cpp/core_account_id_mojom_traits.h
@@ -0,0 +1,29 @@ +// Copyright 2019 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 SERVICES_IDENTITY_PUBLIC_CPP_CORE_ACCOUNT_ID_MOJOM_TRAITS_H_ +#define SERVICES_IDENTITY_PUBLIC_CPP_CORE_ACCOUNT_ID_MOJOM_TRAITS_H_ + +#include <string> + +#include "google_apis/gaia/core_account_id.h" +#include "services/identity/public/mojom/core_account_id.mojom.h" + +namespace mojo { + +template <> +struct StructTraits<identity::mojom::CoreAccountId::DataView, ::CoreAccountId> { + static const std::string& id(const ::CoreAccountId& r) { return r.id; } + + static bool Read(identity::mojom::CoreAccountId::DataView data, + ::CoreAccountId* out); + + static bool IsNull(const ::CoreAccountId& input); + + static void SetToNull(::CoreAccountId* output) { *output = CoreAccountId(); } +}; + +} // namespace mojo + +#endif // SERVICES_IDENTITY_PUBLIC_CPP_CORE_ACCOUNT_ID_MOJOM_TRAITS_H_
diff --git a/services/identity/public/cpp/core_account_info_mojom_traits.cc b/services/identity/public/cpp/core_account_info_mojom_traits.cc index 4029b1c..b388afa 100644 --- a/services/identity/public/cpp/core_account_info_mojom_traits.cc +++ b/services/identity/public/cpp/core_account_info_mojom_traits.cc
@@ -4,6 +4,8 @@ #include "services/identity/public/cpp/core_account_info_mojom_traits.h" +#include "services/identity/public/cpp/core_account_id_mojom_traits.h" + namespace mojo { // static @@ -11,7 +13,7 @@ identity::mojom::CoreAccountInfo::DataView, ::CoreAccountInfo>::Read(identity::mojom::CoreAccountInfo::DataView data, ::CoreAccountInfo* out) { - std::string account_id; + CoreAccountId account_id; std::string gaia; std::string email;
diff --git a/services/identity/public/cpp/core_account_info_mojom_traits.h b/services/identity/public/cpp/core_account_info_mojom_traits.h index 586b0c1..85e4675 100644 --- a/services/identity/public/cpp/core_account_info_mojom_traits.h +++ b/services/identity/public/cpp/core_account_info_mojom_traits.h
@@ -15,8 +15,8 @@ template <> struct StructTraits<identity::mojom::CoreAccountInfo::DataView, ::CoreAccountInfo> { - static const std::string& account_id(const ::CoreAccountInfo& r) { - return r.account_id.id; + static const CoreAccountId& account_id(const ::CoreAccountInfo& r) { + return r.account_id; } static const std::string& gaia(const ::CoreAccountInfo& r) { return r.gaia; }
diff --git a/services/identity/public/cpp/typemaps.gni b/services/identity/public/cpp/typemaps.gni index 45059196..f9ee1786 100644 --- a/services/identity/public/cpp/typemaps.gni +++ b/services/identity/public/cpp/typemaps.gni
@@ -1,6 +1,7 @@ typemaps = [ "//services/identity/public/cpp/account_info.typemap", "//services/identity/public/cpp/account_state.typemap", + "//services/identity/public/cpp/core_account_id.typemap", "//services/identity/public/cpp/google_service_auth_error.typemap", "//services/identity/public/cpp/scope_set.typemap", ]
diff --git a/services/identity/public/mojom/BUILD.gn b/services/identity/public/mojom/BUILD.gn index 91e6a1a..c5b758a 100644 --- a/services/identity/public/mojom/BUILD.gn +++ b/services/identity/public/mojom/BUILD.gn
@@ -8,6 +8,7 @@ sources = [ "account.mojom", "account_state.mojom", + "core_account_id.mojom", "core_account_info.mojom", "google_service_auth_error.mojom", "identity_accessor.mojom",
diff --git a/services/identity/public/mojom/core_account_id.mojom b/services/identity/public/mojom/core_account_id.mojom new file mode 100644 index 0000000..5e96ebc --- /dev/null +++ b/services/identity/public/mojom/core_account_id.mojom
@@ -0,0 +1,11 @@ +// Copyright 2019 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. + +module identity.mojom; + +// Opaque identifier that represents an account within chrome. +struct CoreAccountId { + // This is the value of the account id. + string id; +}; \ No newline at end of file
diff --git a/services/identity/public/mojom/core_account_info.mojom b/services/identity/public/mojom/core_account_info.mojom index a16a87eb..a08ce8bc 100644 --- a/services/identity/public/mojom/core_account_info.mojom +++ b/services/identity/public/mojom/core_account_info.mojom
@@ -4,12 +4,14 @@ module identity.mojom; +import "services/identity/public/mojom/core_account_id.mojom"; + // Information about a specific Google account. A valid CoreAccountInfo will // always have an account ID, gaia ID, and email address. struct CoreAccountInfo { // The account ID used by OAuth2TokenService. This is an opaque identifier // that represents this account within Chrome. - string account_id; + CoreAccountId account_id; // The GAIA ID corresponding to this account. string gaia; // The email address corresponding to this account.
diff --git a/services/identity/public/mojom/identity_accessor.mojom b/services/identity/public/mojom/identity_accessor.mojom index 7859c59..8974cf6 100644 --- a/services/identity/public/mojom/identity_accessor.mojom +++ b/services/identity/public/mojom/identity_accessor.mojom
@@ -6,6 +6,7 @@ import "mojo/public/mojom/base/time.mojom"; import "services/identity/public/mojom/account.mojom"; +import "services/identity/public/mojom/core_account_id.mojom"; import "services/identity/public/mojom/core_account_info.mojom"; import "services/identity/public/mojom/account_state.mojom"; import "services/identity/public/mojom/google_service_auth_error.mojom"; @@ -37,8 +38,8 @@ // |expiration_time| is undefined. |consumer_id| is an arbitrary string used // to identity the consumer (e.g., in about:://signin-internals). // NOTE: |account_id| corresponds to that used by OAuth2TokenService. - GetAccessToken(string account_id, ScopeSet scopes, string consumer_id) => - (string? token, - mojo_base.mojom.Time expiration_time, - GoogleServiceAuthError error); + GetAccessToken(CoreAccountId account_id, ScopeSet scopes, string consumer_id) + => (string? token, + mojo_base.mojom.Time expiration_time, + GoogleServiceAuthError error); };
diff --git a/services/metrics/public/cpp/ukm_recorder.h b/services/metrics/public/cpp/ukm_recorder.h index f9427ebf..0675e9a 100644 --- a/services/metrics/public/cpp/ukm_recorder.h +++ b/services/metrics/public/cpp/ukm_recorder.h
@@ -17,9 +17,7 @@ #include "services/metrics/public/mojom/ukm_interface.mojom-forward.h" #include "url/gurl.h" -class IOSChromePasswordManagerClient; class MediaEngagementSession; -class PluginInfoHostImpl; namespace autofill { class TestAutofillClient; @@ -29,36 +27,10 @@ class Document; } // namespace blink -namespace cc { -class UkmManager; -} // namespace cc - -namespace content { -class CrossSiteDocumentResourceHandler; -class WebContentsImpl; -class PluginServiceImpl; -} // namespace content - -namespace download { -class DownloadUkmHelper; -} // namespace download - -namespace password_manager { -class PasswordManagerMetricsRecorder; -} // namespace password_manager - -namespace payments { -class JourneyLogger; -} // namespace payments - namespace metrics { class UkmRecorderInterface; } // namespace metrics -namespace translate { -class TranslateRankerImpl; -} // namespace translate - namespace ukm { class DelegatingUkmRecorder; @@ -67,7 +39,6 @@ namespace internal { class SourceUrlRecorderWebContentsObserver; -class SourceUrlRecorderWebStateObserver; } // namespace internal // This feature controls whether UkmService should be created. @@ -102,27 +73,16 @@ private: friend DelegatingUkmRecorder; - friend IOSChromePasswordManagerClient; friend MediaEngagementSession; - friend PluginInfoHostImpl; friend TestRecordingHelper; friend UkmBackgroundRecorderService; friend autofill::TestAutofillClient; friend blink::Document; - friend content::CrossSiteDocumentResourceHandler; - friend content::PluginServiceImpl; - friend content::WebContentsImpl; - friend download::DownloadUkmHelper; - friend internal::SourceUrlRecorderWebContentsObserver; - friend internal::SourceUrlRecorderWebStateObserver; friend metrics::UkmRecorderInterface; - friend password_manager::PasswordManagerMetricsRecorder; - friend payments::JourneyLogger; - friend translate::TranslateRankerImpl; // Associates the SourceId with a URL. Most UKM recording code should prefer // to use a shared SourceId that is already associated with a URL, rather - // than using this API directly. New uses of this API must be auditted to + // than using this API directly. New uses of this API must be audited to // maintain privacy constraints. virtual void UpdateSourceURL(SourceId source_id, const GURL& url) = 0;
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc index 743b4f97..fb36d27 100644 --- a/services/network/cors/cors_url_loader.cc +++ b/services/network/cors/cors_url_loader.cc
@@ -401,9 +401,19 @@ request_.request_initiator && (fetch_cors_flag_ || (request_.method != "GET" && request_.method != "HEAD"))) { - request_.headers.SetHeader( - net::HttpRequestHeaders::kOrigin, - (tainted_ ? url::Origin() : *request_.request_initiator).Serialize()); + if (!fetch_cors_flag_ && + request_.headers.HasHeader(net::HttpRequestHeaders::kOrigin) && + request_.request_initiator->scheme() == "chrome-extension") { + // We need to attach an origin header when the request's method is neither + // GET nor HEAD. For requests made by an extension content scripts, we + // want to attach page's origin, whereas the request's origin is the + // content script's origin. See https://crbug.com/944704 for details. + // TODO(crbug.com/940068) Remove this condition. + } else { + request_.headers.SetHeader( + net::HttpRequestHeaders::kOrigin, + (tainted_ ? url::Origin() : *request_.request_initiator).Serialize()); + } } if (fetch_cors_flag_ &&
diff --git a/services/service_manager/sandbox/mac/renderer.sb b/services/service_manager/sandbox/mac/renderer.sb index 47c38ba0..26da9a5 100644 --- a/services/service_manager/sandbox/mac/renderer.sb +++ b/services/service_manager/sandbox/mac/renderer.sb
@@ -96,5 +96,6 @@ ; For V8 to use in thread calculations. (if (>= os-version 1014) (allow sysctl-read (sysctl-name "kern.tcsm_available")) + (allow sysctl-read (sysctl-name "kern.tcsm_enable")) (allow sysctl-write (sysctl-name "kern.tcsm_enable")) )
diff --git a/services/viz/public/cpp/compositing/render_pass_struct_traits.h b/services/viz/public/cpp/compositing/render_pass_struct_traits.h index 0e8c827..b804a96 100644 --- a/services/viz/public/cpp/compositing/render_pass_struct_traits.h +++ b/services/viz/public/cpp/compositing/render_pass_struct_traits.h
@@ -51,9 +51,14 @@ return input->backdrop_filters; } - static const gfx::RRectF& backdrop_filter_bounds( + static gfx::RRectF backdrop_filter_bounds( const std::unique_ptr<viz::RenderPass>& input) { - return input->backdrop_filter_bounds; + return input->backdrop_filter_bounds.value_or(gfx::RRectF()); + } + + static bool has_backdrop_filter_bounds( + const std::unique_ptr<viz::RenderPass>& input) { + return input->backdrop_filter_bounds.has_value(); } static const gfx::ColorSpace& color_space(
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc index d6018b81..3956c578 100644 --- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc +++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -747,8 +747,8 @@ backdrop_filters.Append(cc::FilterOperation::CreateSaturateFilter(4.f)); backdrop_filters.Append(cc::FilterOperation::CreateZoomFilter(2.0f, 1)); backdrop_filters.Append(cc::FilterOperation::CreateSaturateFilter(2.f)); - gfx::RRectF backdrop_filter_bounds = - gfx::RRectF(10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8); + base::Optional<gfx::RRectF> backdrop_filter_bounds( + {10, 20, 130, 140, 1, 2, 3, 4, 5, 6, 7, 8}); gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); const bool has_transparent_background = true; const bool cache_render_pass = true; @@ -900,8 +900,9 @@ const bool generate_mipmap = false; std::unique_ptr<RenderPass> input = RenderPass::Create(); input->SetAll(render_pass_id, output_rect, damage_rect, transform_to_root, - cc::FilterOperations(), cc::FilterOperations(), gfx::RRectF(), - color_space, has_transparent_background, cache_render_pass, + cc::FilterOperations(), cc::FilterOperations(), + base::Optional<gfx::RRectF>(), color_space, + has_transparent_background, cache_render_pass, has_damage_from_contributing_content, generate_mipmap); // Unlike the previous test, don't add any quads to the list; we need to
diff --git a/services/viz/public/interfaces/compositing/render_pass.mojom b/services/viz/public/interfaces/compositing/render_pass.mojom index 9108e9f..ed8b847 100644 --- a/services/viz/public/interfaces/compositing/render_pass.mojom +++ b/services/viz/public/interfaces/compositing/render_pass.mojom
@@ -20,7 +20,7 @@ gfx.mojom.Transform transform_to_root_target; FilterOperations filters; FilterOperations backdrop_filters; - gfx.mojom.RRectF backdrop_filter_bounds; + gfx.mojom.RRectF? backdrop_filter_bounds; gfx.mojom.ColorSpace color_space; bool has_transparent_background; bool cache_render_pass = false;
diff --git a/services/ws/public/cpp/tests/gpu_unittest.cc b/services/ws/public/cpp/tests/gpu_unittest.cc index bceed38..553f093 100644 --- a/services/ws/public/cpp/tests/gpu_unittest.cc +++ b/services/ws/public/cpp/tests/gpu_unittest.cc
@@ -153,7 +153,7 @@ gpu_impl.reset(); event->Signal(); }, - base::Passed(std::move(gpu_impl_)), &event)); + std::move(gpu_impl_), &event)); event.Wait(); }
diff --git a/sql/BUILD.gn b/sql/BUILD.gn index 0d39932..f4deebea 100644 --- a/sql/BUILD.gn +++ b/sql/BUILD.gn
@@ -18,6 +18,24 @@ "internal_api_token.h", "meta_table.cc", "meta_table.h", + "recover_module/btree.cc", + "recover_module/btree.h", + "recover_module/cursor.cc", + "recover_module/cursor.h", + "recover_module/integers.cc", + "recover_module/integers.h", + "recover_module/module.cc", + "recover_module/module.h", + "recover_module/pager.cc", + "recover_module/pager.h", + "recover_module/parsing.cc", + "recover_module/parsing.h", + "recover_module/payload.cc", + "recover_module/payload.h", + "recover_module/record.cc", + "recover_module/record.h", + "recover_module/table.cc", + "recover_module/table.h", "recovery.cc", "recovery.h", "sql_features.cc", @@ -94,7 +112,7 @@ sources = [ "database_unittest.cc", "meta_table_unittest.cc", - "recover_module_unittest.cc", + "recover_module/module_unittest.cc", "recovery_unittest.cc", "sql_memory_dump_provider_unittest.cc", "sqlite_features_unittest.cc",
diff --git a/sql/recover_module/README.md b/sql/recover_module/README.md new file mode 100644 index 0000000..ce405d6 --- /dev/null +++ b/sql/recover_module/README.md
@@ -0,0 +1,94 @@ +# SQLite Data Recovery + +This directory implements data recovery heuristics for SQLite databases whose +files were corrupted on disk. The recovery code walks through the B-tree +holding a SQLite table and recovers all records that seem healthy. Even if +recovery succeeds, a recovered table may be missing records, and existing +records may have corrupted values inside them. Any constraints imposed by Chrome +or by SQLite may be broken. + + +## Usage + +The default approach for handling corruption in SQLite databases is to +immediately stop using the database, delete it, and start over with a new +database. The recovery method implemented here is intended for databases used by +Chrome features that handle high-value user data, such as History and Bookmarks. +These features carefully handle data inconsistency edge cases, and their +database schemas are resilient to partial data loss. + +The code is plugged into the rest of Chrome via +[SQLite's virtual table module API](https://sqlite.org/vtab.html). The example +below covers a typical recovery scenario. + +```sql +-- Feature table schema. +CREATE TABLE data(name TEXT PRIMARY KEY, value TEXT NOT NULL); + +-- Recover in another database. The corrupted one is unreliable. +ATTACH DATABASE '/tmp/db.db' as recovery; +-- Re-create the feature table's schema. +CREATE TABLE recovery.feature(name TEXT PRIMARY KEY, value TEXT NOT NULL); +-- Start reading the corrupted data. +CREATE VIRTUAL TABLE temp.recover_feature USING recover( + main.feature, -- The corrupted database. + -- Recovery will skip row values that don't have the TEXT type. + name TEXT STRICT NOT NULL, + -- Recovery will include any row value coercible to TEXT. + value TEXT NOT NULL); +-- Data recovered from corrupted databases may not meet schema constraints, so +-- recovery insertions must use "OR REPLACE" or "OR IGNORE". +INSERT OR REPLACE INTO recovery.feature(rowid, name, value) +SELECT rowid, name, value FROM temp.recover_feature; +-- Cleanup after the recovery operation. +DROP TABLE temp.recover_feature; +DETACH DATABASE recovery; +-- Replace the corrupted database file with the recovered one. +``` + +The feature invoking the recovery virtual table must know the schema of the +database being recovered. A generic high-level recovery layer should first +recover +[the `sqlite_master` table](https://www.sqlite.org/fileformat.html#storage_of_the_sql_database_schema), +which has a well known format, then use its contents to recover the schema of +any other table. This recovery module already relies on the integrity of the +`sqlite_master` table. + +The column definitions in the virtual table creation statement must follow +the syntax _column\_name_ _type\_name_ [`STRICT`] [`NOT NULL`]. _type\_name_ is +[the SQLite data types](https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes), +or the special types `ANY` or `ROWID`. + +The `ANY` type can be used to recover values of all types. + +The `ROWID` type must be used for columns that alias +[rowid](https://www.sqlite.org/lang_createtable.html#rowid). This typically only +happens when a column is declared as `INTEGER PRIMARY KEY`. +Designating `ROWID` columns is essential for decoding records correctly. + +TODO(pwnall): Look into removing `STRICT`, if it's not used. + + +## Limitations + +The current implementation only handles [table +B-trees](https://www.sqlite.org/fileformat.html#b_tree_pages). It cannot +recover [WITHOUT ROWID](https://www.sqlite.org/rowidtable.html) tables, which +are stored in index B-trees. + + +## Code Map + +The code is structured as follows. + +* integers.{cc,h} decodes the integer formats used by SQLite. +* btree.{cc,h} decodes the cells in SQLite's B-tree pages. +* payload.{cc,h} reads record payloads from B-tree pages and overflow pages. +* record.{cc,h} decodes column values from record. +* cursor.{cc,h} implements a SQLite virtual table cursor. +* table.{cc,h} implements one recovery virtual table. +* parsing.{cc,h} parses the SQL strings passed in via `CREATE VIRTUAL TABLE` + and implements the constraints explained above. +* module.{cc,h} implements the SQLite virtual table interface. + +The feature is tested by integration tests that issue SQLite queries.
diff --git a/sql/recover_module/btree.cc b/sql/recover_module/btree.cc new file mode 100644 index 0000000..72ee3f1 --- /dev/null +++ b/sql/recover_module/btree.cc
@@ -0,0 +1,252 @@ +// Copyright 2019 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 "sql/recover_module/btree.h" + +#include <algorithm> +#include <limits> +#include <type_traits> + +#include "base/logging.h" +#include "sql/recover_module/integers.h" +#include "sql/recover_module/pager.h" +#include "third_party/sqlite/sqlite3.h" + +namespace sql { +namespace recover { + +namespace { + +// The SQLite database format is documented at the following URLs. +// https://www.sqlite.org/fileformat.html +// https://www.sqlite.org/fileformat2.html +constexpr uint8_t kInnerTablePageType = 0x05; +constexpr uint8_t kLeafTablePageType = 0x0D; + +// Offset from the page header to the page type byte. +constexpr int kPageTypePageOffset = 0; +// Offset from the page header to the 2-byte cell count. +constexpr int kCellCountPageOffset = 3; +// Offset from an inner page header to the 4-byte last child page ID. +constexpr int kLastChildIdInnerPageOffset = 8; +// Offset from an inner page header to the cell pointer array. +constexpr int kFirstCellOfsetInnerPageOffset = 12; +// Offset from a leaf page header to the cell pointer array. +constexpr int kFirstCellOfsetLeafPageOffset = 8; + +} // namespace + +#if !DCHECK_IS_ON() +// In DCHECKed builds, the decoder contains a sequence checker, which has a +// non-trivial destructor. +static_assert(std::is_trivially_destructible<InnerPageDecoder>::value, + "Move the destructor to the .cc file if it's non-trival"); +#endif // !DCHECK_IS_ON() + +InnerPageDecoder::InnerPageDecoder(DatabasePageReader* db_reader) + : page_id_(db_reader->page_id()), + db_reader_(db_reader), + cell_count_(ComputeCellCount(db_reader)), + next_read_index_(0) { + DCHECK(IsOnValidPage(db_reader)); + DCHECK(DatabasePageReader::IsValidPageId(page_id_)); +} + +int InnerPageDecoder::TryAdvance() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(CanAdvance()); + + const int sqlite_status = db_reader_->ReadPage(page_id_); + if (sqlite_status != SQLITE_OK) { + // TODO(pwnall): UMA the error code. + + next_read_index_ = cell_count_ + 1; // End the reading process. + return DatabasePageReader::kInvalidPageId; + } + + const uint8_t* const page_data = db_reader_->page_data(); + const int read_index = next_read_index_; + next_read_index_ += 1; + if (read_index == cell_count_) + return LoadBigEndianInt32(page_data + kLastChildIdInnerPageOffset); + + const int cell_pointer_offset = + kFirstCellOfsetInnerPageOffset + (read_index << 1); + DCHECK_LE(cell_pointer_offset + 2, db_reader_->page_size()) + << "ComputeCellCount() used an incorrect upper bound"; + const int cell_pointer = LoadBigEndianUint16(page_data + cell_pointer_offset); + + static_assert(std::numeric_limits<uint16_t>::max() + 4 < + std::numeric_limits<int>::max(), + "The addition below may overflow"); + if (cell_pointer + 4 >= db_reader_->page_size()) { + // Each cell needs 1 byte for the rowid varint, in addition to the 4 bytes + // for the child page number that will be read below. Skip cells that + // obviously go over the page end. + return DatabasePageReader::kInvalidPageId; + } + if (cell_pointer < kFirstCellOfsetInnerPageOffset) { + // The pointer points into the cell's header. + return DatabasePageReader::kInvalidPageId; + } + + return LoadBigEndianInt32(page_data + cell_pointer); +} + +// static +bool InnerPageDecoder::IsOnValidPage(DatabasePageReader* db_reader) { + static_assert(kPageTypePageOffset < DatabasePageReader::kMinUsablePageSize, + "The check below may perform an out-of-bounds memory access"); + return db_reader->page_data()[kPageTypePageOffset] == kInnerTablePageType; +} + +// static +int InnerPageDecoder::ComputeCellCount(DatabasePageReader* db_reader) { + // The B-tree page header stores the cell count. + int header_count = + LoadBigEndianUint16(db_reader->page_data() + kCellCountPageOffset); + static_assert( + kCellCountPageOffset + 2 <= DatabasePageReader::kMinUsablePageSize, + "The read above may be out of bounds"); + + // However, the data may be corrupted. So, use an upper bound based on the + // fact that the cell pointer array should never extend past the end of the + // page. + // + // The page size is always even, because it is either a power of two, for + // most pages, or a power of two minus 100, for the first database page. The + // cell pointer array starts at offset 12. So, each cell pointer must be + // separated from the page buffer's end by an even number of bytes. + DCHECK((db_reader->page_size() - kFirstCellOfsetInnerPageOffset) % 2 == 0); + int upper_bound = + (db_reader->page_size() - kFirstCellOfsetInnerPageOffset) >> 1; + static_assert( + kFirstCellOfsetInnerPageOffset <= DatabasePageReader::kMinUsablePageSize, + "The |upper_bound| computation above may overflow"); + + return std::min(header_count, upper_bound); +} + +#if !DCHECK_IS_ON() +// In DCHECKed builds, the decoder contains a sequence checker, which has a +// non-trivial destructor. +static_assert(std::is_trivially_destructible<LeafPageDecoder>::value, + "Move the destructor to the .cc file if it's non-trival"); +#endif // !DCHECK_IS_ON() + +LeafPageDecoder::LeafPageDecoder(DatabasePageReader* db_reader) + : page_id_(db_reader->page_id()), + db_reader_(db_reader), + cell_count_(ComputeCellCount(db_reader)), + next_read_index_(0), + last_record_size_(0) { + DCHECK(IsOnValidPage(db_reader)); + DCHECK(DatabasePageReader::IsValidPageId(page_id_)); +} + +bool LeafPageDecoder::TryAdvance() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(CanAdvance()); + +#if DCHECK_IS_ON() + // DCHECKs use last_record_size == 0 to check for incorrect access to the + // decoder's state. + last_record_size_ = 0; +#endif // DCHECK_IS_ON() + + const int sqlite_status = db_reader_->ReadPage(page_id_); + if (sqlite_status != SQLITE_OK) { + // TODO(pwnall): UMA the error code. + + next_read_index_ = cell_count_; // End the reading process. + return false; + } + + const uint8_t* page_data = db_reader_->page_data(); + const int read_index = next_read_index_; + next_read_index_ += 1; + + const int cell_pointer_offset = + kFirstCellOfsetLeafPageOffset + (read_index << 1); + DCHECK_LE(cell_pointer_offset + 2, db_reader_->page_size()) + << "ComputeCellCount() used an incorrect upper bound"; + const int cell_pointer = LoadBigEndianUint16(page_data + cell_pointer_offset); + + static_assert(std::numeric_limits<uint16_t>::max() + 3 < + std::numeric_limits<int>::max(), + "The addition below may overflow"); + if (cell_pointer + 3 >= db_reader_->page_size()) { + // Each cell needs at least 1 byte for page type varint, 1 byte for the + // rowid varint, and 1 byte for the record header size varint. Skip cells + // that obviously go over the page end. + return false; + } + if (cell_pointer < kFirstCellOfsetLeafPageOffset) { + // The pointer points into the cell's header. + return false; + } + + const uint8_t* const cell_start = page_data + cell_pointer; + const uint8_t* const page_end = page_data + db_reader_->page_size(); + DCHECK_LT(cell_start, page_end) << "Failed to skip over empty cells"; + + const uint8_t* rowid_start; + std::tie(last_record_size_, rowid_start) = ParseVarint(cell_start, page_end); + if (rowid_start == page_end) { + // The value size varint extended to the end of the page, so the rowid + // varint starts past the page end. + return false; + } + if (last_record_size_ <= 0) { + // Each payload needs at least one varint. Skip empty payloads. +#if DCHECK_IS_ON() + // DCHECKs use last_record_size == 0 to check for incorrect access to the + // decoder's state. + last_record_size_ = 0; +#endif // DCHECK_IS_ON() + return false; + } + + const uint8_t* record_start; + std::tie(last_record_rowid_, record_start) = + ParseVarint(rowid_start, page_end); + if (record_start == page_end) { + // The rowid varint extended to the end of the page, so the record starts + // past the page end. Records need at least 1 byte for their header size + // varint, so this suggests corruption. + last_record_size_ = 0; + return false; + } + + last_record_offset_ = record_start - page_data; + return true; +} + +// static +bool LeafPageDecoder::IsOnValidPage(DatabasePageReader* db_reader) { + static_assert(kPageTypePageOffset < DatabasePageReader::kMinUsablePageSize, + "The check below may perform an out-of-bounds memory access"); + return db_reader->page_data()[kPageTypePageOffset] == kLeafTablePageType; +} + +// static +int LeafPageDecoder::ComputeCellCount(DatabasePageReader* db_reader) { + // See InnerPageDecoder::ComputeCellCount() for the reasoning behind the code. + int header_count = + LoadBigEndianUint16(db_reader->page_data() + kCellCountPageOffset); + static_assert( + kCellCountPageOffset + 2 <= DatabasePageReader::kMinUsablePageSize, + "The read above may be out of bounds"); + + int upper_bound = + (db_reader->page_size() - kFirstCellOfsetLeafPageOffset) >> 1; + static_assert( + kFirstCellOfsetLeafPageOffset <= DatabasePageReader::kMinUsablePageSize, + "The |upper_bound| computation above may overflow"); + + return std::min(header_count, upper_bound); +} + +} // namespace recover +} // namespace sql
diff --git a/sql/recover_module/btree.h b/sql/recover_module/btree.h new file mode 100644 index 0000000..4c965ce --- /dev/null +++ b/sql/recover_module/btree.h
@@ -0,0 +1,185 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_BTREE_H_ +#define SQL_RECOVER_MODULE_BTREE_H_ + +#include <cstdint> + +#include "base/logging.h" +#include "base/sequence_checker.h" + +namespace sql { +namespace recover { + +class DatabasePageReader; + +// Streaming decoder for inner pages in SQLite table B-trees. +// +// The decoder outputs the page IDs of the inner page's children pages. +// +// An instance can only be used to decode a single page. Instances are not +// thread-safe. +class InnerPageDecoder { + public: + // Creates a decoder for a DatabasePageReader's last read page. + // + // |db_reader| must have been used to read an inner page of a table B-tree. + // |db_reader| must outlive this instance. + explicit InnerPageDecoder(DatabasePageReader* db_reader) noexcept; + ~InnerPageDecoder() noexcept = default; + + InnerPageDecoder(const InnerPageDecoder&) = delete; + InnerPageDecoder& operator=(const InnerPageDecoder&) = delete; + + // The ID of the database page decoded by this instance. + int page_id() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return page_id_; + } + + // Returns true iff TryAdvance() may be called. + bool CanAdvance() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // The <= below is not a typo. Inner nodes store the right-most child + // pointer in their headers, so their child count is (cell_count + 1). + return next_read_index_ <= cell_count_; + } + + // Advances the reader and returns the last read value. + // + // May return an invalid page ID if database was corrupted or the read failed. + // The caller must use DatabasePageReader::IsValidPageId() to verify the + // returned page ID. The caller should continue attempting to read as long as + // CanAdvance() returns true. + int TryAdvance(); + + // True if the given reader may point to an inner page in a table B-tree. + // + // The last ReadPage() call on |db_reader| must have succeeded. + static bool IsOnValidPage(DatabasePageReader* db_reader); + + private: + // Returns the number of cells in the B-tree page. + // + // Checks for database corruption. The caller can assume that the cell pointer + // array with the returned size will not extend past the page buffer. + static int ComputeCellCount(DatabasePageReader* db_reader); + + // The number of the B-tree page this reader is reading. + const int page_id_; + // Used to read the tree page. + DatabasePageReader* const db_reader_; + // Caches the ComputeCellCount() value for this reader's page. + const int cell_count_ = ComputeCellCount(db_reader_); + + // The reader's cursor state. + // + // Each B-tree page has a header and many cells. In an inner B-tree page, each + // cell points to a child page, and the header points to the last child page. + // So, an inner page with N cells has N+1 children, and |next_read_index_| + // takes values between 0 and |cell_count_| + 1. + int next_read_index_ = 0; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +// Streaming decoder for leaf pages in SQLite table B-trees. +// +// Conceptually, the decoder outputs (rowid, record size, record offset) tuples +// for all the values stored in the leaf page. The tuple members can be accessed +// via last_record_{rowid, size, offset}() methods. +// +// An instance can only be used to decode a single page. Instances are not +// thread-safe. +class LeafPageDecoder { + public: + // Creates a decoder for a DatabasePageReader's last read page. + // + // |db_reader| must have been used to read an inner page of a table B-tree. + // |db_reader| must outlive this instance. + explicit LeafPageDecoder(DatabasePageReader* db_reader) noexcept; + ~LeafPageDecoder() noexcept = default; + + LeafPageDecoder(const LeafPageDecoder&) = delete; + LeafPageDecoder& operator=(const LeafPageDecoder&) = delete; + + // The rowid of the most recent record read by TryAdvance(). + // + // Must only be called after a successful call to TryAdvance(). + int64_t last_record_rowid() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(last_record_size_ != 0) + << "TryAdvance() not called / did not succeed"; + return last_record_rowid_; + } + + // The size of the most recent record read by TryAdvance(). + // + // Must only be called after a successful call to TryAdvance(). + int64_t last_record_size() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(last_record_size_ != 0) + << "TryAdvance() not called / did not succeed"; + return last_record_size_; + } + + // The page offset of the most recent record read by TryAdvance(). + // + // Must only be called after a successful call to TryAdvance(). + int64_t last_record_offset() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(last_record_size_ != 0) + << "TryAdvance() not called / did not succeed"; + return last_record_offset_; + } + + // Returns true iff TryAdvance() may be called. + bool CanAdvance() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return next_read_index_ < cell_count_; + } + + // Advances the reader and returns the last read value. + // + // Returns false if the read fails. The caller should continue attempting to + // read as long as CanAdvance() returns true. + bool TryAdvance(); + + // True if the given reader may point to an inner page in a table B-tree. + // + // The last ReadPage() call on |db_reader| must have succeeded. + static bool IsOnValidPage(DatabasePageReader* db_reader); + + private: + // Returns the number of cells in the B-tree page. + // + // Checks for database corruption. The caller can assume that the cell pointer + // array with the returned size will not extend past the page buffer. + static int ComputeCellCount(DatabasePageReader* db_reader); + + // The number of the B-tree page this reader is reading. + const int64_t page_id_; + // Used to read the tree page. + DatabasePageReader* const db_reader_; + // Caches the ComputeCellCount() value for this reader's page. + const int cell_count_ = ComputeCellCount(db_reader_); + + // The reader's cursor state. + // + // Each B-tree cell contains a value. So, this member takes values in + // [0, cell_count_). + int next_read_index_ = 0; + + int64_t last_record_size_ = 0; + int64_t last_record_rowid_ = 0; + int last_record_offset_ = 0; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_BTREE_H_
diff --git a/sql/recover_module/cursor.cc b/sql/recover_module/cursor.cc new file mode 100644 index 0000000..0029ff9 --- /dev/null +++ b/sql/recover_module/cursor.cc
@@ -0,0 +1,161 @@ +// Copyright 2019 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 "sql/recover_module/cursor.h" + +#include "base/containers/span.h" +#include "sql/recover_module/table.h" + +namespace sql { +namespace recover { + +VirtualCursor::VirtualCursor(VirtualTable* table) + : table_(table), + db_reader_(table), + payload_reader_(&db_reader_), + record_reader_(&payload_reader_, table->column_specs().size()) { + DCHECK(table_ != nullptr); +} + +VirtualCursor::~VirtualCursor() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + table_->WillDeleteCursor(this); +} + +int VirtualCursor::First() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_decoders_.clear(); + leaf_decoder_ = nullptr; + + AppendPageDecoder(table_->root_page_id()); + return Next(); +} + +int VirtualCursor::Next() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + record_reader_.Reset(); + + while (!inner_decoders_.empty() || leaf_decoder_.get()) { + if (leaf_decoder_.get()) { + if (!leaf_decoder_->CanAdvance()) { + // The leaf has been exhausted. Remove it from the DFS stack. + leaf_decoder_ = nullptr; + continue; + } + if (!leaf_decoder_->TryAdvance()) + continue; + + if (!payload_reader_.Initialize(leaf_decoder_->last_record_size(), + leaf_decoder_->last_record_offset())) { + continue; + } + if (!record_reader_.Initialize()) + continue; + + // Found a healthy record. + if (!IsAcceptableRecord()) { + record_reader_.Reset(); + continue; + } + return SQLITE_OK; + } + + // Try advancing the bottom-most inner node. + DCHECK(!inner_decoders_.empty()); + InnerPageDecoder* inner_decoder = inner_decoders_.back().get(); + if (!inner_decoder->CanAdvance()) { + // The inner node's sub-tree has been visited. Remove from the DFS stack. + inner_decoders_.pop_back(); + continue; + } + int next_page_id = inner_decoder->TryAdvance(); + if (next_page_id == DatabasePageReader::kInvalidPageId) + continue; + AppendPageDecoder(next_page_id); + } + + // The cursor reached the end of the table. + return SQLITE_OK; +} + +int VirtualCursor::ReadColumn(int column_index, + sqlite3_context* result_context) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_GE(column_index, 0); + DCHECK_LT(column_index, static_cast<int>(table_->column_specs().size())); + DCHECK(record_reader_.IsInitialized()); + + if (table_->column_specs()[column_index].type == ModuleColumnType::kRowId) { + sqlite3_result_int64(result_context, RowId()); + return SQLITE_OK; + } + + if (record_reader_.ReadValue(column_index, result_context)) + return SQLITE_OK; + return SQLITE_ERROR; +} + +int64_t VirtualCursor::RowId() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(record_reader_.IsInitialized()); + DCHECK(leaf_decoder_.get()); + return leaf_decoder_->last_record_rowid(); +} + +void VirtualCursor::AppendPageDecoder(int page_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(leaf_decoder_.get() == nullptr) + << __func__ + << " must only be called when the current path has no leaf decoder"; + + if (db_reader_.ReadPage(page_id) != SQLITE_OK) + return; + + if (LeafPageDecoder::IsOnValidPage(&db_reader_)) { + leaf_decoder_ = std::make_unique<LeafPageDecoder>(&db_reader_); + return; + } + + if (InnerPageDecoder::IsOnValidPage(&db_reader_)) { + // Detect cycles. + for (const auto& decoder : inner_decoders_) { + if (decoder->page_id() == page_id) + return; + } + + // Give up on overly deep tree branches. + // + // SQLite supports up to 2^31 pages. SQLite ensures that inner nodes can + // hold at least 4 child pointers, even in the presence of very large keys. + // So, even poorly balanced trees should not exceed 100 nodes in depth. + // InnerPageDecoder instances take up 32 bytes on 64-bit platforms. + // + // The depth limit below balances recovering broken trees with avoiding + // excessive memory consumption. + constexpr int kMaxTreeDepth = 10000; + if (inner_decoders_.size() == kMaxTreeDepth) + return; + + inner_decoders_.emplace_back( + std::make_unique<InnerPageDecoder>(&db_reader_)); + return; + } +} + +bool VirtualCursor::IsAcceptableRecord() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(record_reader_.IsInitialized()); + + const std::vector<RecoveredColumnSpec>& column_specs = table_->column_specs(); + const int column_count = static_cast<int>(column_specs.size()); + for (int column_index = 0; column_index < column_count; ++column_index) { + ValueType value_type = record_reader_.GetValueType(column_index); + if (!column_specs[column_index].IsAcceptableValue(value_type)) + return false; + } + return true; +} + +} // namespace recover +} // namespace sql
diff --git a/sql/recover_module/cursor.h b/sql/recover_module/cursor.h new file mode 100644 index 0000000..a858caa7 --- /dev/null +++ b/sql/recover_module/cursor.h
@@ -0,0 +1,136 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_CURSOR_H_ +#define SQL_RECOVER_MODULE_CURSOR_H_ + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <utility> + +#include "base/logging.h" +#include "base/sequence_checker.h" +#include "sql/recover_module/btree.h" +#include "sql/recover_module/pager.h" +#include "sql/recover_module/parsing.h" +#include "sql/recover_module/payload.h" +#include "sql/recover_module/record.h" +#include "third_party/sqlite/sqlite3.h" + +namespace sql { +namespace recover { + +class VirtualTable; + +// Represents a virtual table cursor created by SQLite in a recovery table. +// +// Instances are allocated on the heap using the C++ new operator, and passed to +// SQLite via pointers to the sqlite_vtab members. SQLite is responsible for +// managing the instances' lifetimes. SQLite will call xClose() for every +// successful xOpen(). +// +// Instances are not thread-safe. This should be fine, as long as each SQLite +// statement that reads from a virtual table is only used on one sequence. This +// assumption is verified by a sequence checker. +// +// If it turns out that VirtualCursor needs to be thread-safe, the best solution +// is to add a base::Lock to VirtualCursor, and keep all underlying classes not +// thread-safe. +class VirtualCursor { + public: + // Creates a cursor that iterates over |table|. + // + // |table| must outlive this instance. SQLite is trusted to call xClose() for + // this cursor before calling xDestroy() / xDisconnect() for the virtual table + // related to the cursor. + explicit VirtualCursor(VirtualTable* table); + ~VirtualCursor(); + + VirtualCursor(const VirtualCursor&) = delete; + VirtualCursor& operator=(const VirtualCursor&) = delete; + + // Returns the embedded SQLite virtual table cursor. + // + // This getter is not const because SQLite wants a non-const pointer to the + // structure. + sqlite3_vtab_cursor* SqliteCursor() { return &sqlite_cursor_; } + + // The VirtualCursor instance that embeds a given SQLite virtual table cursor. + // + // |sqlite_cursor| must have been returned by VirtualTable::SqliteCursor(). + static inline VirtualCursor* FromSqliteCursor( + sqlite3_vtab_cursor* sqlite_cursor) { + static_assert(std::is_standard_layout<VirtualCursor>::value, + "needed for the reinterpret_cast below"); + static_assert(offsetof(VirtualCursor, sqlite_cursor_) == 0, + "sqlite_cursor_ must be the first member of the class"); + VirtualCursor* result = reinterpret_cast<VirtualCursor*>(sqlite_cursor); + DCHECK_EQ(sqlite_cursor, &result->sqlite_cursor_); + return result; + } + + // Seeks the cursor to the first readable row. Returns a SQLite status code. + int First(); + + // Seeks the cursor to the next row. Returns a SQLite status code. + int Next(); + + // Returns true if the cursor points to a valid row, false otherwise. + bool IsValid() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return record_reader_.IsInitialized(); + } + + // Reports a value in the record to SQLite. |column_index| is 0-based. + // + // Returns a SQLite error code. This method can fail can happen if a value is + // stored across overflow pages, and reading one of the overflow pages results + // in an I/O error. + int ReadColumn(int column_index, sqlite3_context* result_context); + + // Returns the rowid of the current row. The cursor must point to a valid row. + int64_t RowId(); + + private: + // Appends a decoder for the given page at the end of the current chain. + // + // No modification is performed in case of failures due to I/O errors or + // database corruption. + void AppendPageDecoder(int page_id); + + // True if the current record is acceptable given the recovery schema. + bool IsAcceptableRecord(); + + // SQLite handle for this cursor. The struct is populated and used by SQLite. + sqlite3_vtab_cursor sqlite_cursor_; + + // The table this cursor was created for. + VirtualTable* const table_; + + // Reads database pages for this cursor. + DatabasePageReader db_reader_; + + // Reads record payloads for this cursor. + LeafPayloadReader payload_reader_; + + // Reads record rows for this cursor. + RecordReader record_reader_; + + // Decoders for the current chain of inner pages. + // + // The current chain of pages consists of the inner page decoders here and the + // decoder in |leaf_decoder_|. + std::vector<std::unique_ptr<InnerPageDecoder>> inner_decoders_; + + // Decodes the leaf page containing records. + std::unique_ptr<LeafPageDecoder> leaf_decoder_; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_CURSOR_H_ \ No newline at end of file
diff --git a/sql/recover_module/integers.cc b/sql/recover_module/integers.cc new file mode 100644 index 0000000..476ccf81 --- /dev/null +++ b/sql/recover_module/integers.cc
@@ -0,0 +1,39 @@ +// Copyright 2019 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 "sql/recover_module/integers.h" + +#include "base/logging.h" + +namespace sql { +namespace recover { + +std::pair<int64_t, const uint8_t*> ParseVarint(const uint8_t* buffer, + const uint8_t* buffer_end) { + DCHECK(buffer != nullptr); + DCHECK(buffer_end != nullptr); + + DCHECK_LT(buffer, buffer_end); + const uint8_t* const regular_buffer_end = + (buffer_end - buffer > kMaxVarintSize - 1) ? buffer + kMaxVarintSize - 1 + : buffer_end; + + uint64_t value = 0; + uint8_t last_byte; + while (buffer < regular_buffer_end) { + last_byte = *buffer; + ++buffer; + value = (value << 7) | (last_byte & 0x7f); + if ((last_byte & 0x80) == 0) + break; + } + if (buffer < buffer_end && (last_byte & 0x80) != 0) { + value = (value << 8) | *buffer; + ++buffer; + } + return {value, buffer}; +} + +} // namespace recover +} // namespace sql
diff --git a/sql/recover_module/integers.h b/sql/recover_module/integers.h new file mode 100644 index 0000000..8b19297 --- /dev/null +++ b/sql/recover_module/integers.h
@@ -0,0 +1,76 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_INTEGERS_H_ +#define SQL_RECOVER_MODULE_INTEGERS_H_ + +#include <cstdint> +#include <limits> + +namespace sql { +namespace recover { + +// Reads an unsigned 16-bit big-endian integer from the given buffer. +// +// |buffer| must point to at least two consecutive bytes of valid memory. +// +// The return type was chosen because it suits the callers best. +inline int LoadBigEndianUint16(const uint8_t* buffer) { + static_assert( + std::numeric_limits<uint16_t>::max() <= std::numeric_limits<int>::max(), + "The value may overflow the return type"); + return (static_cast<int>(buffer[0]) << 8) | static_cast<int>(buffer[1]); +} + +// Reads a signed 32-bit big-endian integer from the given buffer. +// +// |buffer| must point to at least four consecutive bytes of valid memory. +inline int32_t LoadBigEndianInt32(const uint8_t* buffer) { + // The code gets optimized to mov + bswap on x86_64, and to ldr + rev on ARM. + return (static_cast<int32_t>(buffer[0]) << 24) | + (static_cast<int32_t>(buffer[1]) << 16) | + (static_cast<int32_t>(buffer[2]) << 8) | + static_cast<int32_t>(buffer[3]); +} + +// Reads a signed 64-bit big-endian integer from the given buffer. +// +// |buffer| must point to at least eight consecutive bytes of valid memory. +inline int64_t LoadBigEndianInt64(const uint8_t* buffer) { + // The code gets optimized to mov + bswap on x86_64, and to ldr + rev on ARM. + return (static_cast<int64_t>(buffer[0]) << 56) | + (static_cast<int64_t>(buffer[1]) << 48) | + (static_cast<int64_t>(buffer[2]) << 40) | + (static_cast<int64_t>(buffer[3]) << 32) | + (static_cast<int64_t>(buffer[4]) << 24) | + (static_cast<int64_t>(buffer[5]) << 16) | + (static_cast<int64_t>(buffer[6]) << 8) | + static_cast<int64_t>(buffer[7]); +} + +// Reads a SQLite varint. +// +// SQLite varints decode to 64-bit integers, and take up at most 9 bytes. +// If present, the 9th byte holds bits 56-63 of the integer. This deviates from +// Google (protobuf, leveldb) varint encoding, where the last varint byte's top +// bit is always 0. +// +// The implementation assumes that |buffer| and |buffer_end| point into the same +// array of bytes, and that |buffer| < |buffer_end|. The implementation will +// never compute a pointer value larger than |buffer_end|. +// +// Returns the parsed number and a pointer to the first byte past the number. +// Per the rules above, the returned pointer is guaranteed to be between +// |buffer| and |buffer_end|. The returned pointer is also guaranteed to be at +// most |kMaxVarintSize| bytes past |buffer|. +std::pair<int64_t, const uint8_t*> ParseVarint(const uint8_t* buffer, + const uint8_t* buffer_end); + +// The maximum number of bytes used to store a SQLite varint. +constexpr int kMaxVarintSize = 9; + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_INTEGERS_H_
diff --git a/sql/recover_module/module.cc b/sql/recover_module/module.cc new file mode 100644 index 0000000..3b68ea42 --- /dev/null +++ b/sql/recover_module/module.cc
@@ -0,0 +1,282 @@ +// Copyright 2019 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 "sql/recover_module/module.h" + +#include <cstddef> +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + +#include "base/logging.h" +#include "base/strings/strcat.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "sql/recover_module/cursor.h" +#include "sql/recover_module/parsing.h" +#include "sql/recover_module/table.h" +#include "third_party/sqlite/sqlite3.h" + +// https://sqlite.org/vtab.html documents SQLite's virtual table module API. + +namespace sql { +namespace recover { + +namespace { + +// SQLite module argument constants. +static constexpr int kModuleNameArgument = 0; +static constexpr int kVirtualTableDbNameArgument = 1; +static constexpr int kVirtualTableNameArgument = 2; +static constexpr int kBackingTableSpecArgument = 3; +static constexpr int kFirstColumnArgument = 4; + +// Returns an empty vector on parse errors. +std::vector<RecoveredColumnSpec> ParseColumnSpecs(int argc, + const char* const* argv) { + std::vector<RecoveredColumnSpec> result; + DCHECK_GE(argc, kFirstColumnArgument); + result.reserve(argc - kFirstColumnArgument + 1); + + for (int i = kFirstColumnArgument; i < argc; ++i) { + result.emplace_back(ParseColumnSpec(argv[i])); + if (!result.back().IsValid()) { + result.clear(); + break; + } + } + return result; +} + +int ModuleCreate(sqlite3* sqlite_db, + void* /* client_data */, + int argc, + const char* const* argv, + sqlite3_vtab** result_sqlite_table, + char** /* error_string */) { + DCHECK(sqlite_db != nullptr); + if (argc <= kFirstColumnArgument) { + // The recovery module needs at least one column specification. + return SQLITE_MISUSE; + } + DCHECK(argv != nullptr); + DCHECK(result_sqlite_table != nullptr); + + // This module is always expected to be registered as "recover". + DCHECK_EQ("recover", base::StringPiece(argv[kModuleNameArgument])); + + base::StringPiece db_name(argv[kVirtualTableDbNameArgument]); + if (db_name != "temp") { + // Refuse to create tables outside the "temp" database. + // + // This check is overly strict. The virtual table can be safely used on any + // temporary database (ATTACH '' AS other_temp). However, there is no easy + // way to determine if an attachment point corresponds to a temporary + // database, and "temp" is sufficient for Chrome's purposes. + return SQLITE_MISUSE; + } + + base::StringPiece table_name(argv[kVirtualTableNameArgument]); + if (!table_name.starts_with("recover_")) { + // In the future, we may deploy UMA metrics that use the virtual table name + // to attribute recovery events to Chrome features. In preparation for that + // future, require all recovery table names to start with "recover_". + return SQLITE_MISUSE; + } + + TargetTableSpec backing_table_spec = + ParseTableSpec(argv[kBackingTableSpecArgument]); + if (!backing_table_spec.IsValid()) { + // The parser concluded that the string specifying the backing table is + // invalid. This is definitely an error in the SQL using the virtual table. + return SQLITE_MISUSE; + } + + std::vector<RecoveredColumnSpec> column_specs = ParseColumnSpecs(argc, argv); + if (column_specs.empty()) { + // The column specifications were invalid. + return SQLITE_MISUSE; + } + + int sqlite_status; + std::unique_ptr<VirtualTable> table; + std::tie(sqlite_status, table) = VirtualTable::Create( + sqlite_db, std::move(backing_table_spec), std::move(column_specs)); + if (sqlite_status != SQLITE_OK) + return sqlite_status; + + { + std::string create_table_sql = table->ToCreateTableSql(); + sqlite3_declare_vtab(sqlite_db, create_table_sql.c_str()); + } + *result_sqlite_table = table->SqliteTable(); + table.release(); // SQLite manages the lifetime of the table. + return SQLITE_OK; +} + +int ModuleConnect(sqlite3* sqlite_db, + void* client_data, + int argc, + const char* const* argv, + sqlite3_vtab** result_sqlite_table, + char** error_string) { + // TODO(pwnall): Figure out if it's acceptable to have "recover" be an + // eponymous table. If so, use ModuleCreate instead of + // ModuleConnect in the entry point table. + return ModuleCreate(sqlite_db, client_data, argc, argv, result_sqlite_table, + error_string); +} + +int ModuleBestIndex(sqlite3_vtab* sqlite_table, + sqlite3_index_info* index_info) { + DCHECK(sqlite_table != nullptr); + DCHECK(index_info != nullptr); + + // The sqlite3_index_info structure is also documented at + // https://www.sqlite.org/draft/c3ref/index_info.html + for (int i = 0; i < index_info->nConstraint; ++i) { + if (index_info->aConstraint[i].usable == static_cast<char>(false)) + continue; + // True asks SQLite to evaluate the constraint and pass the result to any + // follow-up xFilter() calls, via argc/argv. + index_info->aConstraintUsage[i].argvIndex = 0; + // True indicates that the virtual table will check the constraint. + index_info->aConstraintUsage[i].omit = false; + } + index_info->orderByConsumed = static_cast<int>(false); + + // SQLite saves the sqlite_idx_info fields set here and passes the values to + // xFilter(). + index_info->idxStr = nullptr; + index_info->idxNum = 0; + index_info->needToFreeIdxStr = static_cast<int>(false); + + return SQLITE_OK; +} + +int ModuleDisconnect(sqlite3_vtab* sqlite_table) { + DCHECK(sqlite_table != nullptr); + + // SQLite takes ownership of the VirtualTable (which is passed around as a + // sqlite_table) in ModuleCreate() / ModuleConnect(). SQLite then calls + // ModuleDestroy() / ModuleDisconnect() to relinquish ownership of the + // VirtualTable. At this point, the table will not be used again, and can be + // destroyed. + VirtualTable* const table = VirtualTable::FromSqliteTable(sqlite_table); + delete table; + return SQLITE_OK; +} + +int ModuleDestroy(sqlite3_vtab* sqlite_table) { + return ModuleDisconnect(sqlite_table); +} + +int ModuleOpen(sqlite3_vtab* sqlite_table, + sqlite3_vtab_cursor** result_sqlite_cursor) { + DCHECK(sqlite_table != nullptr); + DCHECK(result_sqlite_cursor != nullptr); + + VirtualTable* const table = VirtualTable::FromSqliteTable(sqlite_table); + VirtualCursor* const cursor = table->CreateCursor(); + *result_sqlite_cursor = cursor->SqliteCursor(); + return SQLITE_OK; +} + +int ModuleClose(sqlite3_vtab_cursor* sqlite_cursor) { + DCHECK(sqlite_cursor != nullptr); + + // SQLite takes ownership of the VirtualCursor (which is passed around as a + // sqlite_cursor) in ModuleOpen(). SQLite then calls ModuleClose() to + // relinquish ownership of the VirtualCursor. At this point, the cursor will + // not be used again, and can be destroyed. + VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor); + delete cursor; + return SQLITE_OK; +} + +int ModuleFilter(sqlite3_vtab_cursor* sqlite_cursor, + int /* best_index_num */, + const char* /* best_index_str */, + int /* argc */, + sqlite3_value** /* argv */) { + DCHECK(sqlite_cursor != nullptr); + + VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor); + return cursor->First(); +} + +int ModuleNext(sqlite3_vtab_cursor* sqlite_cursor) { + DCHECK(sqlite_cursor != nullptr); + + VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor); + return cursor->Next(); +} + +int ModuleEof(sqlite3_vtab_cursor* sqlite_cursor) { + DCHECK(sqlite_cursor != nullptr); + + VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor); + return cursor->IsValid() ? 0 : 1; +} + +int ModuleColumn(sqlite3_vtab_cursor* sqlite_cursor, + sqlite3_context* result_context, + int column_index) { + DCHECK(sqlite_cursor != nullptr); + DCHECK(result_context != nullptr); + + VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor); + DCHECK(cursor->IsValid()) << "SQLite called xRowid() without a valid cursor"; + return cursor->ReadColumn(column_index, result_context); +} + +int ModuleRowid(sqlite3_vtab_cursor* sqlite_cursor, + sqlite3_int64* result_rowid) { + DCHECK(sqlite_cursor != nullptr); + DCHECK(result_rowid != nullptr); + + VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor); + DCHECK(cursor->IsValid()) << "SQLite called xRowid() without a valid cursor"; + *result_rowid = cursor->RowId(); + return SQLITE_OK; +} + +// SQLite module API version supported by this implementation. +constexpr int kSqliteModuleApiVersion = 1; + +// Entry points to the SQLite module. +constexpr sqlite3_module kSqliteModule = { + kSqliteModuleApiVersion, + &ModuleCreate, + &ModuleConnect, + &ModuleBestIndex, + &ModuleDisconnect, + &ModuleDestroy, + &ModuleOpen, + &ModuleClose, + &ModuleFilter, + &ModuleNext, + &ModuleEof, + &ModuleColumn, + &ModuleRowid, + /* xUpdate= */ nullptr, + /* xBegin= */ nullptr, + /* xSync= */ nullptr, + /* xCommit= */ nullptr, + /* xRollback= */ nullptr, + /* xFindFunction= */ nullptr, + /* xRename= */ nullptr, +}; + +} // namespace + +int RegisterRecoverExtension(sqlite3* db) { + return sqlite3_create_module_v2(db, "recover", &kSqliteModule, + /* pClientData= */ nullptr, + /* xDestroy= */ nullptr); +} + +} // namespace recover +} // namespace sql
diff --git a/sql/recover_module/module.h b/sql/recover_module/module.h new file mode 100644 index 0000000..e00aaaf --- /dev/null +++ b/sql/recover_module/module.h
@@ -0,0 +1,21 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_MODULE_H_ +#define SQL_RECOVER_MODULE_MODULE_H_ + +struct sqlite3; + +namespace sql { +namespace recover { + +// Registers the "recover" virtual table with a SQLite connection. +// +// Returns a SQLite error code. +int RegisterRecoverExtension(sqlite3* db); + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_MODULE_H_
diff --git a/sql/recover_module_unittest.cc b/sql/recover_module/module_unittest.cc similarity index 98% rename from sql/recover_module_unittest.cc rename to sql/recover_module/module_unittest.cc index 05a6527..233807ca 100644 --- a/sql/recover_module_unittest.cc +++ b/sql/recover_module/module_unittest.cc
@@ -8,7 +8,6 @@ #include <vector> #include "base/strings/stringprintf.h" -#include "build/build_config.h" // For OS_ANDROID used to disable a test. #include "sql/database.h" #include "sql/statement.h" #include "sql/test/database_test_peer.h" @@ -819,15 +818,7 @@ EXPECT_FALSE(statement.Step()); } -#if OS_ANDROID -// The SQLite patch fails this test on Android. The rewritten recovery code -// passes this test. So, the test will be unconditionally enabled when -// https://crrev.com/c/1546942 lands. -#define MAYBE_IntegerEncodings DISABLED_IntegerEncodings -#else -#define MAYBE_IntegerEncodings IntegerEncodings -#endif -TEST_F(RecoverModuleTest, MAYBE_IntegerEncodings) { +TEST_F(RecoverModuleTest, IntegerEncodings) { ASSERT_TRUE(db().Execute("CREATE TABLE integers(value)")); const std::vector<int64_t> values = {
diff --git a/sql/recover_module/pager.cc b/sql/recover_module/pager.cc new file mode 100644 index 0000000..c16aea6 --- /dev/null +++ b/sql/recover_module/pager.cc
@@ -0,0 +1,121 @@ +// Copyright 2019 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 "sql/recover_module/pager.h" + +#include <limits> + +#include "sql/recover_module/table.h" +#include "third_party/sqlite/sqlite3.h" + +namespace sql { +namespace recover { + +constexpr int DatabasePageReader::kInvalidPageId; +constexpr int DatabasePageReader::kMinPageSize; +constexpr int DatabasePageReader::kMaxPageSize; +constexpr int DatabasePageReader::kDatabaseHeaderSize; +constexpr int DatabasePageReader::kMinUsablePageSize; +constexpr int DatabasePageReader::kMaxPageId; + +static_assert(DatabasePageReader::kMaxPageId <= std::numeric_limits<int>::max(), + "ints are not appropriate for representing page IDs"); + +DatabasePageReader::DatabasePageReader(VirtualTable* table) + : page_data_(std::make_unique<uint8_t[]>(table->page_size())), + table_(table) { + DCHECK(table != nullptr); + DCHECK(IsValidPageSize(table->page_size())); +} + +DatabasePageReader::~DatabasePageReader() = default; + +int DatabasePageReader::ReadPage(int page_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_GT(page_id, kInvalidPageId); + DCHECK_LE(page_id, kMaxPageId); + + if (page_id_ == page_id) + return SQLITE_OK; + + sqlite3_file* const sqlite_file = table_->SqliteFile(); + const int page_size = table_->page_size(); + const int page_offset = (page_id == 1) ? kDatabaseHeaderSize : 0; + const int read_size = page_size - page_offset; + static_assert(kMinPageSize >= kDatabaseHeaderSize, + "The |read_size| computation above may overflow"); + + page_size_ = read_size; + DCHECK_GE(page_size_, kMinUsablePageSize); + DCHECK_LE(page_size_, kMaxPageSize); + + const int64_t read_offset = (page_id - 1) * page_size + page_offset; + static_assert((kMaxPageId - 1) * static_cast<int64_t>(kMaxPageSize) + + kDatabaseHeaderSize <= + std::numeric_limits<int64_t>::max(), + "The |read_offset| computation above may overflow"); + + int sqlite_status = + RawRead(sqlite_file, read_size, read_offset, page_data_.get()); + + // |page_id_| needs to be set to kInvalidPageId if the read failed. + // Otherwise, future ReadPage() calls with the previous |page_id_| value + // would return SQLITE_OK, but the page data buffer might be trashed. + page_id_ = (sqlite_status == SQLITE_OK) ? page_id : kInvalidPageId; + return sqlite_status; +} + +// static +int DatabasePageReader::RawRead(sqlite3_file* sqlite_file, + int read_size, + int64_t read_offset, + uint8_t* result_buffer) { + DCHECK(sqlite_file != nullptr); + DCHECK_GE(read_size, 0); + DCHECK_GE(read_offset, 0); + DCHECK(result_buffer != nullptr); + + // Retry the I/O operations a few times if they fail. This is especially + // useful when recovering from database corruption. + static constexpr int kRetryCount = 10; + + int sqlite_status; + bool got_lock = false; + for (int i = kRetryCount; i > 0; --i) { + sqlite_status = + sqlite_file->pMethods->xLock(sqlite_file, SQLITE_LOCK_SHARED); + if (sqlite_status == SQLITE_OK) { + got_lock = true; + break; + } + } + + // Try reading even if we don't have a shared lock on the database. If the + // read fails, the database page is completely skipped, so any data we might + // get from the read is better than nothing. + for (int i = kRetryCount; i > 0; --i) { + sqlite_status = sqlite_file->pMethods->xRead(sqlite_file, result_buffer, + read_size, read_offset); + if (sqlite_status == SQLITE_OK) + break; + if (sqlite_status == SQLITE_IOERR_SHORT_READ) { + // The read succeeded, but hit EOF. The extra bytes in the page buffer + // are set to zero. This is acceptable for our purposes. + sqlite_status = SQLITE_OK; + break; + } + } + + if (got_lock) { + // TODO(pwnall): This logic was ported from the old C-in-SQLite-style patch. + // Dropping the lock here is incorrect, because the file + // descriptor is shared with the SQLite pager, which may + // expect to be holding a lock. + sqlite_file->pMethods->xUnlock(sqlite_file, SQLITE_LOCK_NONE); + } + return sqlite_status; +} + +} // namespace recover +} // namespace sql \ No newline at end of file
diff --git a/sql/recover_module/pager.h b/sql/recover_module/pager.h new file mode 100644 index 0000000..398904af --- /dev/null +++ b/sql/recover_module/pager.h
@@ -0,0 +1,150 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_PAGER_H_ +#define SQL_RECOVER_MODULE_PAGER_H_ + +#include <cstdint> +#include <memory> + +#include "base/logging.h" +#include "base/sequence_checker.h" + +struct sqlite3_file; + +namespace sql { +namespace recover { + +class VirtualTable; + +// Page reader for SQLite database files. +// +// Contains logic for retrying reads on I/O errors. Caches the last read page, +// to facilitate layering in higher-level code. +// +// Instances should be members of high-level constructs such as tables or +// cursors. Instances are not thread-safe. +class DatabasePageReader { + public: + // Guaranteed to be an invalid page number. + static constexpr int kInvalidPageId = 0; + + // Minimum database page size supported by SQLite. + static constexpr int kMinPageSize = 512; + // Maximum database page size supported by SQLite. + static constexpr int kMaxPageSize = 65536; + + // The size of the header at the beginning of a SQLite database file. + static constexpr int kDatabaseHeaderSize = 100; + + // Minimum usable size of a SQLite database page. + // + // This differs from |kMinPageSize| because the first page in a SQLite + // database starts with the database header. That page's header starts right + // after the database header. + static constexpr int kMinUsablePageSize = kMinPageSize - kDatabaseHeaderSize; + + // Maximum number of pages in a SQLite database. + // + // This is the maximum value of SQLITE_MAX_PAGE_COUNT plus 1, because page IDs + // start at 1. The numerical value, which is the same as + // std::numeric_limits<int32_t>::max() - 1, is quoted from + // https://www.sqlite.org/limits.html. + static constexpr int kMaxPageId = 2147483646 + 1; + + // Creates a reader that uses the SQLite VFS backing |table|. + // + // |table| must outlive this instance. + explicit DatabasePageReader(VirtualTable* table); + ~DatabasePageReader(); + + DatabasePageReader(const DatabasePageReader&) = delete; + DatabasePageReader& operator=(const DatabasePageReader&) = delete; + + // The page data read by the last ReadPage() call. + // + // The page data is undefined if the last ReadPage() call failed, or if + // ReadPage() was never called. + const uint8_t* page_data() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_NE(page_id_, kInvalidPageId) + << "Successful ReadPage() required before accessing pager state"; + return page_data_.get(); + } + + // The number of bytes in the page read by the last ReadPage() call. + // + // The result is guaranteed to be in [kMinUsablePageSize, kMaxPageSize]. + // + // In general, pages have the same size. However, the first page in each + // database is smaller, because it starts after the database header. + // + // The result is undefined if the last ReadPage() call failed, or if + // ReadPage() was never called. + int page_size() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_NE(page_id_, kInvalidPageId) + << "Successful ReadPage() required before accessing pager state"; + DCHECK_GE(page_size_, kMinUsablePageSize); + DCHECK_LE(page_size_, kMaxPageSize); + return page_size_; + } + + // Returns the |page_id| argument for the last successful ReadPage() call. + // + // The result is undefined if the last ReadPage() call failed, or if + // ReadPage() was never called. + int page_id() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_NE(page_id_, kInvalidPageId) + << "Successful ReadPage() required before accessing pager state"; + return page_id_; + } + + // Reads a database page. Returns a SQLite status code. + // + // SQLite uses 1-based indexing for its page numbers. + // + // This method is idempotent, because it caches its result. + int ReadPage(int page_id); + + // True if the given database page size is supported by SQLite. + static constexpr bool IsValidPageSize(int page_size) noexcept { + // SQLite page sizes must be powers of two. + return page_size >= kMinPageSize && page_size <= kMaxPageSize && + (page_size & (page_size - 1)) == 0; + } + + // True if the given number is a valid SQLite database page ID. + // + // Valid page IDs are positive 32-bit integers. + static constexpr bool IsValidPageId(int64_t page_id) noexcept { + return page_id > kInvalidPageId && page_id <= kMaxPageId; + } + + // Low-level read wrapper. Returns a SQLite error code. + // + // |read_size| and |read_offset| are expressed in bytes. + static int RawRead(sqlite3_file* sqlite_file, + int read_size, + int64_t read_offset, + uint8_t* buffer); + + private: + // Points to the last page successfully read by ReadPage(). + // Set to kInvalidPageId if the last read was unsuccessful. + int page_id_ = kInvalidPageId; + // + const std::unique_ptr<uint8_t[]> page_data_; + // Raw + VirtualTable* const table_; + int page_size_ = 0; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_PAGER_H_ \ No newline at end of file
diff --git a/sql/recover_module/parsing.cc b/sql/recover_module/parsing.cc new file mode 100644 index 0000000..85a1b5a --- /dev/null +++ b/sql/recover_module/parsing.cc
@@ -0,0 +1,218 @@ +// Copyright 2019 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 "sql/recover_module/parsing.h" + +#include <cstddef> +#include <tuple> +#include <utility> + +#include "base/logging.h" +#include "base/optional.h" +#include "base/strings/strcat.h" +#include "base/strings/string_piece.h" +#include "sql/recover_module/record.h" + +namespace sql { +namespace recover { + +namespace { + +// This module defines whitespace as space (0x20). +constexpr bool IsWhiteSpace(char character) { + return (character == ' '); +} + +// Splits a token out of a SQL string representing a column type. +// +// Tokens are separated by space (0x20) characters. +// +// The SQL must not start with a space character. +// +// Returns the token and the rest of the SQL string. Consumes the space after +// the returned token -- the rest of the SQL string will not start with space. +std::pair<base::StringPiece, base::StringPiece> SplitToken( + base::StringPiece sql) { + DCHECK(sql.empty() || !IsWhiteSpace(sql[0])); + + size_t token_end = 0; + while (token_end < sql.length() && !IsWhiteSpace(sql[token_end])) + ++token_end; + + size_t split = token_end; + while (split < sql.length() && IsWhiteSpace(sql[split])) + ++split; + + return {sql.substr(0, token_end), sql.substr(split)}; +} + +// Column types. +constexpr base::StringPiece kIntegerSql("INTEGER"); +constexpr base::StringPiece kFloatSql("FLOAT"); +constexpr base::StringPiece kTextSql("TEXT"); +constexpr base::StringPiece kBlobSql("BLOB"); +constexpr base::StringPiece kNumericSql("NUMERIC"); +constexpr base::StringPiece kRowidSql("ROWID"); +constexpr base::StringPiece kAnySql("ANY"); + +// SQL keywords recognized by the recovery module. +constexpr base::StringPiece kStrictSql("STRICT"); +constexpr base::StringPiece kNonNullSql1("NOT"); +constexpr base::StringPiece kNonNullSql2("NULL"); + +base::Optional<ModuleColumnType> ParseColumnType( + base::StringPiece column_type_sql) { + if (column_type_sql == kIntegerSql) + return ModuleColumnType::kInteger; + if (column_type_sql == kFloatSql) + return ModuleColumnType::kFloat; + if (column_type_sql == kTextSql) + return ModuleColumnType::kText; + if (column_type_sql == kBlobSql) + return ModuleColumnType::kBlob; + if (column_type_sql == kNumericSql) + return ModuleColumnType::kNumeric; + if (column_type_sql == kRowidSql) + return ModuleColumnType::kRowId; + if (column_type_sql == kAnySql) + return ModuleColumnType::kAny; + + return base::nullopt; +} + +// Returns a view into a SQL string representing the column type. +// +// The backing string is guaranteed to live for as long as the process runs. +base::StringPiece ColumnTypeToSql(ModuleColumnType column_type) { + switch (column_type) { + case ModuleColumnType::kInteger: + return kIntegerSql; + case ModuleColumnType::kFloat: + return kFloatSql; + case ModuleColumnType::kText: + return kTextSql; + case ModuleColumnType::kBlob: + return kBlobSql; + case ModuleColumnType::kNumeric: + return kNumericSql; + case ModuleColumnType::kRowId: + return kIntegerSql; // rowids are ints. + case ModuleColumnType::kAny: + return base::StringPiece(); + } + NOTREACHED(); +} + +} // namespace + +std::string RecoveredColumnSpec::ToCreateTableSql() const { + base::StringPiece not_null_sql = (is_non_null) ? " NOT NULL" : ""; + return base::StrCat( + {this->name, " ", ColumnTypeToSql(this->type), not_null_sql}); +} + +bool RecoveredColumnSpec::IsAcceptableValue(ValueType value_type) const { + if (value_type == ValueType::kNull) + return !is_non_null || type == ModuleColumnType::kRowId; + if (type == ModuleColumnType::kAny) + return true; + + if (value_type == ValueType::kInteger) { + return type == ModuleColumnType::kInteger || + (!is_strict && type == ModuleColumnType::kFloat); + } + if (value_type == ValueType::kFloat) { + return type == ModuleColumnType::kFloat || + (!is_strict && type == ModuleColumnType::kFloat); + } + if (value_type == ValueType::kText) + return type == ModuleColumnType::kText; + if (value_type == ValueType::kBlob) { + return type == ModuleColumnType::kBlob || + (!is_strict && type == ModuleColumnType::kText); + } + NOTREACHED() << "Unimplemented value type"; + return false; +} + +RecoveredColumnSpec ParseColumnSpec(const char* sqlite_arg) { + // The result is invalid until its |name| member is set. + RecoveredColumnSpec result; + base::StringPiece sql(sqlite_arg); + + base::StringPiece column_name; + std::tie(column_name, sql) = SplitToken(sql); + if (column_name.empty()) { + // Empty column names are invalid. + DCHECK(!result.IsValid()); + return result; + } + + base::StringPiece column_type_sql; + std::tie(column_type_sql, sql) = SplitToken(sql); + base::Optional<ModuleColumnType> column_type = + ParseColumnType(column_type_sql); + if (!column_type.has_value()) { + // Invalid column type. + DCHECK(!result.IsValid()); + return result; + } + result.type = column_type.value(); + + // Consume keywords. + result.is_non_null = result.type == ModuleColumnType::kRowId; + while (!sql.empty()) { + base::StringPiece token; + std::tie(token, sql) = SplitToken(sql); + + if (token == kStrictSql) { + if (result.type == ModuleColumnType::kAny) { + // STRICT is incompatible with ANY. + DCHECK(!result.IsValid()); + return result; + } + + result.is_strict = true; + continue; + } + + if (token != kNonNullSql1) { + // Invalid SQL keyword. + DCHECK(!result.IsValid()); + return result; + } + std::tie(token, sql) = SplitToken(sql); + if (token != kNonNullSql2) { + // Invalid SQL keyword. + DCHECK(!result.IsValid()); + return result; + } + result.is_non_null = true; + } + + result.name = column_name.as_string(); + return result; +} + +TargetTableSpec ParseTableSpec(const char* sqlite_arg) { + base::StringPiece sql(sqlite_arg); + + size_t separator_pos = sql.find('.'); + if (separator_pos == base::StringPiece::npos) { + // The default attachment point name is "main". + return TargetTableSpec{"main", sqlite_arg}; + } + + if (separator_pos == 0) { + // Empty attachment point names are invalid. + return TargetTableSpec(); + } + + base::StringPiece db_name = sql.substr(0, separator_pos); + base::StringPiece table_name = sql.substr(separator_pos + 1); + return TargetTableSpec{db_name.as_string(), table_name.as_string()}; +} + +} // namespace recover +} // namespace sql
diff --git a/sql/recover_module/parsing.h b/sql/recover_module/parsing.h new file mode 100644 index 0000000..a35839bd --- /dev/null +++ b/sql/recover_module/parsing.h
@@ -0,0 +1,72 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_PARSING_H_ +#define SQL_RECOVER_MODULE_PARSING_H_ + +#include <string> + +namespace sql { +namespace recover { + +enum class ValueType; + +// The declared data type of a virtual table column. +enum class ModuleColumnType { + kInteger, + kFloat, + kText, + kBlob, + kNumeric, + kRowId, + kAny, +}; + +// User-supplied specification for recovering a column in a corrupted table. +struct RecoveredColumnSpec { + // False if this represents a parsing error. + bool IsValid() const { return !name.empty(); } + // Column description suitable for use in a CREATE TABLE statement. + std::string ToCreateTableSql() const; + // True if the given value type is admitted by this column specification. + bool IsAcceptableValue(ValueType value_type) const; + + // Column name reported to the SQLite engine. + // + // The empty string is (ab)used for representing invalid column information, + // which can be used to communicate parsing errors. + std::string name; + // The column's canonical type. + ModuleColumnType type; + // If true, recovery will skip over null values in this column. + bool is_non_null = false; + // If true, recovery will accept values in this column with compatible types. + bool is_strict = false; +}; + +// Parses a SQLite module argument that holds a table column specification. +// +// Returns an invalid specification (IsValid() returns false) on parsing errors. +RecoveredColumnSpec ParseColumnSpec(const char* sqlite_arg); + +// User-supplied SQL table identifier. +// +// This points to the table whose data is being recovered. +struct TargetTableSpec { + // False if this represents a parsing error. + bool IsValid() const { return !table_name.empty(); } + + // The name of the attachment point of the database containing the table. + std::string db_name; + // The name of the table. Uniquely identifies a table in a database. + std::string table_name; +}; + +// Parses a SQLite module argument that points to a table. +TargetTableSpec ParseTableSpec(const char* sqlite_arg); + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_PARSING_H_
diff --git a/sql/recover_module/payload.cc b/sql/recover_module/payload.cc new file mode 100644 index 0000000..f7c4f45 --- /dev/null +++ b/sql/recover_module/payload.cc
@@ -0,0 +1,328 @@ + +// Copyright 2019 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 "sql/recover_module/payload.h" + +#include <algorithm> +#include <cstddef> +#include <limits> +#include <type_traits> + +#include "base/logging.h" +#include "sql/recover_module/btree.h" +#include "sql/recover_module/integers.h" +#include "sql/recover_module/pager.h" +#include "third_party/sqlite/sqlite3.h" + +namespace sql { +namespace recover { + +namespace { + +// The size of page IDs pointing to overflow pages. +constexpr int kPageIdSize = sizeof(int32_t); + +// The largest page header size. Inner B-tree pages use this size. +constexpr int kMaxPageOverhead = 12; + +// Maximum number of bytes in a cell used by header and trailer. +// +// The maximum overhead is incurred by cells in leaf table B-tree pages. +// * 2-byte cell pointer, in the cell pointer array +// * 9-byte row ID, for the maximum varint size +// * 8-byte payload size, (varint size for maximum payload size of 2 ** 48) +// * 4-byte first overflow page ID +constexpr int kMaxCellOverhead = 23; + +// Knob used to trade off between having more rows in a tree page and +// avoiding the use of overflow pages for large values. The knob value is +// stored in the database header. +// +// In SQLite 3.6 and above, the knob was fixed to the value below. +static constexpr int kLeafPayloadFraction = 32; + +// Denominator used by all load fractions in SQLite's B-tree logic. +static constexpr int kPayloadFractionDenominator = 255; + +// The maximum size of a payload on a leaf page. +// +// Records whose size exceeds this limit spill over to overflow pages. +// +// The return value is guaranteed to be at least +// LeafPayloadReader::kMinInlineSize, and at most the database page size. +int MaxInlinePayloadSize(int page_size) { + DCHECK_GE(page_size, DatabasePageReader::kMinUsablePageSize); + DCHECK_LE(page_size, DatabasePageReader::kMaxPageSize); + + const int max_inline_payload_size = + page_size - kMaxPageOverhead - kMaxCellOverhead; + DCHECK_GE(max_inline_payload_size, LeafPayloadReader::kMinInlineSize); + static_assert( + DatabasePageReader::kMinPageSize - kMaxPageOverhead - kMaxCellOverhead > + LeafPayloadReader::kMinInlineSize, + "The DCHECK above may fail"); + + return max_inline_payload_size; +} + +// The minimum size of a payload on a B-tree page. +// +// Records that spill over to overflow pages are guaranteed to have at least +// these many bytes stored in the B-tree page. +// +// The return value is guaranteed to be at least +// LeafPayloadReader::kMinInlineSize, and at most +// MaxInlinePayloadSize(page_size). +int MinInlinePayloadSize(int page_size) { + DCHECK_GE(page_size, DatabasePageReader::kMinUsablePageSize); + DCHECK_LE(page_size, DatabasePageReader::kMaxPageSize); + + const int min_inline_payload_size = + ((page_size - kMaxPageOverhead) * kLeafPayloadFraction) / + kPayloadFractionDenominator - + kMaxCellOverhead; + static_assert((DatabasePageReader::kMaxPageSize - kMaxPageOverhead) * + kLeafPayloadFraction <= + std::numeric_limits<int>::max(), + "The |min_inline_payload_size| computation above may overflow"); + DCHECK_GE(min_inline_payload_size, LeafPayloadReader::kMinInlineSize); + static_assert(((DatabasePageReader::kMinUsablePageSize - kMaxPageOverhead) * + kLeafPayloadFraction) / + kPayloadFractionDenominator - + kMaxCellOverhead >= + LeafPayloadReader::kMinInlineSize, + "The DCHECK above may fail"); + + // The minimum inline payload size is ((P - 12) * 32) / 255 - 23. This is + // smaller or equal to ((P - 12) * 255) / 255 - 23, which is P - 35. This is + // the maximum payload size. + DCHECK_LE(min_inline_payload_size, MaxInlinePayloadSize(page_size)); + + return min_inline_payload_size; +} + +// The maximum size of a payload on an overflow page. +// +// The return value is guaranteed to be positive, and at most equal to the page +// size. +int MaxOverflowPayloadSize(int page_size) { + DCHECK_GE(page_size, DatabasePageReader::kMinUsablePageSize); + DCHECK_LE(page_size, DatabasePageReader::kMaxPageSize); + + // Each overflow page starts with a 32-bit integer pointing to the next + // overflow page. The rest of the page stores payload bytes. + const int max_overflow_payload_size = page_size - 4; + + DCHECK_GT(max_overflow_payload_size, 0); + static_assert(DatabasePageReader::kMinUsablePageSize > 4, + "The DCHECK above may fail"); + DCHECK_LE(max_overflow_payload_size, DatabasePageReader::kMaxPageSize); + return max_overflow_payload_size; +} + +} // namespace + +LeafPayloadReader::LeafPayloadReader(DatabasePageReader* db_reader) + : db_reader_(db_reader), page_id_(DatabasePageReader::kInvalidPageId) {} + +LeafPayloadReader::~LeafPayloadReader() = default; + +bool LeafPayloadReader::Initialize(int64_t payload_size, int payload_offset) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + payload_size_ = payload_size; + inline_payload_offset_ = payload_offset; + page_id_ = db_reader_->page_id(); + + const int page_size = db_reader_->page_size(); + + const int max_inline_payload_size = MaxInlinePayloadSize(page_size); + if (payload_size <= max_inline_payload_size) { + // The payload fits inside the page. + inline_payload_size_ = static_cast<int>(payload_size); + overflow_page_count_ = 0; + } else { + const int min_inline_payload_size = MinInlinePayloadSize(page_size); + + // The payload size is bigger than the maximum inline payload size, so it + // must be bigger than the minimum payload size. This check verifies that + // the subtractions below have non-negative results. + DCHECK_GT(payload_size, min_inline_payload_size); + + // Payload sizes are upper-bounded by the page size. + static_assert( + DatabasePageReader::kMaxPageSize * 2 <= std::numeric_limits<int>::max(), + "The additions below may overflow"); + + // Ideally, all bytes in the overflow pages would be used by the payload. + // Check if this can be accomplished within the other payload constraints. + max_overflow_payload_size_ = MaxOverflowPayloadSize(page_size); + const int64_t efficient_overflow_page_count = + (payload_size - min_inline_payload_size) / max_overflow_payload_size_; + const int efficient_overflow_spill = + (payload_size - min_inline_payload_size) % max_overflow_payload_size_; + const int efficient_inline_payload_size = + min_inline_payload_size + efficient_overflow_spill; + + if (efficient_inline_payload_size <= max_inline_payload_size) { + inline_payload_size_ = efficient_inline_payload_size; + overflow_page_count_ = efficient_overflow_page_count; + DCHECK_EQ( + 0, (payload_size - inline_payload_size_) % max_overflow_payload_size_) + << "Overflow pages not fully packed"; + } else { + inline_payload_size_ = min_inline_payload_size; + overflow_page_count_ = efficient_overflow_page_count + 1; + } + + DCHECK_LE(inline_payload_size_, max_inline_payload_size); + DCHECK_EQ(overflow_page_count_, (payload_size - inline_payload_size_ + + (max_overflow_payload_size_ - 1)) / + max_overflow_payload_size_) + << "Incorect overflow page count calculation"; + } + + DCHECK_LE(inline_payload_size_, payload_size); + DCHECK_LE(inline_payload_size_, page_size); + + const int first_overflow_page_id_size = + (overflow_page_count_ == 0) ? 0 : kPageIdSize; + + if (inline_payload_offset_ + inline_payload_size_ + + first_overflow_page_id_size > + page_size) { + // Corruption can result in overly large payload sizes. Reject the obvious + // case where the in-page payload extends past the end of the page. + page_id_ = DatabasePageReader::kInvalidPageId; + return false; + } + + overflow_page_ids_.clear(); + overflow_page_ids_.reserve(overflow_page_count_); + return true; +} + +bool LeafPayloadReader::ReadPayload(int64_t offset, + int64_t size, + uint8_t* buffer) { + DCHECK_GE(offset, 0); + DCHECK_LT(offset, payload_size_); + DCHECK_GT(size, 0); + DCHECK_LE(offset + size, payload_size_); + DCHECK(buffer != nullptr); + + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(page_id_ != DatabasePageReader::kInvalidPageId) + << "Initialize() not called, or last call did not succeed"; + + if (offset < inline_payload_size_) { + // The read overlaps the payload bytes stored in the B-tree page. + if (db_reader_->ReadPage(page_id_) != SQLITE_OK) + return false; + const int page_size = db_reader_->page_size(); + + // The static_cast is safe because inline_payload_size_ is smaller than a + // SQLite page size, which is a 32-bit integer. + const int read_offset = inline_payload_offset_ + static_cast<int>(offset); + DCHECK_LE(read_offset, page_size); + + const int read_size = + (static_cast<int>(offset) + size <= inline_payload_size_) + ? static_cast<int>(size) + : inline_payload_size_ - static_cast<int>(offset); + DCHECK_LE(read_offset + read_size, page_size); + std::copy(db_reader_->page_data() + read_offset, + db_reader_->page_data() + read_offset + read_size, buffer); + + if (read_size == size) { + // The read is entirely inside the B-tree page. + return true; + } + + offset += read_size; + DCHECK_EQ(offset, inline_payload_size_); + DCHECK_GT(size, read_size); + size -= read_size; + buffer += read_size; + } + + // The read is entirely in overflow pages. + DCHECK_GE(offset, inline_payload_size_); + while (size > 0) { + const int overflow_page_index = + (offset - inline_payload_size_) / max_overflow_payload_size_; + DCHECK_LT(overflow_page_index, overflow_page_count_); + const int overflow_page_offset = + (offset - inline_payload_size_) % max_overflow_payload_size_; + + while (overflow_page_ids_.size() <= + static_cast<size_t>(overflow_page_index)) { + if (!PopulateNextOverflowPageId()) + return false; + } + + const int page_id = overflow_page_ids_[overflow_page_index]; + if (db_reader_->ReadPage(page_id) != SQLITE_OK) + return false; + const int page_size = db_reader_->page_size(); + + const int read_offset = kPageIdSize + overflow_page_offset; + DCHECK_LE(read_offset, page_size); + + const int read_size = std::min<int64_t>(page_size - read_offset, size); + DCHECK_LE(read_offset + read_size, page_size); + std::copy(db_reader_->page_data() + read_offset, + db_reader_->page_data() + read_offset + read_size, buffer); + + offset += read_size; + DCHECK_GE(size, read_size); + size -= read_size; + buffer += read_size; + } + + return true; +} + +const uint8_t* LeafPayloadReader::ReadInlinePayload() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(page_id_ != DatabasePageReader::kInvalidPageId) + << "Initialize() not called, or last call did not succeed"; + + if (db_reader_->ReadPage(page_id_) != SQLITE_OK) + return nullptr; + return db_reader_->page_data() + inline_payload_offset_; +} + +bool LeafPayloadReader::PopulateNextOverflowPageId() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_LT(overflow_page_ids_.size(), + static_cast<size_t>(overflow_page_count_)); + + int page_id_offset; + if (overflow_page_ids_.empty()) { + // The first overflow page ID is right after the payload's inline bytes. + page_id_offset = inline_payload_offset_ + inline_payload_size_; + if (db_reader_->ReadPage(page_id_) != SQLITE_OK) + return false; + } else { + // Overflow pages start with the ID of the next overflow page. + page_id_offset = 0; + if (db_reader_->ReadPage(overflow_page_ids_.back()) != SQLITE_OK) + return false; + } + + DCHECK_LE(page_id_offset + kPageIdSize, db_reader_->page_size()); + const int next_page_id = + LoadBigEndianInt32(db_reader_->page_data() + page_id_offset); + if (!DatabasePageReader::IsValidPageId(next_page_id)) { + // The overflow page is corrupted. + return false; + } + + overflow_page_ids_.push_back(next_page_id); + return true; +} + +} // namespace recover +} // namespace sql \ No newline at end of file
diff --git a/sql/recover_module/payload.h b/sql/recover_module/payload.h new file mode 100644 index 0000000..5ddd20b --- /dev/null +++ b/sql/recover_module/payload.h
@@ -0,0 +1,142 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_PAYLOAD_H_ +#define SQL_RECOVER_MODULE_PAYLOAD_H_ + +#include <cstdint> +#include <vector> + +#include "base/logging.h" +#include "base/sequence_checker.h" +#include "sql/recover_module/pager.h" + +namespace sql { +namespace recover { + +class DatabasePageReader; + +// Reads payloads (records) across B-tree pages and overflow pages. +// +// Instances are designed to be reused for reading multiple payloads. Instances +// are not thread-safe. +// +// Reading a payload is started by calling Initialize() with the information +// from LeafPageDecoder. If the call succeeds, ReadPayload() can be called +// repeatedly. +class LeafPayloadReader { + public: + // Number of payload bytes guaranteed to be on the B-tree page. + // + // The value is derived from the minimum SQLite usable page size, which is + // 380 bytes, and the formula for the minimum payload size given a usable page + // size. + static constexpr int kMinInlineSize = ((380 - 12) * 32) / 255 - 23; + + explicit LeafPayloadReader(DatabasePageReader* db_reader); + ~LeafPayloadReader(); + + LeafPayloadReader(const LeafPayloadReader&) = delete; + LeafPayloadReader& operator=(const LeafPayloadReader&) = delete; + + // Sets up the reader for a new payload. + // + // The DatabasePageReader passed to the constructor must be focused on the + // page containing the payload. + // + // This method must complete successfully before any other method on this + // class can be called. + bool Initialize(int64_t payload_size, int payload_offset); + + // The number of payload bytes that are stored on the B-tree page. + // + // The return value is guaranteed to be non-negative and at most + // payload_size(). + int inline_payload_size() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(page_id_ != DatabasePageReader::kInvalidPageId) + << "Initialize() not called, or last call did not succeed"; + DCHECK_LE(inline_payload_size_, payload_size_); + return inline_payload_size_; + } + + // Total payload size, in bytes. + // + // This includes the bytes stored in the B-tree page, as well as any bytes + // stored in overflow pages. + // + // The return value is guaranteed to be at least inline_payload_size(). + int payload_size() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(page_id_ != DatabasePageReader::kInvalidPageId) + << "Initialize() not called, or last call did not succeed"; + DCHECK_LE(inline_payload_size_, payload_size_); + return payload_size_; + } + + // Copies a subset of the payload into a given buffer. + // + // Returns true if the read succeeds. + // + // May only be called after a previous call to Initialize() that returns true. + bool ReadPayload(int64_t offset, int64_t size, uint8_t* buffer); + + // Pulls the B-tree containing the payload into the database reader's cache. + // + // Returns a pointer to the beginning of the payload bytes. The pointer is + // inside the database reader's buffer, and may get invalidated if the + // database reader is used. + // + // Returns null if the read operation fails. + // + // May only be called after a previous call to Initialize() that returns true. + const uint8_t* ReadInlinePayload(); + + private: + // Extends the cached list of overflow page IDs by one page. + // + // Returns false if the operation failed. Failures are due to read errors or + // database corruption. + bool PopulateNextOverflowPageId(); + + // Used to read the pages containing the payload. + DatabasePageReader* const db_reader_; + + // Total size of the current payload. + int64_t payload_size_; + + // The ID of the B-tree page containing the current payload's inline bytes. + // + // Set to kInvalidPageId if the reader wasn't successfully initialized. + int page_id_; + + // The start of the current payload's inline bytes on the B-tree page. + // + // Large payloads extend past the B-tree page containing the payload, via + // overflow pages. + int inline_payload_offset_; + + // Number of bytes in the current payload stored in its B-tree page. + // + // The rest of the payload is stored on overflow pages. + int inline_payload_size_; + + // Number of overflow pages used by the payload. + int overflow_page_count_; + + // Number of bytes in each overflow page that stores the payload. + int max_overflow_payload_size_; + + // Page IDs for all the payload's overflow pages, in order. + // + // This list is populated on-demand. + std::vector<int> overflow_page_ids_; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_PAYLOAD_H_
diff --git a/sql/recover_module/record.cc b/sql/recover_module/record.cc new file mode 100644 index 0000000..7cf0132 --- /dev/null +++ b/sql/recover_module/record.cc
@@ -0,0 +1,314 @@ +// Copyright 2019 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 "sql/recover_module/record.h" + +#include <cstddef> +#include <limits> +#include <type_traits> + +#include "sql/recover_module/integers.h" +#include "sql/recover_module/payload.h" +#include "third_party/sqlite/sqlite3.h" + +namespace sql { +namespace recover { + +RecordReader::RecordReader(LeafPayloadReader* payload_reader, int column_count) + : payload_reader_(payload_reader), column_count_(column_count) { + DCHECK(payload_reader != nullptr); + DCHECK_GT(column_count, 0); + value_headers_.reserve(column_count); +} + +RecordReader::~RecordReader() = default; + +namespace { + +// Value type indicating a null. +constexpr int kNullType = 0; +// Value type indicating a 1-byte signed integer. +constexpr int kInt1Type = 1; +// Value type indicating a 2-byte signed big-endian integer. +constexpr int kInt2Type = 2; +// Value type indicating a 3-byte signed big-endian integer. +constexpr int kInt3Type = 3; +// Value type indicating a 4-byte signed big-endian integer. +constexpr int kInt4Type = 4; +// Value type indicating a 6-byte signed big-endian integer. +constexpr int kInt6Type = 5; +// Value type indicating an 8-byte signed big-endian integer. +constexpr int kInt8Type = 6; +// Value type indicating a big-endian IEEE 754 64-bit floating point number. +constexpr int kDoubleType = 7; +// Value type indicating the integer 0 (zero). +constexpr int kIntZeroType = 8; +// Value type indicating the integer 1 (one). +constexpr int kIntOneType = 9; +// Value types greater than or equal to this indicate blobs or text. +constexpr int kMinBlobOrStringType = 12; + +// The return value of ParseHeaderType below. +struct ParsedHeaderType { + // True for the special value used to communicate a parsing error. + bool IsInvalid() const { + return type == ValueType::kNull && has_inline_value; + } + + const ValueType type; + const int64_t size; + const int8_t inline_value; + const bool has_inline_value; +}; + +// Decodes a type identifier in a SQLite record header. +// +// The type identifier includes the type and the size. +// +// Returns {kNull, 1} when parsing fails. Null values never require any extra +// bytes, so this special return value will never occur during normal +// processing. +ParsedHeaderType ParseHeaderType(int64_t encoded_type) { + static constexpr int8_t kNoInlineValue = 0; + + if (encoded_type == kNullType) + return {ValueType::kNull, 0, kNoInlineValue, false}; + if (encoded_type == kInt1Type) + return {ValueType::kInteger, 1, kNoInlineValue, false}; + if (encoded_type == kInt2Type) + return {ValueType::kInteger, 2, kNoInlineValue, false}; + if (encoded_type == kInt3Type) + return {ValueType::kInteger, 3, kNoInlineValue, false}; + if (encoded_type == kInt4Type) + return {ValueType::kInteger, 4, kNoInlineValue, false}; + if (encoded_type == kInt6Type) + return {ValueType::kInteger, 6, kNoInlineValue, false}; + if (encoded_type == kInt8Type) + return {ValueType::kInteger, 8, kNoInlineValue, false}; + if (encoded_type == kDoubleType) + return {ValueType::kFloat, 8, kNoInlineValue, false}; + if (encoded_type == kIntZeroType) + return {ValueType::kInteger, 0, 0, true}; + if (encoded_type == kIntOneType) + return {ValueType::kInteger, 0, 1, true}; + + if (encoded_type < kMinBlobOrStringType) { + // Types between |kIntOneType| and |kMinBlobOrStringType| are reserved for + // SQLite internal usage, and should not appear in persistent databases. + // This shows database corruption. + return {ValueType::kNull, 0, kNoInlineValue, true}; + } + + // Blobs and texts take alternating numbers starting at 12. + encoded_type -= kMinBlobOrStringType; + const ValueType value_type = + (encoded_type & 1) == 0 ? ValueType::kBlob : ValueType::kText; + const int64_t value_size = encoded_type >> 1; + return {value_type, value_size, kNoInlineValue, false}; +} + +} // namespace + +bool RecordReader::Initialize() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // The size of |value_headers_| is used in DCHECKs to track whether + // Initialize() succeeded. + value_headers_.clear(); + + int64_t next_value_offset = InitializeHeaderBuffer(); + if (next_value_offset == 0) + return false; + + const uint8_t* header_pointer = header_buffer_.data(); + const uint8_t* header_end = header_buffer_.data() + header_buffer_.size(); + + for (int i = 0; i < column_count_; ++i) { + int64_t encoded_type; + if (header_pointer == header_end) { + // SQLite versions built with SQLITE_ENABLE_NULL_TRIM don't store trailing + // null type IDs in the header. + encoded_type = kNullType; + } else { + std::tie(encoded_type, header_pointer) = + ParseVarint(header_pointer, header_end); + } + + ParsedHeaderType parsed_type = ParseHeaderType(encoded_type); + if (parsed_type.IsInvalid()) { + // Parsing failed. The record is corrupted. + return false; + } + value_headers_.emplace_back(next_value_offset, parsed_type.size, + parsed_type.type, parsed_type.inline_value, + parsed_type.has_inline_value); + + next_value_offset += parsed_type.size; + } + + DCHECK_EQ(value_headers_.size(), static_cast<size_t>(column_count_)); + return true; +} + +ValueType RecordReader::GetValueType(int column_index) const { + DCHECK(IsInitialized()); + DCHECK_GE(column_index, 0); + DCHECK_LT(static_cast<size_t>(column_index), value_headers_.size()); + + return value_headers_[column_index].type; +} + +namespace { + +// Deallocates buffers passed to sqlite3_result_{blob,text}64(). +void ValueBytesDeleter(void* buffer) { + DCHECK(buffer != nullptr); + uint8_t* value_bytes = reinterpret_cast<uint8_t*>(buffer); + delete[] value_bytes; +} + +} // namespace + +bool RecordReader::ReadValue(int column_index, + sqlite3_context* receiver) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(IsInitialized()); + DCHECK_GE(column_index, 0); + DCHECK_LT(static_cast<size_t>(column_index), value_headers_.size()); + DCHECK(receiver != nullptr); + + const ValueHeader& header = value_headers_[column_index]; + + const int64_t offset = header.offset; + const int64_t size = header.size; + + if (header.type == ValueType::kNull) { + DCHECK_EQ(size, 0); + DCHECK(!header.has_inline_value); + + sqlite3_result_null(receiver); + return true; + } + + if (header.type == ValueType::kInteger) { + if (header.has_inline_value) { + sqlite3_result_int(receiver, header.inline_value); + return true; + } + + uint8_t value_bytes[8]; + DCHECK_GT(size, 0); + DCHECK_LE(size, static_cast<int64_t>(sizeof(value_bytes))); + // SQLite integers are big-endian, so the least significant bytes are at the + // end of the integer's buffer. + uint8_t* const first_read_byte = value_bytes + 8 - size; + if (!payload_reader_->ReadPayload(offset, size, first_read_byte)) + return false; + + // Sign-extend the number. + const uint8_t sign_byte = (*first_read_byte & 0x80) ? 0xff : 0; + for (uint8_t* sign_extended_byte = &value_bytes[0]; + sign_extended_byte < first_read_byte; ++sign_extended_byte) { + *sign_extended_byte = sign_byte; + } + + const int64_t value = LoadBigEndianInt64(value_bytes); + sqlite3_result_int64(receiver, value); + return true; + } + + if (header.type == ValueType::kFloat) { + DCHECK_EQ(header.size, static_cast<int64_t>(sizeof(double))); + DCHECK(!header.has_inline_value); + + union { + double fp; + int64_t integer; + uint8_t bytes[8]; + } value; + static_assert(sizeof(double) == 8, + "double is not the correct type to represent SQLite floats"); + if (!payload_reader_->ReadPayload(header.offset, sizeof(double), + reinterpret_cast<uint8_t*>(&value))) { + return false; + } + // SQLite's doubles are big-endian. + value.integer = LoadBigEndianInt64(value.bytes); + sqlite3_result_double(receiver, value.fp); + return true; + } + + if (header.type == ValueType::kBlob || header.type == ValueType::kText) { + DCHECK_GE(header.size, 0); + DCHECK(!header.has_inline_value); + + uint8_t* const value_bytes = new uint8_t[size]; + if (!payload_reader_->ReadPayload(offset, size, value_bytes)) { + delete[] value_bytes; + return false; + } + if (header.type == ValueType::kBlob) { + sqlite3_result_blob64(receiver, value_bytes, static_cast<uint64_t>(size), + &ValueBytesDeleter); + } else { + DCHECK_EQ(header.type, ValueType::kText); + + const unsigned char encoding = SQLITE_UTF8; + sqlite3_result_text64(receiver, reinterpret_cast<char*>(value_bytes), + static_cast<uint64_t>(size), &ValueBytesDeleter, + encoding); + } + return true; + } + + NOTREACHED() << "Invalid value type"; + return false; +} + +void RecordReader::Reset() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + value_headers_.clear(); +} + +int64_t RecordReader::InitializeHeaderBuffer() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + const uint8_t* const inline_payload_start = + payload_reader_->ReadInlinePayload(); + if (inline_payload_start == nullptr) { + // Read failure. + return 0; + } + + const int64_t inline_payload_size = payload_reader_->inline_payload_size(); + const uint8_t* const inline_payload_end = + inline_payload_start + inline_payload_size; + int64_t header_size; + const uint8_t* payload_header_start; + std::tie(header_size, payload_header_start) = + ParseVarint(inline_payload_start, inline_payload_end); + + if (header_size < 0 || header_size > payload_reader_->payload_size()) { + // The header is bigger than the entire record. This record is corrupted. + return 0; + } + + int header_size_size = payload_header_start - inline_payload_start; + static_assert(std::numeric_limits<int>::max() > kMaxVarintSize, + "The |header_size_size| computation above may overflow"); + + // The header size varint is included in the header size computation. + const int64_t header_data_size = header_size - header_size_size; + header_buffer_.resize(header_data_size); + if (!payload_reader_->ReadPayload(header_size_size, header_data_size, + header_buffer_.data())) { + // Read failure. + return 0; + } + + return header_size; +} + +} // namespace recover +} // namespace sql \ No newline at end of file
diff --git a/sql/recover_module/record.h b/sql/recover_module/record.h new file mode 100644 index 0000000..2481d214 --- /dev/null +++ b/sql/recover_module/record.h
@@ -0,0 +1,143 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_RECORD_H_ +#define SQL_RECOVER_MODULE_RECORD_H_ + +#include <cstdint> +#include <vector> + +#include "base/sequence_checker.h" + +struct sqlite3_context; + +namespace sql { +namespace recover { + +// The effective type of a column's value in a SQLite row. +enum class ValueType { + kNull, + kInteger, + kFloat, + kText, + kBlob, +}; + +class LeafPayloadReader; + +// Reads records from SQLite B-trees. +// +// Instances are designed to be reused for reading multiple records. Instances +// are not thread-safe. +// +// A record is a list of column values. SQLite uses "manifest typing", meaning +// that values don't necessarily match the column types declared in the +// table/index schema. +// +// Reading a record is started by calling Initialize(). Afterwards, +// GetValueType() can be used to validate the types of the record's values, and +// ReadValue() can be used to read the values into a SQLite user-defined +// function context. +class RecordReader { + public: + struct ValueHeader { + explicit ValueHeader(int64_t offset, + int64_t size, + ValueType type, + int8_t inline_value, + bool has_inline_value) + : offset(offset), + size(size), + type(type), + inline_value(inline_value), + has_inline_value(has_inline_value) {} + + // The position of the first byte used to encode the value, in the record. + int64_t offset; + // The number of bytes used to encode the value. + int64_t size; + // The SQLite type for the value. + ValueType type; + // The value encoded directly in the type, if |has_inline_value| is true. + int8_t inline_value; + // True if |inline_value| is defined. + bool has_inline_value; + }; + + explicit RecordReader(LeafPayloadReader* payload_reader_, int column_count); + ~RecordReader(); + + RecordReader(const RecordReader&) = delete; + RecordReader& operator=(const RecordReader&) = delete; + + // Sets up the reader for a new payload. + // + // The LeafPayloadReader passed to the constructor must be focused on the + // page containing the payload. + // + // This method must complete successfully before any other method on this + // class can be called. + bool Initialize(); + + // True if the last call to Initialize succeeded. + bool IsInitialized() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return value_headers_.size() == static_cast<size_t>(column_count_); + } + + // The type of a value in the record. |column_index| is 0-based. + ValueType GetValueType(int column_index) const; + + // Reads a value in the record into a SQLite user-defined function context. + // + // |column_index| is 0-based. + // + // The value is reported by calling a sqlite3_result_*() function on + // |receiver|. SQLite's result-reporting API is documented at + // https://www.sqlite.org/c3ref/result_blob.html + // + // Returns false if the reading value fails. This can happen if a value is + // stored across overflow pages, and reading one of the overflow pages results + // in an I/O error. + bool ReadValue(int column_index, sqlite3_context* receiver) const; + + // Resets the reader. + // + // This method is idempotent. After it is called, IsInitialized() will return + // false. + void Reset(); + + private: + // Reads the record's header into |header_buffer_|. + // + // Returns the size of the record's header, or 0 (zero) in case of failure. + // No valid record header has 0 bytes, because the record header includes at + // least one varint. + // + // On success, |header_buffer_|'s size will be set correctly. + int64_t InitializeHeaderBuffer(); + + // Stores decoded type IDs from the record's header. + std::vector<ValueHeader> value_headers_; + + // Stores the header of the record being read. + // + // The header is only used during Initialize(). This buffer is reused across + // multiple Initialize() calls to reduce heap churn. + std::vector<uint8_t> header_buffer_; + + // Brings the record's bytes from the SQLite database pages. + LeafPayloadReader* const payload_reader_; + + // The number of columns in the table schema. No payload should have more than + // this number of columns. + const int column_count_; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_RECORD_H_
diff --git a/sql/recover_module/table.cc b/sql/recover_module/table.cc new file mode 100644 index 0000000..01af64f --- /dev/null +++ b/sql/recover_module/table.cc
@@ -0,0 +1,222 @@ +// Copyright 2019 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 "sql/recover_module/table.h" + +#include "base/logging.h" +#include "base/strings/strcat.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "sql/recover_module/cursor.h" +#include "sql/recover_module/integers.h" +#include "sql/recover_module/pager.h" + +namespace sql { +namespace recover { + +// Returns the number of the page holding the root page of a table's B-tree. +// +// Returns a null optional if the operation fails in any way. The failure is +// most likely due to an incorrect table spec (missing attachment or table). +// Corrupted SQLite metadata can cause failures here. +base::Optional<int> GetTableRootPageId(sqlite3* sqlite_db, + const TargetTableSpec& table) { + if (table.table_name == "sqlite_master") { + // The sqlite_master table is always rooted at the first page. + // SQLite page IDs use 1-based indexing. + return base::Optional<int64_t>(1); + } + + std::string select_sql = + base::StrCat({"SELECT rootpage FROM ", table.db_name, + ".sqlite_master WHERE type='table' AND tbl_name=?"}); + sqlite3_stmt* sqlite_statement; + if (sqlite3_prepare_v3(sqlite_db, select_sql.c_str(), select_sql.size() + 1, + SQLITE_PREPARE_NO_VTAB, &sqlite_statement, + nullptr) != SQLITE_OK) { + // The sqlite_master table is missing or its schema is corrupted. + return base::nullopt; + } + + if (sqlite3_bind_text(sqlite_statement, 1, table.table_name.c_str(), + static_cast<int>(table.table_name.size()), + SQLITE_STATIC) != SQLITE_OK) { + // Binding the table name failed. This shouldn't happen. + sqlite3_finalize(sqlite_statement); + return base::nullopt; + } + + if (sqlite3_step(sqlite_statement) != SQLITE_ROW) { + // The database attachment point or table does not exist. + sqlite3_finalize(sqlite_statement); + return base::nullopt; + } + + int64_t root_page = sqlite3_column_int64(sqlite_statement, 0); + sqlite3_finalize(sqlite_statement); + + if (!DatabasePageReader::IsValidPageId(root_page)) { + // Database corruption. + return base::nullopt; + } + + static_assert( + DatabasePageReader::kMaxPageId <= std::numeric_limits<int>::max(), + "Converting the page ID to int may overflow"); + return base::make_optional(static_cast<int>(root_page)); +} + +// Returns (SQLite status, a SQLite database's page size). +std::pair<int, int> GetDatabasePageSize(sqlite3_file* sqlite_file) { + // The SQLite header is documented at: + // https://www.sqlite.org/fileformat.html#the_database_header + // + // Read the entire header. + static constexpr int kHeaderOffset = 0; + static constexpr int kHeaderSize = 100; + uint8_t header_bytes[kHeaderSize]; + int sqlite_status = DatabasePageReader::RawRead(sqlite_file, kHeaderSize, + kHeaderOffset, header_bytes); + if (sqlite_status != SQLITE_OK) + return {sqlite_status, 0}; + + // This computation uses the alternate interpretation that the page size + // header field is a little-endian number encoding the page size divided by + // 256. + static constexpr int kPageSizeHeaderOffset = 16; + const int page_size = + LoadBigEndianUint16(header_bytes + kPageSizeHeaderOffset); + + if (!DatabasePageReader::IsValidPageSize(page_size)) { + // Invalid page numbers are considered irrecoverable corruption. + return {SQLITE_CORRUPT, 0}; + } + + // TODO(pwnall): This method needs a better name. It also checks the database + // header for unsupported edge cases. + + static constexpr int kReservedSizeHeaderOffset = 20; + const uint8_t page_reserved_size = header_bytes[kReservedSizeHeaderOffset]; + if (page_reserved_size != 0) { + // Chrome does not use any extension that requires reserved page space. + return {SQLITE_CORRUPT, 0}; + } + + // The text encoding is stored at offset 56, as a 4-byte big-endian integer. + // However, the range of values is 1-3, so reading the last byte is + // sufficient. + static_assert(SQLITE_UTF8 <= std::numeric_limits<uint8_t>::max(), + "Text encoding field reading shortcut is invalid."); + static constexpr int kTextEncodingHeaderOffset = 59; + const uint8_t text_encoding = header_bytes[kTextEncodingHeaderOffset]; + if (text_encoding != SQLITE_UTF8) { + // This extension only supports databases that use UTF-8 encoding. + return {SQLITE_CORRUPT, 0}; + } + + return {SQLITE_OK, page_size}; +} + +// static +std::pair<int, std::unique_ptr<VirtualTable>> VirtualTable::Create( + sqlite3* sqlite_db, + TargetTableSpec backing_table_spec, + std::vector<RecoveredColumnSpec> column_specs) { + DCHECK(backing_table_spec.IsValid()); + + base::Optional<int64_t> backing_table_root_page_id = + GetTableRootPageId(sqlite_db, backing_table_spec); + if (!backing_table_root_page_id.has_value()) { + // Either the backing table specification is incorrect, or the database + // metadata is corrupted beyond hope. + // + // This virtual table is intended to be used by Chrome features, whose code + // is covered by tests. Therefore, the most likely cause is metadata + // corruption. + return {SQLITE_CORRUPT, nullptr}; + } + + sqlite3_file* sqlite_file; + int sqlite_status = + sqlite3_file_control(sqlite_db, backing_table_spec.db_name.c_str(), + SQLITE_FCNTL_FILE_POINTER, &sqlite_file); + if (sqlite_status != SQLITE_OK) { + // Failed to get the backing store's file. GetTableRootPage() succeeded, so + // the attachment point name must be correct. So, this is definitely a + // SQLite error, not a virtual table use error. Report the error code as-is, + // so it can be captured in histograms. + return {sqlite_status, nullptr}; + } + + int page_size; + std::tie(sqlite_status, page_size) = GetDatabasePageSize(sqlite_file); + if (sqlite_status != SQLITE_OK) { + // By the same reasoning as above, report the error code as-is. + return {sqlite_status, nullptr}; + } + + return {SQLITE_OK, + std::make_unique<VirtualTable>(sqlite_db, sqlite_file, + backing_table_root_page_id.value(), + page_size, std::move(column_specs))}; +} + +VirtualTable::VirtualTable(sqlite3* sqlite_db, + sqlite3_file* sqlite_file, + int root_page_id, + int page_size, + std::vector<RecoveredColumnSpec> column_specs) + : sqlite_db_(sqlite_db), + sqlite_file_(sqlite_file), + root_page_id_(root_page_id), + page_size_(page_size), + column_specs_(std::move(column_specs)) { + DCHECK(sqlite_db != nullptr); + DCHECK(sqlite_file != nullptr); + DCHECK_GT(root_page_id_, 0); + DCHECK(DatabasePageReader::IsValidPageSize(page_size)); + DCHECK(!column_specs_.empty()); +} + +VirtualTable::~VirtualTable() { +#if DCHECK_IS_ON() + DCHECK_EQ(0, open_cursor_count_.load(std::memory_order_relaxed)) + << "SQLite forgot to xClose() an xOpen()ed cursor"; +#endif // DCHECK_IS_ON() +} + +std::string VirtualTable::ToCreateTableSql() const { + std::vector<std::string> column_sqls; + column_sqls.reserve(column_specs_.size()); + for (const RecoveredColumnSpec& column_spec : column_specs_) + column_sqls.push_back(column_spec.ToCreateTableSql()); + + static constexpr base::StringPiece kCreateTableSqlStart("CREATE TABLE t("); + static constexpr base::StringPiece kCreateTableSqlEnd(")"); + static constexpr base::StringPiece kColumnSqlSeparator(","); + return base::StrCat({kCreateTableSqlStart, + base::JoinString(column_sqls, kColumnSqlSeparator), + kCreateTableSqlEnd}); +} + +VirtualCursor* VirtualTable::CreateCursor() { +#if DCHECK_IS_ON() + open_cursor_count_.fetch_add(1, std::memory_order_relaxed); +#endif // DCHECK_IS_ON() + + (void)sqlite_db_; + + VirtualCursor* result = new VirtualCursor(this); + return result; +} + +void VirtualTable::WillDeleteCursor(VirtualCursor* cursor) { +#if DCHECK_IS_ON() + DCHECK_GT(open_cursor_count_.load(std::memory_order_relaxed), 0); + open_cursor_count_.fetch_sub(1, std::memory_order_relaxed); +#endif // DCHECK_IS_ON() +} + +} // namespace recover +} // namespace sql
diff --git a/sql/recover_module/table.h b/sql/recover_module/table.h new file mode 100644 index 0000000..c5732aa --- /dev/null +++ b/sql/recover_module/table.h
@@ -0,0 +1,123 @@ +// Copyright 2019 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 SQL_RECOVER_MODULE_TABLE_H_ +#define SQL_RECOVER_MODULE_TABLE_H_ + +#include <atomic> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/logging.h" +#include "base/optional.h" +#include "sql/recover_module/parsing.h" +#include "third_party/sqlite/sqlite3.h" + +namespace sql { +namespace recover { + +class VirtualCursor; + +// Represents a virtual table created by CREATE VIRTUAL TABLE recover(...). +// +// Instances are allocated on the heap using the C++ new operator, and passed to +// SQLite via pointers to the sqlite_vtab members. SQLite is responsible for +// managing the instances' lifetimes. SQLite will call xDisconnect() for every +// successful xConnect(), and xDestroy() for every successful xCreate(). +// +// Instances are thread-safe. +class VirtualTable { + public: + // Returns a SQLite status and a VirtualTable instance. + // + // The VirtualTable is non-null iff the status is SQLITE_OK. + // + // SQLite is trusted to keep |sqlite_db| alive for as long as this instance + // lives. + static std::pair<int, std::unique_ptr<VirtualTable>> Create( + sqlite3* sqlite_db, + TargetTableSpec backing_table_spec, + std::vector<RecoveredColumnSpec> column_specs); + + // Use Create() instead of calling the constructor directly. + explicit VirtualTable(sqlite3* sqlite_db, + sqlite3_file* sqlite_file, + int root_page, + int page_size, + std::vector<RecoveredColumnSpec> column_specs); + ~VirtualTable(); + + VirtualTable(const VirtualTable&) = delete; + VirtualTable& operator=(const VirtualTable&) = delete; + + // Returns the embedded SQLite virtual table. + // + // This getter is not const because SQLite wants a non-const pointer to the + // structure. + sqlite3_vtab* SqliteTable() { return &sqlite_table_; } + + // Returns SQLite VFS file used to access the backing table's database. + // + // This getter is not const because it must return a non-const pointer. + sqlite3_file* SqliteFile() { return sqlite_file_; } + + // Returns the page number of the root page for the table's B-tree. + int root_page_id() const { return root_page_id_; } + + // Returns the page size used by the backing table's database. + int page_size() const { return page_size_; } + + // Returns the schema of the corrupted table being recovered. + const std::vector<RecoveredColumnSpec> column_specs() const { + return column_specs_; + } + + // Returns a SQL statement describing the virtual table's schema. + // + // The return value is suitable to be passed to sqlite3_declare_vtab(). + std::string ToCreateTableSql() const; + + // The VirtualTable instance that embeds a given SQLite virtual table. + // + // |sqlite_table| must have been returned by VirtualTable::SqliteTable(). + static inline VirtualTable* FromSqliteTable(sqlite3_vtab* sqlite_table) { + static_assert(std::is_standard_layout<VirtualTable>::value, + "needed for the reinterpret_cast below"); + static_assert(offsetof(VirtualTable, sqlite_table_) == 0, + "sqlite_table_ must be the first member of the class"); + VirtualTable* const result = reinterpret_cast<VirtualTable*>(sqlite_table); + DCHECK_EQ(sqlite_table, &result->sqlite_table_); + return result; + } + + // Creates a new cursor for iterating over this table. + VirtualCursor* CreateCursor(); + + // Called right before a cursor belonging to this table will be destroyed. + void WillDeleteCursor(VirtualCursor* cursor); + + private: + // SQLite handle for this table. The struct is populated and used by SQLite. + sqlite3_vtab sqlite_table_; + + // SQLite connection for both the recovered table and the virtual table. + sqlite3* const sqlite_db_; + + sqlite3_file* const sqlite_file_; + const int root_page_id_; + const int page_size_; + const std::vector<RecoveredColumnSpec> column_specs_; + +#if DCHECK_IS_ON() + // Number of cursors that are still opened. + std::atomic<int> open_cursor_count_{0}; +#endif // DCHECK_IS_ON() +}; + +} // namespace recover +} // namespace sql + +#endif // SQL_RECOVER_MODULE_TABLE_H_ \ No newline at end of file
diff --git a/sql/recovery.cc b/sql/recovery.cc index dfd80db..a6af79e 100644 --- a/sql/recovery.cc +++ b/sql/recovery.cc
@@ -14,12 +14,10 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "sql/database.h" +#include "sql/recover_module/module.h" #include "sql/statement.h" #include "third_party/sqlite/sqlite3.h" -// Needs to be included after "third_party/sqlite/sqlite.h". -#include "third_party/sqlite/patched/src/recover.h" - namespace sql { namespace { @@ -800,7 +798,7 @@ // static int Recovery::EnableRecoveryExtension(Database* db, InternalApiToken) { - return chrome_sqlite3_recoverVtableInit(db->db(InternalApiToken())); + return sql::recover::RegisterRecoverExtension(db->db(InternalApiToken())); } } // namespace sql
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json index f163dbb..051bfd6 100644 --- a/testing/buildbot/chromium.dawn.json +++ b/testing/buildbot/chromium.dawn.json
@@ -120,7 +120,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -142,7 +142,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -163,7 +163,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -197,7 +197,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -247,7 +247,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ],
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index ee4419c..2b529f9d 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -358,7 +358,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -382,7 +382,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -403,7 +403,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -424,7 +424,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -445,7 +445,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -465,7 +465,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -493,7 +493,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -524,7 +524,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -552,7 +552,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -582,7 +582,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -613,7 +613,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -642,7 +642,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -671,7 +671,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -6646,7 +6646,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -6818,7 +6818,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -6839,7 +6839,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -6860,7 +6860,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -6881,7 +6881,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -6901,7 +6901,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -6918,7 +6918,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -6948,7 +6948,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -6976,7 +6976,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7004,7 +7004,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7032,7 +7032,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7064,7 +7064,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7099,7 +7099,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7142,7 +7142,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7171,7 +7171,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7199,7 +7199,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7227,7 +7227,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -7256,7 +7256,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -8465,7 +8465,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -8486,7 +8486,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -8507,7 +8507,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -8528,7 +8528,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -8548,7 +8548,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -8565,7 +8565,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9822,7 +9822,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -9846,7 +9846,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9867,7 +9867,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9892,7 +9892,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9913,7 +9913,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9934,7 +9934,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9954,7 +9954,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9971,7 +9971,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -9999,7 +9999,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10026,7 +10026,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10054,7 +10054,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10082,7 +10082,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10110,7 +10110,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10142,7 +10142,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10177,7 +10177,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10228,7 +10228,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10272,7 +10272,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10301,7 +10301,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10329,7 +10329,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10359,7 +10359,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10390,7 +10390,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10419,7 +10419,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10448,7 +10448,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10475,7 +10475,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10499,7 +10499,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10520,7 +10520,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10545,7 +10545,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10566,7 +10566,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10587,7 +10587,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10607,7 +10607,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10624,7 +10624,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -10656,7 +10656,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10711,7 +10711,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10735,7 +10735,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10759,7 +10759,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10783,7 +10783,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10807,7 +10807,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10831,7 +10831,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -10855,7 +10855,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -19304,7 +19304,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -19326,7 +19326,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -19359,7 +19359,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -19379,7 +19379,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -19396,7 +19396,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -19424,7 +19424,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -19455,7 +19455,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -19506,7 +19506,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -19526,7 +19526,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -19553,7 +19553,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -19583,7 +19583,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -19612,7 +19612,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ],
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json index 99ff722..4b5a0cd 100644 --- a/testing/buildbot/chromium.gpu.json +++ b/testing/buildbot/chromium.gpu.json
@@ -339,7 +339,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -360,7 +360,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -381,7 +381,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -411,7 +411,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -439,7 +439,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -467,7 +467,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -495,7 +495,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -527,7 +527,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -562,7 +562,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -605,7 +605,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -634,7 +634,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -662,7 +662,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -690,7 +690,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -718,7 +718,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -743,7 +743,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -764,7 +764,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -785,7 +785,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -815,7 +815,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -843,7 +843,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -871,7 +871,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -899,7 +899,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -931,7 +931,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -966,7 +966,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1009,7 +1009,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1038,7 +1038,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1066,7 +1066,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1094,7 +1094,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1123,7 +1123,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -1149,7 +1149,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -1171,7 +1171,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -1193,7 +1193,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ] @@ -1224,7 +1224,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1253,7 +1253,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1282,7 +1282,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1311,7 +1311,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1344,7 +1344,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1380,7 +1380,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1424,7 +1424,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1454,7 +1454,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1483,7 +1483,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -1512,7 +1512,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ],
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json index 020a1b69..758c919 100644 --- a/testing/buildbot/client.v8.fyi.json +++ b/testing/buildbot/client.v8.fyi.json
@@ -335,7 +335,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -363,7 +363,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -391,7 +391,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -419,7 +419,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -454,7 +454,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -497,7 +497,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -526,7 +526,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -554,7 +554,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -584,7 +584,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -613,7 +613,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -646,7 +646,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -674,7 +674,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -702,7 +702,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -730,7 +730,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -765,7 +765,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -808,7 +808,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -837,7 +837,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -865,7 +865,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -895,7 +895,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ], @@ -924,7 +924,7 @@ "dimension_sets": [ { "gpu": "nvidia-quadro-p400-ubuntu-stable", - "os": "Ubuntu", + "os": "Ubuntu-14.04", "pool": "Chrome-GPU" } ],
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl index 729290e1..575d005 100644 --- a/testing/buildbot/mixins.pyl +++ b/testing/buildbot/mixins.pyl
@@ -281,7 +281,7 @@ 'dimensions': { # Defined in bot_config.py in internal infradata/config workspace 'gpu': 'nvidia-quadro-p400-ubuntu-stable', - 'os': 'Ubuntu', + 'os': 'Ubuntu-14.04', 'pool': 'Chrome-GPU', } }
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index 85b81c5..c0e7c6f 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -64,7 +64,6 @@ header = "public_buildflags.h" flags = [ "DEBUG_DEVTOOLS=$debug_devtools", - "USE_DEFAULT_RENDER_THEME=$use_default_render_theme", "USE_MINIKIN_HYPHENATION=$use_minikin_hyphenation", "ENABLE_UNHANDLED_TAP=$enable_unhandled_tap", ]
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index 65dd09a..edebb4a 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2291,6 +2291,7 @@ kPaymentRequestShippingAddressChange = 2896, kPaymentRequestShippingOptionChange = 2897, kPaymentRequestPaymentMethodChange = 2898, + kV8Animation_UpdatePlaybackRate_Method = 2899, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/public_features.gni b/third_party/blink/public/public_features.gni index 2e9fc40..f9775696 100644 --- a/third_party/blink/public/public_features.gni +++ b/third_party/blink/public/public_features.gni
@@ -15,7 +15,5 @@ # Unhandled Tap enable means Contextual Search aka Tap to Search. enable_unhandled_tap = is_android -use_default_render_theme = use_aura - # Use Minikin hyphenation engine. use_minikin_hyphenation = is_android
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index c54638f..22098a2 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -2221,7 +2221,7 @@ sources += [ "scroll/scroll_animator_test.cc" ] } - if (use_default_render_theme) { + if (use_aura) { sources += [ "scroll/scrollbar_theme_aura_test.cc" ] }
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc index 8f5aa68..44f138b9 100644 --- a/third_party/blink/renderer/core/animation/animation.cc +++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -535,7 +535,7 @@ double previous_current_time = CurrentTimeInternal(); start_time_ = new_start_time; if (hold_time_ && playback_rate_) { - // If held, the start time would still be derrived from the hold time. + // If held, the start time would still be derived from the hold time. // Force a new, limited, current time. hold_time_ = base::nullopt; double current_time = CalculateCurrentTime(); @@ -655,7 +655,16 @@ return pending_pause_ || pending_play_; } +// https://drafts.csswg.org/web-animations-1/#reset-an-animations-pending-tasks. void Animation::ResetPendingTasks() { + // We use an active playback rate instead of a pending playback rate to + // sidestep complications of maintaining correct sequencing for updating + // properties like current time and start time. Our implementation performs + // calculations based on what will happen rather than waiting on a scheduled + // task to commit the changes. + // TODO(crbug.com/960944): Bring implementation into closer alignment with the + // spec. + active_playback_rate_.reset(); pending_pause_ = false; pending_play_ = false; } @@ -713,6 +722,7 @@ SetCurrentTimeInternal(CurrentTimeInternal(), kTimingUpdateOnDemand); } +// https://drafts.csswg.org/web-animations/#playing-an-animation-section void Animation::play(ExceptionState& exception_state) { PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); @@ -749,13 +759,23 @@ } } +// https://drafts.csswg.org/web-animations/#reversing-an-animation-section void Animation::reverse(ExceptionState& exception_state) { if (!playback_rate_) { return; } + if (!active_playback_rate_.has_value()) { + active_playback_rate_ = playback_rate_; + } + + double stored_playback_rate = playback_rate_; SetPlaybackRateInternal(-playback_rate_); play(exception_state); + + if (exception_state.HadException()) { + SetPlaybackRateInternal(stored_playback_rate); + } } // https://drafts.csswg.org/web-animations/#finishing-an-animation-section @@ -795,6 +815,26 @@ QueueFinishedEvent(); } +// https://drafts.csswg.org/web-animations/#setting-the-playback-rate-of-an-animation +void Animation::updatePlaybackRate(double playback_rate) { + // The implementation differs from the spec; however, the end result is + // consistent. Whereas Animation.playbackRate updates the playback rate + // immediately, updatePlaybackRate is to take effect on the next async cycle. + // From an implementation perspective, the difference lies in what gets + // reported by the playbackRate getter ahead of the async update cycle, as the + // Blink implementation guards against a discontinuity in current time even + // when updating via the playbackRate setter. + double stored_playback_rate = active_playback_rate_.value_or(playback_rate_); + AnimationPlayState play_state = CalculateAnimationPlayState(); + if (play_state == kRunning) + pending_play_ = true; + + setPlaybackRate(playback_rate); + + if (pending()) + active_playback_rate_ = stored_playback_rate; +} + ScriptPromise Animation::finished(ScriptState* script_state) { if (!finished_promise_) { finished_promise_ = MakeGarbageCollected<AnimationPromise>( @@ -847,10 +887,14 @@ } double Animation::playbackRate() const { - return playback_rate_; + // TODO(crbug.com/960944): Deviates from spec implementation, which instead + // uses an 'effective playback rate' to be forward looking and 'playback rate' + // for its current value. + return active_playback_rate_.value_or(playback_rate_); } void Animation::setPlaybackRate(double playback_rate) { + active_playback_rate_.reset(); if (playback_rate == playback_rate_) return; @@ -1050,6 +1094,17 @@ if (!timeline_) return false; + if (reason == kTimingUpdateForAnimationFrame) { + // Pending tasks are committed when the animation is 'ready'. This can be + // at the time of promise resolution or after a frame tick. Whereas the + // spec calls for creating scheduled tasks to commit pending changes, in the + // Blink implementation, this is an acknowledgment that the changes have + // taken affect. + // TODO(crbug.com/960944): Consider restructuring implementation to more + // closely align with the recommended algorithm in the spec. + ResetPendingTasks(); + } + PlayStateUpdateScope update_scope(*this, reason, kDoNotSetCompositorPending); ClearOutdated();
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h index 2d4b6dc6..323897b 100644 --- a/third_party/blink/renderer/core/animation/animation.h +++ b/third_party/blink/renderer/core/animation/animation.h
@@ -135,6 +135,7 @@ void play(ExceptionState& = ASSERT_NO_EXCEPTION); void reverse(ExceptionState& = ASSERT_NO_EXCEPTION); void finish(ExceptionState& = ASSERT_NO_EXCEPTION); + void updatePlaybackRate(double playback_rate); ScriptPromise finished(ScriptState*); ScriptPromise ready(ScriptState*); @@ -241,6 +242,12 @@ double EffectEnd() const; bool Limited(double current_time) const; + // Playback rate that will take effect once any pending tasks are resolved. + // If there are no pending tasks, then the effective playback rate equals the + // active playback rate. + double EffectivePlaybackRate() const; + void ResolvePendingPlaybackRate(); + // https://drafts.csswg.org/web-animations/#play-states // Per spec the viable states are: idle, running, paused and finished. // Our implementation has an additional state called 'pending' which serves a @@ -297,6 +304,14 @@ // Web exposed play state, which does not have pending state. AnimationPlayState animation_play_state_; double playback_rate_; + // Playback rate that is currently in effect if differing from playback_rate_. + // When playback_rate_ is modified, the new rate takes effect on the next + // async tick. The currently active value is stored for use by the + // Animation.playbackRate method. + // TODO(crbug.com/960944): Switch to using pending_playback_rate_ once the + // web-animations implementation is more closely aligned with the spec (i.e. + // supports scheduling of pending tasks). + base::Optional<double> active_playback_rate_; base::Optional<double> start_time_; base::Optional<double> hold_time_;
diff --git a/third_party/blink/renderer/core/animation/animation.idl b/third_party/blink/renderer/core/animation/animation.idl index ea86c2d..351eda96 100644 --- a/third_party/blink/renderer/core/animation/animation.idl +++ b/third_party/blink/renderer/core/animation/animation.idl
@@ -51,6 +51,7 @@ [Measure, RaisesException] void play(); [Measure, RaisesException] void pause(); [Measure, RaisesException] void reverse(); + [Measure] void updatePlaybackRate(double playback_rate); [Measure] attribute DOMString id; [Measure] void cancel(); [Measure] attribute EventHandler onfinish;
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc index b3a679a..3be7601b 100644 --- a/third_party/blink/renderer/core/animation/animation_test.cc +++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -443,8 +443,12 @@ animation->pause(); animation->reverse(); EXPECT_FALSE(animation->Paused()); - EXPECT_EQ(-1, animation->playbackRate()); + EXPECT_TRUE(animation->pending()); + EXPECT_EQ(1, animation->playbackRate()); EXPECT_EQ(10, animation->CurrentTimeInternal()); + SimulateFrame(0); + EXPECT_FALSE(animation->pending()); + EXPECT_EQ(-1, animation->playbackRate()); } TEST_F(AnimationAnimationTest, ReverseDoesNothingWithPlaybackRateZero) { @@ -618,6 +622,67 @@ EXPECT_EQ(30, animation->CurrentTimeInternal()); } +TEST_F(AnimationAnimationTest, UpdatePlaybackRate) { + animation->updatePlaybackRate(2); + EXPECT_EQ(1, animation->playbackRate()); + + SimulateFrame(0); + EXPECT_EQ(2, animation->playbackRate()); + EXPECT_EQ(0, animation->CurrentTimeInternal()); + + SimulateFrame(10); + EXPECT_EQ(20, animation->CurrentTimeInternal()); +} + +TEST_F(AnimationAnimationTest, UpdatePlaybackRateWhilePaused) { + animation->pause(); + + // Pending playback rate on pending-paused animation is picked up after async + // tick. + EXPECT_TRUE(animation->Paused()); + EXPECT_TRUE(animation->pending()); + animation->updatePlaybackRate(2); + EXPECT_EQ(1, animation->playbackRate()); + + SimulateFrame(1); + EXPECT_FALSE(animation->pending()); + EXPECT_EQ(2, animation->playbackRate()); + + // Pending playback rate on a paused animation is resolved immediately. + animation->updatePlaybackRate(3); + EXPECT_FALSE(animation->pending()); + EXPECT_EQ(3, animation->playbackRate()); +} + +TEST_F(AnimationAnimationTest, UpdatePlaybackRateWhileLimited) { + NonThrowableExceptionState exception_state; + animation->finish(exception_state); + EXPECT_EQ(30, animation->CurrentTimeInternal()); + + // Updating playback rate does not affect current time. + animation->updatePlaybackRate(2); + EXPECT_EQ(30, animation->CurrentTimeInternal()); + + // Updating payback rate is resolved immediately for an animation in the + // finished state. + EXPECT_EQ(2, animation->playbackRate()); +} + +TEST_F(AnimationAnimationTest, UpdatePlaybackRateWhileRunning) { + animation->play(); + SimulateFrame(1); + animation->updatePlaybackRate(2); + + // Updating playback rate triggers pending state for the play state. + // Pending playback rate is not resolved until next async tick. + EXPECT_TRUE(animation->pending()); + EXPECT_EQ(1, animation->playbackRate()); + + SimulateFrame(1); + EXPECT_FALSE(animation->pending()); + EXPECT_EQ(2, animation->playbackRate()); +} + TEST_F(AnimationAnimationTest, SetEffect) { animation = timeline->Play(nullptr); animation->setStartTime(0, false);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 6bd9009..8ee7276 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3579,6 +3579,16 @@ void Element::UpdateForceLegacyLayout(const ComputedStyle& new_style, const ComputedStyle* old_style) { + // ::first-letter may cause structure discrepancies between DOM and layout + // tree (in layout the layout object will be wrapped around the actual text + // layout object, which may be deep down in the tree somewhere, while in DOM, + // the pseudo element will be a direct child of the node that matched the + // ::first-letter selector). Because of that, it's going to be tricky to + // determine whether we need to force legacy layout or not. Luckily, the + // ::first-letter pseudo element cannot introduce the need for legacy layout + // on its own, so just bail. We'll do whatever the parent layout object does. + if (IsFirstLetterPseudoElement()) + return; bool old_force = old_style && ShouldForceLegacyLayout(); SetStyleShouldForceLegacyLayout( CalculateStyleShouldForceLegacyLayout(*this, new_style));
diff --git a/third_party/blink/renderer/core/editing/local_caret_rect.cc b/third_party/blink/renderer/core/editing/local_caret_rect.cc index d5d92a3..b025cdae 100644 --- a/third_party/blink/renderer/core/editing/local_caret_rect.cc +++ b/third_party/blink/renderer/core/editing/local_caret_rect.cc
@@ -63,15 +63,6 @@ if (NGInlineFormattingContextOf(adjusted.GetPosition())) return ComputeNGLocalCaretRect(adjusted); - // TODO(editing-dev): This DCHECK is for ensuring the correctness of - // breaking |ComputeInlineBoxPosition| into |ComputeInlineAdjustedPosition| - // and |ComputeInlineBoxPositionForInlineAdjustedPosition|. If there is any - // DCHECK hit, we should pass primary direction to the latter function. - // TODO(crbug.com/793098): Fix it so that we don't need to bother about - // primary direction. - DCHECK_EQ( - PrimaryDirectionOf(*position.GetPosition().ComputeContainerNode()), - PrimaryDirectionOf(*adjusted.GetPosition().ComputeContainerNode())); const InlineBoxPosition& box_position = ComputeInlineBoxPositionForInlineAdjustedPosition(adjusted); @@ -114,14 +105,6 @@ return ComputeNGLocalSelectionRect(adjusted); } - // TODO(editing-dev): This DCHECK is for ensuring the correctness of - // breaking |ComputeInlineBoxPosition| into |ComputeInlineAdjustedPosition| - // and |ComputeInlineBoxPositionForInlineAdjustedPosition|. If there is any - // DCHECK hit, we should pass primary direction to the latter function. - // TODO(crbug.com/793098): Fix it so that we don't need to bother about - // primary direction. - DCHECK_EQ(PrimaryDirectionOf(*position.GetPosition().ComputeContainerNode()), - PrimaryDirectionOf(*adjusted.GetPosition().ComputeContainerNode())); const InlineBoxPosition& box_position = ComputeInlineBoxPositionForInlineAdjustedPosition(adjusted);
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc index 33883eb..2eefa2a 100644 --- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc +++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -546,9 +546,9 @@ return; // FIXME: send a notification in this case? FrameLoadRequest frame_request(frame->GetDocument(), - request.ToResourceRequest(), target); + request.ToResourceRequest()); Frame* target_frame = - frame->Tree().FindOrCreateFrameForNavigation(frame_request).frame; + frame->Tree().FindOrCreateFrameForNavigation(frame_request, target).frame; if (target_frame) target_frame->Navigate(frame_request, WebFrameLoadType::kStandard); }
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc index e90967e..be571fc 100644 --- a/third_party/blink/renderer/core/exported/web_view_test.cc +++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -3494,8 +3494,9 @@ ->GetFrame(); FrameLoadRequest request_with_target_start( local_frame->GetDocument(), - web_url_request_with_target_start.ToResourceRequest(), "_top"); - local_frame->Tree().FindOrCreateFrameForNavigation(request_with_target_start); + web_url_request_with_target_start.ToResourceRequest()); + local_frame->Tree().FindOrCreateFrameForNavigation(request_with_target_start, + "_top"); EXPECT_FALSE(client.DidFocusCalled()); web_view_helper.Reset(); // Remove dependency on locally scoped client. @@ -3510,11 +3511,10 @@ // Make a request that will open a new window WebURLRequest web_url_request(KURL("about:blank")); - FrameLoadRequest request(nullptr, web_url_request.ToResourceRequest(), - "_blank"); + FrameLoadRequest request(nullptr, web_url_request.ToResourceRequest()); To<LocalFrame>(web_view_impl->GetPage()->MainFrame()) ->Tree() - .FindOrCreateFrameForNavigation(request); + .FindOrCreateFrameForNavigation(request, "_blank"); ASSERT_TRUE(client.CreatedWebView()); EXPECT_FALSE(client.DidFocusCalled()); @@ -3522,12 +3522,12 @@ // The original window should be focused. WebURLRequest web_url_request_with_target_start(KURL("about:blank")); FrameLoadRequest request_with_target_start( - nullptr, web_url_request_with_target_start.ToResourceRequest(), "_start"); + nullptr, web_url_request_with_target_start.ToResourceRequest()); To<LocalFrame>(static_cast<WebViewImpl*>(client.CreatedWebView()) ->GetPage() ->MainFrame()) ->Tree() - .FindOrCreateFrameForNavigation(request_with_target_start); + .FindOrCreateFrameForNavigation(request_with_target_start, "_start"); EXPECT_TRUE(client.DidFocusCalled()); web_view_helper.Reset(); // Remove dependency on locally scoped client. @@ -3568,9 +3568,9 @@ // return the current window. WebURLRequest web_url_request(KURL("about:blank")); FrameLoadRequest request(frame->GetDocument(), - web_url_request.ToResourceRequest(), "_blank"); + web_url_request.ToResourceRequest()); FrameTree::FindResult result = - frame->Tree().FindOrCreateFrameForNavigation(request); + frame->Tree().FindOrCreateFrameForNavigation(request, "_blank"); EXPECT_EQ(frame, result.frame); EXPECT_EQ(kNavigationPolicyCurrentTab, request.GetNavigationPolicy()); }
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index c2631b41..755578a 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1495,8 +1495,7 @@ WebWindowFeatures window_features = GetWindowFeaturesFromString(features); FrameLoadRequest frame_request(active_document, - ResourceRequest(completed_url), - target.IsEmpty() ? "_blank" : target); + ResourceRequest(completed_url)); frame_request.SetFeaturesForWindowOpen(window_features); // Normally, FrameLoader would take care of setting the referrer for a @@ -1518,7 +1517,8 @@ GetFrame()->MaybeLogAdClickNavigation(); FrameTree::FindResult result = - GetFrame()->Tree().FindOrCreateFrameForNavigation(frame_request); + GetFrame()->Tree().FindOrCreateFrameForNavigation( + frame_request, target.IsEmpty() ? "_blank" : target); if (!result.frame) return nullptr;
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index bee484d2..bed1035 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2000,9 +2000,7 @@ } WebFrame* WebLocalFrameImpl::FindFrameByName(const WebString& name) { - FrameLoadRequest request(nullptr, ResourceRequest(), name); - Frame* result = GetFrame()->Tree().FindFrameForNavigation(request).frame; - return WebFrame::FromFrame(result); + return WebFrame::FromFrame(GetFrame()->Tree().FindFrameByName(name)); } bool WebLocalFrameImpl::ScrollTo(const gfx::Point& scrollPosition,
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc index 1727da5..ff9618a 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -488,19 +488,7 @@ WebFeature::kFormDisabledAttributePresentAndSubmit); } - FrameLoadRequest frame_load_request = - submission->CreateFrameLoadRequest(&GetDocument()); - frame_load_request.SetNavigationPolicy(submission->GetNavigationPolicy()); - frame_load_request.GetResourceRequest().SetHasUserGesture( - LocalFrame::HasTransientUserActivation(GetDocument().GetFrame())); - - Frame* target_frame = GetDocument() - .GetFrame() - ->Tree() - .FindOrCreateFrameForNavigation(frame_load_request) - .frame; - if (target_frame) - target_frame->Navigate(frame_load_request, WebFrameLoadType::kStandard); + submission->Navigate(); } void HTMLFormElement::reset() {
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc index ef13662a..6afd127 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.cc +++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -426,9 +426,7 @@ request.SetRequestContext(mojom::RequestContextType::HYPERLINK); const AtomicString& target = getAttribute(kTargetAttr); - FrameLoadRequest frame_request( - &GetDocument(), request, - target.IsEmpty() ? GetDocument().BaseTarget() : target); + FrameLoadRequest frame_request(&GetDocument(), request); frame_request.SetNavigationPolicy(NavigationPolicyFromEvent(&event)); if (HasRel(kRelationNoReferrer)) { frame_request.SetNoReferrer(); @@ -450,7 +448,11 @@ frame->MaybeLogAdClickNavigation(); Frame* target_frame = - frame->Tree().FindOrCreateFrameForNavigation(frame_request).frame; + frame->Tree() + .FindOrCreateFrameForNavigation( + frame_request, + target.IsEmpty() ? GetDocument().BaseTarget() : target) + .frame; if (target_frame) target_frame->Navigate(frame_request, WebFrameLoadType::kStandard); }
diff --git a/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc b/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc index ce5b754..17a3f6f8 100644 --- a/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc +++ b/third_party/blink/renderer/core/html/media/picture_in_picture_interstitial.cc
@@ -11,6 +11,7 @@ #include "third_party/blink/renderer/core/html/html_image_element.h" #include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/html/media/media_controls.h" +#include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer.h" #include "third_party/blink/renderer/core/resize_observer/resize_observer_entry.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -147,6 +148,11 @@ message_element_->setAttribute( "class", MediaControls::GetSizingCSSClass( MediaControls::GetSizingClass(new_size.width()))); + + // Force a layout since |LayoutMedia::UpdateLayout()| will sometimes miss a + // layout otherwise. + if (GetLayoutObject()) + GetLayoutObject()->SetNeedsLayout(layout_invalidation_reason::kSizeChanged); } void PictureInPictureInterstitial::ToggleInterstitialTimerFired(TimerBase*) {
diff --git a/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc b/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc index 7489904a..1af4bdb 100644 --- a/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc +++ b/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
@@ -101,7 +101,6 @@ worker_threads_.erase(worker_context_group_id); if (worker_context_group_id == paused_context_group_id_) { paused_context_group_id_ = kInvalidContextGroupId; - nested_runner_->QuitNow(); } } @@ -179,11 +178,7 @@ WorkerThread* thread = worker_threads_.at(context_group_id); DCHECK(!thread->GlobalScope()->IsClosing()); thread->GetWorkerInspectorController()->FlushProtocolNotifications(); - thread->GlobalScope()->SetLifecycleState(mojom::FrameLifecycleState::kPaused); - auto pause_handle = thread->GetScheduler()->Pause(); - if (!nested_runner_) - nested_runner_ = Platform::Current()->CreateNestedMessageLoopRunner(); - nested_runner_->Run(); + thread->Pause(); } void WorkerThreadDebugger::quitMessageLoopOnPause() { @@ -193,10 +188,7 @@ WorkerThread* thread = worker_threads_.at(paused_context_group_id_); paused_context_group_id_ = kInvalidContextGroupId; DCHECK(!thread->GlobalScope()->IsClosing()); - - nested_runner_->QuitNow(); - thread->GlobalScope()->SetLifecycleState( - mojom::FrameLifecycleState::kRunning); + thread->Resume(); } void WorkerThreadDebugger::muteMetrics(int context_group_id) {
diff --git a/third_party/blink/renderer/core/inspector/worker_thread_debugger.h b/third_party/blink/renderer/core/inspector/worker_thread_debugger.h index 53d12b4..8b94feb 100644 --- a/third_party/blink/renderer/core/inspector/worker_thread_debugger.h +++ b/third_party/blink/renderer/core/inspector/worker_thread_debugger.h
@@ -32,7 +32,6 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_WORKER_THREAD_DEBUGGER_H_ #include "base/macros.h" -#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/inspector/thread_debugger.h" @@ -92,7 +91,6 @@ int paused_context_group_id_; WTF::HashMap<int, WorkerThread*> worker_threads_; - std::unique_ptr<Platform::NestedMessageLoopRunner> nested_runner_; DISALLOW_COPY_AND_ASSIGN(WorkerThreadDebugger); };
diff --git a/third_party/blink/renderer/core/layout/jank_tracker.cc b/third_party/blink/renderer/core/layout/jank_tracker.cc index b5ba3ae..9623ac1 100644 --- a/third_party/blink/renderer/core/layout/jank_tracker.cc +++ b/third_party/blink/renderer/core/layout/jank_tracker.cc
@@ -96,6 +96,12 @@ RegionToTracedValue(old_region, granularity_scale, value); } +#if DCHECK_IS_ON() +static bool ShouldLog(const LocalFrame& frame) { + return !frame.GetDocument()->Url().GetString().StartsWith("chrome-devtools:"); +} +#endif + JankTracker::JankTracker(LocalFrameView* frame_view) : frame_view_(frame_view), score_(0.0), @@ -145,8 +151,15 @@ if (!old_rect.Intersects(viewport) && !new_rect.Intersects(viewport)) return; - DVLOG(2) << source.DebugName() << " moved from " << old_rect.ToString() - << " to " << new_rect.ToString(); +#if DCHECK_IS_ON() + LocalFrame& frame = frame_view_->GetFrame(); + if (ShouldLog(frame)) { + DVLOG(2) << "in " << (frame.IsMainFrame() ? "" : "subframe ") + << frame.GetDocument()->Url().GetString() << ", " + << source.DebugName() << " moved from " << old_rect.ToString() + << " to " << new_rect.ToString(); + } +#endif max_distance_ = std::max(max_distance_, GetMoveDistance(old_rect, new_rect, source)); @@ -249,10 +262,15 @@ score_ += jank_fraction; - DVLOG(1) << "viewport " << (jank_fraction * 100) - << "% janked, raising score to " << score_; - LocalFrame& frame = frame_view_->GetFrame(); +#if DCHECK_IS_ON() + if (ShouldLog(frame)) { + DVLOG(1) << "in " << (frame.IsMainFrame() ? "" : "subframe ") + << frame.GetDocument()->Url().GetString() << ", viewport was " + << (jank_fraction * 100) << "% janked; raising score to " + << score_; + } +#endif TRACE_EVENT_INSTANT2("loading", "FrameLayoutJank", TRACE_EVENT_SCOPE_THREAD, "data",
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index a499f8c4..850e989 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -1445,13 +1445,6 @@ LayoutUnit& max_logical_width) const { int scrollbar_width = ScrollbarLogicalWidth(); - if (DisplayLockInducesSizeContainment()) { - min_logical_width = max_logical_width = - LayoutUnit(scrollbar_width) + - GetDisplayLockContext()->GetLockedContentLogicalWidth(); - return; - } - // Size-contained elements don't consider their contents for preferred sizing. if (ShouldApplySizeContainment()) { // For multicol containers we need the column gaps. So allow descending into @@ -1462,6 +1455,11 @@ min_logical_width = LayoutUnit(scrollbar_width); return; } + } else if (DisplayLockInducesSizeContainment()) { + min_logical_width = max_logical_width = + LayoutUnit(scrollbar_width) + + GetDisplayLockContext()->GetLockedContentLogicalWidth(); + return; } if (ChildrenInline()) {
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index 89cf2ca..bda6b13 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2866,13 +2866,13 @@ DISABLE_CFI_PERF void LayoutBox::ComputeLogicalWidth( LogicalExtentComputedValues& computed_values) const { - if (DisplayLockInducesSizeContainment()) { + if (ShouldApplySizeContainment()) { + computed_values.extent_ = + BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth(); + } else if (DisplayLockInducesSizeContainment()) { computed_values.extent_ = BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth() + GetDisplayLockContext()->GetLockedContentLogicalWidth(); - } else if (ShouldApplySizeContainment()) { - computed_values.extent_ = - BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth(); } else { computed_values.extent_ = LogicalWidth(); } @@ -3369,11 +3369,14 @@ void LayoutBox::ComputeLogicalHeight( LogicalExtentComputedValues& computed_values) const { LayoutUnit height; - if (DisplayLockInducesSizeContainment()) { + // TODO(962979): Implement grid layout with display locking. We need to figure + // out what happens here if IsLayoutGrid() is true and size containment is + // specified while the box is locked. + if (ShouldApplySizeContainment() && !IsLayoutGrid()) { + height = BorderAndPaddingLogicalHeight() + ScrollbarLogicalHeight(); + } else if (DisplayLockInducesSizeContainment()) { height = BorderAndPaddingLogicalHeight() + ScrollbarLogicalHeight() + GetDisplayLockContext()->GetLockedContentLogicalHeight(); - } else if (ShouldApplySizeContainment() && !IsLayoutGrid()) { - height = BorderAndPaddingLogicalHeight() + ScrollbarLogicalHeight(); } else { height = LogicalHeight(); } @@ -3511,7 +3514,8 @@ LayoutUnit LayoutBox::ComputeLogicalHeightWithoutLayout() const { LogicalExtentComputedValues computed_values; - if (!SelfNeedsLayout() && DisplayLockInducesSizeContainment()) { + if (!SelfNeedsLayout() && !ShouldApplySizeContainment() && + DisplayLockInducesSizeContainment()) { ComputeLogicalHeight( BorderAndPaddingLogicalHeight() + GetDisplayLockContext()->GetLockedContentLogicalHeight(),
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc index e6dbfeb..03ba871 100644 --- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc +++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -68,17 +68,17 @@ LayoutUnit& min_logical_width, LayoutUnit& max_logical_width) const { LayoutUnit scrollbar_width(ScrollbarLogicalWidth()); + if (ShouldApplySizeContainment()) { + max_logical_width = scrollbar_width; + min_logical_width = scrollbar_width; + return; + } if (DisplayLockInducesSizeContainment()) { min_logical_width = max_logical_width = scrollbar_width + GetDisplayLockContext()->GetLockedContentLogicalWidth(); return; } - if (ShouldApplySizeContainment()) { - max_logical_width = scrollbar_width; - min_logical_width = scrollbar_width; - return; - } // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start // honoring it though until the flex shorthand stops setting it to 0. See @@ -504,12 +504,14 @@ DCHECK(MainAxisIsInlineAxis(child)); if (NeedToStretchChildLogicalHeight(child)) { LayoutUnit child_intrinsic_content_logical_height; - if (child.DisplayLockInducesSizeContainment()) { - child_intrinsic_content_logical_height = - child.GetDisplayLockContext()->GetLockedContentLogicalHeight(); - } else if (!child.ShouldApplySizeContainment()) { - child_intrinsic_content_logical_height = - child.IntrinsicContentLogicalHeight(); + if (!child.ShouldApplySizeContainment()) { + if (child.DisplayLockInducesSizeContainment()) { + child_intrinsic_content_logical_height = + child.GetDisplayLockContext()->GetLockedContentLogicalHeight(); + } else { + child_intrinsic_content_logical_height = + child.IntrinsicContentLogicalHeight(); + } } LayoutUnit child_intrinsic_logical_height =
diff --git a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc index 319da17..3ef3ebaf 100644 --- a/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc +++ b/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc
@@ -25,7 +25,82 @@ INSTANTIATE_TEST_SUITE_P(All, AbstractInlineTextBoxTest, testing::Bool()); -TEST_P(AbstractInlineTextBoxTest, GetTextWithTrailingWhiteSpace) { +TEST_P(AbstractInlineTextBoxTest, GetTextWithCollapsedWhiteSpace) { + SetBodyInnerHTML(R"HTML( + <style>* { font-size: 10px; }</style> + <div id="target">abc </div>)HTML"); + + const Element& target = *GetDocument().getElementById("target"); + LayoutText& layout_text = + *ToLayoutText(target.firstChild()->GetLayoutObject()); + scoped_refptr<AbstractInlineTextBox> inline_text_box = + layout_text.FirstAbstractInlineTextBox(); + + EXPECT_EQ("abc", inline_text_box->GetText()); +} + +// For DumpAccessibilityTreeTest.AccessibilityInputTextValue/blink +TEST_P(AbstractInlineTextBoxTest, GetTextWithLineBreakAtCollapsedWhiteSpace) { + // Line break at space between <label> and <input>. + SetBodyInnerHTML(R"HTML( + <style>* { font-size: 10px; }</style> + <div style="width: 10ch"><label id=label>abc:</label> <input></div>)HTML"); + + const Element& label = *GetDocument().getElementById("label"); + LayoutText& layout_text = + *ToLayoutText(label.firstChild()->GetLayoutObject()); + scoped_refptr<AbstractInlineTextBox> inline_text_box = + layout_text.FirstAbstractInlineTextBox(); + + EXPECT_EQ("abc:", inline_text_box->GetText()); +} + +// For "web_tests/accessibility/inline-text-change-style.html" +TEST_P(AbstractInlineTextBoxTest, + GetTextWithLineBreakAtMiddleCollapsedWhiteSpace) { + // Line break at a space after "012". + SetBodyInnerHTML(R"HTML( + <style>* { font-size: 10px; }</style> + <div id="target" style="width: 0ch">012 345</div>)HTML"); + + const Element& target = *GetDocument().getElementById("target"); + LayoutText& layout_text = + *ToLayoutText(target.firstChild()->GetLayoutObject()); + scoped_refptr<AbstractInlineTextBox> inline_text_box = + layout_text.FirstAbstractInlineTextBox(); + + EXPECT_EQ("012 ", inline_text_box->GetText()); +} + +// DumpAccessibilityTreeTest.AccessibilitySpanLineBreak/blink +TEST_P(AbstractInlineTextBoxTest, + GetTextWithLineBreakAtSpanCollapsedWhiteSpace) { + // Line break at a space in <span>. + SetBodyInnerHTML(R"HTML( + <style>* { font-size: 10px; }</style> + <p id="t1" style="width: 0ch">012<span id="t2"> </span>345</p>)HTML"); + + const Element& target1 = *GetDocument().getElementById("t1"); + LayoutText& layout_text1 = + *ToLayoutText(target1.firstChild()->GetLayoutObject()); + scoped_refptr<AbstractInlineTextBox> inline_text_box1 = + layout_text1.FirstAbstractInlineTextBox(); + + EXPECT_EQ("012", inline_text_box1->GetText()); + + const Element& target2 = *GetDocument().getElementById("t2"); + LayoutText& layout_text2 = + *ToLayoutText(target2.firstChild()->GetLayoutObject()); + scoped_refptr<AbstractInlineTextBox> inline_text_box2 = + layout_text2.FirstAbstractInlineTextBox(); + + EXPECT_FALSE(inline_text_box2) << "We don't have inline box when <span> " + "contains only collapsed white spaces."; +} + +// For DumpAccessibilityTreeTest.AccessibilityInputTypes/blink +TEST_P(AbstractInlineTextBoxTest, GetTextWithLineBreakAtTrailingWhiteSpace) { + // Line break at a space of "abc: ". SetBodyInnerHTML(R"HTML( <style>* { font-size: 10px; }</style> <div style="width: 10ch"><label id=label>abc: <input></label></div>)HTML");
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc index daf805ec..e147e28 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
@@ -94,7 +94,19 @@ *To<NGInlineBreakToken>(line_box.PhysicalFragment().BreakToken()); // TODO(yosin): We should support OOF fragments between |fragment_| and // break token. - return break_token.TextOffset() == text_fragment.EndOffset() + 1; + if (break_token.TextOffset() != text_fragment.EndOffset() + 1) + return false; + // Check a character in text content after |fragment_| comes from same + // layout text of |fragment_|. + const NGOffsetMapping& mapping = + *NGOffsetMapping::GetFor(fragment_->GetLayoutObject()); + const NGMappingUnitRange& mapping_units = + mapping.GetMappingUnitsForTextContentOffsetRange( + text_fragment.EndOffset(), text_fragment.EndOffset() + 1); + if (mapping_units.begin() == mapping_units.end()) + return false; + const NGOffsetMappingUnit* const mapping_unit = mapping_units.begin(); + return mapping_unit->GetLayoutObject() == fragment_->GetLayoutObject(); } const NGPaintFragment*
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc index e5a38af..d19aa62e 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -347,10 +347,12 @@ block_flow->ResetNGInlineNodeData(); } - if (NGPaintFragment* fragment = block_flow->PaintFragment()) { - NGDirtyLines dirty_lines(fragment); - PrepareLayout(std::move(previous_data), &dirty_lines); - return; + if (RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) { + if (NGPaintFragment* fragment = block_flow->PaintFragment()) { + NGDirtyLines dirty_lines(fragment); + PrepareLayout(std::move(previous_data), &dirty_lines); + return; + } } PrepareLayout(std::move(previous_data), /* dirty_lines */ nullptr); } @@ -946,6 +948,7 @@ const NGPaintFragment* NGInlineNode::ReusableLineBoxContainer( const NGConstraintSpace& constraint_space) { + DCHECK(RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()); // |SelfNeedsLayout()| is the most common reason that we check it earlier. LayoutBlockFlow* block_flow = GetLayoutBlockFlow(); DCHECK(!block_flow->SelfNeedsLayout()); @@ -1012,6 +1015,7 @@ // marked yet. bool NGInlineNode::MarkLineBoxesDirty(LayoutBlockFlow* block_flow, NGPaintFragment* paint_fragment) { + DCHECK(RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()); NGDirtyLines dirty_lines(paint_fragment); if (block_flow->NeedsCollectInlines()) { std::unique_ptr<NGInlineNodeData> previous_data;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc index 500f099..5f5ad0b0 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -664,7 +664,8 @@ EXPECT_FALSE(previous->GetLayoutObject()->NeedsCollectInlines()); EXPECT_FALSE(next->GetLayoutObject()->NeedsCollectInlines()); - if (data.is_line_dirty) { + if (data.is_line_dirty && + RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) { layout_block_flow_ = ToLayoutNGBlockFlow(container->GetLayoutObject()); auto lines = MarkLineBoxesDirty(); EXPECT_EQ(*data.is_line_dirty, lines[0]->IsDirty()); @@ -982,6 +983,8 @@ // Test marking line boxes when inserting a span before the first child. TEST_P(NodeInsertTest, MarkLineBoxesDirtyOnInsert) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <style> .abspos { position: absolute; } @@ -1002,6 +1005,8 @@ // Test marking line boxes when appending a span. TEST_P(NodeInsertTest, MarkLineBoxesDirtyOnAppend) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <style> .abspos { position: absolute; } @@ -1021,6 +1026,8 @@ // Test marking line boxes when appending a span on 2nd line. TEST_P(NodeInsertTest, MarkLineBoxesDirtyOnAppend2) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <style> .abspos { position: absolute; } @@ -1042,6 +1049,8 @@ // Test marking line boxes when appending a span on 2nd line. TEST_P(NodeInsertTest, MarkLineBoxesDirtyOnAppendAfterBR) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <style> .abspos { position: absolute; } @@ -1063,6 +1072,8 @@ // Test marking line boxes when removing a span. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnRemove) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="font-size: 10px; width: 10ch"> 1234<span id=t>5678</span> @@ -1078,6 +1089,8 @@ // Test marking line boxes when removing a span. TEST_P(NodeParameterTest, MarkLineBoxesDirtyOnRemoveFirst) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", String(R"HTML( <div id=container style="font-size: 10px; width: 10ch">)HTML") + GetParam() + R"HTML(<span>after</span> @@ -1095,6 +1108,8 @@ // Test marking line boxes when removing a span on 2nd line. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnRemove2) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="font-size: 10px; width: 10ch"> 12345678 @@ -1112,6 +1127,8 @@ // Test marking line boxes when removing a text node on 2nd line. TEST_P(NodeParameterTest, MarkLineBoxesDirtyOnRemoveAfterBR) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", String(R"HTML( <div id=container style="font-size: 10px; width: 10ch"> line 1 @@ -1132,6 +1149,8 @@ } TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnEndSpaceCollapsed) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <style> div { @@ -1166,6 +1185,8 @@ // Test marking line boxes when the first span has NeedsLayout. The span is // culled. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnNeedsLayoutFirst) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="font-size: 10px; width: 10ch"> <span id=t>1234</span>5678 @@ -1182,6 +1203,8 @@ // Test marking line boxes when the first span has NeedsLayout. The span has a // box fragment. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnNeedsLayoutFirstWithBox) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="font-size: 10px; width: 10ch"> <span id=t style="background: blue">1234</span>5678 @@ -1197,6 +1220,8 @@ // Test marking line boxes when a span has NeedsLayout. The span is culled. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnNeedsLayout) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="font-size: 10px; width: 10ch"> 12345678 @@ -1215,6 +1240,8 @@ // Test marking line boxes when a span has NeedsLayout. The span has a box // fragment. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnNeedsLayoutWithBox) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="font-size: 10px; width: 10ch"> 12345678 @@ -1234,6 +1261,8 @@ // The parent span has a box fragment, and wraps, so that its fragment // is seen earlier in pre-order DFS. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnChildOfWrappedBox) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="font-size: 10px"> <span style="background: yellow"> @@ -1254,6 +1283,8 @@ // Test marking line boxes when a span has NeedsLayout. The span has a box // fragment. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyInInlineBlock) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetupHtml("container", R"HTML( <div id=container style="display: inline-block; font-size: 10px"> 12345678<br>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index 1daad73..8d288862 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -704,6 +704,7 @@ NGInlineNode inline_node, NGPreviousInflowPosition* previous_inflow_position, bool* aborted_out) { + DCHECK(RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()); LayoutBox* layout_box = inline_node.GetLayoutBox(); if (layout_box->SelfNeedsLayout()) return nullptr; @@ -1195,7 +1196,8 @@ DCHECK(!child.CreatesNewFormattingContext()); auto* child_inline_node = DynamicTo<NGInlineNode>(child); - if (child_inline_node && !child_break_token) { + if (child_inline_node && !child_break_token && + RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) { DCHECK(!*previous_inline_break_token); bool aborted = false; *previous_inline_break_token = TryReuseFragmentsFromCache(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h index 4c553a3d..53be162 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
@@ -38,16 +38,23 @@ const NGConstraintSpace&) const; NGBoxStrut Borders() const { - const auto& physical_fragment = + const NGPhysicalBoxFragment& physical_box_fragment = To<NGPhysicalBoxFragment>(physical_fragment_); - return physical_fragment.Borders().ConvertToLogical(GetWritingMode(), - direction_); + return physical_box_fragment.Borders().ConvertToLogical(GetWritingMode(), + direction_); } NGBoxStrut Padding() const { - const auto& physical_fragment = + const NGPhysicalBoxFragment& physical_box_fragment = To<NGPhysicalBoxFragment>(physical_fragment_); - return physical_fragment.Padding().ConvertToLogical(GetWritingMode(), - direction_); + return physical_box_fragment.Padding().ConvertToLogical(GetWritingMode(), + direction_); + } + + NGBorderEdges BorderEdges() const { + const NGPhysicalBoxFragment& physical_box_fragment = + To<NGPhysicalBoxFragment>(physical_fragment_); + return NGBorderEdges::FromPhysical(physical_box_fragment.BorderEdges(), + GetWritingMode()); } protected:
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_fragment.h index 3b0cc4d2..cd5ac2a 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_fragment.h
@@ -13,7 +13,6 @@ namespace blink { -struct NGBorderEdges; struct LogicalSize; class CORE_EXPORT NGFragment { @@ -45,11 +44,6 @@ static_cast<WritingMode>(writing_mode_)); } - NGBorderEdges BorderEdges() const { - return NGBorderEdges::FromPhysical(physical_fragment_.BorderEdges(), - GetWritingMode()); - } - NGPhysicalFragment::NGFragmentType Type() const { return physical_fragment_.Type(); }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc index bf0defa9..35f12fa 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -1191,16 +1191,17 @@ LayoutUnit ClampIntrinsicBlockSize(const NGBlockNode& node, const NGBoxStrut& border_scrollbar_padding, LayoutUnit current_intrinsic_block_size) { + // With contain: size, we ignore intrinsic sizing. If the block-size was + // specified as auto, its content-box size will become 0. + if (node.ShouldApplySizeContainment()) + return border_scrollbar_padding.BlockSum(); + // If display locking induces size containment, then we replace its content // size with the locked content size. if (node.DisplayLockInducesSizeContainment()) { return node.GetDisplayLockContext().GetLockedContentLogicalHeight() + border_scrollbar_padding.BlockSum(); } - // With contain: size, we ignore intrinsic sizing. If the block-size was - // specified as auto, its content-box size will become 0. - if (node.ShouldApplySizeContainment()) - return border_scrollbar_padding.BlockSum(); return current_intrinsic_block_size; } @@ -1210,23 +1211,25 @@ const NGBoxStrut& border_scrollbar_padding, NGMinMaxSizeType type) { MinMaxSize sizes; - // Display locked elements override the content size, without considering - // children. Note that this check has to be first, since display locking - // overrides the content sizes even if |node| has no children. - // TODO(961297): Investigate whether contain: size should "win" here. - if (node.DisplayLockInducesSizeContainment()) { - sizes = node.GetDisplayLockContext().GetLockedContentLogicalWidth(); - if (type == NGMinMaxSizeType::kBorderBoxSize) - sizes += border_scrollbar_padding.InlineSum(); - return sizes; - } + if (type == NGMinMaxSizeType::kBorderBoxSize) + sizes += border_scrollbar_padding.InlineSum(); + // Size contained elements don't consider children for intrinsic sizing. - // This is the same path as if the node has no children. - if (node.ShouldApplySizeContainment() || !node.FirstChild()) { - if (type == NGMinMaxSizeType::kBorderBoxSize) - sizes += border_scrollbar_padding.InlineSum(); + if (node.ShouldApplySizeContainment()) + return sizes; + + // Display locked elements override the content size, without considering + // children. Note that contain: size (above) takes precedence over display + // locking. + if (node.DisplayLockInducesSizeContainment()) { + sizes += node.GetDisplayLockContext().GetLockedContentLogicalWidth(); return sizes; } + + // If we don't have children, we can also determine the size immediately. + if (!node.FirstChild()) + return sizes; + return base::nullopt; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc index 81faafa..90453c5 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -34,6 +34,10 @@ return box && box->HasControlClip(); } +LayoutUnit BorderWidth(unsigned edges, unsigned edge, float border_width) { + return (edges & edge) ? LayoutUnit(border_width) : LayoutUnit(); +} + } // namespace scoped_refptr<const NGPhysicalBoxFragment> NGPhysicalBoxFragment::Create( @@ -224,4 +228,14 @@ return self_item->BidiLevel(); } +NGPixelSnappedPhysicalBoxStrut NGPhysicalBoxFragment::BorderWidths() const { + unsigned edges = BorderEdges(); + NGPhysicalBoxStrut box_strut( + BorderWidth(edges, NGBorderEdges::kTop, Style().BorderTopWidth()), + BorderWidth(edges, NGBorderEdges::kRight, Style().BorderRightWidth()), + BorderWidth(edges, NGBorderEdges::kBottom, Style().BorderBottomWidth()), + BorderWidth(edges, NGBorderEdges::kLeft, Style().BorderLeftWidth())); + return box_strut.SnapToDevicePixels(); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h index e02fedda6..d9a7c04 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -66,6 +66,10 @@ UBiDiLevel BidiLevel() const; + // Bitmask for border edges, see NGBorderEdges::Physical. + unsigned BorderEdges() const { return border_edge_; } + NGPixelSnappedPhysicalBoxStrut BorderWidths() const; + private: NGPhysicalBoxFragment(NGBoxFragmentBuilder* builder, WritingMode block_or_line_writing_mode);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc index 4c72c5fd..28fbd5f 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -209,10 +209,6 @@ builder->Append("\n"); } -LayoutUnit BorderWidth(unsigned edges, unsigned edge, float border_width) { - return (edges & edge) ? LayoutUnit(border_width) : LayoutUnit(); -} - } // namespace // static @@ -351,16 +347,6 @@ return container->IsLayoutNGMixin() || container->IsLayoutNGFlexibleBox(); } -NGPixelSnappedPhysicalBoxStrut NGPhysicalFragment::BorderWidths() const { - unsigned edges = BorderEdges(); - NGPhysicalBoxStrut box_strut( - BorderWidth(edges, NGBorderEdges::kTop, Style().BorderTopWidth()), - BorderWidth(edges, NGBorderEdges::kRight, Style().BorderRightWidth()), - BorderWidth(edges, NGBorderEdges::kBottom, Style().BorderBottomWidth()), - BorderWidth(edges, NGBorderEdges::kLeft, Style().BorderLeftWidth())); - return box_strut.SnapToDevicePixels(); -} - #if DCHECK_IS_ON() void NGPhysicalFragment::CheckCanUpdateInkOverflow() const { if (!GetLayoutObject())
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h index 489de1ce..c1e4e9f 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -26,7 +26,6 @@ class NGFragmentBuilder; class NGBreakToken; class NGInlineItem; -struct NGPixelSnappedPhysicalBoxStrut; class PaintLayer; class NGPhysicalFragment; @@ -157,10 +156,6 @@ // (0, 0). PhysicalRect LocalRect() const { return {{}, size_}; } - // Bitmask for border edges, see NGBorderEdges::Physical. - unsigned BorderEdges() const { return border_edge_; } - NGPixelSnappedPhysicalBoxStrut BorderWidths() const; - NGBreakToken* BreakToken() const { return break_token_.get(); } NGStyleVariant StyleVariant() const { return static_cast<NGStyleVariant>(style_variant_); @@ -270,9 +265,12 @@ // The following bitfields are only to be used by NGPhysicalBoxFragment // (it's defined here to save memory, since that class has no bitfields). unsigned children_inline_ : 1; + unsigned border_edge_ : 4; // NGBorderEdges::Physical + + // The following are only used by NGPhysicalBoxFragment but are initialized + // for all types to allow methods using them to be inlined. unsigned is_fieldset_container_ : 1; unsigned is_legacy_layout_root_ : 1; - unsigned border_edge_ : 4; // NGBorderEdges::Physical // The following bitfields are only to be used by NGPhysicalTextFragment // (it's defined here to save memory, since that class has no bitfields).
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h index c83aba2..22bad34 100644 --- a/third_party/blink/renderer/core/loader/empty_clients.h +++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -134,6 +134,7 @@ Page* CreateWindowDelegate(LocalFrame*, const FrameLoadRequest&, + const AtomicString&, const WebWindowFeatures&, WebSandboxFlags, const FeaturePolicy::FeatureState&,
diff --git a/third_party/blink/renderer/core/loader/form_submission.cc b/third_party/blink/renderer/core/loader/form_submission.cc index 46872a2..e001505 100644 --- a/third_party/blink/renderer/core/loader/form_submission.cc +++ b/third_party/blink/renderer/core/loader/form_submission.cc
@@ -33,6 +33,7 @@ #include "third_party/blink/public/platform/web_insecure_request_policy.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/events/event.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/html/forms/form_data.h" #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h" @@ -282,8 +283,7 @@ return request_url; } -FrameLoadRequest FormSubmission::CreateFrameLoadRequest( - Document* origin_document) { +void FormSubmission::Navigate() { ResourceRequest resource_request(RequestURL()); ClientNavigationReason reason = ClientNavigationReason::kFormSubmissionGet; if (method_ == FormSubmission::kPostMethod) { @@ -299,14 +299,23 @@ "; boundary=" + boundary_); } } + resource_request.SetHasUserGesture( + LocalFrame::HasTransientUserActivation(form_->GetDocument().GetFrame())); - FrameLoadRequest frame_request( - origin_document, resource_request, - target_.IsEmpty() ? origin_document->BaseTarget() : target_); + FrameLoadRequest frame_request(&form_->GetDocument(), resource_request); + frame_request.SetNavigationPolicy(navigation_policy_); frame_request.SetClientRedirectReason(reason); frame_request.SetForm(form_); frame_request.SetTriggeringEventInfo(triggering_event_info_); - return frame_request; + + Frame* target_frame = + form_->GetDocument() + .GetFrame() + ->Tree() + .FindOrCreateFrameForNavigation(frame_request, target_) + .frame; + if (target_frame) + target_frame->Navigate(frame_request, WebFrameLoadType::kStandard); } } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/form_submission.h b/third_party/blink/renderer/core/loader/form_submission.h index 58cd913..fa4405e 100644 --- a/third_party/blink/renderer/core/loader/form_submission.h +++ b/third_party/blink/renderer/core/loader/form_submission.h
@@ -42,7 +42,6 @@ namespace blink { -class Document; class EncodedFormData; class Event; class HTMLFormControlElement; @@ -112,7 +111,7 @@ void Trace(blink::Visitor*); - FrameLoadRequest CreateFrameLoadRequest(Document* origin_document); + void Navigate(); KURL RequestURL() const; @@ -120,7 +119,6 @@ const KURL& Action() const { return action_; } HTMLFormElement* Form() const { return form_.Get(); } EncodedFormData* Data() const { return form_data_.get(); } - NavigationPolicy GetNavigationPolicy() const { return navigation_policy_; } const String& Result() const { return result_; }
diff --git a/third_party/blink/renderer/core/loader/frame_load_request.cc b/third_party/blink/renderer/core/loader/frame_load_request.cc index 7cd61ef3..78317813 100644 --- a/third_party/blink/renderer/core/loader/frame_load_request.cc +++ b/third_party/blink/renderer/core/loader/frame_load_request.cc
@@ -43,14 +43,9 @@ FrameLoadRequest::FrameLoadRequest(Document* origin_document, const ResourceRequest& resource_request) - : FrameLoadRequest(origin_document, resource_request, AtomicString()) {} -FrameLoadRequest::FrameLoadRequest(Document* origin_document, - const ResourceRequest& resource_request, - const AtomicString& frame_name) : origin_document_(origin_document), resource_request_(resource_request), - frame_name_(frame_name), client_redirect_(ClientRedirectPolicy::kNotClientRedirect), should_send_referrer_(kMaybeSendReferrer) { // These flags are passed to a service worker which controls the page.
diff --git a/third_party/blink/renderer/core/loader/frame_load_request.h b/third_party/blink/renderer/core/loader/frame_load_request.h index f998781..0e418be 100644 --- a/third_party/blink/renderer/core/loader/frame_load_request.h +++ b/third_party/blink/renderer/core/loader/frame_load_request.h
@@ -46,9 +46,6 @@ public: FrameLoadRequest(Document* origin_document, const ResourceRequest&); - FrameLoadRequest(Document* origin_document, - const ResourceRequest&, - const AtomicString& frame_name); Document* OriginDocument() const { return origin_document_.Get(); } @@ -64,9 +61,6 @@ return resource_request_; } - const AtomicString& FrameName() const { return frame_name_; } - void ClearFrameName() { frame_name_ = AtomicString(); } - ClientRedirectPolicy ClientRedirect() const { return client_redirect_; } void SetClientRedirectReason(ClientNavigationReason reason) { @@ -147,7 +141,6 @@ private: Member<Document> origin_document_; ResourceRequest resource_request_; - AtomicString frame_name_; AtomicString href_translate_; // TODO(caseq): merge ClientRedirectPolicy and ClientNavigationReason. // Currently, client_navigation_reason_ is set iff ClientRedirectPolicy
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index b209c2b4..c4405d6 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -628,9 +628,6 @@ CHECK(!IsBackForwardLoadType(frame_load_type)); DCHECK(passed_request.TriggeringEventInfo() != WebTriggeringEventInfo::kUnknown); - // Finding the correct frame must happen before calling StartNavigation(). - DCHECK(passed_request.FrameName().IsEmpty()); - DCHECK(frame_->GetDocument()); if (HTMLFrameOwnerElement* element = frame_->DeprecatedLocalOwner()) element->CancelPendingLazyLoad();
diff --git a/third_party/blink/renderer/core/page/chrome_client.cc b/third_party/blink/renderer/core/page/chrome_client.cc index 845d607..54f2a8f4 100644 --- a/third_party/blink/renderer/core/page/chrome_client.cc +++ b/third_party/blink/renderer/core/page/chrome_client.cc
@@ -102,6 +102,7 @@ Page* ChromeClient::CreateWindow( LocalFrame* frame, const FrameLoadRequest& r, + const AtomicString& frame_name, const WebWindowFeatures& features, WebSandboxFlags sandbox_flags, const FeaturePolicy::FeatureState& opener_feature_state, @@ -115,7 +116,7 @@ } #endif - return CreateWindowDelegate(frame, r, features, sandbox_flags, + return CreateWindowDelegate(frame, r, frame_name, features, sandbox_flags, opener_feature_state, session_storage_namespace_id); }
diff --git a/third_party/blink/renderer/core/page/chrome_client.h b/third_party/blink/renderer/core/page/chrome_client.h index a36fbec..865fdda 100644 --- a/third_party/blink/renderer/core/page/chrome_client.h +++ b/third_party/blink/renderer/core/page/chrome_client.h
@@ -163,6 +163,7 @@ // request could be fulfilled. The ChromeClient should not load the request. Page* CreateWindow(LocalFrame*, const FrameLoadRequest&, + const AtomicString& frame_name, const WebWindowFeatures&, WebSandboxFlags, const FeaturePolicy::FeatureState&, @@ -447,6 +448,7 @@ virtual void PrintDelegate(LocalFrame*) = 0; virtual Page* CreateWindowDelegate(LocalFrame*, const FrameLoadRequest&, + const AtomicString& frame_name, const WebWindowFeatures&, WebSandboxFlags, const FeaturePolicy::FeatureState&,
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc index 3ac1c41..60f7bf3 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl.cc +++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -253,6 +253,7 @@ Page* ChromeClientImpl::CreateWindowDelegate( LocalFrame* frame, const FrameLoadRequest& r, + const AtomicString& name, const WebWindowFeatures& features, WebSandboxFlags sandbox_flags, const FeaturePolicy::FeatureState& opener_feature_state, @@ -265,8 +266,7 @@ NotifyPopupOpeningObservers(); const AtomicString& frame_name = - !EqualIgnoringASCIICase(r.FrameName(), "_blank") ? r.FrameName() - : g_empty_atom; + !EqualIgnoringASCIICase(name, "_blank") ? name : g_empty_atom; WebViewImpl* new_view = static_cast<WebViewImpl*>(web_view_->Client()->CreateView( WebLocalFrameImpl::FromFrame(frame),
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h index d946d9b..d65d3fdf 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl.h +++ b/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -79,6 +79,7 @@ bool AcceptsLoadDrops() const override; Page* CreateWindowDelegate(LocalFrame*, const FrameLoadRequest&, + const AtomicString& name, const WebWindowFeatures&, WebSandboxFlags, const FeaturePolicy::FeatureState&,
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc index 5cf958b..61bc163 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc +++ b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
@@ -94,7 +94,7 @@ request.SetNavigationPolicy(kNavigationPolicyNewForegroundTab); WebWindowFeatures features; EXPECT_EQ(nullptr, chrome_client_impl_->CreateWindow( - frame, request, features, WebSandboxFlags::kNone, + frame, request, "", features, WebSandboxFlags::kNone, FeaturePolicy::FeatureState(), "")); }
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc index 04b5a34..8268e909 100644 --- a/third_party/blink/renderer/core/page/create_window.cc +++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -220,7 +220,9 @@ } } -Frame* CreateNewWindow(LocalFrame& opener_frame, FrameLoadRequest& request) { +Frame* CreateNewWindow(LocalFrame& opener_frame, + FrameLoadRequest& request, + const AtomicString& frame_name) { DCHECK(request.GetResourceRequest().RequestorOrigin() || opener_frame.GetDocument()->Url().IsEmpty()); DCHECK_EQ(kNavigationPolicyCurrentTab, request.GetNavigationPolicy()); @@ -254,8 +256,7 @@ const WebWindowFeatures& features = request.GetWindowFeatures(); request.SetNavigationPolicy(NavigationPolicyForCreateWindow(features)); - probe::WindowOpen(opener_frame.GetDocument(), url, request.FrameName(), - features, + probe::WindowOpen(opener_frame.GetDocument(), url, frame_name, features, LocalFrame::HasTransientUserActivation(&opener_frame)); // Sandboxed frames cannot open new auxiliary browsing contexts. @@ -296,8 +297,8 @@ } Page* page = old_page->GetChromeClient().CreateWindow( - &opener_frame, request, features, sandbox_flags, opener_feature_state, - new_namespace_id); + &opener_frame, request, frame_name, features, sandbox_flags, + opener_feature_state, new_namespace_id); if (!page) return nullptr;
diff --git a/third_party/blink/renderer/core/page/create_window.h b/third_party/blink/renderer/core/page/create_window.h index d33f8b8..65ad2ef 100644 --- a/third_party/blink/renderer/core/page/create_window.h +++ b/third_party/blink/renderer/core/page/create_window.h
@@ -36,7 +36,9 @@ class LocalFrame; struct FrameLoadRequest; -Frame* CreateNewWindow(LocalFrame& opener_frame, FrameLoadRequest&); +Frame* CreateNewWindow(LocalFrame& opener_frame, + FrameLoadRequest&, + const AtomicString& name); CORE_EXPORT WebWindowFeatures GetWindowFeaturesFromString(const String&);
diff --git a/third_party/blink/renderer/core/page/frame_tree.cc b/third_party/blink/renderer/core/page/frame_tree.cc index 58ecc4e5..4dedf52 100644 --- a/third_party/blink/renderer/core/page/frame_tree.cc +++ b/third_party/blink/renderer/core/page/frame_tree.cc
@@ -180,19 +180,19 @@ return count; } -FrameTree::FindResult FrameTree::FindFrameForNavigation( - FrameLoadRequest& request) const { +Frame* FrameTree::FindFrameByName(const AtomicString& name) const { // Named frame lookup should always be relative to a local frame. DCHECK(IsA<LocalFrame>(this_frame_.Get())); - Frame* frame = FindFrameForNavigationInternal(request); + Frame* frame = FindFrameForNavigationInternal(name, KURL()); if (frame && !To<LocalFrame>(this_frame_.Get())->CanNavigate(*frame)) frame = nullptr; - return FindResult(frame, false); + return frame; } FrameTree::FindResult FrameTree::FindOrCreateFrameForNavigation( - FrameLoadRequest& request) const { + FrameLoadRequest& request, + const AtomicString& name) const { // Named frame lookup should always be relative to a local frame. DCHECK(IsA<LocalFrame>(this_frame_.Get())); LocalFrame* current_frame = To<LocalFrame>(this_frame_.Get()); @@ -200,15 +200,14 @@ // A GetNavigationPolicy() value other than kNavigationPolicyCurrentTab at // this point indicates that a user event modified the navigation policy // (e.g., a ctrl-click). Let the user's action override any target attribute. - if (request.GetNavigationPolicy() != kNavigationPolicyCurrentTab) { - request.ClearFrameName(); + if (request.GetNavigationPolicy() != kNavigationPolicyCurrentTab) return FindResult(current_frame, false); - } - Frame* frame = FindFrameForNavigationInternal(request); + Frame* frame = + FindFrameForNavigationInternal(name, request.GetResourceRequest().Url()); bool new_window = false; if (!frame) { - frame = CreateNewWindow(*current_frame, request); + frame = CreateNewWindow(*current_frame, request, name); new_window = true; // CreateNewWindow() might have modified NavigationPolicy. // Set it back now that the new window is known to be the right one. @@ -217,7 +216,6 @@ frame = nullptr; } - request.ClearFrameName(); if (frame && !new_window) { if (frame->GetPage() == current_frame->GetPage()) frame->GetPage()->GetFocusController().SetFocusedFrame(frame); @@ -230,10 +228,8 @@ return FindResult(frame, new_window); } -Frame* FrameTree::FindFrameForNavigationInternal( - FrameLoadRequest& request) const { - const AtomicString& name = request.FrameName(); - +Frame* FrameTree::FindFrameForNavigationInternal(const AtomicString& name, + const KURL& url) const { if (EqualIgnoringASCIICase(name, "_current")) { UseCounter::Count( blink::DynamicTo<blink::LocalFrame>(this_frame_.Get())->GetDocument(), @@ -255,7 +251,6 @@ if (EqualIgnoringASCIICase(name, "_blank")) return nullptr; - const KURL& url = request.GetResourceRequest().Url(); // Search subtree starting with this frame first. for (Frame* frame = this_frame_; frame; frame = frame->Tree().TraverseNext(this_frame_)) {
diff --git a/third_party/blink/renderer/core/page/frame_tree.h b/third_party/blink/renderer/core/page/frame_tree.h index 7071d43..4da9295 100644 --- a/third_party/blink/renderer/core/page/frame_tree.h +++ b/third_party/blink/renderer/core/page/frame_tree.h
@@ -29,6 +29,7 @@ class Frame; struct FrameLoadRequest; +class KURL; class CORE_EXPORT FrameTree final { DISALLOW_NEW(); @@ -59,6 +60,9 @@ bool IsDescendantOf(const Frame* ancestor) const; Frame* TraverseNext(const Frame* stay_within = nullptr) const; + // For plugins and tests only. + Frame* FindFrameByName(const AtomicString& name) const; + // https://html.spec.whatwg.org/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name struct FindResult { STACK_ALLOCATED(); @@ -68,8 +72,8 @@ Member<Frame> frame; bool new_window; }; - FindResult FindFrameForNavigation(FrameLoadRequest&) const; - FindResult FindOrCreateFrameForNavigation(FrameLoadRequest&) const; + FindResult FindOrCreateFrameForNavigation(FrameLoadRequest&, + const AtomicString& name) const; unsigned ChildCount() const; @@ -86,7 +90,8 @@ void Trace(blink::Visitor*); private: - Frame* FindFrameForNavigationInternal(FrameLoadRequest&) const; + Frame* FindFrameForNavigationInternal(const AtomicString& name, + const KURL&) const; Member<Frame> this_frame_;
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc index 6c395d0..b17afbe 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -48,6 +48,14 @@ namespace blink { +// A small integer that easily fits into a double with a good margin for +// arithmetic. In particular, we don't want to use +// std::numeric_limits<double>::lowest() because, if subtracted, it becomes +// NaN which will make all following arithmetic NaN too (an unusable number). +constexpr double kMinDistance = std::numeric_limits<int>::lowest(); + +constexpr int kFudgeFactor = 2; + static void DeflateIfOverlapped(LayoutRect&, LayoutRect&); FocusCandidate::FocusCandidate(Node* node, SpatialNavigationDirection direction) @@ -290,7 +298,7 @@ if (!a.Intersects(b) || a.Contains(b) || b.Contains(a)) return; - LayoutUnit deflate_factor = LayoutUnit(-FudgeFactor()); + LayoutUnit deflate_factor = LayoutUnit(-kFudgeFactor); // Avoid negative width or height values. if ((a.Width() + 2 * deflate_factor > 0) && @@ -525,55 +533,42 @@ } } -bool AreElementsOnSameLine(const FocusCandidate& first_candidate, - const FocusCandidate& second_candidate) { - if (first_candidate.IsNull() || second_candidate.IsNull()) - return false; - - if (!first_candidate.visible_node->GetLayoutObject() || - !second_candidate.visible_node->GetLayoutObject()) - return false; - - if (!first_candidate.rect_in_root_frame.Intersects( - second_candidate.rect_in_root_frame)) - return false; - - if (IsHTMLAreaElement(*first_candidate.focusable_node) || - IsHTMLAreaElement(*second_candidate.focusable_node)) - return false; - - if (!first_candidate.visible_node->GetLayoutObject()->IsLayoutInline() || - !second_candidate.visible_node->GetLayoutObject()->IsLayoutInline()) - return false; - - if (first_candidate.visible_node->GetLayoutObject()->ContainingBlock() != - second_candidate.visible_node->GetLayoutObject()->ContainingBlock()) - return false; - - return true; -} - double ComputeDistanceDataForNode(SpatialNavigationDirection direction, const FocusCandidate& current_interest, const FocusCandidate& candidate) { - if (!IsRectInDirection(direction, current_interest.rect_in_root_frame, - candidate.rect_in_root_frame)) - return MaxDistance(); - - if (AreElementsOnSameLine(current_interest, candidate)) { - if ((direction == SpatialNavigationDirection::kUp && - current_interest.rect_in_root_frame.Y() > - candidate.rect_in_root_frame.Y()) || - (direction == SpatialNavigationDirection::kDown && - candidate.rect_in_root_frame.Y() > - current_interest.rect_in_root_frame.Y())) { - return 0.0; - } - } - + double distance = 0.0; + double overlap = 0.0; LayoutRect node_rect = candidate.rect_in_root_frame; LayoutRect current_rect = current_interest.rect_in_root_frame; - DeflateIfOverlapped(current_rect, node_rect); + if (node_rect.Contains(current_rect)) { + // When leaving an "insider", don't focus its underlaying container box. + // Go directly to the outside world. This avoids focus from being trapped + // inside a container. + return kMaxDistance; + } + + if (current_rect.Contains(node_rect)) { + // We give priority to "insiders", candidates that are completely inside the + // current focus rect, by giving them a negative, < 0, distance number. + distance = kMinDistance; + + // For insiders we cannot meassure the distance from the outer box. Instead, + // we meassure distance _from_ the focused container's rect's "opposite + // edge" in the navigated direction, just like we do when we look for + // candidates inside a focused scroll container. + current_rect = OppositeEdge(direction, current_rect); + + // This candidate fully overlaps the current focus rect so we can omit the + // overlap term of the equation. An "insider" will always win against an + // "outsider". + } else if (!IsRectInDirection(direction, current_rect, node_rect)) { + return kMaxDistance; + } else { + DeflateIfOverlapped(current_rect, node_rect); + LayoutRect intersection_rect = Intersection(current_rect, node_rect); + overlap = + (intersection_rect.Width() * intersection_rect.Height()).ToDouble(); + } LayoutPoint exit_point; LayoutPoint entry_point; @@ -582,6 +577,9 @@ LayoutUnit x_axis = (exit_point.X() - entry_point.X()).Abs(); LayoutUnit y_axis = (exit_point.Y() - entry_point.Y()).Abs(); + double euclidian_distance = + sqrt((x_axis * x_axis + y_axis * y_axis).ToDouble()); + distance += euclidian_distance; LayoutUnit navigation_axis_distance; LayoutUnit weighted_orthogonal_axis_distance; @@ -616,21 +614,17 @@ break; default: NOTREACHED(); - return MaxDistance(); + return kMaxDistance; } - double euclidian_distance_pow2 = - (x_axis * x_axis + y_axis * y_axis).ToDouble(); - LayoutRect intersection_rect = Intersection(current_rect, node_rect); - double overlap = - (intersection_rect.Width() * intersection_rect.Height()).ToDouble(); - // Distance calculation is based on http://www.w3.org/TR/WICD/#focus-handling - return sqrt(euclidian_distance_pow2) + navigation_axis_distance + + return distance + navigation_axis_distance + weighted_orthogonal_axis_distance - sqrt(overlap); } -// Returns a thin rectangle that represents one of box's sides. +// Returns a thin rectangle that represents one of |box|'s edges. +// To not intersect elements that are positioned inside |box|, we add one +// LayoutUnit of margin that puts the returned slice "just outside" |box|. LayoutRect OppositeEdge(SpatialNavigationDirection side, const LayoutRect& box, LayoutUnit thickness) { @@ -639,16 +633,20 @@ case SpatialNavigationDirection::kLeft: thin_rect.SetX(thin_rect.MaxX() - thickness); thin_rect.SetWidth(thickness); + thin_rect.Move(1, 0); break; case SpatialNavigationDirection::kRight: thin_rect.SetWidth(thickness); + thin_rect.Move(-1, 0); break; case SpatialNavigationDirection::kDown: thin_rect.SetHeight(thickness); + thin_rect.Move(0, -1); break; case SpatialNavigationDirection::kUp: thin_rect.SetY(thin_rect.MaxY() - thickness); thin_rect.SetHeight(thickness); + thin_rect.Move(0, 1); break; default: NOTREACHED(); @@ -667,7 +665,7 @@ direction, area.GetDocument().GetFrame()->View()->ConvertToRootFrame( area.ComputeAbsoluteRect(area.ImageElement()->GetLayoutObject())), - LayoutUnit(1) /* snav-imagemap-overlapped-areas.html */); + LayoutUnit(kFudgeFactor) /* snav-imagemap-overlapped-areas.html */); return rect; }
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.h b/third_party/blink/renderer/core/page/spatial_navigation.h index 0031cc85..7112a4d 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation.h +++ b/third_party/blink/renderer/core/page/spatial_navigation.h
@@ -36,13 +36,7 @@ enum class SpatialNavigationDirection { kNone, kUp, kRight, kDown, kLeft }; -inline double MaxDistance() { - return std::numeric_limits<double>::max(); -} - -inline int FudgeFactor() { - return 2; -} +constexpr double kMaxDistance = std::numeric_limits<double>::max(); CORE_EXPORT bool IsSpatialNavigationEnabled(const LocalFrame*); @@ -80,8 +74,6 @@ CORE_EXPORT Node* ScrollableAreaOrDocumentOf(Node*); bool CanScrollInDirection(const Node* container, SpatialNavigationDirection); bool CanScrollInDirection(const LocalFrame*, SpatialNavigationDirection); -bool AreElementsOnSameLine(const FocusCandidate& first_candidate, - const FocusCandidate& second_candidate); double ComputeDistanceDataForNode(SpatialNavigationDirection, const FocusCandidate& current_interest,
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc index 8c7f9c93..53d29f21 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -91,42 +91,9 @@ double distance = ComputeDistanceDataForNode(direction, current_interest, candidate); - if (distance == MaxDistance()) + if (distance == kMaxDistance) return; - if (!best_candidate->IsNull()) { - LayoutRect intersection_rect = Intersection( - candidate.rect_in_root_frame, best_candidate->rect_in_root_frame); - if (!intersection_rect.IsEmpty() && - !AreElementsOnSameLine(*best_candidate, candidate) && - intersection_rect == candidate.rect_in_root_frame) { - // If 2 nodes are intersecting, do hit test to find which node in on top. - LayoutUnit x = intersection_rect.X() + intersection_rect.Width() / 2; - LayoutUnit y = intersection_rect.Y() + intersection_rect.Height() / 2; - if (!IsA<LocalFrame>( - candidate.visible_node->GetDocument().GetPage()->MainFrame())) - return; - HitTestLocation location(IntPoint(x.ToInt(), y.ToInt())); - HitTestResult result = - candidate.visible_node->GetDocument() - .GetPage() - ->DeprecatedLocalMainFrame() - ->GetEventHandler() - .HitTestResultAtLocation(location, - HitTestRequest::kReadOnly | - HitTestRequest::kActive | - HitTestRequest::kIgnoreClipping); - if (candidate.visible_node->ContainsIncludingHostElements( - *result.InnerNode())) { - *best_candidate = candidate; - *best_distance = distance; - return; - } - if (best_candidate->visible_node->ContainsIncludingHostElements( - *result.InnerNode())) - return; - } - } if (distance < *best_distance && IsUnobscured(candidate)) { *best_candidate = candidate; @@ -303,7 +270,7 @@ current_interest.visible_node = interest_child_in_container; FocusCandidate best_candidate; - double best_distance = MaxDistance(); + double best_distance = kMaxDistance; for (; element; element = IsScrollableAreaOrDocument(element)
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/third_party/blink/renderer/core/page/spatial_navigation_test.cc index e0716b1..a7416224 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_test.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -26,26 +26,28 @@ LayoutRect TopOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); + visual_viewport.SetY(visual_viewport.Y() - 1); visual_viewport.SetHeight(LayoutUnit(0)); return visual_viewport; } LayoutRect BottomOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); - visual_viewport.SetY(visual_viewport.MaxY()); + visual_viewport.SetY(visual_viewport.MaxY() + 1); visual_viewport.SetHeight(LayoutUnit(0)); return visual_viewport; } LayoutRect LeftSideOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); + visual_viewport.SetX(visual_viewport.X() - 1); visual_viewport.SetWidth(LayoutUnit(0)); return visual_viewport; } LayoutRect RightSideOfVisualViewport() { LayoutRect visual_viewport = RootViewport(&GetFrame()); - visual_viewport.SetX(visual_viewport.MaxX()); + visual_viewport.SetX(visual_viewport.MaxX() + 1); visual_viewport.SetWidth(LayoutUnit(0)); return visual_viewport; } @@ -245,7 +247,7 @@ } TEST_F(SpatialNavigationTest, StartAtTopWhenGoingDownwardsWithoutFocus) { - EXPECT_EQ(LayoutRect(0, 0, 111, 0), + EXPECT_EQ(LayoutRect(0, -1, 111, 0), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kDown)); @@ -256,7 +258,7 @@ TEST_F(SpatialNavigationTest, StartAtBottomWhenGoingUpwardsWithoutFocus) { EXPECT_EQ( - LayoutRect(0, 222, 111, 0), + LayoutRect(0, 222 + 1, 111, 0), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kUp)); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), nullptr, @@ -265,7 +267,7 @@ } TEST_F(SpatialNavigationTest, StartAtLeftSideWhenGoingEastWithoutFocus) { - EXPECT_EQ(LayoutRect(0, 0, 0, 222), + EXPECT_EQ(LayoutRect(-1, 0, 0, 222), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kRight)); @@ -275,7 +277,7 @@ } TEST_F(SpatialNavigationTest, StartAtRightSideWhenGoingWestWithoutFocus) { - EXPECT_EQ(LayoutRect(111, 0, 0, 222), + EXPECT_EQ(LayoutRect(111 + 1, 0, 0, 222), SearchOrigin({0, 0, 111, 222}, nullptr, SpatialNavigationDirection::kLeft)); @@ -330,14 +332,15 @@ // Go down. LayoutRect container_top_edge = container_box; container_top_edge.SetHeight(LayoutUnit(0)); + container_top_edge.SetY(container_top_edge.Y() - 1); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kDown), container_top_edge); // Go up. LayoutRect container_bottom_edge = container_box; - container_bottom_edge.SetY(container_bottom_edge.MaxX()); container_bottom_edge.SetHeight(LayoutUnit(0)); + container_bottom_edge.SetY(container_bottom_edge.MaxX() + 1); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kUp), container_bottom_edge); @@ -345,13 +348,14 @@ // Go right. LayoutRect container_leftmost_edge = container_box; container_leftmost_edge.SetWidth(LayoutUnit(0)); + container_leftmost_edge.SetX(container_leftmost_edge.X() - 1); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kRight), container_leftmost_edge); // Go left. LayoutRect container_rightmost_edge = container_box; - container_rightmost_edge.SetX(container_bottom_edge.MaxX()); + container_rightmost_edge.SetX(container_bottom_edge.MaxX() + 1); container_rightmost_edge.SetWidth(LayoutUnit(0)); EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b, SpatialNavigationDirection::kLeft), @@ -596,7 +600,7 @@ EXPECT_EQ(origin.Height(), 0); EXPECT_EQ(origin.Width(), GetFrame().View()->Width()); EXPECT_EQ(origin.X(), 0); - EXPECT_EQ(origin.Y(), GetFrame().View()->Height()); + EXPECT_EQ(origin.Y(), GetFrame().View()->Height() + 1); EXPECT_EQ(origin, BottomOfVisualViewport()); // Now, test SearchOrigin with a pinched viewport. @@ -608,7 +612,7 @@ EXPECT_EQ(origin.Height(), 0); EXPECT_LT(origin.Width(), GetFrame().View()->Width()); EXPECT_GT(origin.X(), 0); - EXPECT_LT(origin.Y(), GetFrame().View()->Height()); + EXPECT_LT(origin.Y(), GetFrame().View()->Height() + 1); EXPECT_EQ(origin, BottomOfVisualViewport()); } @@ -618,7 +622,7 @@ EXPECT_EQ(origin.Height(), 0); EXPECT_EQ(origin.Width(), GetFrame().View()->Width()); EXPECT_EQ(origin.X(), 0); - EXPECT_EQ(origin.Y(), 0); + EXPECT_EQ(origin.Y(), -1); EXPECT_EQ(origin, TopOfVisualViewport()); // Now, test SearchOrigin with a pinched viewport. @@ -630,7 +634,7 @@ EXPECT_EQ(origin.Height(), 0); EXPECT_LT(origin.Width(), GetFrame().View()->Width()); EXPECT_GT(origin.X(), 0); - EXPECT_GT(origin.Y(), 0); + EXPECT_GT(origin.Y(), -1); EXPECT_EQ(origin, TopOfVisualViewport()); }
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc index 42e3bb3..079d43bc 100644 --- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc +++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -330,9 +330,9 @@ return; CompositorFilterOperations backdrop_filters = OwningLayer().CreateCompositorFilterOperationsForBackdropFilter(); - gfx::RRectF filter_bounds = OwningLayer().BackdropFilterBounds( + gfx::RRectF backdrop_filter_bounds = OwningLayer().BackdropFilterBounds( OwningLayer().BackdropFilterReferenceBox()); - graphics_layer_->SetBackdropFilters(backdrop_filters, filter_bounds); + graphics_layer_->SetBackdropFilters(backdrop_filters, backdrop_filter_bounds); } void CompositedLayerMapping::UpdateStickyConstraints(
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc index d4400031..462a5b6 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -77,8 +77,7 @@ void ImagePaintTimingDetector::PopulateTraceValue( TracedValue& value, - const ImageRecord& first_image_paint, - unsigned candidate_index) const { + const ImageRecord& first_image_paint) { value.SetInteger("DOMNodeId", static_cast<int>(first_image_paint.node_id)); // The cached_image could have been deleted when this is called. value.SetString("imageUrl", @@ -86,7 +85,7 @@ ? String(first_image_paint.cached_image->Url()) : "(deleted)"); value.SetInteger("size", static_cast<int>(first_image_paint.first_size)); - value.SetInteger("candidateIndex", candidate_index); + value.SetInteger("candidateIndex", ++count_candidates_); value.SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame()); value.SetBoolean("isOOPIF", !frame_view_->GetFrame().LocalFrameRoot().IsMainFrame()); @@ -96,13 +95,24 @@ ImageRecord& largest_image_record) { DCHECK(!largest_image_record.paint_time.is_null()); auto value = std::make_unique<TracedValue>(); - PopulateTraceValue(*value, largest_image_record, ++count_candidates_); + PopulateTraceValue(*value, largest_image_record); TRACE_EVENT_MARK_WITH_TIMESTAMP2("loading", "LargestImagePaint::Candidate", largest_image_record.paint_time, "data", std::move(value), "frame", ToTraceValue(&frame_view_->GetFrame())); } +void ImagePaintTimingDetector::ReportNoCandidateToTrace() { + auto value = std::make_unique<TracedValue>(); + value->SetInteger("candidateIndex", ++count_candidates_); + value->SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame()); + value->SetBoolean("isOOPIF", + !frame_view_->GetFrame().LocalFrameRoot().IsMainFrame()); + TRACE_EVENT2("loading", "LargestImagePaint::NoCandidate", "data", + std::move(value), "frame", + ToTraceValue(&frame_view_->GetFrame())); +} + void ImagePaintTimingDetector::UpdateCandidate() { ImageRecord* largest_image_record = records_manager_.FindLargestPaintCandidate(); @@ -112,21 +122,17 @@ const uint64_t size = largest_image_record ? largest_image_record->first_size : 0; bool changed = - frame_view_->GetPaintTimingDetector().HasLargestImagePaintChanged(time, - size); + frame_view_->GetPaintTimingDetector().NotifyIfChangedLargestImagePaint( + time, size); if (!changed) return; if (largest_image_record && !largest_image_record->paint_time.is_null()) { // If an image has paint time, it must have been loaded. DCHECK(largest_image_record->loaded); - // TODO(crbug.com/960365): we need to figure out how to communicate to the - // trace (devtools/trace-viewer/benchmarks) that the largest image is still - // loading (when paint_time is null). Before we decide how to handle it, we - // do not notify the trace about this specific case for now. ReportCandidateToTrace(*largest_image_record); + } else { + ReportNoCandidateToTrace(); } - frame_view_->GetPaintTimingDetector().NotifyLargestImagePaintChange(time, - size); } void ImagePaintTimingDetector::OnPaintFinished() {
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.h b/third_party/blink/renderer/core/paint/image_paint_timing_detector.h index ed80031..ae21edd0 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.h
@@ -184,15 +184,14 @@ private: ImageRecord* FindLargestPaintCandidate() const; - void PopulateTraceValue(TracedValue&, - const ImageRecord& first_image_paint, - unsigned report_count) const; + void PopulateTraceValue(TracedValue&, const ImageRecord& first_image_paint); // This is provided for unit test to force invoking swap promise callback. void ReportSwapTime(unsigned last_queued_frame_index, WebWidgetClient::SwapResult, base::TimeTicks); void RegisterNotifySwapTime(); void ReportCandidateToTrace(ImageRecord&); + void ReportNoCandidateToTrace(); void Deactivate(); void HandleTooManyNodes();
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index 3126b7c..ad50bde3 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -942,7 +942,8 @@ LayoutRectOutsets NGBoxFragmentPainter::ComputeBorders() const { return BoxStrutToLayoutRectOutsets( - box_fragment_.PhysicalFragment().BorderWidths()); + To<NGPhysicalBoxFragment>(box_fragment_.PhysicalFragment()) + .BorderWidths()); } LayoutRectOutsets NGBoxFragmentPainter::ComputePadding() const { @@ -1064,16 +1065,6 @@ To<NGPhysicalTextFragment>(text_paint_fragment.PhysicalFragment()); LayoutSize size(text_fragment.Size().width, text_fragment.Size().height); LayoutRect border_rect(physical_offset, size); - const ComputedStyle& style = text_fragment.Style(); - - if (style.HasBorderRadius()) { - FloatRoundedRect border = style.GetRoundedBorderFor( - border_rect, - text_fragment.BorderEdges() & NGBorderEdges::Physical::kLeft, - text_fragment.BorderEdges() & NGBorderEdges::Physical::kRight); - if (!location_in_container.Intersects(border)) - return false; - } // TODO(layout-dev): Clip to line-top/bottom. LayoutRect rect = LayoutRect(PixelSnappedIntRect(border_rect));
diff --git a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc index 40a1567..ebf69e9 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.cc
@@ -31,7 +31,9 @@ line_style), inline_box_fragment_(inline_box_fragment), border_edges_(NGBorderEdges::FromPhysical( - inline_box_fragment.PhysicalFragment().BorderEdges(), + static_cast<const NGPhysicalBoxFragment&>( + inline_box_fragment.PhysicalFragment()) + .BorderEdges(), style.GetWritingMode())) {} NGInlineBoxFragmentPainter::NGInlineBoxFragmentPainter(
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc index 247e8cd..704f9577 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -717,6 +717,9 @@ } void NGPaintFragment::DirtyLinesFromChangedChild(LayoutObject* child) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; + // This function should be called on every child that has // |IsInLayoutNGInlineFormattingContext()|, meaning it was once collected into // |NGInlineNode|. @@ -729,6 +732,7 @@ } void NGPaintFragment::MarkLineBoxesDirtyFor(const LayoutObject& layout_object) { + DCHECK(RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()); DCHECK(layout_object.IsInline() || layout_object.IsFloatingOrOutOfFlowPositioned()) << layout_object; @@ -768,6 +772,7 @@ } void NGPaintFragment::MarkContainingLineBoxDirty() { + DCHECK(RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()); DCHECK(PhysicalFragment().IsInline() || PhysicalFragment().IsLineBox()); for (NGPaintFragment* fragment : NGPaintFragmentTraversal::InclusiveAncestorsOf(*this)) {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc index c541218..33daddd 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_test.cc
@@ -488,6 +488,8 @@ } TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveBr) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML( "<div id=container>line 1<br>line 2<br id=target>line 3<br>" "</div>"); @@ -500,6 +502,8 @@ } TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveChild) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML( "<div id=container>line 1<br><b id=target>line 2</b><br>line 3<br>" "</div>"); @@ -513,6 +517,8 @@ } TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByRemoveSpanWithBr) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML( "<div id=container>line 1<br>line 2<span id=target><br></span>line 3<br>" "</div>"); @@ -529,6 +535,8 @@ // to update |IsDirty|, but NGPaintFragment maybe re-used during the layout. In // such case, the result is not deterministic. TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtStart) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML( "<div id=container>line 1<br><b id=target>line 2</b><br>line 3<br>" "</div>"); @@ -555,6 +563,8 @@ // to update |IsDirty|, but NGPaintFragment maybe re-used during the layout. In // such case, the result is not deterministic. TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtLast) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML( "<div id=container>line 1<br><b id=target>line 2</b><br>line 3<br>" "</div>"); @@ -580,6 +590,8 @@ // to update |IsDirty|, but NGPaintFragment maybe re-used during the layout. In // such case, the result is not deterministic. TEST_F(NGPaintFragmentTest, DISABLED_MarkLineBoxesDirtyByInsertAtMiddle) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML( "<div id=container>line 1<br><b id=target>line 2</b><br>line 3<br>" "</div>"); @@ -603,6 +615,8 @@ } TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyByTextSetData) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML( "<div id=container>line 1<br><b id=target>line 2</b><br>line " "3<br></div>"); @@ -616,6 +630,8 @@ } TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyWrappedLine) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML(R"HTML( <style> #container { @@ -638,6 +654,8 @@ } TEST_F(NGPaintFragmentTest, MarkLineBoxesDirtyInsideInlineBlock) { + if (!RuntimeEnabledFeatures::LayoutNGLineCacheEnabled()) + return; SetBodyInnerHTML(R"HTML( <div id=container> <div id="inline-block" style="display: inline-block">
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index 3a3075cd..4191340 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -3269,12 +3269,12 @@ void PaintLayer::UpdateCompositorFilterOperationsForBackdropFilter( CompositorFilterOperations& operations, - gfx::RRectF* backdrop_filter_bounds) const { + base::Optional<gfx::RRectF>* backdrop_filter_bounds) const { DCHECK(backdrop_filter_bounds); const auto& style = GetLayoutObject().StyleRef(); if (style.BackdropFilter().IsEmpty()) { operations.Clear(); - *backdrop_filter_bounds = gfx::RRectF(); + backdrop_filter_bounds->reset(); return; } FloatRect reference_box = BackdropFilterReferenceBox();
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h index c002e63a..e66f77a 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.h +++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -617,7 +617,7 @@ // EffectPaintPropertyNode. void UpdateCompositorFilterOperationsForBackdropFilter( CompositorFilterOperations& operations, - gfx::RRectF* backdrop_filter_bounds) const; + base::Optional<gfx::RRectF>* backdrop_filter_bounds) const; CompositorFilterOperations CreateCompositorFilterOperationsForBackdropFilter() const;
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/paint_timing_detector.cc index e1d91a96..a246bf7 100644 --- a/third_party/blink/renderer/core/paint/paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -174,33 +174,47 @@ image_paint_timing_detector_->StopRecordEntries(); } -bool PaintTimingDetector::NeedToNotifyInputOrScroll() { +bool PaintTimingDetector::NeedToNotifyInputOrScroll() const { return (text_paint_timing_detector_ && text_paint_timing_detector_->IsRecording()) || (image_paint_timing_detector_ && image_paint_timing_detector_->IsRecording()); } -void PaintTimingDetector::NotifyLargestImagePaintChange( +bool PaintTimingDetector::NotifyIfChangedLargestImagePaint( base::TimeTicks image_paint_time, uint64_t image_paint_size) { - DCHECK(HasLargestImagePaintChanged(image_paint_time, image_paint_size)); + if (!HasLargestImagePaintChanged(image_paint_time, image_paint_size)) + return false; largest_image_paint_time_ = image_paint_time; largest_image_paint_size_ = image_paint_size; DidChangePerformanceTiming(); + return true; +} + +bool PaintTimingDetector::NotifyIfChangedLargestTextPaint( + base::TimeTicks text_paint_time, + uint64_t text_paint_size) { + if (!HasLargestTextPaintChanged(text_paint_time, text_paint_size)) + return false; + largest_text_paint_time_ = text_paint_time; + largest_text_paint_size_ = text_paint_size; + DidChangePerformanceTiming(); + return true; } bool PaintTimingDetector::HasLargestImagePaintChanged( base::TimeTicks largest_image_paint_time, - uint64_t largest_image_paint_size) { + uint64_t largest_image_paint_size) const { return largest_image_paint_time != largest_image_paint_time_ || largest_image_paint_size != largest_image_paint_size_; } -void PaintTimingDetector::NotifyLargestText(base::TimeTicks text_paint_time, - uint64_t text_paint_size) { - largest_text_paint_time_ = text_paint_time; - largest_text_paint_size_ = text_paint_size; +bool PaintTimingDetector::HasLargestTextPaintChanged( + base::TimeTicks largest_text_paint_time, + uint64_t largest_text_paint_size) const { + return largest_text_paint_time != largest_text_paint_time_ || + largest_text_paint_size != largest_text_paint_size_; } void PaintTimingDetector::DidChangePerformanceTiming() {
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.h b/third_party/blink/renderer/core/paint/paint_timing_detector.h index 5324b2d..e64eaa9 100644 --- a/third_party/blink/renderer/core/paint/paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -31,6 +31,7 @@ class CORE_EXPORT PaintTimingDetector : public GarbageCollected<PaintTimingDetector> { friend class ImagePaintTimingDetectorTest; + friend class TextPaintTimingDetectorTest; public: PaintTimingDetector(LocalFrameView*); @@ -52,20 +53,21 @@ const ImageResourceContent*); void NotifyPaintFinished(); void NotifyInputEvent(WebInputEvent::Type); - bool NeedToNotifyInputOrScroll(); + bool NeedToNotifyInputOrScroll() const; void NotifyScroll(ScrollType); - void NotifyLargestImagePaintChange(base::TimeTicks, uint64_t size); - void NotifyLargestText(base::TimeTicks, uint64_t size); - bool HasLargestImagePaintChanged(base::TimeTicks, uint64_t size); + // The returned value indicates whether the candidates have changed. + bool NotifyIfChangedLargestImagePaint(base::TimeTicks, uint64_t size); + bool NotifyIfChangedLargestTextPaint(base::TimeTicks, uint64_t size); + void DidChangePerformanceTiming(); FloatRect CalculateVisualRect(const IntRect& visual_rect, const PropertyTreeState&) const; - TextPaintTimingDetector* GetTextPaintTimingDetector() { + TextPaintTimingDetector* GetTextPaintTimingDetector() const { return text_paint_timing_detector_; } - ImagePaintTimingDetector* GetImagePaintTimingDetector() { + ImagePaintTimingDetector* GetImagePaintTimingDetector() const { return image_paint_timing_detector_; } base::TimeTicks LargestImagePaint() const { @@ -77,6 +79,8 @@ void Trace(Visitor* visitor); private: + bool HasLargestImagePaintChanged(base::TimeTicks, uint64_t size) const; + bool HasLargestTextPaintChanged(base::TimeTicks, uint64_t size) const; Member<LocalFrameView> frame_view_; // This member lives until the end of the paint phase after the largest text // paint is found.
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc index 881e7e15..c6cef7b8 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -48,28 +48,37 @@ void TextPaintTimingDetector::PopulateTraceValue( TracedValue& value, - const TextRecord& first_text_paint, - unsigned candidate_index) const { + const TextRecord& first_text_paint) { value.SetInteger("DOMNodeId", static_cast<int>(first_text_paint.node_id)); #ifndef NDEBUG value.SetString("text", first_text_paint.text); #endif value.SetInteger("size", static_cast<int>(first_text_paint.first_size)); - value.SetInteger("candidateIndex", candidate_index); + value.SetInteger("candidateIndex", ++count_candidates_); value.SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame()); value.SetBoolean("isOOPIF", !frame_view_->GetFrame().LocalFrameRoot().IsMainFrame()); } -void TextPaintTimingDetector::OnLargestTextDetected( +void TextPaintTimingDetector::ReportCandidateToTrace( const TextRecord& largest_text_record) { - largest_text_paint_ = largest_text_record.paint_time; - largest_text_paint_size_ = largest_text_record.first_size; auto value = std::make_unique<TracedValue>(); - PopulateTraceValue(*value, largest_text_record, count_candidates_++); - TRACE_EVENT_MARK_WITH_TIMESTAMP2( - "loading", "LargestTextPaint::Candidate", largest_text_paint_, "data", - std::move(value), "frame", ToTraceValue(&frame_view_->GetFrame())); + PopulateTraceValue(*value, largest_text_record); + TRACE_EVENT_MARK_WITH_TIMESTAMP2("loading", "LargestTextPaint::Candidate", + largest_text_record.paint_time, "data", + std::move(value), "frame", + ToTraceValue(&frame_view_->GetFrame())); +} + +void TextPaintTimingDetector::ReportNoCandidateToTrace() { + auto value = std::make_unique<TracedValue>(); + value->SetInteger("candidateIndex", ++count_candidates_); + value->SetBoolean("isMainFrame", frame_view_->GetFrame().IsMainFrame()); + value->SetBoolean("isOOPIF", + !frame_view_->GetFrame().LocalFrameRoot().IsMainFrame()); + TRACE_EVENT2("loading", "LargestTextPaint::NoCandidate", "data", + std::move(value), "frame", + ToTraceValue(&frame_view_->GetFrame())); } void TextPaintTimingDetector::TimerFired(TimerBase* time) { @@ -79,17 +88,21 @@ } void TextPaintTimingDetector::UpdateCandidate() { - TextRecord* candidate = records_manager_.FindLargestPaintCandidate(); - if (!candidate) { - largest_text_paint_ = base::TimeTicks(); - largest_text_paint_size_ = 0; - frame_view_->GetPaintTimingDetector().DidChangePerformanceTiming(); - } else if (candidate->paint_time != largest_text_paint_) { - OnLargestTextDetected(*candidate); - frame_view_->GetPaintTimingDetector().DidChangePerformanceTiming(); - } - frame_view_->GetPaintTimingDetector().NotifyLargestText( - largest_text_paint_, largest_text_paint_size_); + TextRecord* largest_text_record = + records_manager_.FindLargestPaintCandidate(); + const base::TimeTicks time = + largest_text_record ? largest_text_record->paint_time : base::TimeTicks(); + const uint64_t size = + largest_text_record ? largest_text_record->first_size : 0; + bool changed = + frame_view_->GetPaintTimingDetector().NotifyIfChangedLargestTextPaint( + time, size); + if (!changed) + return; + if (largest_text_record && !largest_text_record->paint_time.is_null()) + ReportCandidateToTrace(*largest_text_record); + else + ReportNoCandidateToTrace(); } void TextPaintTimingDetector::OnPaintFinished() {
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h index 32e1483..51985f35 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -145,9 +145,7 @@ private: void AggregateTextToClosestBlock(const LayoutObject&, const PropertyTreeState&); - void PopulateTraceValue(TracedValue&, - const TextRecord& first_text_paint, - unsigned candidate_index) const; + void PopulateTraceValue(TracedValue&, const TextRecord& first_text_paint); void TimerFired(TimerBase*); void UpdateCandidate(); void RecordAggregatedText(const LayoutObject& aggregating_object, @@ -156,7 +154,8 @@ void ReportSwapTime(WebWidgetClient::SwapResult result, base::TimeTicks timestamp); void RegisterNotifySwapTime(ReportTimeCallback callback); - void OnLargestTextDetected(const TextRecord&); + void ReportCandidateToTrace(const TextRecord&); + void ReportNoCandidateToTrace(); TextRecordsManager records_manager_; @@ -172,8 +171,6 @@ Vector<BlockInfo> walking_block_stack_; - base::TimeTicks largest_text_paint_; - uint64_t largest_text_paint_size_ = 0; TaskRunnerTimer<TextPaintTimingDetector> timer_; Member<LocalFrameView> frame_view_;
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc index b5796186..a942228c2 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -71,9 +71,7 @@ } TimeTicks LargestPaintStoredResult() { - return GetPaintTimingDetector() - .GetTextPaintTimingDetector() - ->largest_text_paint_; + return GetPaintTimingDetector().largest_text_paint_time_; } // This only triggers ReportSwapTime in main frame.
diff --git a/third_party/blink/renderer/core/scroll/BUILD.gn b/third_party/blink/renderer/core/scroll/BUILD.gn index d3157f4..5717a7c 100644 --- a/third_party/blink/renderer/core/scroll/BUILD.gn +++ b/third_party/blink/renderer/core/scroll/BUILD.gn
@@ -53,7 +53,7 @@ sources += [ "web_scrollbar_theme.mm" ] } - if (use_default_render_theme) { + if (use_aura) { sources += [ "scrollbar_theme_aura.cc", "scrollbar_theme_aura.h",
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.cc b/third_party/blink/renderer/core/svg/svg_a_element.cc index 65e06fa..0a7bb9f2 100644 --- a/third_party/blink/renderer/core/svg/svg_a_element.cc +++ b/third_party/blink/renderer/core/svg/svg_a_element.cc
@@ -133,8 +133,7 @@ event.SetDefaultHandled(); FrameLoadRequest frame_request( - &GetDocument(), ResourceRequest(GetDocument().CompleteURL(url)), - target); + &GetDocument(), ResourceRequest(GetDocument().CompleteURL(url))); frame_request.SetNavigationPolicy(NavigationPolicyFromEvent(&event)); frame_request.SetTriggeringEventInfo( event.isTrusted() ? WebTriggeringEventInfo::kFromTrustedEvent @@ -144,7 +143,7 @@ Frame* frame = GetDocument() .GetFrame() ->Tree() - .FindOrCreateFrameForNavigation(frame_request) + .FindOrCreateFrameForNavigation(frame_request, target) .frame; if (!frame) return;
diff --git a/third_party/blink/renderer/core/workers/abstract_worker.cc b/third_party/blink/renderer/core/workers/abstract_worker.cc index 33f0133..a9ff272 100644 --- a/third_party/blink/renderer/core/workers/abstract_worker.cc +++ b/third_party/blink/renderer/core/workers/abstract_worker.cc
@@ -38,7 +38,7 @@ namespace blink { AbstractWorker::AbstractWorker(ExecutionContext* context) - : ContextLifecycleObserver(context) {} + : ContextLifecycleStateObserver(context) {} AbstractWorker::~AbstractWorker() = default;
diff --git a/third_party/blink/renderer/core/workers/abstract_worker.h b/third_party/blink/renderer/core/workers/abstract_worker.h index 174a4430..7b21022 100644 --- a/third_party/blink/renderer/core/workers/abstract_worker.h +++ b/third_party/blink/renderer/core/workers/abstract_worker.h
@@ -35,7 +35,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/events/event_listener.h" #include "third_party/blink/renderer/core/dom/events/event_target.h" -#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -48,7 +48,7 @@ // Implementation of the AbstractWorker interface defined in the WebWorker HTML // spec: https://html.spec.whatwg.org/C/#abstractworker class CORE_EXPORT AbstractWorker : public EventTargetWithInlineData, - public ContextLifecycleObserver { + public ContextLifecycleStateObserver { USING_GARBAGE_COLLECTED_MIXIN(AbstractWorker); public:
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc index 50957ff4..9c221ad 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker.cc +++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -129,6 +129,7 @@ DedicatedWorker* worker = MakeGarbageCollected<DedicatedWorker>( context, script_request_url, options); + worker->UpdateStateIfNeeded(); worker->Start(); return worker; } @@ -144,9 +145,7 @@ factory_client_( Platform::Current()->CreateDedicatedWorkerHostFactoryClient( this, - GetExecutionContext()->GetInterfaceProvider())), - v8_stack_trace_id_(ThreadDebugger::From(context->GetIsolate()) - ->StoreCurrentStackTrace("Worker Created")) { + GetExecutionContext()->GetInterfaceProvider())) { DCHECK(context->IsContextThread()); DCHECK(script_request_url_.IsValid()); DCHECK(context_proxy_); @@ -205,6 +204,10 @@ void DedicatedWorker::Start() { DCHECK(GetExecutionContext()->IsContextThread()); + // This needs to be done after the UpdateStateIfNeeded is called as + // calling into the debugger can cause a breakpoint. + v8_stack_trace_id_ = ThreadDebugger::From(GetExecutionContext()->GetIsolate()) + ->StoreCurrentStackTrace("Worker Created"); if (auto* scope = DynamicTo<WorkerGlobalScope>(*GetExecutionContext())) scope->EnsureFetcher(); if (blink::features::IsPlzDedicatedWorkerEnabled()) { @@ -484,6 +487,31 @@ return event_target_names::kWorker; } +void DedicatedWorker::ContextLifecycleStateChanged( + mojom::FrameLifecycleState state) { + DCHECK(GetExecutionContext()->IsContextThread()); + switch (state) { + case mojom::FrameLifecycleState::kPaused: + // Do not do anything in this case. kPaused is only used + // for when the main thread is paused we shouldn't worry + // about pausing the worker thread in this case. + break; + case mojom::FrameLifecycleState::kFrozen: + case mojom::FrameLifecycleState::kFrozenAutoResumeMedia: + if (!requested_frozen_) { + requested_frozen_ = true; + context_proxy_->Freeze(); + } + break; + case mojom::FrameLifecycleState::kRunning: + if (requested_frozen_) { + context_proxy_->Resume(); + requested_frozen_ = false; + } + break; + } +} + void DedicatedWorker::Trace(blink::Visitor* visitor) { visitor->Trace(context_proxy_); visitor->Trace(options_);
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.h b/third_party/blink/renderer/core/workers/dedicated_worker.h index f78ce9b..a305ae0 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker.h +++ b/third_party/blink/renderer/core/workers/dedicated_worker.h
@@ -113,6 +113,7 @@ DEFINE_ATTRIBUTE_EVENT_LISTENER(message, kMessage) + void ContextLifecycleStateChanged(mojom::FrameLifecycleState state) override; void Trace(blink::Visitor*) override; private: @@ -149,9 +150,12 @@ std::unique_ptr<WebDedicatedWorkerHostFactoryClient> factory_client_; // Used for tracking cross-debugger calls. - const v8_inspector::V8StackTraceId v8_stack_trace_id_; + v8_inspector::V8StackTraceId v8_stack_trace_id_; service_manager::mojom::blink::InterfaceProviderPtrInfo interface_provider_; + + // Whether the worker is frozen due to a call from this context. + bool requested_frozen_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc index dd790d4..d661bc67 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc +++ b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.cc
@@ -131,6 +131,22 @@ worker_object_->DispatchErrorEventForScriptFetchFailure(); } +void DedicatedWorkerMessagingProxy::Freeze() { + DCHECK(IsParentContextThread()); + auto* worker_thread = GetWorkerThread(); + if (AskedToTerminate() || !worker_thread) + return; + worker_thread->Freeze(); +} + +void DedicatedWorkerMessagingProxy::Resume() { + DCHECK(IsParentContextThread()); + auto* worker_thread = GetWorkerThread(); + if (AskedToTerminate() || !worker_thread) + return; + worker_thread->Resume(); +} + void DedicatedWorkerMessagingProxy::DidEvaluateScript(bool success) { DCHECK(IsParentContextThread()); was_script_evaluated_ = true;
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h index 89e215d..4e963e8 100644 --- a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h +++ b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
@@ -59,6 +59,9 @@ std::unique_ptr<SourceLocation>, int exception_id); + void Freeze(); + void Resume(); + DedicatedWorkerObjectProxy& WorkerObjectProxy() { return *worker_object_proxy_.get(); }
diff --git a/third_party/blink/renderer/core/workers/shared_worker.cc b/third_party/blink/renderer/core/workers/shared_worker.cc index 5746444f..7cceae2e 100644 --- a/third_party/blink/renderer/core/workers/shared_worker.cc +++ b/third_party/blink/renderer/core/workers/shared_worker.cc
@@ -57,6 +57,7 @@ UseCounter::Count(context, WebFeature::kSharedWorkerStart); SharedWorker* worker = MakeGarbageCollected<SharedWorker>(context); + worker->UpdateStateIfNeeded(); auto* channel = MakeGarbageCollected<MessageChannel>(context); worker->port_ = channel->port1(); @@ -111,6 +112,9 @@ return is_being_connected_; } +void SharedWorker::ContextLifecycleStateChanged( + mojom::FrameLifecycleState state) {} + void SharedWorker::Trace(blink::Visitor* visitor) { visitor->Trace(port_); AbstractWorker::Trace(visitor);
diff --git a/third_party/blink/renderer/core/workers/shared_worker.h b/third_party/blink/renderer/core/workers/shared_worker.h index 3a1851e..f47d2a5e 100644 --- a/third_party/blink/renderer/core/workers/shared_worker.h +++ b/third_party/blink/renderer/core/workers/shared_worker.h
@@ -67,6 +67,7 @@ bool HasPendingActivity() const final; + void ContextLifecycleStateChanged(mojom::FrameLifecycleState state) override; void Trace(blink::Visitor*) override; private:
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc index 9848460..4b2aaca 100644 --- a/third_party/blink/renderer/core/workers/worker_thread.cc +++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -110,6 +110,31 @@ DISALLOW_COPY_AND_ASSIGN(RefCountedWaitableEvent); }; +// A class that is passed into V8 Interrupt and via a PostTask. Once both have +// run this object will be destroyed in +// PauseOrFreezeWithInterruptDataOnWorkerThread. The V8 API only takes a raw ptr +// otherwise this could have been done with base::Bind and ref counted objects. +class WorkerThread::InterruptData { + public: + InterruptData(WorkerThread* worker_thread, mojom::FrameLifecycleState state) + : worker_thread_(worker_thread), state_(state) {} + + bool ShouldRemoveFromList() { return seen_interrupt_ && seen_post_task_; } + void MarkPostTaskCalled() { seen_post_task_ = true; } + void MarkInterruptCalled() { seen_interrupt_ = true; } + + mojom::FrameLifecycleState state() { return state_; } + WorkerThread* worker_thread() { return worker_thread_; } + + private: + WorkerThread* worker_thread_; + mojom::FrameLifecycleState state_; + bool seen_interrupt_ = false; + bool seen_post_task_ = false; + + DISALLOW_COPY_AND_ASSIGN(InterruptData); +}; + WorkerThread::~WorkerThread() { MutexLocker lock(ThreadSetMutex()); DCHECK(WorkerThreads().Contains(this)); @@ -200,6 +225,25 @@ credentials_mode)); } +void WorkerThread::Pause() { + PauseOrFreeze(mojom::FrameLifecycleState::kPaused); +} + +void WorkerThread::Freeze() { + PauseOrFreeze(mojom::FrameLifecycleState::kFrozen); +} + +void WorkerThread::Resume() { + // Might be called from any thread. + if (IsCurrentThread()) { + ResumeOnWorkerThread(); + } else { + GetWorkerBackingThread().BackingThread().PostTask( + FROM_HERE, CrossThreadBind(&WorkerThread::ResumeOnWorkerThread, + CrossThreadUnretained(this))); + } +} + void WorkerThread::Terminate() { DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_); { @@ -590,6 +634,12 @@ SetThreadState(ThreadState::kReadyToShutdown); } + if (pause_or_freeze_count_ > 0) { + DCHECK(nested_runner_); + pause_or_freeze_count_ = 0; + nested_runner_->QuitNow(); + } + if (WorkerThreadDebugger* debugger = WorkerThreadDebugger::From(GetIsolate())) debugger->WorkerThreadDestroyed(this); @@ -680,4 +730,111 @@ return requested_to_terminate_; } +void WorkerThread::PauseOrFreeze(mojom::FrameLifecycleState state) { + if (IsCurrentThread()) { + PauseOrFreezeOnWorkerThread(state); + } else { + // We send a V8 interrupt to break active JS script execution because + // workers might not yield. Likewise we might not be in JS and the + // interrupt might not fire right away, so we post a task as well. + // Use a token to mitigate both the interrupt and post task firing. + MutexLocker lock(mutex_); + + InterruptData* interrupt_data = new InterruptData(this, state); + pending_interrupts_.insert(std::unique_ptr<InterruptData>(interrupt_data)); + + if (auto* isolate = GetIsolate()) { + isolate->RequestInterrupt(&PauseOrFreezeInsideV8InterruptOnWorkerThread, + interrupt_data); + } + GetWorkerBackingThread().BackingThread().PostTask( + FROM_HERE, CrossThreadBind( + &WorkerThread::PauseOrFreezeInsidePostTaskOnWorkerThread, + CrossThreadUnretained(interrupt_data))); + } +} + +void WorkerThread::PauseOrFreezeOnWorkerThread( + mojom::FrameLifecycleState state) { + DCHECK(IsCurrentThread()); + DCHECK(state == mojom::FrameLifecycleState::kFrozen || + state == mojom::FrameLifecycleState::kPaused); + pause_or_freeze_count_++; + GlobalScope()->SetLifecycleState(state); + + // If already paused return early. + if (pause_or_freeze_count_ > 1) + return; + + std::unique_ptr<scheduler::WorkerScheduler::PauseHandle> pause_handle = + GetScheduler()->Pause(); + { + // Since the nested message loop runner needs to be created an destroyed on + // the same thread we allocate and destroy a new message loop runner each + // time we pause or freeze. The AutoReset allows a raw ptr to be stored in + // the worker thread such that the resume/terminate can quit this runner. + std::unique_ptr<Platform::NestedMessageLoopRunner> nested_runner = + Platform::Current()->CreateNestedMessageLoopRunner(); + base::AutoReset<Platform::NestedMessageLoopRunner*> nested_runner_autoreset( + &nested_runner_, nested_runner.get()); + nested_runner->Run(); + } + GlobalScope()->SetLifecycleState(mojom::FrameLifecycleState::kRunning); +} + +void WorkerThread::ResumeOnWorkerThread() { + DCHECK(IsCurrentThread()); + if (pause_or_freeze_count_ > 0) { + DCHECK(nested_runner_); + pause_or_freeze_count_--; + if (pause_or_freeze_count_ == 0) + nested_runner_->QuitNow(); + } +} + +void WorkerThread::PauseOrFreezeWithInterruptDataOnWorkerThread( + InterruptData* interrupt_data) { + DCHECK(IsCurrentThread()); + bool should_execute = false; + mojom::FrameLifecycleState state; + { + MutexLocker lock(mutex_); + state = interrupt_data->state(); + // If both the V8 interrupt and PostTask have executed we can remove + // the matching InterruptData from the |pending_interrupts_| as it is + // no longer used. + if (interrupt_data->ShouldRemoveFromList()) { + auto iter = pending_interrupts_.begin(); + while (iter != pending_interrupts_.end()) { + if (iter->get() == interrupt_data) { + pending_interrupts_.erase(iter); + break; + } + ++iter; + } + } else { + should_execute = true; + } + } + + if (should_execute) { + PauseOrFreezeOnWorkerThread(state); + } +} + +void WorkerThread::PauseOrFreezeInsideV8InterruptOnWorkerThread(v8::Isolate*, + void* data) { + InterruptData* interrupt_data = static_cast<InterruptData*>(data); + interrupt_data->MarkInterruptCalled(); + interrupt_data->worker_thread()->PauseOrFreezeWithInterruptDataOnWorkerThread( + interrupt_data); +} + +void WorkerThread::PauseOrFreezeInsidePostTaskOnWorkerThread( + InterruptData* interrupt_data) { + interrupt_data->MarkPostTaskCalled(); + interrupt_data->worker_thread()->PauseOrFreezeWithInterruptDataOnWorkerThread( + interrupt_data); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h index c3914fc..e23ab0a 100644 --- a/third_party/blink/renderer/core/workers/worker_thread.h +++ b/third_party/blink/renderer/core/workers/worker_thread.h
@@ -36,6 +36,7 @@ #include "base/thread_annotations.h" #include "base/unguessable_token.h" #include "services/network/public/mojom/fetch_api.mojom-shared.h" +#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/web_thread_type.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h" @@ -233,6 +234,23 @@ void ChildThreadStartedOnWorkerThread(WorkerThread*); void ChildThreadTerminatedOnWorkerThread(WorkerThread*); + // Changes the lifecycle state of the associated execution context for + // this worker to Paused and may enter a nested run loop. Only one nested + // message loop will be entered but |pause_or_freeze_count_| will be + // incremented on each call. Inspector can call pause when this thread is + // first created. May be called multiple times and from any thread. + void Pause(); + + // Changes the lifecycle state of the associated execution context for + // this worker to FrozenPaused and may enter a nested run loop. Only one + // nested message loop will be entered but |pause_or_freeze_count_| will be + // incremented on each call. May be called multiple times and from any thread. + void Freeze(); + + // Decrements |pause_or_freeze_count_| and if count is zero then + // it will exit the entered nested run loop. Might be called from any thread. + void Resume(); + protected: explicit WorkerThread(WorkerReportingProxy&); @@ -329,6 +347,16 @@ bool CheckRequestedToTerminate() LOCKS_EXCLUDED(mutex_); + class InterruptData; + void PauseOrFreeze(mojom::FrameLifecycleState state); + void PauseOrFreezeOnWorkerThread(mojom::FrameLifecycleState state); + void ResumeOnWorkerThread(); + void PauseOrFreezeWithInterruptDataOnWorkerThread(InterruptData*); + static void PauseOrFreezeInsideV8InterruptOnWorkerThread(v8::Isolate*, + void* data); + static void PauseOrFreezeInsidePostTaskOnWorkerThread( + InterruptData* interrupt_data); + // A unique identifier among all WorkerThreads. const int worker_thread_id_; @@ -358,6 +386,14 @@ // file. Mutex mutex_; + // Whether the thread is paused in a nested message loop or not. Used + // only on the worker thread. + int pause_or_freeze_count_ = 0; + + // A nested message loop for handling pausing. Pointer is not owned. Used only + // on the worker thread. + Platform::NestedMessageLoopRunner* nested_runner_ = nullptr; + CrossThreadPersistent<ConsoleMessageStorage> console_message_storage_; CrossThreadPersistent<WorkerOrWorkletGlobalScope> global_scope_; CrossThreadPersistent<WorkerInspectorController> worker_inspector_controller_; @@ -374,6 +410,12 @@ HashSet<WorkerThread*> child_threads_; + // List of data to passed into the interrupt callbacks. The V8 API takes + // a void* and we need to pass more data that just a ptr, so we pass + // a pointer to a member in this list. + HashSet<std::unique_ptr<InterruptData>> pending_interrupts_ + GUARDED_BY(mutex_); + THREAD_CHECKER(parent_thread_checker_); };
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test.cc b/third_party/blink/renderer/core/workers/worker_thread_test.cc index 1d3f091..70943fb 100644 --- a/third_party/blink/renderer/core/workers/worker_thread_test.cc +++ b/third_party/blink/renderer/core/workers/worker_thread_test.cc
@@ -532,4 +532,116 @@ EXPECT_EQ(ExitCode::kAsyncForciblyTerminated, GetExitCode()); } +TEST_F(WorkerThreadTest, TerminateFrozenScript) { + constexpr TimeDelta kDelay = TimeDelta::FromMilliseconds(10); + SetForcibleTerminationDelay(kDelay); + + ExpectReportingCallsForWorkerForciblyTerminated(); + StartWithSourceCodeNotToFinish(); + reporting_proxy_->WaitUntilScriptEvaluation(); + + base::WaitableEvent child_waitable; + PostCrossThreadTask(*worker_thread_->GetTaskRunner(TaskType::kInternalTest), + FROM_HERE, + CrossThreadBind(&base::WaitableEvent::Signal, + CrossThreadUnretained(&child_waitable))); + + // Freeze() enters a nested event loop where the kInternalTest should run. + worker_thread_->Freeze(); + child_waitable.Wait(); + + // Terminate() schedules a forcible termination task. + worker_thread_->Terminate(); + EXPECT_TRUE(IsForcibleTerminationTaskScheduled()); + EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); + + test::RunDelayedTasks(kDelay); + worker_thread_->WaitForShutdownForTesting(); + EXPECT_EQ(ExitCode::kAsyncForciblyTerminated, GetExitCode()); +} + +TEST_F(WorkerThreadTest, NestedPauseFreeze) { + constexpr TimeDelta kDelay = TimeDelta::FromMilliseconds(10); + SetForcibleTerminationDelay(kDelay); + + ExpectReportingCallsForWorkerForciblyTerminated(); + StartWithSourceCodeNotToFinish(); + reporting_proxy_->WaitUntilScriptEvaluation(); + + base::WaitableEvent child_waitable; + PostCrossThreadTask(*worker_thread_->GetTaskRunner(TaskType::kInternalTest), + FROM_HERE, + CrossThreadBind(&base::WaitableEvent::Signal, + CrossThreadUnretained(&child_waitable))); + + // Pause() enters a nested event loop where the kInternalTest should run. + worker_thread_->Pause(); + worker_thread_->Freeze(); + child_waitable.Wait(); + + // Resume Freeze. + worker_thread_->Resume(); + + // Resume Pause. + worker_thread_->Resume(); + + // Ensure an extra Resume does nothing. Since this is called from + // the javascript debugger API. + worker_thread_->Resume(); + + // Terminate() schedules a forcible termination task. + worker_thread_->Terminate(); + EXPECT_TRUE(IsForcibleTerminationTaskScheduled()); + EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); + + test::RunDelayedTasks(kDelay); + worker_thread_->WaitForShutdownForTesting(); + EXPECT_EQ(ExitCode::kAsyncForciblyTerminated, GetExitCode()); +} + +TEST_F(WorkerThreadTest, NestedPauseFreezeNoInterrupts) { + constexpr TimeDelta kDelay = TimeDelta::FromMilliseconds(10); + SetForcibleTerminationDelay(kDelay); + + ExpectReportingCalls(); + Start(); + + base::WaitableEvent child_waitable; + PostCrossThreadTask(*worker_thread_->GetTaskRunner(TaskType::kInternalTest), + FROM_HERE, + CrossThreadBind(&base::WaitableEvent::Signal, + CrossThreadUnretained(&child_waitable))); + + child_waitable.Wait(); + base::WaitableEvent child_waitable2; + PostCrossThreadTask(*worker_thread_->GetTaskRunner(TaskType::kInternalTest), + FROM_HERE, + CrossThreadBind(&base::WaitableEvent::Signal, + CrossThreadUnretained(&child_waitable2))); + + // Pause() enters a nested event loop where the kInternalTest should run. + worker_thread_->Pause(); + worker_thread_->Freeze(); + child_waitable2.Wait(); + + // Resume for Freeze. + worker_thread_->Resume(); + + // Resume for Pause. + worker_thread_->Resume(); + + // Ensure an extra Resume does nothing. Since this is called from + // the javascript debugger API. + worker_thread_->Resume(); + + // Terminate() schedules a forcible termination task. + worker_thread_->Terminate(); + EXPECT_TRUE(IsForcibleTerminationTaskScheduled()); + EXPECT_EQ(ExitCode::kNotTerminated, GetExitCode()); + + test::RunDelayedTasks(kDelay); + worker_thread_->WaitForShutdownForTesting(); + EXPECT_EQ(ExitCode::kGracefullyTerminated, GetExitCode()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc index 57cdeb26..4eb08cc 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -1318,7 +1318,7 @@ DCHECK(!layout_object.IsListMarkerIncludingNG()) << layout_object; DCHECK(ShouldUseLayoutNG(layout_object)) << layout_object; const auto fragments = NGPaintFragment::InlineFragmentsFor(&layout_object); - if (fragments.IsEmpty() || fragments.IsInLayoutNGInlineFormattingContext()) + if (fragments.IsEmpty() || !fragments.IsInLayoutNGInlineFormattingContext()) return nullptr; for (NGPaintFragmentTraversalContext runner = NGPaintFragmentTraversal::PreviousInlineLeafOf(
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker.cc b/third_party/blink/renderer/modules/service_worker/service_worker.cc index bb61236..c1888cc 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker.cc
@@ -171,6 +171,9 @@ return state_ != mojom::blink::ServiceWorkerState::kRedundant; } +void ServiceWorker::ContextLifecycleStateChanged( + mojom::FrameLifecycleState state) {} + void ServiceWorker::ContextDestroyed(ExecutionContext*) { was_stopped_ = true; }
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker.h b/third_party/blink/renderer/modules/service_worker/service_worker.h index d31e769..1d206bf 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker.h +++ b/third_party/blink/renderer/modules/service_worker/service_worker.h
@@ -61,6 +61,14 @@ // and use the above From() everywhere instead of this one. static ServiceWorker* From(ExecutionContext*, WebServiceWorkerObjectInfo); + static ServiceWorker* Create(ExecutionContext* context, + WebServiceWorkerObjectInfo info) { + ServiceWorker* worker = + MakeGarbageCollected<ServiceWorker>(context, std::move(info)); + worker->UpdateStateIfNeeded(); + return worker; + } + ServiceWorker(ExecutionContext*, WebServiceWorkerObjectInfo); ~ServiceWorker() override; void Trace(blink::Visitor*) override; @@ -95,7 +103,8 @@ ScriptPromise InternalsTerminate(ScriptState*); private: - // ContextLifecycleObserver overrides. + // ContextLifecycleStateObserver overrides. + void ContextLifecycleStateChanged(mojom::FrameLifecycleState state) override; void ContextDestroyed(ExecutionContext*) override; bool was_stopped_;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc index e9123ef..07e3d67f 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_container.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_container.cc
@@ -578,8 +578,7 @@ return nullptr; ServiceWorker* worker = service_worker_objects_.at(info.version_id); if (!worker) { - worker = MakeGarbageCollected<ServiceWorker>(GetSupplementable(), - std::move(info)); + worker = ServiceWorker::Create(GetSupplementable(), std::move(info)); service_worker_objects_.Set(info.version_id, worker); } return worker;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc index 3180109..bd3c57d 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -552,7 +552,7 @@ return nullptr; ServiceWorker* worker = service_worker_objects_.at(info.version_id); if (!worker) { - worker = MakeGarbageCollected<ServiceWorker>(this, std::move(info)); + worker = ServiceWorker::Create(this, std::move(info)); service_worker_objects_.Set(info.version_id, worker); } return worker;
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.cc b/third_party/blink/renderer/modules/xr/xr_input_source.cc index 353fce01..d4fa34f 100644 --- a/third_party/blink/renderer/modules/xr/xr_input_source.cc +++ b/third_party/blink/renderer/modules/xr/xr_input_source.cc
@@ -13,6 +13,99 @@ namespace blink { +namespace { + +// TODO(https://crbug.com/962712): Switch to use typemapping instead. +XRInputSource::TargetRayMode MojomToBlinkTargetRayMode( + device::mojom::XRTargetRayMode target_ray_mode) { + switch (target_ray_mode) { + case device::mojom::XRTargetRayMode::GAZING: + return XRInputSource::TargetRayMode::kGaze; + case device::mojom::XRTargetRayMode::POINTING: + return XRInputSource::TargetRayMode::kTrackedPointer; + case device::mojom::XRTargetRayMode::TAPPING: + return XRInputSource::TargetRayMode::kScreen; + } + + NOTREACHED(); +} + +// TODO(https://crbug.com/962712): Switch to use typemapping instead. +XRInputSource::Handedness MojomToBlinkHandedness( + device::mojom::XRHandedness handedness) { + switch (handedness) { + case device::mojom::XRHandedness::NONE: + return XRInputSource::Handedness::kHandNone; + case device::mojom::XRHandedness::LEFT: + return XRInputSource::Handedness::kHandLeft; + case device::mojom::XRHandedness::RIGHT: + return XRInputSource::Handedness::kHandRight; + } + + NOTREACHED(); +} +} // anonymous namespace + +XRInputSource* XRInputSource::CreateOrUpdateFrom( + XRInputSource* other, + XRSession* session, + const device::mojom::blink::XRInputSourceStatePtr& state) { + if (!state) + return other; + + XRInputSource* updated_source = other; + if (other && other->InvalidatesSameObject(state)) { + updated_source = MakeGarbageCollected<XRInputSource>(*other); + + // Need to explicitly override any of the properties that could cause us to + // recreate the object. + // TODO(https://crbug.com/962724): Simplify this creation pattern + if (state->gamepad) { + updated_source->gamepad_ = MakeGarbageCollected<Gamepad>( + updated_source, 0, updated_source->base_timestamp_, TimeTicks::Now()); + } else { + updated_source->gamepad_ = nullptr; + } + } else if (!other) { + updated_source = MakeGarbageCollected<XRInputSource>(session, state); + } + + if (state->gamepad) { + updated_source->UpdateGamepad(*(state->gamepad)); + } + + // Update the input source's description if this state update includes them. + if (state->description) { + const device::mojom::blink::XRInputSourceDescriptionPtr& desc = + state->description; + + updated_source->SetTargetRayMode( + MojomToBlinkTargetRayMode(desc->target_ray_mode)); + updated_source->SetHandedness(MojomToBlinkHandedness(desc->handedness)); + updated_source->SetEmulatedPosition(desc->emulated_position); + + if (desc->pointer_offset && desc->pointer_offset->matrix.has_value()) { + const WTF::Vector<float>& m = desc->pointer_offset->matrix.value(); + std::unique_ptr<TransformationMatrix> pointer_matrix = + std::make_unique<TransformationMatrix>( + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], + m[11], m[12], m[13], m[14], m[15]); + updated_source->SetPointerTransformMatrix(std::move(pointer_matrix)); + } + } + + if (state->grip && state->grip->matrix.has_value()) { + const Vector<float>& m = state->grip->matrix.value(); + std::unique_ptr<TransformationMatrix> grip_matrix = + std::make_unique<TransformationMatrix>( + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], + m[11], m[12], m[13], m[14], m[15]); + updated_source->SetBasePoseMatrix(std::move(grip_matrix)); + } + + return updated_source; +} + XRInputSource::XRInputSource(XRSession* session, uint32_t source_id) : session_(session), source_id_(source_id), @@ -23,6 +116,39 @@ SetHandedness(kHandNone); } +XRInputSource::XRInputSource( + XRSession* session, + const device::mojom::blink::XRInputSourceStatePtr& state) + : XRInputSource(session, state->source_id) { + if (state->gamepad) { + gamepad_ = MakeGarbageCollected<Gamepad>(this, 0, base_timestamp_, + TimeTicks::Now()); + } +} + +// Deep copy because of the unique_ptrs +XRInputSource::XRInputSource(const XRInputSource& other) + : active_frame_id(other.active_frame_id), + primary_input_pressed(other.primary_input_pressed), + selection_cancelled(other.selection_cancelled), + session_(other.session_), + source_id_(other.source_id_), + target_ray_space_(other.target_ray_space_), + grip_space_(other.grip_space_), + gamepad_(other.gamepad_), + emulated_position_(other.emulated_position_), + base_timestamp_(other.base_timestamp_) { + // Since these setters also set strings, for convenience, setting them via + // their existing setters. + SetTargetRayMode(other.target_ray_mode_); + SetHandedness(other.handedness_); + + base_pose_matrix_ = + std::make_unique<TransformationMatrix>(*(other.base_pose_matrix_.get())); + pointer_transform_matrix_ = std::make_unique<TransformationMatrix>( + *(other.pointer_transform_matrix_.get())); +} + XRSpace* XRInputSource::gripSpace() const { if (target_ray_mode_ == kTrackedPointer) { return grip_space_; @@ -39,6 +165,20 @@ return gamepad_; } +bool XRInputSource::InvalidatesSameObject( + const device::mojom::blink::XRInputSourceStatePtr& state) { + if ((state->gamepad && !gamepad_) || (!state->gamepad && gamepad_)) { + return true; + } + + return false; +} + +void XRInputSource::UpdateGamepad(const device::Gamepad& gamepad) { + DCHECK(gamepad_); + gamepad_->UpdateFromDeviceState(gamepad); +} + void XRInputSource::SetTargetRayMode(TargetRayMode target_ray_mode) { if (target_ray_mode_ == target_ray_mode) return; @@ -98,23 +238,6 @@ pointer_transform_matrix_ = std::move(pointer_transform_matrix); } -// TODO(https://crbug.com/955101): Should Gamepad objects be updated in-place, -// or should a new object be created on every call? -void XRInputSource::SetGamepad(const base::Optional<device::Gamepad> gamepad) { - if (gamepad) { - if (!gamepad_) { - // TODO(https://crbug.com/955104): Is the Gamepad object creation time the - // correct time floor? - gamepad_ = MakeGarbageCollected<Gamepad>(this, 0, base_timestamp_, - TimeTicks::Now()); - } - - gamepad_->UpdateFromDeviceState(*gamepad); - } else { - gamepad_ = nullptr; - } -} - void XRInputSource::Trace(blink::Visitor* visitor) { visitor->Trace(session_); visitor->Trace(target_ray_space_);
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.h b/third_party/blink/renderer/modules/xr/xr_input_source.h index 4f096eb..f1b545e2 100644 --- a/third_party/blink/renderer/modules/xr/xr_input_source.h +++ b/third_party/blink/renderer/modules/xr/xr_input_source.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_XR_XR_INPUT_SOURCE_H_ +#include "device/vr/public/mojom/vr_service.mojom-blink.h" #include "third_party/blink/renderer/modules/gamepad/gamepad.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -34,9 +35,18 @@ kHandLeft = 1, kHandRight = 2 }; + enum TargetRayMode { kGaze = 1, kTrackedPointer = 2, kScreen = 3 }; + static XRInputSource* CreateOrUpdateFrom( + XRInputSource* other /* may be null, input */, + XRSession* session, + const device::mojom::blink::XRInputSourceStatePtr& state); + XRInputSource(XRSession*, uint32_t source_id); + XRInputSource(XRSession*, + const device::mojom::blink::XRInputSourceStatePtr& state); + XRInputSource(const XRInputSource& other); ~XRInputSource() override = default; XRSession* session() const { return session_; } @@ -51,11 +61,7 @@ uint32_t source_id() const { return source_id_; } void SetTargetRayMode(TargetRayMode); - void SetHandedness(Handedness); - void SetEmulatedPosition(bool emulated_position); - void SetBasePoseMatrix(std::unique_ptr<TransformationMatrix>); void SetPointerTransformMatrix(std::unique_ptr<TransformationMatrix>); - void SetGamepad(const base::Optional<device::Gamepad>); // Gamepad::Client GamepadHapticActuator* GetVibrationActuatorForGamepad( @@ -76,6 +82,17 @@ friend class XRGripSpace; friend class XRTargetRaySpace; + void SetHandedness(Handedness); + void SetEmulatedPosition(bool emulated_position); + void SetBasePoseMatrix(std::unique_ptr<TransformationMatrix>); + + // Use to check if the updates that would/should be made by a given + // XRInputSourceState would invalidate any SameObject properties guaranteed + // by the idl, and thus require the xr_input_source to be recreated. + bool InvalidatesSameObject( + const device::mojom::blink::XRInputSourceStatePtr& state); + void UpdateGamepad(const device::Gamepad& gamepad); + const Member<XRSession> session_; const uint32_t source_id_; Member<XRTargetRaySpace> target_ray_space_; @@ -90,10 +107,12 @@ bool emulated_position_ = false; + // TODO(crbug.com/945947): Revisit use of std::unique_ptr. std::unique_ptr<TransformationMatrix> base_pose_matrix_; // This is the transform to apply to the base_pose_matrix_ to get the pointer // matrix. In most cases it should be static. + // TODO(crbug.com/945947): Revisit use of std::unique_ptr. std::unique_ptr<TransformationMatrix> pointer_transform_matrix_; // gamepad_ uses this to get relative timestamps.
diff --git a/third_party/blink/renderer/modules/xr/xr_input_source.idl b/third_party/blink/renderer/modules/xr/xr_input_source.idl index ad23e109..9b347a8 100644 --- a/third_party/blink/renderer/modules/xr/xr_input_source.idl +++ b/third_party/blink/renderer/modules/xr/xr_input_source.idl
@@ -23,7 +23,5 @@ readonly attribute XRTargetRayMode targetRayMode; [SameObject] readonly attribute XRSpace targetRaySpace; [SameObject] readonly attribute XRSpace? gripSpace; - - // TODO(https://crbug.com/955101): This should be tagged [SameObject]. - readonly attribute Gamepad? gamepad; + [SameObject] readonly attribute Gamepad? gamepad; };
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index a4ff3659..34c4911 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -762,28 +762,34 @@ int16_t frame_id, const WTF::Vector<device::mojom::blink::XRInputSourceStatePtr>& input_states) { - bool devices_changed = false; + bool input_sources_changed = false; // Update any input sources with new state information. Any updated input // sources are marked as active. for (const auto& input_state : input_states) { - XRInputSource* input_source = input_sources_.at(input_state->source_id); - if (!input_source) { - input_source = - MakeGarbageCollected<XRInputSource>(this, input_state->source_id); + XRInputSource* stored_input_source = + input_sources_.at(input_state->source_id); + XRInputSource* input_source = XRInputSource::CreateOrUpdateFrom( + stored_input_source, this, input_state); + + // Using pointer equality to determine if the pointer needs to be set. + if (stored_input_source != input_source) { input_sources_.Set(input_state->source_id, input_source); - devices_changed = true; + input_sources_changed = true; } + input_source->active_frame_id = frame_id; - UpdateInputSourceState(input_source, input_state); + UpdateSelectState(input_source, input_state); } - // Remove any input sources that are inactive.. + // Remove any input sources that are inactive. Note that this is done in + // two passes because HeapHashMap makes no guarantees about iterators on + // removal. std::vector<uint32_t> inactive_sources; for (const auto& input_source : input_sources_.Values()) { if (input_source->active_frame_id != frame_id) { inactive_sources.push_back(input_source->source_id()); - devices_changed = true; + input_sources_changed = true; } } @@ -793,7 +799,7 @@ } } - if (devices_changed) { + if (input_sources_changed) { DispatchEvent( *XRSessionEvent::Create(event_type_names::kInputsourceschange, this)); } @@ -870,47 +876,12 @@ } } -void XRSession::UpdateInputSourceState( +void XRSession::UpdateSelectState( XRInputSource* input_source, const device::mojom::blink::XRInputSourceStatePtr& state) { if (!input_source || !state) return; - input_source->SetGamepad(state->gamepad); - - // Update the input source's description if this state update - // includes them. - if (state->description) { - const device::mojom::blink::XRInputSourceDescriptionPtr& desc = - state->description; - - input_source->SetTargetRayMode( - static_cast<XRInputSource::TargetRayMode>(desc->target_ray_mode)); - - input_source->SetHandedness( - static_cast<XRInputSource::Handedness>(desc->handedness)); - - input_source->SetEmulatedPosition(desc->emulated_position); - - if (desc->pointer_offset && desc->pointer_offset->matrix.has_value()) { - const WTF::Vector<float>& m = desc->pointer_offset->matrix.value(); - std::unique_ptr<TransformationMatrix> pointer_matrix = - std::make_unique<TransformationMatrix>( - m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], - m[11], m[12], m[13], m[14], m[15]); - input_source->SetPointerTransformMatrix(std::move(pointer_matrix)); - } - } - - if (state->grip && state->grip->matrix.has_value()) { - const Vector<float>& m = state->grip->matrix.value(); - std::unique_ptr<TransformationMatrix> grip_matrix = - std::make_unique<TransformationMatrix>( - m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], - m[11], m[12], m[13], m[14], m[15]); - input_source->SetBasePoseMatrix(std::move(grip_matrix)); - } - // Handle state change of the primary input, which may fire events if (state->primary_input_clicked) OnSelect(input_source);
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h index c7f533e..129a63a7 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.h +++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -192,9 +192,8 @@ void UpdateCanvasDimensions(Element*); void ApplyPendingRenderState(); - void UpdateInputSourceState( - XRInputSource*, - const device::mojom::blink::XRInputSourceStatePtr&); + void UpdateSelectState(XRInputSource*, + const device::mojom::blink::XRInputSourceStatePtr&); XRInputSourceEvent* CreateInputSourceEvent(const AtomicString&, XRInputSource*);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc b/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc index 87142ac..70cd474d 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/chunk_to_layer_mapper_test.cc
@@ -38,7 +38,7 @@ e0(), EffectPaintPropertyNode::State{ layer_transform_, layer_clip_, kColorFilterLuminanceToAlpha, CompositorFilterOperations(), 0.789f, - CompositorFilterOperations(), gfx::RRectF(), + CompositorFilterOperations(), base::Optional<gfx::RRectF>(), SkBlendMode::kSrcIn}); } return PropertyTreeState(*layer_transform_, *layer_clip_, *layer_effect_);
diff --git a/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h b/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h index 8922edb..c27731b 100644 --- a/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h +++ b/third_party/blink/renderer/platform/graphics/paint/effect_paint_property_node.h
@@ -53,7 +53,7 @@ CompositorFilterOperations filter; float opacity = 1; CompositorFilterOperations backdrop_filter; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; SkBlendMode blend_mode = SkBlendMode::kSrcOver; // === End of effects === CompositingReasons direct_compositing_reasons = CompositingReason::kNone; @@ -186,7 +186,7 @@ return state_.backdrop_filter; } - const gfx::RRectF& BackdropFilterBounds() const { + const base::Optional<gfx::RRectF>& BackdropFilterBounds() const { return state_.backdrop_filter_bounds; }
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h index 8b97356..4b07732 100644 --- a/third_party/blink/renderer/platform/heap/heap.h +++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -255,8 +255,6 @@ const char* type_name); template <typename T> static Address Allocate(size_t, bool eagerly_sweep = false); - template <typename T> - static Address Reallocate(void* previous, size_t); void WeakProcessing(Visitor*); @@ -616,56 +614,6 @@ } template <typename T> -Address ThreadHeap::Reallocate(void* previous, size_t size) { - // Not intended to be a full C realloc() substitute; - // realloc(nullptr, size) is not a supported alias for malloc(size). - - // TODO(sof): promptly free the previous object. - if (!size) { - // If the new size is 0 this is considered equivalent to free(previous). - return nullptr; - } - - ThreadState* state = ThreadStateFor<ThreadingTrait<T>::kAffinity>::GetState(); - HeapObjectHeader* previous_header = HeapObjectHeader::FromPayload(previous); - BasePage* page = PageFromObject(previous_header); - DCHECK(page); - - // Determine arena index of new allocation. - int arena_index; - if (size >= kLargeObjectSizeThreshold) { - arena_index = BlinkGC::kLargeObjectArenaIndex; - } else { - arena_index = page->Arena()->ArenaIndex(); - if (IsNormalArenaIndex(arena_index) || - arena_index == BlinkGC::kLargeObjectArenaIndex) - arena_index = ArenaIndexForObjectSize(size); - } - - uint32_t gc_info_index = GCInfoTrait<T>::Index(); - // TODO(haraken): We don't support reallocate() for finalizable objects. - DCHECK(!GCInfoTable::Get() - .GCInfoFromIndex(previous_header->GcInfoIndex()) - ->finalize); - DCHECK_EQ(previous_header->GcInfoIndex(), gc_info_index); - HeapAllocHooks::FreeHookIfEnabled(static_cast<Address>(previous)); - Address address; - if (arena_index == BlinkGC::kLargeObjectArenaIndex) { - address = page->Arena()->AllocateLargeObject(AllocationSizeFromSize(size), - gc_info_index); - } else { - const char* type_name = WTF_HEAP_PROFILER_TYPE_NAME(T); - address = state->Heap().AllocateOnArenaIndex(state, size, arena_index, - gc_info_index, type_name); - } - size_t copy_size = previous_header->PayloadSize(); - if (copy_size > size) - copy_size = size; - memcpy(address, previous, copy_size); - return address; -} - -template <typename T> void Visitor::HandleWeakCell(Visitor* self, void* object) { T** cell = reinterpret_cast<T**>(object); T* contents = *cell;
diff --git a/third_party/blink/renderer/platform/heap/heap_test.cc b/third_party/blink/renderer/platform/heap/heap_test.cc index 422a25d..2ade1743 100644 --- a/third_party/blink/renderer/platform/heap/heap_test.cc +++ b/third_party/blink/renderer/platform/heap/heap_test.cc
@@ -1768,27 +1768,6 @@ delete persistents[i]; persistents[i] = nullptr; } - - uint8_t* address = reinterpret_cast<uint8_t*>( - ThreadHeap::Allocate<DynamicallySizedObject>(100)); - for (int i = 0; i < 100; i++) - address[i] = i; - address = reinterpret_cast<uint8_t*>( - ThreadHeap::Reallocate<DynamicallySizedObject>(address, 100000)); - for (int i = 0; i < 100; i++) - EXPECT_EQ(address[i], i); - address = reinterpret_cast<uint8_t*>( - ThreadHeap::Reallocate<DynamicallySizedObject>(address, 50)); - for (int i = 0; i < 50; i++) - EXPECT_EQ(address[i], i); - // This should be equivalent to free(address). - EXPECT_EQ(reinterpret_cast<uintptr_t>( - ThreadHeap::Reallocate<DynamicallySizedObject>(address, 0)), - 0ul); - // This should be equivalent to malloc(0). - EXPECT_EQ(reinterpret_cast<uintptr_t>( - ThreadHeap::Reallocate<DynamicallySizedObject>(nullptr, 0)), - 0ul); } TEST(HeapTest, SimpleAllocation) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index d5e8c9e..788045c 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1050,6 +1050,20 @@ } } + // We need to attach an origin header when the request's method is neither + // GET nor HEAD. For requests made by an extension content scripts, we want to + // attach page's origin, whereas the request's origin is the content script's + // origin. See https://crbug.com/944704 for details. + // TODO(crbug.com/940068) Remove this. + if (resource_request.HttpMethod() != http_names::kGET && + resource_request.HttpMethod() != http_names::kHEAD && + resource_request.RequestorOrigin() && + !resource_request.RequestorOrigin()->IsSameSchemeHostPort( + properties_->GetFetchClientSettingsObject().GetSecurityOrigin())) { + resource_request.SetHttpOriginIfNeeded( + properties_->GetFetchClientSettingsObject().GetSecurityOrigin()); + } + // |resource_request|'s origin can be null here, corresponding to the "client" // value in the spec. In that case client's origin is used. if (!resource_request.RequestorOrigin()) {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index e275dad0..e372a58 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -744,7 +744,7 @@ }, { name: "LayoutNG", - implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFieldset", "LayoutNGFlexBox", "EditingNG", "BidiCaretAffinity"], + implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFieldset", "LayoutNGFlexBox", "LayoutNGLineCache", "EditingNG", "BidiCaretAffinity"], }, { name: "LayoutNGBlockFragmentation", @@ -760,6 +760,9 @@ implied_by: ["LayoutNG"], }, { + name: "LayoutNGLineCache", + }, + { name: "LazyFrameLoading", }, {
diff --git a/third_party/blink/tools/blinkpy/common/config/builders.json b/third_party/blink/tools/blinkpy/common/config/builders.json index 4e1c723..84bbf9c 100644 --- a/third_party/blink/tools/blinkpy/common/config/builders.json +++ b/third_party/blink/tools/blinkpy/common/config/builders.json
@@ -1,61 +1,71 @@ { - "Chromium Mac10.13": { - "port_name": "mac-mac10.13", - "specifiers": ["Mac10.13", "Release"] - }, - "Fuchsia": { + "Fuchsia x64": { + "master": "chromium.linux", "port_name": "fuchsia", "specifiers": ["Fuchsia", "Release"] }, + "KitKat Phone Tester (dbg)": { + "master": "chromium.android", + "port_name": "android-kitkat", + "specifiers": ["KitKat", "Debug"] + }, "Linux Tests": { + "master": "chromium.linux", "port_name": "linux-trusty", "specifiers": ["Trusty", "Release"] }, "Linux Tests (dbg)(1)": { + "master": "chromium.linux", "port_name": "linux-trusty", "specifiers": ["Trusty", "Debug"] }, "Mac10.10 Tests": { + "master": "chromium.mac", "port_name": "mac-mac10.10", "specifiers": ["Mac10.10", "Release"] }, "Mac10.11 Tests": { + "master": "chromium.mac", "port_name": "mac-mac10.11", "specifiers": ["Mac10.11", "Release"] }, - "Mac10.13 Tests": { + "Mac10.12 Tests": { + "master": "chromium.mac", "port_name": "mac-mac10.12", "specifiers": ["Mac10.12", "Release"] }, - "Mac10.13 Tests (dbg)": { - "port_name": "mac-mac10.11", - "specifiers": ["Mac10.13", "Debug"] + "Mac10.13 Tests": { + "master": "chromium.mac", + "port_name": "mac-mac10.13", + "specifiers": ["Mac10.13", "Release"] }, "WebKit Mac10.13 (retina)": { + "master": "chromium.mac", "port_name": "mac-retina", "specifiers": ["Retina", "Release"] }, - "WebKit Android (Nexus4)": { - "port_name": "android-kitkat", - "specifiers": ["KitKat", "Release"] + "Mac10.13 Tests (dbg)": { + "master": "chromium.mac", + "port_name": "mac-mac10.13", + "specifiers": ["Mac10.13", "Debug"] }, - "WebKit Win10": { - "port_name": "win-win10", - "specifiers": ["Win10", "Release"] - }, - "Win7 Tests": { + "Win7 Tests (1)": { + "master": "chromium.win", "port_name": "win-win7", "specifiers": ["Win7", "Release"] }, - "Win7 Tests (dbg)(1)": { - "port_name": "win-win7", - "specifiers": ["Win7", "Debug"] - }, "Win10 Tests x64": { + "master": "chromium.win", "port_name": "win-win10", "specifiers": ["Win10", "Release"] }, + "Win7 Tests (dbg)(1)": { + "master": "chromium.win", + "port_name": "win-win7", + "specifiers": ["Win7", "Debug"] + }, "Win10 Tests x64 (dbg)": { + "master": "chromium.win", "port_name": "win-win10", "specifiers": ["Win10", "Debug"] },
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 0dfea7d..16571be9b 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -510,6 +510,7 @@ 'third_party/blink/renderer/modules/device_orientation/', 'third_party/blink/renderer/modules/gamepad/', 'third_party/blink/renderer/modules/sensor/', + 'third_party/blink/renderer/modules/xr/', ], 'allowed': [ 'base::subtle::Atomic32',
diff --git a/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py index 81d036eb..1524479 100644 --- a/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py +++ b/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations.py
@@ -110,9 +110,9 @@ class BotTestExpectationsFactory(object): - RESULTS_URL_PREFIX = ( - 'https://test-results.appspot.com/testfile?master=chromium.webkit&' - 'testtype=webkit_tests&name=results-small.json&builder=') + RESULTS_URL_FORMAT = ( + 'https://test-results.appspot.com/testfile?testtype=webkit_layout_tests' + '&name=results-small.json&master=%s&builder=%s') def __init__(self, builders): self.builders = builders @@ -123,10 +123,14 @@ return None return self._results_json_for_builder(builder) + def _results_url_for_builder(self, builder): + return self.RESULTS_URL_FORMAT % ( + urllib.quote(self.builders.master_for_builder(builder)), urllib.quote(builder)) + def _results_json_for_builder(self, builder): - results_url = self.RESULTS_URL_PREFIX + urllib.quote(builder) + results_url = self._results_url_for_builder(builder) try: - _log.debug('Fetching flakiness data from appengine.') + _log.debug('Fetching flakiness data from appengine: %s', results_url) return ResultsJSON(builder, json.load(urllib2.urlopen(results_url))) except urllib2.URLError as error: _log.warning('Could not retrieve flakiness data from the bot. url: %s', results_url)
diff --git a/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations_unittest.py b/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations_unittest.py index 02f7c43..491e469f 100644 --- a/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/layout_package/bot_test_expectations_unittest.py
@@ -35,14 +35,27 @@ class BotTestExpectationsFactoryTest(unittest.TestCase): + # pylint: disable=protected-access + def fake_builder_list(self): return BuilderList({ - 'Dummy builder name': {'port_name': 'dummy-port', 'specifiers': ['dummy', 'release']}, + 'Dummy builder name': { + 'master': 'dummy.master', + 'port_name': 'dummy-port', + 'specifiers': ['dummy', 'release'], + }, }) def fake_results_json_for_builder(self, builder): return bot_test_expectations.ResultsJSON(builder, 'Dummy content') + def test_results_url_for_builder(self): + factory = bot_test_expectations.BotTestExpectationsFactory(self.fake_builder_list()) + + self.assertEqual(factory._results_url_for_builder('Dummy builder name'), + 'https://test-results.appspot.com/testfile?testtype=webkit_layout_tests' + '&name=results-small.json&master=dummy.master&builder=Dummy%20builder%20name') + def test_expectations_for_builder(self): factory = bot_test_expectations.BotTestExpectationsFactory(self.fake_builder_list()) factory._results_json_for_builder = self.fake_results_json_for_builder @@ -73,7 +86,8 @@ if expected: results_entry[bot_test_expectations.ResultsJSON.EXPECTATIONS_KEY] = expected - num_actual_results = len(expectations._flaky_types_in_results(results_entry, only_ignore_very_flaky)) + num_actual_results = len(expectations._flaky_types_in_results( # pylint: disable=protected-access + results_entry, only_ignore_very_flaky)) if should_be_flaky: self.assertGreater(num_actual_results, 1) else: @@ -201,7 +215,6 @@ } } } - self.maxDiff = None self._assert_unexpected_results(test_data, { 'foo/pass1.html': sorted(['FAIL', 'PASS']), 'foo/pass2.html': sorted(['IMAGE', 'PASS']),
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py index bc03ea8fac..027e41f 100644 --- a/third_party/blink/tools/blinkpy/web_tests/port/base.py +++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -260,6 +260,14 @@ def additional_driver_flags(self): # Clone list to avoid mutating option state. flags = list(self.get_option('additional_driver_flag', [])) + + # Disable LayoutNG unless explicitly enabled during transition period to + # avoid having to unnecessarily update test expectations every time the flag + # is flipped and to allow us to update expectations one bot at a time. + # TODO(eae): Remove once LayoutNG launches. https://crbug.com/961437 + if not '--enable-blink-features=LayoutNG' in flags: + flags += ['--disable-blink-features=LayoutNG'] + if flags and flags[0] == self.primary_driver_flag(): flags = flags[1:] if self.driver_name() == self.CONTENT_SHELL_NAME:
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py index f0a15139..5bd63d54 100644 --- a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py +++ b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py
@@ -46,13 +46,6 @@ def main(argv, stderr): options, args = parse_args(argv) - # Disable LayoutNG unless explicitly enabled during transition period to - # avoid having to unnecessarily update test expectations every time the flag - # is flipped and to allow us to update expectations one bot at a time. - # TODO(eae): Remove once LayoutNG launches. https://crbug.com/961437 - if not '--enable-blink-features=LayoutNG' in options.additional_driver_flag: - options.additional_driver_flag.append('--disable-blink-features=LayoutNG') - if options.platform and 'test' in options.platform and not 'browser_test' in options.platform: # It's a bit lame to import mocks into real code, but this allows the user # to run tests against the test platform interactively, which is useful for
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG index 8c4a710..bbeb03e 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -102,9 +102,9 @@ crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Pass ] crbug.com/845902 external/wpt/css/css-sizing/whitespace-and-break.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-001.html [ Pass ] -crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-003.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-004.html [ Failure Pass ] -crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-005.html [ Failure Pass ] +crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-003.html [ Pass ] +crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-004.html [ Pass ] +crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-005.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-009.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-010.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/hyphens/hyphens-out-of-flow-002.html [ Failure ] @@ -127,6 +127,7 @@ crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-005.html [ Failure ] crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-shaping-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-000.html [ Pass ] +crbug.com/591099 external/wpt/css/css-text/shaping/shaping-001.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-002.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-003.html [ Pass ] crbug.com/591099 external/wpt/css/css-text/shaping/shaping-004.html [ Pass ] @@ -272,15 +273,13 @@ crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-004.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-padding-box-border-radius-002.html [ Pass ] -crbug.com/591099 external/wpt/event-timing/programmatic-click-not-observed.html [ Failure Pass ] +crbug.com/591099 external/wpt/event-timing/programmatic-click-not-observed.html [ Failure ] crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ] crbug.com/591099 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/javascript-url-abort/javascript-url-abort-return-value-string.tentative.html [ Pass ] crbug.com/591099 external/wpt/html/user-activation/activation-transfer-without-click.tentative.html [ Pass ] crbug.com/591099 external/wpt/payment-handler/change-payment-method.https.html [ Crash Pass ] crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch.html [ Failure Pass ] -crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html [ Failure Pass ] crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html [ Pass ] -crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html [ Failure Pass ] crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html [ Pass ] crbug.com/845902 external/wpt/quirks/line-height-trailing-collapsable-whitespace.html [ Pass ] crbug.com/591099 external/wpt/referrer-policy/no-referrer/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Pass ] @@ -294,7 +293,7 @@ crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ] crbug.com/591099 fast/block/float/4145535Crash.html [ Pass ] crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ] -crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Failure Pass ] +crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Pass ] crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Pass ] crbug.com/591099 fast/css-intrinsic-dimensions/height-tables.html [ Failure Pass ] crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ] @@ -306,7 +305,7 @@ crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ] crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ] crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ] -crbug.com/591099 fast/forms/autofocus-in-sandbox-with-allow-scripts.html [ Pass ] +crbug.com/591099 fast/forms/autofocus-in-sandbox-with-allow-scripts.html [ Pass Timeout ] crbug.com/889721 fast/inline/outline-continuations.html [ Failure ] crbug.com/591099 fast/multicol/border-radius-clipped-layer.html [ Pass ] crbug.com/591099 fast/overflow/overflow-height-float-not-removed-crash3.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index d12f539..82859892 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2716,6 +2716,26 @@ crbug.com/939181 virtual/not-site-per-process/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Failure Timeout ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-pseudo/marker-content-006.html [ Failure ] +crbug.com/626703 external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box.html [ Failure ] +crbug.com/626703 external/wpt/html/rendering/widgets/button-layout/inline-level.html [ Failure ] +crbug.com/626703 external/wpt/css/css-pseudo/marker-list-style-position.html [ Failure ] +crbug.com/626703 external/wpt/css/css-values/ch-unit-015.html [ Failure ] +crbug.com/626703 external/wpt/css/css-values/ch-unit-013.html [ Failure ] +crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Failure ] +crbug.com/626703 external/wpt/css/css-values/ch-unit-018.html [ Failure ] +crbug.com/626703 external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html [ Failure ] +crbug.com/626703 external/wpt/css/css-values/ch-unit-014.html [ Failure ] +crbug.com/626703 external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html [ Failure ] +crbug.com/626703 external/wpt/css/css-pseudo/marker-content-007.html [ Failure ] +crbug.com/626703 external/wpt/css/css-values/ch-unit-017.html [ Failure ] +crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html [ Failure ] +crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html [ Failure ] +crbug.com/626703 [ Mac ] external/wpt/html/rendering/widgets/button-layout/propagate-text-decoration.html [ Failure ] +crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html [ Failure ] +crbug.com/626703 external/wpt/css/css-pseudo/marker-content-008.html [ Failure ] +crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy_ini_short.html [ Failure ] crbug.com/626703 virtual/omt-worker-fetch/external/wpt/xhr/abort-after-stop.any.worker.html [ Timeout ] crbug.com/626703 external/wpt/xhr/abort-after-stop.any.worker.html [ Timeout ] crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/vertical_rl.html [ Failure ] @@ -2877,7 +2897,7 @@ crbug.com/626703 external/wpt/svg/text/reftests/text-text-anchor-003.svg [ Failure ] crbug.com/626703 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Timeout ] crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Timeout ] -crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy.html [ Failure ] +crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy_ini_full.html [ Failure ] crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy_1.html [ Failure ] crbug.com/626703 external/wpt/screen-orientation/onchange-event.html [ Timeout ] crbug.com/626703 external/wpt/html/semantics/forms/the-fieldset-element/accessibility/fieldset-div-display-contents-manual.html [ Skip ] @@ -4495,9 +4515,6 @@ # Sheriff failures 2017-11-16 crbug.com/785980 [ Win ] http/tests/devtools/network/network-xhr-same-url-as-main-resource.js [ Failure Pass ] -# Sheriff failures 2017-11-28 -crbug.com/785179 [ Mac10.11 Debug ] http/tests/devtools/console/console-viewport-stick-to-bottom.js [ Pass Failure ] - # Sheriff failures 2017-11-29 crbug.com/789567 scrollbars/custom-scrollbar-inactive-pseudo.html [ Failure Pass ] crbug.com/789567 scrollbars/custom-scrollbar-adjust-on-inactive-pseudo.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index c9c4da6..1c7afa1 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -52397,6 +52397,18 @@ {} ] ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-004.svg": [ + [ + "css/css-masking/clip-path-svg-content/clip-path-content-clip-004.svg", + [ + [ + "/css/css-masking/clip-path-svg-content/reference/clip-path-content-clip-004-ref.svg", + "==" + ] + ], + {} + ] + ], "css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg": [ [ "css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg", @@ -56165,6 +56177,42 @@ {} ] ], + "css/css-multicol/multicol-span-all-fieldset-001.html": [ + [ + "css/css-multicol/multicol-span-all-fieldset-001.html", + [ + [ + "/css/css-multicol/multicol-span-all-fieldset-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-multicol/multicol-span-all-fieldset-002.html": [ + [ + "css/css-multicol/multicol-span-all-fieldset-002.html", + [ + [ + "/css/css-multicol/multicol-span-all-fieldset-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-multicol/multicol-span-all-fieldset-003.html": [ + [ + "css/css-multicol/multicol-span-all-fieldset-003.html", + [ + [ + "/css/css-multicol/multicol-span-all-fieldset-003-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-multicol/multicol-span-all-list-item-001.html": [ [ "css/css-multicol/multicol-span-all-list-item-001.html", @@ -58853,6 +58901,138 @@ {} ] ], + "css/css-pseudo/marker-content-001.html": [ + [ + "css/css-pseudo/marker-content-001.html", + [ + [ + "/css/css-pseudo/marker-content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-001b.html": [ + [ + "css/css-pseudo/marker-content-001b.html", + [ + [ + "/css/css-pseudo/marker-content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-001c.html": [ + [ + "css/css-pseudo/marker-content-001c.html", + [ + [ + "/css/css-pseudo/marker-content-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-002.html": [ + [ + "css/css-pseudo/marker-content-002.html", + [ + [ + "/css/css-pseudo/marker-content-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-003.html": [ + [ + "css/css-pseudo/marker-content-003.html", + [ + [ + "/css/css-pseudo/marker-content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-003b.html": [ + [ + "css/css-pseudo/marker-content-003b.html", + [ + [ + "/css/css-pseudo/marker-content-003-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-004.html": [ + [ + "css/css-pseudo/marker-content-004.html", + [ + [ + "/css/css-pseudo/marker-content-004-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-005.html": [ + [ + "css/css-pseudo/marker-content-005.html", + [ + [ + "/css/css-pseudo/marker-content-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-006.html": [ + [ + "css/css-pseudo/marker-content-006.html", + [ + [ + "/css/css-pseudo/marker-content-006-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-007.html": [ + [ + "css/css-pseudo/marker-content-007.html", + [ + [ + "/css/css-pseudo/marker-content-007-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-pseudo/marker-content-008.html": [ + [ + "css/css-pseudo/marker-content-008.html", + [ + [ + "/css/css-pseudo/marker-content-008-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-pseudo/marker-content-009.html": [ [ "css/css-pseudo/marker-content-009.html", @@ -58937,6 +59117,18 @@ {} ] ], + "css/css-pseudo/marker-list-style-position.html": [ + [ + "css/css-pseudo/marker-list-style-position.html", + [ + [ + "/css/css-pseudo/marker-list-style-position-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-pseudo/placeholder-input-number.html": [ [ "css/css-pseudo/placeholder-input-number.html", @@ -68097,6 +68289,162 @@ {} ] ], + "css/css-text/white-space/break-spaces-before-first-char-001.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-001.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-002.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-002.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-003.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-003.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-004.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-004.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-005.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-005.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-006.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-006.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-007.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-007.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-008.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-008.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-009.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-009.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-010.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-010.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-011.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-011.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-012.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-012.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-text/white-space/break-spaces-before-first-char-013.html": [ + [ + "css/css-text/white-space/break-spaces-before-first-char-013.html", + [ + [ + "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-text/white-space/control-chars-000.html": [ [ "css/css-text/white-space/control-chars-000.html", @@ -84213,6 +84561,78 @@ {} ] ], + "css/css-values/ch-unit-013.html": [ + [ + "css/css-values/ch-unit-013.html", + [ + [ + "/css/css-values/reference/ch-unit-013-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-values/ch-unit-014.html": [ + [ + "css/css-values/ch-unit-014.html", + [ + [ + "/css/css-values/reference/ch-unit-013-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-values/ch-unit-015.html": [ + [ + "css/css-values/ch-unit-015.html", + [ + [ + "/css/css-values/reference/ch-unit-013-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-values/ch-unit-016.html": [ + [ + "css/css-values/ch-unit-016.html", + [ + [ + "/css/css-values/reference/ch-unit-013-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-values/ch-unit-017.html": [ + [ + "css/css-values/ch-unit-017.html", + [ + [ + "/css/css-values/reference/ch-unit-013-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-values/ch-unit-018.html": [ + [ + "css/css-values/ch-unit-018.html", + [ + [ + "/css/css-values/reference/ch-unit-013-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-values/ex-calc-expression-001.html": [ [ "css/css-values/ex-calc-expression-001.html", @@ -84225,6 +84645,42 @@ {} ] ], + "css/css-values/ex-unit-001.html": [ + [ + "css/css-values/ex-unit-001.html", + [ + [ + "/css/css-values/reference/ex-unit-001-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-values/ex-unit-002.html": [ + [ + "css/css-values/ex-unit-002.html", + [ + [ + "/css/css-values/reference/ex-unit-002-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-values/ex-unit-003.html": [ + [ + "css/css-values/ex-unit-003.html", + [ + [ + "/css/css-values/reference/ex-unit-002-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-values/ic-unit-001.html": [ [ "css/css-values/ic-unit-001.html", @@ -109643,6 +110099,42 @@ {} ] ], + "html/rendering/widgets/button-layout/anonymous-button-content-box.html": [ + [ + "html/rendering/widgets/button-layout/anonymous-button-content-box.html", + [ + [ + "/html/rendering/widgets/button-layout/anonymous-button-content-box-ref.html", + "==" + ] + ], + {} + ] + ], + "html/rendering/widgets/button-layout/inline-level.html": [ + [ + "html/rendering/widgets/button-layout/inline-level.html", + [ + [ + "/html/rendering/widgets/button-layout/inline-level-ref.html", + "==" + ] + ], + {} + ] + ], + "html/rendering/widgets/button-layout/propagate-text-decoration.html": [ + [ + "html/rendering/widgets/button-layout/propagate-text-decoration.html", + [ + [ + "/html/rendering/widgets/button-layout/propagate-text-decoration-ref.html", + "==" + ] + ], + {} + ] + ], "html/semantics/document-metadata/the-link-element/stylesheet-change-href.html": [ [ "html/semantics/document-metadata/the-link-element/stylesheet-change-href.html", @@ -110915,38 +111407,6 @@ {} ] ], - "infrastructure/reftest/reftest_fuzzy.html": [ - [ - "infrastructure/reftest/reftest_fuzzy.html", - [ - [ - "/infrastructure/reftest/fuzzy-ref-1.html", - "==" - ] - ], - { - "fuzzy": [ - [ - [ - "/infrastructure/reftest/reftest_fuzzy.html", - "/infrastructure/reftest/fuzzy-ref-1.html", - "==" - ], - [ - [ - 128, - 128 - ], - [ - 100, - 100 - ] - ] - ] - ] - } - ] - ], "infrastructure/reftest/reftest_fuzzy_1.html": [ [ "infrastructure/reftest/reftest_fuzzy_1.html", @@ -110979,6 +111439,102 @@ } ] ], + "infrastructure/reftest/reftest_fuzzy_ini_full.html": [ + [ + "infrastructure/reftest/reftest_fuzzy_ini_full.html", + [ + [ + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ] + ], + { + "fuzzy": [ + [ + [ + "/infrastructure/reftest/reftest_fuzzy_ini_full.html", + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ], + [ + [ + 128, + 128 + ], + [ + 100, + 100 + ] + ] + ] + ] + } + ] + ], + "infrastructure/reftest/reftest_fuzzy_ini_ref_only.html": [ + [ + "infrastructure/reftest/reftest_fuzzy_ini_ref_only.html", + [ + [ + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ] + ], + { + "fuzzy": [ + [ + [ + "/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html", + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ], + [ + [ + 128, + 128 + ], + [ + 100, + 100 + ] + ] + ] + ] + } + ] + ], + "infrastructure/reftest/reftest_fuzzy_ini_short.html": [ + [ + "infrastructure/reftest/reftest_fuzzy_ini_short.html", + [ + [ + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ] + ], + { + "fuzzy": [ + [ + [ + "/infrastructure/reftest/reftest_fuzzy_ini_short.html", + "/infrastructure/reftest/fuzzy-ref-1.html", + "==" + ], + [ + [ + 128, + 128 + ], + [ + 100, + 100 + ] + ] + ] + ] + } + ] + ], "infrastructure/reftest/reftest_fuzzy_no_differences.html": [ [ "infrastructure/reftest/reftest_fuzzy_no_differences.html", @@ -144247,6 +144803,11 @@ {} ] ], + "css/css-masking/clip-path-svg-content/reference/clip-path-content-clip-004-ref.svg": [ + [ + {} + ] + ], "css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg": [ [ {} @@ -145087,6 +145648,21 @@ {} ] ], + "css/css-multicol/multicol-span-all-fieldset-001-ref.html": [ + [ + {} + ] + ], + "css/css-multicol/multicol-span-all-fieldset-002-ref.html": [ + [ + {} + ] + ], + "css/css-multicol/multicol-span-all-fieldset-003-ref.html": [ + [ + {} + ] + ], "css/css-multicol/multicol-span-all-list-item-001-ref.html": [ [ {} @@ -146072,6 +146648,46 @@ {} ] ], + "css/css-pseudo/marker-content-001-ref.html": [ + [ + {} + ] + ], + "css/css-pseudo/marker-content-002-ref.html": [ + [ + {} + ] + ], + "css/css-pseudo/marker-content-003-ref.html": [ + [ + {} + ] + ], + "css/css-pseudo/marker-content-004-ref.html": [ + [ + {} + ] + ], + "css/css-pseudo/marker-content-005-ref.html": [ + [ + {} + ] + ], + "css/css-pseudo/marker-content-006-ref.html": [ + [ + {} + ] + ], + "css/css-pseudo/marker-content-007-ref.html": [ + [ + {} + ] + ], + "css/css-pseudo/marker-content-008-ref.html": [ + [ + {} + ] + ], "css/css-pseudo/marker-content-009-ref.html": [ [ {} @@ -146102,6 +146718,11 @@ {} ] ], + "css/css-pseudo/marker-list-style-position-ref.html": [ + [ + {} + ] + ], "css/css-pseudo/placeholder-input-number-notref.html": [ [ {} @@ -154402,6 +155023,21 @@ {} ] ], + "css/css-values/reference/ch-unit-013-ref.html": [ + [ + {} + ] + ], + "css/css-values/reference/ex-unit-001-ref.html": [ + [ + {} + ] + ], + "css/css-values/reference/ex-unit-002-ref.html": [ + [ + {} + ] + ], "css/css-values/reference/ic-unit-001-ref.html": [ [ {} @@ -154442,6 +155078,26 @@ {} ] ], + "css/css-values/resources/ChTestNoZero.woff": [ + [ + {} + ] + ], + "css/css-values/resources/ChTestShortZero.woff": [ + [ + {} + ] + ], + "css/css-values/resources/ChTestZeroWidthZero.woff": [ + [ + {} + ] + ], + "css/css-values/resources/ExTest.woff": [ + [ + {} + ] + ], "css/css-values/support/1x1-green.png": [ [ {} @@ -174532,6 +175188,11 @@ {} ] ], + "html/rendering/non-replaced-elements/form-controls/button-style-expected.txt": [ + [ + {} + ] + ], "html/rendering/non-replaced-elements/lists/OWNERS": [ [ {} @@ -175032,6 +175693,31 @@ {} ] ], + "html/rendering/widgets/button-layout/anonymous-button-content-box-ref.html": [ + [ + {} + ] + ], + "html/rendering/widgets/button-layout/computed-style-expected.txt": [ + [ + {} + ] + ], + "html/rendering/widgets/button-layout/display-other-expected.txt": [ + [ + {} + ] + ], + "html/rendering/widgets/button-layout/inline-level-ref.html": [ + [ + {} + ] + ], + "html/rendering/widgets/button-layout/propagate-text-decoration-ref.html": [ + [ + {} + ] + ], "html/resources/common.js": [ [ {} @@ -179927,7 +180613,17 @@ {} ] ], - "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini": [ + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini": [ + [ + {} + ] + ], + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini": [ + [ + {} + ] + ], + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini": [ [ {} ] @@ -188572,6 +189268,11 @@ {} ] ], + "selection/script-and-style-elements-expected.txt": [ + [ + {} + ] + ], "selection/setBaseAndExtent-expected.txt": [ [ {} @@ -199012,6 +199713,11 @@ {} ] ], + "tools/wptrunner/requirements_edge_chromium.txt": [ + [ + {} + ] + ], "tools/wptrunner/requirements_epiphany.txt": [ [ {} @@ -199102,6 +199808,11 @@ {} ] ], + "tools/wptrunner/wptrunner/browsers/edgechromium.py": [ + [ + {} + ] + ], "tools/wptrunner/wptrunner/browsers/epiphany.py": [ [ {} @@ -199182,6 +199893,11 @@ {} ] ], + "tools/wptrunner/wptrunner/executors/executoredgechromium.py": [ + [ + {} + ] + ], "tools/wptrunner/wptrunner/executors/executorinternetexplorer.py": [ [ {} @@ -201272,6 +201988,11 @@ {} ] ], + "webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel-expected.txt": [ + [ + {} + ] + ], "webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/audiobuffersource-multi-channels-expected.wav": [ [ {} @@ -264018,6 +264739,12 @@ {} ] ], + "html/rendering/non-replaced-elements/form-controls/button-style.html": [ + [ + "html/rendering/non-replaced-elements/form-controls/button-style.html", + {} + ] + ], "html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-quirks-mode.html": [ [ "html/rendering/non-replaced-elements/margin-collapsing-quirks/multicol-quirks-mode.html", @@ -264258,6 +264985,12 @@ {} ] ], + "html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-replaced-box-while-loading.html": [ + [ + "html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-replaced-box-while-loading.html", + {} + ] + ], "html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html": [ [ "html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html", @@ -264294,6 +265027,42 @@ {} ] ], + "html/rendering/widgets/button-layout/abspos.html": [ + [ + "html/rendering/widgets/button-layout/abspos.html", + {} + ] + ], + "html/rendering/widgets/button-layout/computed-style.html": [ + [ + "html/rendering/widgets/button-layout/computed-style.html", + {} + ] + ], + "html/rendering/widgets/button-layout/display-other.html": [ + [ + "html/rendering/widgets/button-layout/display-other.html", + {} + ] + ], + "html/rendering/widgets/button-layout/flex.html": [ + [ + "html/rendering/widgets/button-layout/flex.html", + {} + ] + ], + "html/rendering/widgets/button-layout/grid.html": [ + [ + "html/rendering/widgets/button-layout/grid.html", + {} + ] + ], + "html/rendering/widgets/button-layout/shrink-wrap.html": [ + [ + "html/rendering/widgets/button-layout/shrink-wrap.html", + {} + ] + ], "html/semantics/disabled-elements/disabledElement.html": [ [ "html/semantics/disabled-elements/disabledElement.html", @@ -303146,6 +303915,12 @@ {} ] ], + "selection/script-and-style-elements.html": [ + [ + "selection/script-and-style-elements.html", + {} + ] + ], "selection/selectAllChildren.html": [ [ "selection/selectAllChildren.html", @@ -389461,6 +390236,10 @@ "fd1b29162570d5f6264ea36abbb72e90a8fdcee4", "reftest" ], + "css/css-masking/clip-path-svg-content/clip-path-content-clip-004.svg": [ + "2317842e5ff2526635097511999ebc007724c514", + "reftest" + ], "css/css-masking/clip-path-svg-content/clip-path-content-invisible.svg": [ "0696d4b09fd125f0682ac6652236f8122d4b4d7c", "reftest" @@ -389793,6 +390572,10 @@ "8a25ffebe6dd7c5803ee1fd56628e4dafab9d684", "support" ], + "css/css-masking/clip-path-svg-content/reference/clip-path-content-clip-004-ref.svg": [ + "269d289b4a9e6e7e90546ffa9d08f26bf8cb8dec", + "support" + ], "css/css-masking/clip-path-svg-content/reference/clip-path-ellipse-001-ref.svg": [ "2532eb3c1bbacb5a66a84b26e4a35b966512c977", "support" @@ -391509,6 +392292,30 @@ "5b23814aed9cef84c83997198c80e169bc37c1d6", "reftest" ], + "css/css-multicol/multicol-span-all-fieldset-001-ref.html": [ + "16c86366c98ab9f603dd05ba899899f85d13dbbd", + "support" + ], + "css/css-multicol/multicol-span-all-fieldset-001.html": [ + "f1bced0be935647440a55e6d7f8793129a5da7f3", + "reftest" + ], + "css/css-multicol/multicol-span-all-fieldset-002-ref.html": [ + "d2f86b5fe41114a9ff426b2b6d95928ce963652c", + "support" + ], + "css/css-multicol/multicol-span-all-fieldset-002.html": [ + "2c7e47ca894a56f17330be24b55a0c67826cc20b", + "reftest" + ], + "css/css-multicol/multicol-span-all-fieldset-003-ref.html": [ + "6201818f66744d372f0ef2242f057ab174bf59ab", + "support" + ], + "css/css-multicol/multicol-span-all-fieldset-003.html": [ + "d3ca8a4468c93e1dda2e9cd01b7d19dd5f844602", + "reftest" + ], "css/css-multicol/multicol-span-all-list-item-001-ref.html": [ "4f3fe18a6d5804a4a7a6874fd46d5614c0a8dff2", "support" @@ -393761,6 +394568,82 @@ "d45c76696eca826456988d7884adcaa52bfad9cd", "reftest" ], + "css/css-pseudo/marker-content-001-ref.html": [ + "e2c2daa1761563dc6b74ac3bc1bd0de05ff3766a", + "support" + ], + "css/css-pseudo/marker-content-001.html": [ + "5e5bfe1c23abc34c28e3af1504bce8420407f162", + "reftest" + ], + "css/css-pseudo/marker-content-001b.html": [ + "6ab87a31d802601297715b64561c74b6cb04c81b", + "reftest" + ], + "css/css-pseudo/marker-content-001c.html": [ + "0a32b2ada03593635fda4bae45fc97845fb28ab8", + "reftest" + ], + "css/css-pseudo/marker-content-002-ref.html": [ + "5886f4216b6bee9f59afdb5303ffdacf7c044fcd", + "support" + ], + "css/css-pseudo/marker-content-002.html": [ + "4c46c4b0b01bfeae7c473f3507d920d7229a64cb", + "reftest" + ], + "css/css-pseudo/marker-content-003-ref.html": [ + "5214d853c1680126904848464da0ef7ea611018d", + "support" + ], + "css/css-pseudo/marker-content-003.html": [ + "b4a41ce6d87ef464a525a9252c2ffc8d824bf901", + "reftest" + ], + "css/css-pseudo/marker-content-003b.html": [ + "da7a2723ce32fae72092795cb30cd2e33709ca5d", + "reftest" + ], + "css/css-pseudo/marker-content-004-ref.html": [ + "3d706d9d622da5335a23947b7da86895bccd5aa8", + "support" + ], + "css/css-pseudo/marker-content-004.html": [ + "24dbaae123cce2882324b59c395d049a8ab7600e", + "reftest" + ], + "css/css-pseudo/marker-content-005-ref.html": [ + "46e77ddc27780854511edcc0019ef29c78412612", + "support" + ], + "css/css-pseudo/marker-content-005.html": [ + "ad37a65738f98fe4daf2cf0c11b1bb1ed2cd3b60", + "reftest" + ], + "css/css-pseudo/marker-content-006-ref.html": [ + "f258c88731e5df4b2a16bd1822956598c5c85403", + "support" + ], + "css/css-pseudo/marker-content-006.html": [ + "bf941ef3b1e83d36daa912f1cd7d3259a6519211", + "reftest" + ], + "css/css-pseudo/marker-content-007-ref.html": [ + "8cec2799c2e0218e2e0c796ee4589b64d732cb39", + "support" + ], + "css/css-pseudo/marker-content-007.html": [ + "fb452666e3c16094945ea5212e66cf04914f47f4", + "reftest" + ], + "css/css-pseudo/marker-content-008-ref.html": [ + "6d5052b378b7a5f626a51cb033fba8f7339192aa", + "support" + ], + "css/css-pseudo/marker-content-008.html": [ + "88aee13dc8c9530967d73da7f09a609a40e483ac", + "reftest" + ], "css/css-pseudo/marker-content-009-ref.html": [ "a3db09f078148cdfe8105bc0d12186e15cf33d48", "support" @@ -393813,6 +394696,14 @@ "82456afb6c6058a209ddb8bbcee523a900665dee", "reftest" ], + "css/css-pseudo/marker-list-style-position-ref.html": [ + "2593194d298fe3ee8bb14ffe9923a654a19d5c8a", + "support" + ], + "css/css-pseudo/marker-list-style-position.html": [ + "5b4391d4e7e43c330eb848ca29645b8c820c02de", + "reftest" + ], "css/css-pseudo/placeholder-input-number-notref.html": [ "92ae71d83fcbea52e4120ed28af5438dd54d4509", "support" @@ -402921,6 +403812,58 @@ "36aa9dafd6e588c292f598179465233be653ab54", "reftest" ], + "css/css-text/white-space/break-spaces-before-first-char-001.html": [ + "e5221e15501064f216337a358a80058720cd7dad", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-002.html": [ + "c7c36889ce81292a4fb52cae4f26214fd7eb458c", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-003.html": [ + "5848f4e72a4357b3d400bf10f4b944de283a1a40", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-004.html": [ + "c14f5c15ea72d7a2cec2626b3f7c302fda2ddb08", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-005.html": [ + "2759c936901b0a1be6c31828b69b450d2a6922f4", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-006.html": [ + "aabc3baff9b20a1a87a57ac88f0d5f1b971e8bf9", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-007.html": [ + "0336fd47992a2de94f892caa8a8aad488cdb5027", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-008.html": [ + "d93a56fb75bba5105f64382130f9924e0dd01e18", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-009.html": [ + "11b623e7161da15d2f61eaaa667f22d47b4c2719", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-010.html": [ + "5012e98af002cd01f23b16efd822b67619cca491", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-011.html": [ + "3134b0364ad2e59b6163fd46e59a6b06a1c2e621", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-012.html": [ + "e811053b9a8b8c16047667099c734089df637db8", + "reftest" + ], + "css/css-text/white-space/break-spaces-before-first-char-013.html": [ + "0d6e398c0a83b779413fd03f73998be4d8b658f0", + "reftest" + ], "css/css-text/white-space/control-chars-000.html": [ "b038fe9a90d3b8b9cb3bde7fd46396c7121688c9", "reftest" @@ -414781,6 +415724,30 @@ "b844d9b3fa45e9a340ab79da7175875c6187d99f", "reftest" ], + "css/css-values/ch-unit-013.html": [ + "c5782f175328dd374905fca5ebd4251ef3269abb", + "reftest" + ], + "css/css-values/ch-unit-014.html": [ + "a8a04c8c45ba390931c22655c7ba98ac72e92bd5", + "reftest" + ], + "css/css-values/ch-unit-015.html": [ + "e098e3f80310ab987e04c1879ec28f2f1fffe76c", + "reftest" + ], + "css/css-values/ch-unit-016.html": [ + "1a61e1522f1bebe4bb19a03561ff4cbba31b11bd", + "reftest" + ], + "css/css-values/ch-unit-017.html": [ + "a52c9785d6be254531ebcfe579f953dc5eed6764", + "reftest" + ], + "css/css-values/ch-unit-018.html": [ + "fee5e92a9312f80b6d36966b721d01269f1ad30b", + "reftest" + ], "css/css-values/ex-calc-expression-001-ref.html": [ "888a51ea9b6ac04fb065ee5d84a18be8fe765aca", "support" @@ -414789,6 +415756,18 @@ "4eab829697f87606a64d60f360a04639e61ccabb", "reftest" ], + "css/css-values/ex-unit-001.html": [ + "ad296b4174e4331f445931c2aa2a959dffad51c9", + "reftest" + ], + "css/css-values/ex-unit-002.html": [ + "a0293cf45b40732a46dfeced89ee85ad2ca0d88a", + "reftest" + ], + "css/css-values/ex-unit-003.html": [ + "67bb0c6eb31d449dbf7b32c47a38634c22b77e0e", + "reftest" + ], "css/css-values/getComputedStyle-border-radius-001.html": [ "6f3ba3ac4776045c94603b647d0a1ba134f5caf6", "testharness" @@ -414893,6 +415872,18 @@ "78b484fe718321d2d0b7c213d72f8bd2dc333acb", "support" ], + "css/css-values/reference/ch-unit-013-ref.html": [ + "74e304be728daa5ae3d5425b5b125b46c7ad1800", + "support" + ], + "css/css-values/reference/ex-unit-001-ref.html": [ + "11a06e7210ce1eafc8928a6dd371d9b333fcd617", + "support" + ], + "css/css-values/reference/ex-unit-002-ref.html": [ + "74e304be728daa5ae3d5425b5b125b46c7ad1800", + "support" + ], "css/css-values/reference/ic-unit-001-ref.html": [ "2151f3b0c5dd883ffd2e04157726474eff0a5c2b", "support" @@ -414925,6 +415916,22 @@ "e56c6ec8451370e86fb16f76c50acd627bd5be78", "support" ], + "css/css-values/resources/ChTestNoZero.woff": [ + "b873b48b631017d1758cbda670b3377d79664a3a", + "support" + ], + "css/css-values/resources/ChTestShortZero.woff": [ + "c7e7cc5ad813ec267af49b0a22ba7a633b96c1bb", + "support" + ], + "css/css-values/resources/ChTestZeroWidthZero.woff": [ + "9c34dda475fd2f753447238d1f69fd66ba274fb6", + "support" + ], + "css/css-values/resources/ExTest.woff": [ + "31312cb801acb9c28abe7647218f18546bff392e", + "support" + ], "css/css-values/rgba-011.html": [ "84c317033063b72716e36cfd15466780e010ba11", "testharness" @@ -437946,7 +438953,7 @@ "support" ], "feature-policy/reporting/fullscreen-reporting.html": [ - "0153647d3a65425d606b6a8be9ba440272bdb1cc", + "3ac1ef40ccef608af92f489b0218228933af664e", "testharness" ], "feature-policy/reporting/fullscreen-reporting.html.headers": [ @@ -449661,6 +450668,14 @@ "f9c414c246d1f89e697536f458e08ae33359e457", "support" ], + "html/rendering/non-replaced-elements/form-controls/button-style-expected.txt": [ + "4d6a202a4574857a62ecae237b6cf20c1a1dcdec", + "support" + ], + "html/rendering/non-replaced-elements/form-controls/button-style.html": [ + "2d23b4a77d716b5a4545aa180f4ddbddbbb52098", + "testharness" + ], "html/rendering/non-replaced-elements/lists/OWNERS": [ "9b2e5be0a19c48f73b57fe0ad8bbeea81238a1d1", "support" @@ -450509,6 +451524,10 @@ "896c7363113ca8872208059bbac51f7616b05f3f", "testharness" ], + "html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-replaced-box-while-loading.html": [ + "48bbd36db9a39f353d77a9d3ca9ba9e7eed54abf", + "testharness" + ], "html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img_border-ref.xhtml": [ "0050c542cde7b176d0332af8da4687592b9fe3c3", "support" @@ -450693,6 +451712,62 @@ "1f09e7e75f9126982a07902ae0693f9ea2fd5823", "support" ], + "html/rendering/widgets/button-layout/abspos.html": [ + "c3089b1e39749e003fcadd7d822a8343575be212", + "testharness" + ], + "html/rendering/widgets/button-layout/anonymous-button-content-box-ref.html": [ + "243f0add0deb144ff4fc9d7c822c7b283aef9dba", + "support" + ], + "html/rendering/widgets/button-layout/anonymous-button-content-box.html": [ + "07c7b8e366f076996d3d1d5e49a54c4d8f96f800", + "reftest" + ], + "html/rendering/widgets/button-layout/computed-style-expected.txt": [ + "8135c007bcff630d04e1f8d2c26d169dabd1e100", + "support" + ], + "html/rendering/widgets/button-layout/computed-style.html": [ + "696b551bae37c54a4e2466659e3840e4b4e67982", + "testharness" + ], + "html/rendering/widgets/button-layout/display-other-expected.txt": [ + "8b5aeae1b3425002bf2a6394324ec7e48af5f100", + "support" + ], + "html/rendering/widgets/button-layout/display-other.html": [ + "6ed3f5894a75d51da3850077140064a62bfcb263", + "testharness" + ], + "html/rendering/widgets/button-layout/flex.html": [ + "ce845eb2b49854c88075f11e0a62b07bbaea01c8", + "testharness" + ], + "html/rendering/widgets/button-layout/grid.html": [ + "7c2a46709934eef03de96bf1320fb60742d31615", + "testharness" + ], + "html/rendering/widgets/button-layout/inline-level-ref.html": [ + "3784cc30dbee61cae594c92e59883c18142336ba", + "support" + ], + "html/rendering/widgets/button-layout/inline-level.html": [ + "e23aba731ce2ff58a0e0ca173cce97ac2d9f70de", + "reftest" + ], + "html/rendering/widgets/button-layout/propagate-text-decoration-ref.html": [ + "f33a011a2040e3752c225e05f9bef4f58a7f607e", + "support" + ], + "html/rendering/widgets/button-layout/propagate-text-decoration.html": [ + "9bdbbef0c274fd09e25722c04edeb0cb40693d67", + "reftest" + ], + "html/rendering/widgets/button-layout/shrink-wrap.html": [ + "6d61102608c0dfdc9a7ff13b8fba99bd14dd7b05", + "testharness" + ], "html/resources/common.js": [ "273f3a47be6707f3722922e34bcb272889636003", "support" @@ -461493,8 +462568,16 @@ "472b33f7764bde6e2aea7bc2ccd8bf3739babad2", "support" ], - "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini": [ - "1ab2d770afef92b0af4eaf9153ce5344bbbdc964", + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini": [ + "0ebde2f4a62f4df54dd5639904df0478b457e56b", + "support" + ], + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini": [ + "70c0446b5dc9a41dd692b131453ef8931fe5165a", + "support" + ], + "infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini": [ + "1859d256800414818d55117ab8e05d19cdb819e0", "support" ], "infrastructure/metadata/infrastructure/reftest/reftest_match_fail.html.ini": [ @@ -461633,12 +462716,20 @@ "c8e548c462255638a32c474a177759ff6d7cceaf", "reftest_node" ], - "infrastructure/reftest/reftest_fuzzy.html": [ + "infrastructure/reftest/reftest_fuzzy_1.html": [ + "1930fe0ae8fb1aee30e91e691fe6a73ccfc87d0e", + "reftest" + ], + "infrastructure/reftest/reftest_fuzzy_ini_full.html": [ "7429025798151b620dd72db71a46070aafe6c070", "reftest" ], - "infrastructure/reftest/reftest_fuzzy_1.html": [ - "1930fe0ae8fb1aee30e91e691fe6a73ccfc87d0e", + "infrastructure/reftest/reftest_fuzzy_ini_ref_only.html": [ + "7429025798151b620dd72db71a46070aafe6c070", + "reftest" + ], + "infrastructure/reftest/reftest_fuzzy_ini_short.html": [ + "7429025798151b620dd72db71a46070aafe6c070", "reftest" ], "infrastructure/reftest/reftest_fuzzy_no_differences.html": [ @@ -464638,7 +465729,7 @@ "support" ], "mediacapture-streams/MediaDevices-SecureContext.html": [ - "d0fc70ca0e84d4f02970b1fa81d649b96116c1c4", + "e6e8587cdd11f6da78c3a1605dc13ddd5e80f803", "testharness" ], "mediacapture-streams/MediaDevices-enumerateDevices.https.html": [ @@ -487165,6 +488256,14 @@ "6ddccc66f225d4b6b2a1362e5e0c06a3ddf622d0", "testharness" ], + "selection/script-and-style-elements-expected.txt": [ + "4e31b6467fa008cf9ede770d3d82b8a7f6fb5639", + "support" + ], + "selection/script-and-style-elements.html": [ + "b75665917d89f8f606f71c8abb02574df2e879a2", + "testharness" + ], "selection/selectAllChildren.html": [ "65a4ff3c6c58768b259bb637a52ef28c91c5c313", "testharness" @@ -499066,7 +500165,7 @@ "support" ], "tools/wpt/browser.py": [ - "66ad8b50e8c00cce6aa49c28ec8dbfa07a2db31e", + "f617fc3252b13b7fba3d24619ece65e2c51f0a4e", "support" ], "tools/wpt/commands.json": [ @@ -499094,7 +500193,7 @@ "support" ], "tools/wpt/run.py": [ - "c0cfa58950edfdf8a814624b5e0a232c995cdd0f", + "98bcc2111ec45161c907581a4455730e98e33cfa", "support" ], "tools/wpt/testfiles.py": [ @@ -499149,6 +500248,10 @@ "1bf6ef32ad473a716cc969d06f147e5e827ade35", "support" ], + "tools/wptrunner/requirements_edge_chromium.txt": [ + "70c12443243e6655d9772cde3fdaa20ab6023bf7", + "support" + ], "tools/wptrunner/requirements_epiphany.txt": [ "9115b7ac4e8f6a6e4703a7b61d2715075e2f6053", "support" @@ -499198,7 +500301,7 @@ "support" ], "tools/wptrunner/wptrunner/browsers/__init__.py": [ - "fdedda44d28dcdd079b059864d9fafc992eff8c0", + "a98604fe908a6c75e8cdec41471dda40bb7a573c", "support" ], "tools/wptrunner/wptrunner/browsers/base.py": [ @@ -499221,6 +500324,10 @@ "c2545de46f0b5def00c273ecfb5a57f0d4029531", "support" ], + "tools/wptrunner/wptrunner/browsers/edgechromium.py": [ + "5c51f066f0441321660cab96f6de51af868d310b", + "support" + ], "tools/wptrunner/wptrunner/browsers/epiphany.py": [ "599ec9f3110f89f5d64effe98130ede930f1fb7c", "support" @@ -499285,6 +500392,10 @@ "bd6553fadcb16db177e522a0e60c82e8c55bca03", "support" ], + "tools/wptrunner/wptrunner/executors/executoredgechromium.py": [ + "33ebe197e717de94c3931d3f09856972446d76ec", + "support" + ], "tools/wptrunner/wptrunner/executors/executorinternetexplorer.py": [ "898ff144593877c3be33a33be567816e869dcf3e", "support" @@ -499478,7 +500589,7 @@ "support" ], "tools/wptrunner/wptrunner/webdriver_server.py": [ - "4ec415ce78bb89a82d5f098b1c4e8560e7ec39e4", + "d8d9f339f2c3aa72be0c443409ffe80bf1e00c3f", "support" ], "tools/wptrunner/wptrunner/wptcommandline.py": [ @@ -499546,7 +500657,7 @@ "support" ], "tools/wptrunner/wptrunner/wpttest.py": [ - "0a17fd486123f8eb3be3becff9318c23d675c5e1", + "b2c4490bffa3a89a44b45d0edd155422ad447770", "support" ], "tools/wptserve/LICENSE": [ @@ -502601,8 +503712,12 @@ "a8b5a7154e94479460c1085c6b5cb584e9b6976c", "testharness" ], + "webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel-expected.txt": [ + "85e66d4dea10fca57cb5db88bda887a40502a586", + "support" + ], "webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html": [ - "e0359953d2e909f69066885515f4a3f3cc00ff02", + "a1a5f3fce54e11e33580ec875909e4e1645cf713", "testharness" ], "webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-getChannelData.html": [ @@ -505082,7 +506197,7 @@ "testharness" ], "webrtc/RTCDTMFSender-helper.js": [ - "84cc771dda283da81a0568fe58ad52a77a262347", + "87f7ae13c7e21cccc11e3810df6cf705e3cee68b", "support" ], "webrtc/RTCDTMFSender-insertDTMF.https-expected.txt": [ @@ -505306,7 +506421,7 @@ "testharness" ], "webrtc/RTCPeerConnection-remote-track-mute.https.html": [ - "c4c6b4fd0410dd45e99d8ae313ede42ae7593e49", + "9f220157d19a0b050c595bb27a630e0d06691db3", "testharness" ], "webrtc/RTCPeerConnection-removeTrack.https-expected.txt": [ @@ -505582,7 +506697,7 @@ "testharness" ], "webrtc/RTCTrackEvent-fire.html": [ - "eca8644120e86c99f01cfbaf27a1b33847b975bb", + "4c65daaba86f6d8ff56e1c30957e445d4e3713b8", "testharness" ], "webrtc/coverage/RTCDTMFSender.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-004.svg b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-004.svg new file mode 100644 index 0000000..2317842 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path-svg-content/clip-path-content-clip-004.svg
@@ -0,0 +1,29 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>CSS Masking: clip-path applied to an element in a clipPath with objectBoundingBox units</title> + <html:link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-clipping-paths"/> + <html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#ClipPathElement"/> + <html:link rel="match" href="reference/clip-path-content-clip-004-ref.svg" /> + <metadata class="flags">svg</metadata> + <desc class="assert"> + When a clipPath establishes a coordinate system using objectBoundingBox + units, any other clipPath referenced through the clip-path property on + the first clipPath's children must use that same coordinate system if + it is using userSpaceOnUse units. + </desc> + </g> + <defs> + <clipPath id="inner"> + <rect width="0.25" height="0.25"/> + </clipPath> + <clipPath id="outer" clipPathUnits="objectBoundingBox"> + <rect width="0.5" height="0.5" clip-path="url(#inner)"/> + </clipPath> + </defs> + <rect width="100" height="100" fill="red"/> + <g clip-path="url(#outer)"> + <rect width="400" height="400" fill="red"/> + <rect width="100" height="100" fill="green"/> + </g> +</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-content-clip-004-ref.svg b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-content-clip-004-ref.svg new file mode 100644 index 0000000..269d289 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path-svg-content/reference/clip-path-content-clip-004-ref.svg
@@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> + <g id="testmeta"> + <title>CSS Reference</title> + <html:link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"/> + <metadata class="flags">svg</metadata> + </g> + <rect width="100" height="100" fill="green"/> +</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-001-ref.html new file mode 100644 index 0000000..16c86366 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-001-ref.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <title>CSS Multi-column Layout Test: Test a multi-column container on fieldset works with a column-span:all child</title> + <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="http://www.mozilla.org/"> + + <style> + fieldset { + width: 400px; + } + .inner { + column-count: 3; + column-rule: 6px solid; + } + h3 { + column-span: all; + outline: 1px solid blue; + } + </style> + + <fieldset> + <legend>Legend</legend> + <div class="inner"> + <div>block1</div><div>block2</div> + <h3>spanner</h3> + <div>block3</div><div>block4</div> + </div> + </fieldset> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html new file mode 100644 index 0000000..f1bced0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <title>CSS Multi-column Layout Test: Test a multi-column container on fieldset works with a column-span:all child</title> + <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="http://www.mozilla.org/"> + <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span"> + <link rel="match" href="multicol-span-all-fieldset-001-ref.html"> + <meta name="assert" content="This test checks the page is rendered correctly for a simple fieldset multi-column container with a column-span:all child."> + + <style> + fieldset { + column-count: 3; + column-rule: 6px solid; + width: 400px; + } + h3 { + column-span: all; + outline: 1px solid blue; + } + </style> + + <fieldset> + <legend>Legend</legend> + <div>block1</div><div>block2</div> + <h3>spanner</h3> + <div>block3</div><div>block4</div> + </fieldset> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-002-ref.html new file mode 100644 index 0000000..d2f86b5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-002-ref.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on fieldset works with a column-span:all child and position:absolute boxes</title> + <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="http://www.mozilla.org/"> + + <style> + fieldset { + width: 400px; + overflow: hidden; + position: absolute; + } + .inner { + column-count: 3; + column-rule: 6px solid; + } + h3 { + column-span: all; + outline: 1px solid blue; + } + a { + position: absolute; + width: 1em; + height: 1em; + background-color: blue; + } + </style> + + <fieldset> + <legend>Legend<a></a></legend> + <div class="inner"> + <div>block1</div><div>block2</div><a></a> + <h3>spanner<a></a></h3> + <div>block3</div><div>block4</div><a></a> + </div> + </fieldset> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html new file mode 100644 index 0000000..2c7e47c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on fieldset works with a column-span:all child and position:absolute boxes</title> + <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="http://www.mozilla.org/"> + <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span"> + <link rel="match" href="multicol-span-all-fieldset-002-ref.html"> + <meta name="assert" content="This test checks the page is rendered correctly for a overflow:hidden and position:absolute fieldset multi-column container with a column-span:all child and position:absolute boxes."> + + <style> + fieldset { + column-count: 3; + column-rule: 6px solid; + width: 400px; + overflow: hidden; + position: absolute; + } + h3 { + column-span: all; + outline: 1px solid blue; + } + a { + position: absolute; + width: 1em; + height: 1em; + background-color: blue; + } + </style> + + <fieldset> + <legend>Legend<a></a></legend> + <div>block1</div><div>block2</div><a></a> + <h3>spanner<a></a></h3> + <div>block3</div><div>block4</div><a></a> + </fieldset> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-003-ref.html new file mode 100644 index 0000000..6201818 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-003-ref.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on fieldset works with a column-span:all child and position:fixed boxes</title> + <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="http://www.mozilla.org/"> + + <style> + fieldset { + width: 400px; + overflow: hidden; + position: absolute; + } + .inner { + column-count: 3; + column-rule: 6px solid; + } + h3 { + column-span: all; + outline: 1px solid blue; + } + a { + position: fixed; + width: 1em; + height: 1em; + background-color: blue; + } + </style> + + <fieldset> + <legend>Legend<a></a></legend> + <div class="inner"> + <div>block1</div><div>block2</div><a></a> + <h3>spanner<a></a></h3> + <div>block3</div><div>block4</div><a></a> + </div> + </fieldset> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html new file mode 100644 index 0000000..d3ca8a4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<html> + <meta charset="utf-8"> + <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on fieldset works with a column-span:all child and position:fixed boxes</title> + <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="http://www.mozilla.org/"> + <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span"> + <link rel="match" href="multicol-span-all-fieldset-003-ref.html"> + <meta name="assert" content="This test checks the page is rendered correctly for a overflow:hidden and position:absolute fieldset multi-column container with a column-span:all child and position:absolute boxes."> + + <style> + fieldset { + column-count: 3; + column-rule: 6px solid; + width: 400px; + overflow: hidden; + position: absolute; + } + h3 { + column-span: all; + outline: 1px solid blue; + } + a { + position: fixed; + width: 1em; + height: 1em; + background-color: blue; + } + </style> + + <fieldset> + <legend>Legend<a></a></legend> + <div>block1</div><div>block2</div><a></a> + <h3>spanner<a></a></h3> + <div>block3</div><div>block4</div><a></a> + </fieldset> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001-ref.html new file mode 100644 index 0000000..e2c2daa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001-ref.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001.html new file mode 100644 index 0000000..5e5bfe1c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-001-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li::marker { + content: "1.\00a0"; +} +li:nth-of-type(2)::marker { + content: "2.\00a0"; +} +li:nth-child(3)::marker { + content: "3.\00a0"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001b.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001b.html new file mode 100644 index 0000000..6ab87a3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001b.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-001-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li::marker { + content: "1.\00a0"; + display: block; +} +li:nth-of-type(2)::marker { + content: "2.\00a0"; +} +li:nth-child(3)::marker { + content: "3.\00a0"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001c.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001c.html new file mode 100644 index 0000000..0a32b2a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-001c.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-001-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li::marker { + content: "1.\00a0"; + display: block; + margin: 0 auto 0 auto; +} +li:nth-of-type(2)::marker { + content: "2.\00a0"; +} +li:nth-child(3)::marker { + content: "3.\00a0"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-002-ref.html new file mode 100644 index 0000000..5886f421 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-002-ref.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li style="list-style-type:'a1b'"></li><li style="list-style-type:'a2b'">B</li><li style="list-style-type:'a3b'"><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-002.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-002.html new file mode 100644 index 0000000..4c46c4b0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-002.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-002-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li::marker { + content: "a" counters(list-item, ".") "b"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003-ref.html new file mode 100644 index 0000000..5214d853 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003-ref.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property and display:grid</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +li { + list-style-type: 'X'; + background: grey; +} +li::marker { + padding-right: 10px; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003.html new file mode 100644 index 0000000..b4a41ce --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property and display:grid</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-003-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li::marker { + content: "X"; + display: grid; + grid-template-columns: auto 10px; +} +li { background: grey; } +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003b.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003b.html new file mode 100644 index 0000000..da7a272 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-003b.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property and display:inline-grid</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-003-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li::marker { + content: "X"; + display: inline-grid; + grid-template-columns: auto 10px; +} +li { background: grey; } +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-004-ref.html new file mode 100644 index 0000000..3d706d9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-004-ref.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property and display:flex</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +body { margin-left: 100px; } +li { + list-style-type: 'FAIL'; + background: grey; +} +li::marker { + content: "X"; + display: block; + width: 100px; + text-align: start; + background: lime; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-004.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-004.html new file mode 100644 index 0000000..24dbaae1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-004.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property and display:flex</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-004-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +body { margin-left: 100px; } +li { background: grey; } +li::marker { + content: "X"; + display: flex; + width: 100px; + align-content: start; + background: lime; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-005-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-005-ref.html new file mode 100644 index 0000000..46e77dd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-005-ref.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li style="list-style-type:'105'"><li style="list-style-type:'210'">B<li style="list-style-type:'315'"><span>C</span></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-005.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-005.html new file mode 100644 index 0000000..ad37a65 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-005.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-005-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li { + counter-increment: foo 5; +} +li::marker { + content: counters(list-item, ".") counter(foo, decimal-leading-zero); +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-006-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-006-ref.html new file mode 100644 index 0000000..f258c88 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-006-ref.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +li { + list-style-position: inside; + list-style-type: none; +} +li::before { + content: "ab"; +} +li::after { + content: "d"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li>c</li><li>cB</li><li>c<span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-006.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-006.html new file mode 100644 index 0000000..bf941ef --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-006.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-006-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li { + list-style-position: inside; +} +li::marker { + content: "a" "b"; +} +li::before { + content: "c"; +} +li::after { + content: "d"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-007-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-007-ref.html new file mode 100644 index 0000000..8cec2799 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-007-ref.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property and display:inline-grid</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +li { + list-style-position: inside; + list-style-type: none; +} +li::before { + content: "ab"; + display: inline-block; + width: 50px; + text-align: right; + padding-right: 60px; +} +li::after { + content: "d"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li>c</li><li>cB</li><li>c<span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-007.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-007.html new file mode 100644 index 0000000..fb45266 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-007.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property and display:inline-grid</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-007-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li { + list-style-position: inside; +} +li::marker { + content: "a" "b"; + display: inline-grid; + grid-template-columns: 50px 60px; +} +li::before { + content: "c"; +} +li::after { + content: "d"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-008-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-008-ref.html new file mode 100644 index 0000000..6d5052b3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-008-ref.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +li { list-style-type: "ab"; } +#t1 > li { list-style-type: "ab"; } +#t2 > li { list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAIAAAD3UuoiAAAAGklEQVQoz2Nk%2BP%2BfgRqAiYFKYNSgUYOGp0EA%2BQMCFrJdTgsAAAAASUVORK5CYII%3D); } +li::after { + content: "d"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol id="t1"><li>c</li><li>cB</li><li>c<span>C</span></li></ol> +<ol id="t2"><li>c</li><li>cB</li><li>c<span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-008.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-008.html new file mode 100644 index 0000000..88aee13 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-008.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'content' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-content-008-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<style> +li { + list-style-position: outside; +} +#t1 > li::marker { content: "a" "b"; } +#t2 > li::marker { content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAIAAAD3UuoiAAAAGklEQVQoz2Nk%2BP%2BfgRqAiYFKYNSgUYOGp0EA%2BQMCFrJdTgsAAAAASUVORK5CYII%3D); padding-inline-end: calc(1em / 2); } +li::before { + content: "c"; +} +li::after { + content: "d"; +} +span { font-size: 32pt; } +</style> +</head> +<body> +<ol id="t1"><li></li><li>B</li><li><span>C</span></li></ol> +<ol id="t2"><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-list-style-position-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-list-style-position-ref.html new file mode 100644 index 0000000..2593194 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-list-style-position-ref.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Reference: ::marker pseudo elements styled with 'list-style-position' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<style> +body { color: black; background: white; } +#t1 > li { list-style-position: inside; } +#t2 > li { list-style-position: outside; } +#t3 > li { list-style-position: inside; } +#t4 > li { list-style-position: inside; } + +#t1, #t2, #t3, blue { color: blue; } +black { color: black; } + +span { font-size: 32pt; } +</style> +</head> +<body> +<ol id="t1"><li></li><li><black>B</black></li><li><span><black>C</black></span></li></ol> +<ol id="t2"><li></li><li><black>B</black></li><li><span><black>C</black></span></li></ol> +<ol id="t3"><li></li><li>B</li><li><span>C</span></li></ol> +<ol id="t4"><li></li><li><blue>B</blue></li><li><span><blue>C</blue></span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-list-style-position.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-list-style-position.html new file mode 100644 index 0000000..5b4391d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-list-style-position.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Test: ::marker pseudo elements styled with 'list-style-position' property</title> +<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com"> +<link rel="match" href="marker-list-style-position-ref.html"> +<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo"> +<meta name="assert" content="It's the list-style-position on the list item element that decides where its ::marker is placed, not the value on the ::marker itself."> +<style> +body { color: black; background: white; } +#t1 > li { list-style-position: inside; } +#t1 li::marker { list-style-position: outside; color: blue; } + +#t2 > li { list-style-position: outside; } +#t2 li::marker { list-style-position: inside; color: blue; } + +#t3 > li { list-style-position: inside; } +#t3 > li::first-line { list-style-position: outside; color: blue; } +#t3 li::marker { list-style-position: outside; } + +#t4 > li { list-style-position: inside; } +#t4 > li::first-letter { list-style-position: outside; color: blue; } +#t4 li::marker { list-style-position: outside; } + +span { font-size: 32pt; } +</style> +</head> +<body> +<ol id="t1"><li></li><li>B</li><li><span>C</span></li></ol> +<ol id="t2"><li></li><li>B</li><li><span>C</span></li></ol> +<ol id="t3"><li></li><li>B</li><li><span>C</span></li></ol> +<ol id="t4"><li></li><li>B</li><li><span>C</span></li></ol> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-013.html b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-013.html new file mode 100644 index 0000000..c5782f1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-013.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ch unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ch-unit-013-ref.html"> +<meta name="assert" content="When a zero glyph is not present, in horizontal writing modes the ch unit falls back to 0.5em."> +<style> +@font-face { + font-family: ChTestNoZero; + src: url(resources/ChTestNoZero.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + width: 5ch; +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- ChTestNoZero has no '0' glyph, so ch units should compute to 0.5em, + resulting in the div being 100px wide. --> +<div class="test" style="font: 40px ChTestNoZero;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-014.html b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-014.html new file mode 100644 index 0000000..a8a04c8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-014.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ch unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ch-unit-013-ref.html"> +<meta name="assert" content="When a zero glyph is not present, in vertical mixed writing modes the ch unit falls back to 0.5em."> +<style> +@font-face { + font-family: ChTestNoZero; + src: url(resources/ChTestNoZero.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + writing-mode: vertical-rl; + width: 5ch; +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- ChTestNoZero has no '0' glyph, so ch units should compute to 0.5em, + resulting in the div being 100px wide. --> +<div class="test" style="font: 40px ChTestNoZero;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-015.html b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-015.html new file mode 100644 index 0000000..e098e3f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-015.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ch unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ch-unit-013-ref.html"> +<meta name="assert" content="When a zero glyph is not present, in vertical upright writing modes the ch unit falls back to 1em."> +<style> +@font-face { + font-family: ChTestNoZero; + src: url(resources/ChTestNoZero.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + writing-mode: vertical-rl; + text-orientation: upright; + width: 5ch; +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- ChTestNoZero has no '0' glyph, and we have a vertical writing mode + with upright glyphs, so ch units should compute to 1em, resulting in + the div being 100px wide. --> +<div class="test" style="font: 20px ChTestNoZero;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-016.html b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-016.html new file mode 100644 index 0000000..1a61e15 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-016.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ch unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ch-unit-013-ref.html"> +<meta name="assert" content="The ch unit is equal to 0em if the zero glyph's advance is 0."> +<style> +@font-face { + font-family: ChTestZeroWidthZero; + src: url(resources/ChTestZeroWidthZero.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + width: calc(100px + 5ch); +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- The '0' glyph in ChTestZeroWidthZero has a horizontal advance of + zero, so ch units should compute to 0em, resulting in the div being + 100px wide. --> +<div class="test" style="font: 20px ChTestZeroWidthZero;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-017.html b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-017.html new file mode 100644 index 0000000..a52c9785 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-017.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ch unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ch-unit-013-ref.html"> +<meta name="assert" content="In vertical upright writing modes, the ch unit is equal to the vertical advance of the zero glyph."> +<style> +@font-face { + font-family: ChTestShortZero; + src: url(resources/ChTestShortZero.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + writing-mode: vertical-rl; + text-orientation: upright; + width: 5ch; +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- ChTestShortZero has a '0' glyph whose vertical advance is a quarter + of the units per em, so ch units in vertical upright writing modes + should compute to 0.25em, resulting in the div being 100px width. --> +<div class="test" style="font: 80px ChTestShortZero;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-018.html b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-018.html new file mode 100644 index 0000000..fee5e92 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ch-unit-018.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ch unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ch-unit-013-ref.html"> +<meta name="assert" content="When a zero glyph is not present, in horizontal writing modes and with text-orientation set to upright, the ch unit falls back to 0.5em."> +<style> +@font-face { + font-family: ChTestNoZero; + src: url(resources/ChTestNoZero.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + text-orientation: upright; + width: 5ch; +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- ChTestNoZero has no '0' glyph, so ch units should compute to 0.5em, + resulting in the div being 100px wide. --> +<div class="test" style="font: 40px ChTestNoZero;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-001.html b/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-001.html new file mode 100644 index 0000000..ad296b4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-001.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: ex unit computation and dependencies</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Mozilla" href="https://mozilla.org"> +<link rel="help" href="https://drafts.csswg.org/css-values/#font-relative-lengths"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1529537"> +<link rel="match" href="reference/ex-unit-001-ref.html"> +<meta name="flags" content="ahem"> +<style> + @font-face { + font-family: foo; + src: local(Ahem); + } + + @font-face { + font-family: foo; + font-weight: 900; + /* It doesn't really matter if Arial is not found, as + long as we fall-back to a font with different metrics + than Ahem */ + src: local(Arial); + } + + div { + font-family: foo, sans-serif; + width: 10ex; + height: 20px; + background: blue; + margin: 20px; + font-size: 20px; + } +</style> +<p>All lines except the first should be the same length</p> +<div></div> +<div style="font-weight: 900"></div> +<div style="font-weight: 900; width: 10ex;"></div> +<section style="font-weight: 900"><div></div></section>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-002.html b/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-002.html new file mode 100644 index 0000000..a0293cf4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-002.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ex unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ex-unit-002-ref.html"> +<meta name="assert" content="The ex unit equals the x-height of the first available font if it has reliable metrics for the x-height."> +<style> +@font-face { + font-family: ExTest; + src: url(resources/ExTest.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + width: 10ex; +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- ExTest is a font whose OS/2 table's sxHeight field is set to an + eighth of the font's units per em, so ex units should compute to + 0.125em, resulting in the div being 100px wide. --> +<div class="test" style="font: 80px ExTest;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-003.html b/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-003.html new file mode 100644 index 0000000..67bb0c6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/ex-unit-003.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test: support for the ex unit</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<link rel="help" href="https://drafts.csswg.org/css-values-3/#font-relative-lengths"> +<link rel="match" href="reference/ex-unit-002-ref.html"> +<meta name="assert" content="Even in vertical writing modes, the ex unit equals the x-height of the first available font if it has reliable metrics for the x-height."> +<style> +@font-face { + font-family: ExTest; + src: url(resources/ExTest.woff); +} +div { + height: 10px; + background-color: blue; + margin-top: 10px; +} +.test { + writing-mode: vertical-rl; + width: 10ex; +} +.ref { + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<!-- ExTest is a font whose OS/2 table's sxHeight field is set to an + eighth of the font's units per em, so ex units should compute to + 0.125em, resulting in the div being 100px wide. --> +<div class="test" style="font: 80px ExTest;"></div> +<div class="ref"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/reference/ch-unit-013-ref.html b/third_party/blink/web_tests/external/wpt/css/css-values/reference/ch-unit-013-ref.html new file mode 100644 index 0000000..74e304b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/reference/ch-unit-013-ref.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test Reference File</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<style> +div { + height: 10px; + background-color: blue; + margin-top: 10px; + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<div></div> +<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/reference/ex-unit-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-values/reference/ex-unit-001-ref.html new file mode 100644 index 0000000..11a06e7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/reference/ex-unit-001-ref.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Test Reference</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<meta name="flags" content="ahem"> +<style> + div { + font-family: Arial, sans-serif; + font-weight: 900; + width: 10ex; + height: 20px; + background: blue; + margin: 20px; + font-size: 20px; + } +</style> +<p>All lines except the first should be the same length</p> +<div style="font-family: Ahem; font-weight: normal;"></div> +<div></div> +<div></div> +<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/reference/ex-unit-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-values/reference/ex-unit-002-ref.html new file mode 100644 index 0000000..74e304b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/reference/ex-unit-002-ref.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Values and Units Test Reference File</title> +<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au"> +<style> +div { + height: 10px; + background-color: blue; + margin-top: 10px; + width: 100px; +} +</style> +<p>The test passes if there are two blue rectangles of equal length.</p> +<div></div> +<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestNoZero.woff b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestNoZero.woff new file mode 100644 index 0000000..b873b48 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestNoZero.woff Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestShortZero.woff b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestShortZero.woff new file mode 100644 index 0000000..c7e7cc5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestShortZero.woff Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestZeroWidthZero.woff b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestZeroWidthZero.woff new file mode 100644 index 0000000..9c34dda --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ChTestZeroWidthZero.woff Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/resources/ExTest.woff b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ExTest.woff new file mode 100644 index 0000000..31312cb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-values/resources/ExTest.woff Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-zero-size-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-zero-size-ref.html new file mode 100644 index 0000000..05383cd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-zero-size-ref.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>backdrop-filter: Zero-size div with backdrop filter shouldn't filter anything</title> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> + + + +<p>Expected: A single green box.</p> +<div></div> + + + + +<style> +div { + position: absolute; + width: 100px; + height: 100px; + background: green; + left: 10px; + top: 100px; +} +</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-zero-size.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-zero-size.html new file mode 100644 index 0000000..bcefe042 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-zero-size.html
@@ -0,0 +1,37 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>backdrop-filter: Zero-size div with backdrop filter shouldn't filter anything</title> +<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org"> +<link rel="help" href="https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty"> +<link rel="match" href="backdrop-filter-zero-size-ref.html"> + +<p>Expected: A single green box.</p> +<div class="colorbox"></div> +<div class="filterparent"> + <div class="filterchild"></div> +</div> + +<style> +div { + position: absolute; + width: 100px; + height: 100px; +} +.colorbox { + background: green; + left: 10px; + top: 100px; +} +.filterparent { + width: 0px; + height: 0px; + left: 50px; + top: 150px; + backdrop-filter: invert(1); + background: lime; +} +.filterchild { + top: 100px; + background: #FFFFFF00; +} +</style>
diff --git a/third_party/blink/web_tests/external/wpt/editing/run/first-letter-crossing-engine-boundary-crash.html b/third_party/blink/web_tests/external/wpt/editing/run/first-letter-crossing-engine-boundary-crash.html new file mode 100644 index 0000000..be6325f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/editing/run/first-letter-crossing-engine-boundary-crash.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org"> +<link rel="help" href="http://crbug.com/962090"> +<style> + #container::first-letter { background:blue; } +</style> +<div id="container"> + <div id="edit" style="overflow:hidden;" contenteditable>xx</div> + <div id="elm" style="display:none;">PASS</div> +</div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + document.body.offsetTop; + elm.style.display = "initial"; + test(()=>{}, "No crash or DCHECK failure"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/fullscreen-reporting.html b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/fullscreen-reporting.html index 0153647..3ac1ef4 100644 --- a/third_party/blink/web_tests/external/wpt/feature-policy/reporting/fullscreen-reporting.html +++ b/third_party/blink/web_tests/external/wpt/feature-policy/reporting/fullscreen-reporting.html
@@ -7,7 +7,13 @@ <body> <div id='fs'></div> <script> +var observer1; +var observer2; + var check_report_format = (reports, observer) => { + // Test that observer2 is notified, even if it is disconnected. + observer1.disconnect(); + observer2.disconnect(); let report = reports[0]; assert_equals(report.type, "feature-policy-violation"); assert_equals(report.url, document.location.href); @@ -18,9 +24,19 @@ assert_equals(report.body.disposition, "enforce"); }; +var check_second_observer = (reports, observer) => { + let report = reports[0]; + assert_equals(report.type, "feature-policy-violation"); + assert_equals(report.body.featureId, "fullscreen"); +}; + async_test(t => { - new ReportingObserver(t.step_func_done(check_report_format), - {types: ['feature-policy-violation']}).observe(); + observer1 = new ReportingObserver(t.step_func(check_report_format), + {types: ['feature-policy-violation']}); + observer1.observe(); + observer2 = new ReportingObserver(t.step_func_done(check_second_observer), + {types: ['feature-policy-violation']}); + observer2.observe(); document.getElementById('fs').requestFullscreen().then(t.unreached_func( "Fullscreen should not be allowed in this document.")).catch(()=>{}); }, "Fullscreen Report Format");
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/button-style-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/button-style-expected.txt new file mode 100644 index 0000000..4d6a202 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/button-style-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS default display on <input type="reset"> +PASS default box-sizing on <input type="reset"> +PASS default display on <input type="button"> +PASS default box-sizing on <input type="button"> +PASS default display on <input type="submit"> +PASS default box-sizing on <input type="submit"> +PASS default display on <input type="color"> +FAIL default box-sizing on <input type="color"> assert_equals: expected "border-box" but got "content-box" +PASS default display on <button></button> +PASS default box-sizing on <button></button> +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/button-style.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/button-style.html new file mode 100644 index 0000000..2d23b4a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/form-controls/button-style.html
@@ -0,0 +1,20 @@ +<!doctype html> +<title>default style on buttons</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div class="tests"> + <input type="reset"> + <input type="button"> + <input type="submit"> + <input type="color"> + <button></button> +</div> +<script> +[].slice.call(document.querySelectorAll('.tests > *')).forEach(el => { + test(() => { + assert_equals(getComputedStyle(el).display, 'inline-block'); + }, `default display on ${el.outerHTML}`); + test(() => { + assert_equals(getComputedStyle(el).boxSizing, 'border-box'); + }, `default box-sizing on ${el.outerHTML}`);}) +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-replaced-box-while-loading.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-replaced-box-while-loading.html new file mode 100644 index 0000000..48bbd36 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/img-replaced-box-while-loading.html
@@ -0,0 +1,29 @@ +<!doctype html> +<title>Images don't render as a non-replaced inline while loading, even when there's no concrete size specified</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="author" href="https://mozilla.org" title="Mozilla"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1472637"> +<style> + img { + min-width: 1000px; + } +</style> +<img alt="T"> +<script> +// Do an async test off the onload handler to avoid waiting for the load even for too long unnecessarily. +let t = async_test("Loading images should get a replaced box, even without specified size"); +onload = t.step_func(function() { + const image = document.querySelector("img"); + // Use the trickle pipe to have 100 seconds until the image actually loads, + // that should be enough to run the test. + image.src = "../../../../../images/blue.png?pipe=trickle(d100)"; + t.step_timeout(t.step_func_done(function() { + assert_equals( + image.offsetWidth, + 1000, + ); + }), 0); +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/abspos.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/abspos.html new file mode 100644 index 0000000..c3089b1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/abspos.html
@@ -0,0 +1,31 @@ +<!doctype html> +<title>abspos button with auto width, non-auto left/right</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<link rel=help href=https://html.spec.whatwg.org/multipage/rendering.html#button-layout> +<!-- +If the element is absolutely positioned, then for the purpose of the CSS visual formatting model, act as if the element is a replaced element. [CSS] +--> +<link rel=help href=https://drafts.csswg.org/css2/visudet.html#abs-replaced-width> +<!-- +If at this point the values are over-constrained, ignore the value for either 'left' (in case the 'direction' property of the containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that value. +--> +<style> +#overconstrained { position: absolute; left: 100px; right: 100px; } +#ltr { position: absolute; left: 100px; margin-top: 2em } +#rtl { position: absolute; right: 100px; margin-top: 2em } +</style> +<button id=overconstrained>test</button> +<button id=ltr>test</button> +<button id=rtl>test</button> +<script> +for (const dir of ['rtl', 'ltr']) { + test(() => { + document.documentElement.dir = dir; + const overconstrained = document.getElementById('overconstrained'); + const ref = document.getElementById(dir); + assert_equals(overconstrained.offsetLeft, ref.offsetLeft, 'offsetLeft'); + assert_equals(overconstrained.clientWidth, ref.clientWidth, 'clientWidth'); + }, `${document.title} (${dir})`); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box-ref.html new file mode 100644 index 0000000..243f0ad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box-ref.html
@@ -0,0 +1,31 @@ +<!doctype html> +<title>Reference for Anonymous button content box</title> +<style> +body { margin: 0 } +.button { width: 124px; height: 124px; background: papayawhip; border: 2px solid; display: table-cell; vertical-align: middle; text-align: center; box-sizing: border-box; } +.top { vertical-align: top } +.left { text-align: left } +.float { display: block; float: left; } +body > div { clear: left; } +.button > div { width: 50px; height: 50px; border: solid } +.button > .tall { height: 150px } +.button > .wide { width: 150px; margin-top: 32px } +</style> +<div> + <div class=button>input</div> + <div class="button">input grid</div> + <div class="button">input flex</div> + <div class=button>button</div> +</div> +<div> + <div class=button style="text-align: left">button left</div> + <div class=button><div>div</div></div> + <div class="button top">grid</div> + <div class="button top"><div>grid</div></div> +</div> +<div> + <div class="button top left float">flex</div> + <div class="button top float"><div>flex</div></div> + <div class="button float"><div class=tall>tall</div></div> + <div class="button float"><div class=wide>wide</div></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box.html new file mode 100644 index 0000000..07c7b8e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/anonymous-button-content-box.html
@@ -0,0 +1,31 @@ +<!doctype html> +<title>Anonymous button content box</title> +<link rel=match href=anonymous-button-content-box-ref.html> +<style> +body { margin: 0 } +button, input { width: 124px; height: 124px; background: papayawhip; border: 2px solid; margin: 0; padding: 0; float: left; font: inherit } +body > div { clear: left; } +button > div { width: 50px; height: 50px; border: solid } +.grid { display: grid } +.flex { display: flex } +.tall { height: 150px } +.wide { width: 150px } +</style> +<div> + <input type=button value=input> + <input type=button value="input grid" class=grid> + <input type=button value="input flex" class=flex> + <button>button</button> +</div> +<div> + <button style="text-align: left">button left</button> + <button><div>div</div></button> + <button class=grid>grid</button> + <button class=grid><div>grid</div></button> +</div> +<div> + <button class=flex>flex</button> + <button class=flex><div>flex</div></button> + <button><div class=tall>tall</div></button> + <button><div class=wide>wide</div></button> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style-expected.txt new file mode 100644 index 0000000..8135c00 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style-expected.txt
@@ -0,0 +1,139 @@ +This is a testharness.js-based test. +Found 135 tests; 45 PASS, 90 FAIL, 0 TIMEOUT, 0 NOTRUN. +FAIL computed display of <input type=reset> with display: inline assert_equals: expected "inline" but got "inline-block" +FAIL computed display of <input type=button> with display: inline assert_equals: expected "inline" but got "inline-block" +FAIL computed display of <input type=submit> with display: inline assert_equals: expected "inline" but got "inline-block" +FAIL computed display of <input type=color> with display: inline assert_equals: expected "inline" but got "inline-block" +FAIL computed display of <button type=submit> with display: inline assert_equals: expected "inline" but got "inline-block" +PASS computed display of <input type=reset> with display: block +PASS computed display of <input type=button> with display: block +PASS computed display of <input type=submit> with display: block +PASS computed display of <input type=color> with display: block +PASS computed display of <button type=submit> with display: block +FAIL computed display of <input type=reset> with display: list-item assert_equals: expected "list-item" but got "block" +FAIL computed display of <input type=button> with display: list-item assert_equals: expected "list-item" but got "block" +FAIL computed display of <input type=submit> with display: list-item assert_equals: expected "list-item" but got "block" +FAIL computed display of <input type=color> with display: list-item assert_equals: expected "list-item" but got "block" +FAIL computed display of <button type=submit> with display: list-item assert_equals: expected "list-item" but got "block" +PASS computed display of <input type=reset> with display: inline-block +PASS computed display of <input type=button> with display: inline-block +PASS computed display of <input type=submit> with display: inline-block +PASS computed display of <input type=color> with display: inline-block +PASS computed display of <button type=submit> with display: inline-block +FAIL computed display of <input type=reset> with display: table assert_equals: expected "table" but got "block" +FAIL computed display of <input type=button> with display: table assert_equals: expected "table" but got "block" +FAIL computed display of <input type=submit> with display: table assert_equals: expected "table" but got "block" +FAIL computed display of <input type=color> with display: table assert_equals: expected "table" but got "block" +FAIL computed display of <button type=submit> with display: table assert_equals: expected "table" but got "block" +FAIL computed display of <input type=reset> with display: inline-table assert_equals: expected "inline-table" but got "inline-block" +FAIL computed display of <input type=button> with display: inline-table assert_equals: expected "inline-table" but got "inline-block" +FAIL computed display of <input type=submit> with display: inline-table assert_equals: expected "inline-table" but got "inline-block" +FAIL computed display of <input type=color> with display: inline-table assert_equals: expected "inline-table" but got "inline-block" +FAIL computed display of <button type=submit> with display: inline-table assert_equals: expected "inline-table" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-row-group assert_equals: expected "table-row-group" but got "inline-block" +FAIL computed display of <input type=button> with display: table-row-group assert_equals: expected "table-row-group" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-row-group assert_equals: expected "table-row-group" but got "inline-block" +FAIL computed display of <input type=color> with display: table-row-group assert_equals: expected "table-row-group" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-row-group assert_equals: expected "table-row-group" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-header-group assert_equals: expected "table-header-group" but got "inline-block" +FAIL computed display of <input type=button> with display: table-header-group assert_equals: expected "table-header-group" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-header-group assert_equals: expected "table-header-group" but got "inline-block" +FAIL computed display of <input type=color> with display: table-header-group assert_equals: expected "table-header-group" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-header-group assert_equals: expected "table-header-group" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-footer-group assert_equals: expected "table-footer-group" but got "inline-block" +FAIL computed display of <input type=button> with display: table-footer-group assert_equals: expected "table-footer-group" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-footer-group assert_equals: expected "table-footer-group" but got "inline-block" +FAIL computed display of <input type=color> with display: table-footer-group assert_equals: expected "table-footer-group" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-footer-group assert_equals: expected "table-footer-group" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-row assert_equals: expected "table-row" but got "inline-block" +FAIL computed display of <input type=button> with display: table-row assert_equals: expected "table-row" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-row assert_equals: expected "table-row" but got "inline-block" +FAIL computed display of <input type=color> with display: table-row assert_equals: expected "table-row" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-row assert_equals: expected "table-row" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-column-group assert_equals: expected "table-column-group" but got "inline-block" +FAIL computed display of <input type=button> with display: table-column-group assert_equals: expected "table-column-group" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-column-group assert_equals: expected "table-column-group" but got "inline-block" +FAIL computed display of <input type=color> with display: table-column-group assert_equals: expected "table-column-group" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-column-group assert_equals: expected "table-column-group" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-column assert_equals: expected "table-column" but got "inline-block" +FAIL computed display of <input type=button> with display: table-column assert_equals: expected "table-column" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-column assert_equals: expected "table-column" but got "inline-block" +FAIL computed display of <input type=color> with display: table-column assert_equals: expected "table-column" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-column assert_equals: expected "table-column" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-cell assert_equals: expected "table-cell" but got "inline-block" +FAIL computed display of <input type=button> with display: table-cell assert_equals: expected "table-cell" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-cell assert_equals: expected "table-cell" but got "inline-block" +FAIL computed display of <input type=color> with display: table-cell assert_equals: expected "table-cell" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-cell assert_equals: expected "table-cell" but got "inline-block" +FAIL computed display of <input type=reset> with display: table-caption assert_equals: expected "table-caption" but got "inline-block" +FAIL computed display of <input type=button> with display: table-caption assert_equals: expected "table-caption" but got "inline-block" +FAIL computed display of <input type=submit> with display: table-caption assert_equals: expected "table-caption" but got "inline-block" +FAIL computed display of <input type=color> with display: table-caption assert_equals: expected "table-caption" but got "inline-block" +FAIL computed display of <button type=submit> with display: table-caption assert_equals: expected "table-caption" but got "inline-block" +PASS computed display of <input type=reset> with display: none +PASS computed display of <input type=button> with display: none +PASS computed display of <input type=submit> with display: none +PASS computed display of <input type=color> with display: none +PASS computed display of <button type=submit> with display: none +PASS computed display of <input type=reset> with display: contents +PASS computed display of <input type=button> with display: contents +PASS computed display of <input type=submit> with display: contents +PASS computed display of <input type=color> with display: contents +PASS computed display of <button type=submit> with display: contents +FAIL computed display of <input type=reset> with display: flow assert_not_equals: display: flow is not supported got disallowed value "" +FAIL computed display of <input type=button> with display: flow assert_not_equals: display: flow is not supported got disallowed value "" +FAIL computed display of <input type=submit> with display: flow assert_not_equals: display: flow is not supported got disallowed value "" +FAIL computed display of <input type=color> with display: flow assert_not_equals: display: flow is not supported got disallowed value "" +FAIL computed display of <button type=submit> with display: flow assert_not_equals: display: flow is not supported got disallowed value "" +PASS computed display of <input type=reset> with display: flow-root +PASS computed display of <input type=button> with display: flow-root +PASS computed display of <input type=submit> with display: flow-root +PASS computed display of <input type=color> with display: flow-root +PASS computed display of <button type=submit> with display: flow-root +PASS computed display of <input type=reset> with display: flex +PASS computed display of <input type=button> with display: flex +PASS computed display of <input type=submit> with display: flex +PASS computed display of <input type=color> with display: flex +PASS computed display of <button type=submit> with display: flex +PASS computed display of <input type=reset> with display: grid +PASS computed display of <input type=button> with display: grid +PASS computed display of <input type=submit> with display: grid +PASS computed display of <input type=color> with display: grid +PASS computed display of <button type=submit> with display: grid +FAIL computed display of <input type=reset> with display: ruby assert_not_equals: display: ruby is not supported got disallowed value "" +FAIL computed display of <input type=button> with display: ruby assert_not_equals: display: ruby is not supported got disallowed value "" +FAIL computed display of <input type=submit> with display: ruby assert_not_equals: display: ruby is not supported got disallowed value "" +FAIL computed display of <input type=color> with display: ruby assert_not_equals: display: ruby is not supported got disallowed value "" +FAIL computed display of <button type=submit> with display: ruby assert_not_equals: display: ruby is not supported got disallowed value "" +FAIL computed display of <input type=reset> with display: ruby-base assert_not_equals: display: ruby-base is not supported got disallowed value "" +FAIL computed display of <input type=button> with display: ruby-base assert_not_equals: display: ruby-base is not supported got disallowed value "" +FAIL computed display of <input type=submit> with display: ruby-base assert_not_equals: display: ruby-base is not supported got disallowed value "" +FAIL computed display of <input type=color> with display: ruby-base assert_not_equals: display: ruby-base is not supported got disallowed value "" +FAIL computed display of <button type=submit> with display: ruby-base assert_not_equals: display: ruby-base is not supported got disallowed value "" +FAIL computed display of <input type=reset> with display: ruby-text assert_not_equals: display: ruby-text is not supported got disallowed value "" +FAIL computed display of <input type=button> with display: ruby-text assert_not_equals: display: ruby-text is not supported got disallowed value "" +FAIL computed display of <input type=submit> with display: ruby-text assert_not_equals: display: ruby-text is not supported got disallowed value "" +FAIL computed display of <input type=color> with display: ruby-text assert_not_equals: display: ruby-text is not supported got disallowed value "" +FAIL computed display of <button type=submit> with display: ruby-text assert_not_equals: display: ruby-text is not supported got disallowed value "" +FAIL computed display of <input type=reset> with display: ruby-base-container assert_not_equals: display: ruby-base-container is not supported got disallowed value "" +FAIL computed display of <input type=button> with display: ruby-base-container assert_not_equals: display: ruby-base-container is not supported got disallowed value "" +FAIL computed display of <input type=submit> with display: ruby-base-container assert_not_equals: display: ruby-base-container is not supported got disallowed value "" +FAIL computed display of <input type=color> with display: ruby-base-container assert_not_equals: display: ruby-base-container is not supported got disallowed value "" +FAIL computed display of <button type=submit> with display: ruby-base-container assert_not_equals: display: ruby-base-container is not supported got disallowed value "" +FAIL computed display of <input type=reset> with display: ruby-text-container assert_not_equals: display: ruby-text-container is not supported got disallowed value "" +FAIL computed display of <input type=button> with display: ruby-text-container assert_not_equals: display: ruby-text-container is not supported got disallowed value "" +FAIL computed display of <input type=submit> with display: ruby-text-container assert_not_equals: display: ruby-text-container is not supported got disallowed value "" +FAIL computed display of <input type=color> with display: ruby-text-container assert_not_equals: display: ruby-text-container is not supported got disallowed value "" +FAIL computed display of <button type=submit> with display: ruby-text-container assert_not_equals: display: ruby-text-container is not supported got disallowed value "" +PASS computed display of <input type=reset> with display: inline-flex +PASS computed display of <input type=button> with display: inline-flex +PASS computed display of <input type=submit> with display: inline-flex +PASS computed display of <input type=color> with display: inline-flex +PASS computed display of <button type=submit> with display: inline-flex +PASS computed display of <input type=reset> with display: inline-grid +PASS computed display of <input type=button> with display: inline-grid +PASS computed display of <input type=submit> with display: inline-grid +PASS computed display of <input type=color> with display: inline-grid +PASS computed display of <button type=submit> with display: inline-grid +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style.html new file mode 100644 index 0000000..696b551b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style.html
@@ -0,0 +1,31 @@ +<!doctype html> +<title>computed style on buttons</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div class="tests"> + <input type="reset"> + <input type="button"> + <input type="submit"> + <input type="color"> + <button></button> +</div> +<script> +// "behave as" doesn't change computed value. +const displayValues = ['inline', 'block', 'list-item', 'inline-block', 'table', 'inline-table', 'table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none', 'contents', 'flow', 'flow-root', 'flex', 'grid', 'ruby', 'ruby-base', 'ruby-text', 'ruby-base-container', 'ruby-text-container', 'inline-flex', 'inline-grid']; +for (const val of displayValues) { + [].slice.call(document.querySelectorAll('.tests > *')).forEach(el => { + el.style.display = '' + el.style.display = val; + const attrs = el.type ? ` type=${el.type}` : ''; + const tag = `<${el.localName}${attrs}>`; + test(() => { + assert_not_equals(el.style.display, '', `display: ${val} is not supported`) + let expectedVal = val; + if (el instanceof HTMLInputElement && val === 'contents') { + expectedVal = 'none'; // https://drafts.csswg.org/css-display/#unbox-html + } + assert_equals(getComputedStyle(el).display, expectedVal); + }, `computed display of ${tag} with display: ${val}`); + }); +} +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other-expected.txt new file mode 100644 index 0000000..8b5aeae --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other-expected.txt
@@ -0,0 +1,21 @@ +This is a testharness.js-based test. +PASS display: block +FAIL display: run-in assert_true: display: run-in is not supported expected true got false +FAIL display: flow assert_true: display: flow is not supported expected true got false +PASS display: flow-root +PASS display: table +PASS display: list-item +FAIL display: table-row-group assert_equals: afterLeft expected 0 but got 256 +FAIL display: table-header-group assert_equals: afterLeft expected 0 but got 256 +FAIL display: table-footer-group assert_equals: afterLeft expected 0 but got 256 +FAIL display: table-row assert_equals: afterLeft expected 0 but got 256 +FAIL display: table-cell assert_equals: afterLeft expected 0 but got 256 +FAIL display: table-column-group assert_equals: afterLeft expected 0 but got 256 +FAIL display: table-column assert_equals: afterLeft expected 0 but got 256 +FAIL display: table-caption assert_equals: afterLeft expected 0 but got 256 +FAIL display: ruby-base assert_true: display: ruby-base is not supported expected true got false +FAIL display: ruby-text assert_true: display: ruby-text is not supported expected true got false +FAIL display: ruby-base-container assert_true: display: ruby-base-container is not supported expected true got false +FAIL display: ruby-text-container assert_true: display: ruby-text-container is not supported expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other.html new file mode 100644 index 0000000..6ed3f58 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other.html
@@ -0,0 +1,52 @@ +<!doctype html> +<title>button with other display values</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<style> +body { margin: 0 } +.float { width: 100px; height: 100px; float: left; background: blue; margin: 10px } +</style> +<div class=float></div> +<button id=button style="display: block;"><div class=float></div></button><span id=after>after</span> +<script> +// These should all behave as flow-root. +const displayValues = ['run-in', 'flow', 'flow-root', 'table', 'list-item', + 'table-row-group', 'table-header-group', 'table-footer-group', + 'table-row', 'table-cell', 'table-column-group', 'table-column', + 'table-caption', 'ruby-base', 'ruby-text', 'ruby-base-container', + 'ruby-text-container']; +const button = document.getElementById('button'); +const after = document.getElementById('after'); +function getValues() { + return { + buttonLeft: button.offsetLeft, + buttonTop: button.offsetTop, + buttonWidth: button.clientWidth, + buttonHeight: button.clientHeight, + afterLeft: after.offsetLeft, + afterTop: after.offsetTop, + }; +} +const expected = getValues(); +test(t => { + assert_equals(expected.buttonLeft, 120, 'buttonLeft'); + assert_equals(expected.buttonTop, 0, 'buttonTop'); + assert_greater_than_equal(expected.buttonWidth, 120, 'buttonWidth'); + assert_greater_than_equal(expected.buttonHeight, 120, 'buttonHeight'); + assert_equals(expected.afterLeft, 0, 'afterLeft'); + assert_greater_than_equal(expected.afterTop, 120, 'afterTop'); +}, 'display: block'); +for (const val of displayValues) { + test(t => { + t.add_cleanup(() => { + button.style.display = 'block'; + }); + assert_true(CSS.supports(`display: ${val}`), `display: ${val} is not supported`); + button.style.display = val; + const values = getValues(); + for (const prop in values) { + assert_equals(values[prop], expected[prop], prop); + } + }, `display: ${val}`); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/flex.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/flex.html new file mode 100644 index 0000000..ce845eb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/flex.html
@@ -0,0 +1,29 @@ +<!doctype html> +<title>button with flex/inline-flex</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<style> +#inline-flex { display: inline-flex } +#flex { display: flex } +#ref > div { display: flex } +</style> +<button id=inline-flex><div>1</div><div>2</div><div>3</div><div>4</div></button> +<button id=flex><div>1</div><div>2</div><div>3</div><div>4</div></button> +<button id=ref><div><div>1</div><div>2</div><div>3</div><div>4</div></div></button> +<script> +const ref = document.getElementById('ref'); +const expectedWidth = ref.clientWidth; +const expectedHeight = ref.clientHeight; +for (const elm of [document.getElementById('inline-flex'), + document.getElementById('flex')]) { + test(() => { + // check that flex is supported + const flexValue = elm.id; + assert_equals(getComputedStyle(elm).display, flexValue, `${flexValue} is not supported`); + const width = elm.clientWidth; + const height = elm.clientHeight; + assert_equals(width, expectedWidth, 'clientWidth'); + assert_equals(height, expectedHeight, 'clientHeight'); + }, elm.id); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/grid.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/grid.html new file mode 100644 index 0000000..7c2a467 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/grid.html
@@ -0,0 +1,30 @@ +<!doctype html> +<title>button with grid/inline-grid</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<style> +#inline-grid { display: inline-grid } +#grid { display: grid } +#ref > div { display: grid } +#inline-grid, #grid, #ref > div { grid-template: auto auto / auto auto } +</style> +<button id=inline-grid><div>1</div><div>2</div><div>3</div><div>4</div></button> +<button id=grid><div>1</div><div>2</div><div>3</div><div>4</div></button> +<button id=ref><div><div>1</div><div>2</div><div>3</div><div>4</div></div></button> +<script> +const ref = document.getElementById('ref'); +const expectedWidth = ref.clientWidth; +const expectedHeight = ref.clientHeight; +for (const elm of [document.getElementById('inline-grid'), + document.getElementById('grid')]) { + test(() => { + // check that grid is supported + const gridValue = elm.id; + assert_equals(getComputedStyle(elm).display, gridValue, `${gridValue} is not supported`); + const width = elm.clientWidth; + const height = elm.clientHeight; + assert_equals(width, expectedWidth, 'clientWidth'); + assert_equals(height, expectedHeight, 'clientHeight'); + }, elm.id); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/inline-level-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/inline-level-ref.html new file mode 100644 index 0000000..3784cc30 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/inline-level-ref.html
@@ -0,0 +1,10 @@ +<!doctype html> +<title>Reference for button with inline-level display</title> +<style> +button { font: inherit } +</style> +<p>There should be three buttons below containing "1" and "2" on separate lines, and "a" and "b" before and after on the same baseline as the "2".</p> +<p>a<button>1<br>2</button>b</p> +<p>a<button>1<br>2</button>b</p> +<p>a<button>1<br>2</button>b</p> +<p>a<button>1<br>2</button>b</p>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/inline-level.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/inline-level.html new file mode 100644 index 0000000..e23aba73 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/inline-level.html
@@ -0,0 +1,25 @@ +<!doctype html> +<title>button with inline-level display</title> +<link rel=match href=inline-level-ref.html> +<style> +button, input { font: inherit } +.inline { display: inline } +.inline-block { display: inline-block } +.inline-table { display: inline-table } +</style> +<p>There should be three buttons below containing "1" and "2" on separate lines, and "a" and "b" before and after on the same baseline as the "2".</p> +<p>a<button class=inline>1<br><span class=check-baseline>2</span></button><span class=ref-baseline>b</span></p> +<p>a<button class=inline-block>1<br><span class=check-baseline>2</span></button><span class=ref-baseline>b</span></p> +<p>a<button class=inline-table>1<br><span class=check-baseline>2</span></button><span class=ref-baseline>b</span></p> +<p>a<input type=button class=inline-table value="1 2">b</p> +<script> +const spans = document.querySelectorAll('.check-baseline'); +for (const span of [].slice.call(spans)) { + const baseline = span.offsetTop + span.offsetHeight; + const refSpan = span.parentNode.nextSibling; + const refBaseline = refSpan.offsetTop + refSpan.offsetHeight; + if (baseline !== refBaseline) { + refSpan.textContent += " (wrong baseline)"; + } +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/propagate-text-decoration-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/propagate-text-decoration-ref.html new file mode 100644 index 0000000..f33a011a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/propagate-text-decoration-ref.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<title>Reference for propagating text-decoration into buttons</title> +<style> +button { font: inherit } +</style> +<p>The text in the following buttons should be underlined.</p> +<p><button><u>foo</u></button><button><u>foo</u></button></p> +<p>The text in the following buttons should NOT be underlined.</p> +<p><button>foo</button><button>foo</button></p>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/propagate-text-decoration.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/propagate-text-decoration.html new file mode 100644 index 0000000..9bdbbef0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/propagate-text-decoration.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>propagating text-decoration into buttons</title> +<link rel=match href=propagate-text-decoration-ref.html> +<style> +button, input { font: inherit } +.inline > u > * { display: inline } +.inline-block > u > * { display: inline-block } +</style> +<p>The text in the following buttons should be underlined.</p> +<p class=inline><u><button>foo</button><input type=button value=foo></u></p> +<p>The text in the following buttons should NOT be underlined.</p> +<p class=inline-block><u><button>foo</button><input type=button value=foo></u></p>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/shrink-wrap.html b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/shrink-wrap.html new file mode 100644 index 0000000..6d61102 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/shrink-wrap.html
@@ -0,0 +1,42 @@ +<!doctype html> +<title>shrink-wrap button</title> +<link rel=help href=https://html.spec.whatwg.org/multipage/rendering.html#button-layout> +<link rel=help href=https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<!-- + minimum preferred width 100px + preferred width 250px + available width vary +--> +<style> +div.available-width { border: thin dotted red; margin: 1em 0; padding: 1em 0 } +button { border: none; margin: 0; padding: 0; background: papayawhip; } +button > span.minimum-preferred-width { width: 100px } +button > span { width: 50px; display: inline-block; outline: thin dotted blue } +</style> +<div class="available-width" style="width: 50px"> + <button data-expected="100"><span class="minimum-preferred-width">x</span><span>x</span><span>x</span><span>x</span></button> +</div> + +<div class="available-width" style="width: 200px"> + <button data-expected="200"><span class="minimum-preferred-width">x</span><span>x</span><span>x</span><span>x</span></button> +</div> + +<div class="available-width" style="width: 300px"> + <button data-expected="250"><span class="minimum-preferred-width">x</span><span>x</span><span>x</span><span>x</span></button> +</div> + +<script> +const styles = ['display: block', 'display: inline', 'display: inline-block', + 'display: list-item', 'display: table', 'display: table-row', + 'display: table-cell', 'float: left']; +for (const style of styles) { + for (const button of [].slice.call(document.querySelectorAll('button'))) { + test(() => { + button.setAttribute('style', style); + assert_equals(button.clientWidth, parseInt(button.dataset.expected, 10)); + }, `${style} - available ${button.parentNode.getAttribute('style')}`); + } +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini deleted file mode 100644 index 1ab2d77..0000000 --- a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy.html.ini +++ /dev/null
@@ -1,2 +0,0 @@ -[reftest_fuzzy.html] - fuzzy: fuzzy-ref-1.html:maxDifference=255;100-100
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini new file mode 100644 index 0000000..0ebde2f4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_full.html.ini
@@ -0,0 +1,3 @@ +[reftest_fuzzy_ini_full.html] + fuzzy: [maxDifference=1;100-100, + reftest_fuzzy_ini_full.html==fuzzy-ref-1.html:255;100]
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini new file mode 100644 index 0000000..70c0446 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html.ini
@@ -0,0 +1,4 @@ +[reftest_fuzzy_ini_ref_only.html] + fuzzy: [maxDifference=1;100-100, + fuzzy-ref-1.html:maxDifference=255;100-100, + reftest_fuzzy==fuzzy-ref-2.html:maxDifference=1;100-100]
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini new file mode 100644 index 0000000..1859d25 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/infrastructure/metadata/infrastructure/reftest/reftest_fuzzy_ini_short.html.ini
@@ -0,0 +1,2 @@ +[reftest_fuzzy_ini_short.html] + fuzzy: maxDifference=255;100-100
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_ini_full.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html rename to third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_ini_full.html
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html similarity index 100% copy from third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html copy to third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_ini_ref_only.html
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_ini_short.html similarity index 100% copy from third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy.html copy to third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_ini_short.html
diff --git a/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker.html b/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker.html new file mode 100644 index 0000000..350d274 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script> +window.addEventListener('load', () => { + window.parent.postMessage('load'); +}); + +document.addEventListener('freeze', () => { + window.parent.postMessage('freeze'); +}); + +document.addEventListener('resume', () => { + window.parent.postMessage('resume'); +}); + +worker = new Worker("subframe_worker1.js"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker1.js b/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker1.js new file mode 100644 index 0000000..2d13e890 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker1.js
@@ -0,0 +1,7 @@ +var bc = new BroadcastChannel('subworker_channel'); + +setInterval(() => { + bc.postMessage('subworker'); +}, 10); + +w2 = new Worker("subframe_worker2.js");
diff --git a/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker2.js b/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker2.js new file mode 100644 index 0000000..32d2741 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/lifecycle/resources/subframe_worker2.js
@@ -0,0 +1,5 @@ +var bc = new BroadcastChannel('subworker_channel'); + +setInterval(() => { + bc.postMessage('subworker2'); +}, 10);
diff --git a/third_party/blink/web_tests/external/wpt/lifecycle/worker-dispay-none.tentative.html b/third_party/blink/web_tests/external/wpt/lifecycle/worker-dispay-none.tentative.html new file mode 100644 index 0000000..0bcfde6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/lifecycle/worker-dispay-none.tentative.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Child frame with worker marked as frozen</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +async_test((t) => { + + var child = document.createElement('iframe'); + + var loaded = false; + var frozen = false; + var resumed = false; + + var subworker_freeze_count = 0; + var subworker2_freeze_count = 0; + var subworker_count = 0; + var subworker2_count = 0; + var bc = new BroadcastChannel('subworker_channel'); + bc.onmessage = t.step_func((e) => { + if (e.data == 'subworker') { + subworker_count++; + } else if (e.data == 'subworker2') { + subworker2_count++; + } else { + assert_unreached('bad message'); + } + + // Ensure that if we have resumed that we get at least + // one message from each worker. + if (loaded && frozen && resumed && + subworker2_count > subworker2_freeze_count && + subworker_count > subworker_freeze_count) { + t.done(); + } else if (loaded && frozen && !resumed) { + // Ensure that at most one message is sent after the frozen state. + assert_true(subworker_count - subworker_freeze_count <= 1); + assert_true(subworker2_count - subworker2_freeze_count <= 1); + } + }); + + window.addEventListener('message', t.step_func((e) => { + if (e.data == "load") { + loaded = true; + } else if (e.data == "freeze") { + assert_true(loaded); + frozen = true; + subworker_freeze_count = subworker_count; + subworker2_freeze_count = subworker2_count; + child.style = "display: block"; + } else if (e.data == "resume") { + assert_true(loaded); + assert_true(frozen); + resumed = true; + } + })); + + child.allow = "execution-while-not-rendered 'none'"; + child.src = "resources/subframe_worker.html"; + document.body.appendChild(child); + child.style = "display: none"; +}, "Child frame frozen"); + +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-SecureContext.html b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-SecureContext.html index d0fc70c..e6e8587c 100644 --- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-SecureContext.html +++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/MediaDevices-SecureContext.html
@@ -10,6 +10,7 @@ assert_false(window.isSecureContext, "This test must be run in a non secure context"); assert_false('MediaDevices' in window, "MediaDevices is not exposed"); +assert_false('MediaDeviceInfo' in window, "MediaDeviceInfo is not exposed"); assert_false('getUserMedia' in navigator, "getUserMedia is not exposed"); assert_false('mediaDevices' in navigator, "mediaDevices is not exposed");
diff --git a/third_party/blink/web_tests/external/wpt/selection/script-and-style-elements-expected.txt b/third_party/blink/web_tests/external/wpt/selection/script-and-style-elements-expected.txt new file mode 100644 index 0000000..4e31b646 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/selection/script-and-style-elements-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL Selection: STYLE and SCRIPT elements should be included in Selection.toString() if they are display!=none assert_equals: expected "\nstyle { display:block; color: green; } script { color: blue; }\nfunction test_block_script() { let pre = document.createElement(\"pre\"); pre.append(document.createTextNode(\"PASS\")); document.getElementById(\"p1\").append(pre); }\n\nPASS" but got "style { display:block; color: green; } script { color: blue; }\nfunction test_block_script() { let pre = document.createElement(\"pre\"); pre.append(document.createTextNode(\"PASS\")); document.getElementById(\"p1\").append(pre); }\nPASS" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/selection/script-and-style-elements.html b/third_party/blink/web_tests/external/wpt/selection/script-and-style-elements.html new file mode 100644 index 0000000..b7566591 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/selection/script-and-style-elements.html
@@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Selection: STYLE and SCRIPT elements should be included in Selection.toString() if they are display!=none</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +window.onload = function() { + test(function() { + var selection = window.getSelection(); + var p1 = document.getElementById("p1"); + + var range = document.createRange(); + test_block_script(); + range.selectNode(p1); + selection.addRange(range); + assert_equals(selection.toString().replace(/\r\n/g, "\n"), '\nstyle { display:block; color: green; } script { color: blue; }\nfunction test_block_script() { let pre = document.createElement("pre"); pre.append(document.createTextNode("PASS")); document.getElementById("p1").append(pre); }\n\nPASS'); + }); +}; +</script> +<div id=log></div> +<div id="p1"> +<style style="display:none">#not_included{}</style> +<style> + style { display:block; color: green; } + script { color: blue; } +</style> +<script>function not_included(){}</script> +<script style="display:block"> +function test_block_script() { + let pre = document.createElement("pre"); + pre.append(document.createTextNode("PASS")); + document.getElementById("p1").append(pre); +} +</script> +</div> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py b/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py index 66ad8b50..f617fc3 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py +++ b/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py
@@ -632,6 +632,53 @@ if m: return m.group(0) +class EdgeChromium(Browser): + """MicrosoftEdge-specific interface.""" + + product = "edgechromium" + requirements = "requirements_edge_chromium.txt" + + def install(self, dest=None, channel=None): + raise NotImplementedError + + def find_binary(self, venv_path=None, channel=None): + raise find_executable("msedge") + + def find_webdriver(self, channel=None): + return find_executable("msedgedriver") + + def install_webdriver(self, dest=None, channel=None, browser_binary=None): + if uname[0] != "Windows": + raise ValueError("Only Windows platform is currently supported") + + if dest is None: + dest = os.pwd + + platform = "x64" if uname[4] == "x86_64" else "x86" + url = "https://az813057.vo.msecnd.net/webdriver/msedgedriver_%s/msedgedriver.exe" % platform + + self.logger.info("Downloading MSEdgeDriver from %s" % url) + resp = get(url) + installer_path = os.path.join(dest, "msedgedriver.exe") + with open(installer_path, "wb") as f: + f.write(resp.content) + + return find_executable("msedgedriver", dest) + + def version(self, binary=None, webdriver_binary=None): + if uname[0] != "Windows": + try: + version_string = call(binary, "--version").strip() + except subprocess.CalledProcessError: + self.logger.warning("Failed to call %s" % binary) + return None + m = re.match(r"(?:MSEdge|Edge) (.*)", version_string) + if not m: + self.logger.warning("Failed to extract version from: %s" % version_string) + return None + return m.group(1) + self.logger.warning("Unable to extract version from binary on Windows.") + return None class Edge(Browser): """Edge-specific interface."""
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py index c0cfa58..98bcc21 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py +++ b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
@@ -327,6 +327,29 @@ raise WptrunError("Unable to locate or install operadriver binary") +class EdgeChromium(BrowserSetup): + name = "MicrosoftEdge" + browser_cls = browser.EdgeChromium + + def setup_kwargs(self, kwargs): + if kwargs["webdriver_binary"] is None: + webdriver_binary = self.browser.find_webdriver() + + if webdriver_binary is None: + install = self.prompt_install("msedgedriver") + + if install: + logger.info("Downloading msedgedriver") + webdriver_binary = self.browser.install_webdriver(dest=self.venv.bin_path) + else: + logger.info("Using webdriver binary %s" % webdriver_binary) + + if webdriver_binary: + kwargs["webdriver_binary"] = webdriver_binary + else: + raise WptrunError("Unable to locate or install msedgedriver binary") + + class Edge(BrowserSetup): name = "edge" browser_cls = browser.Edge @@ -465,6 +488,7 @@ "firefox": Firefox, "chrome": Chrome, "chrome_android": ChromeAndroid, + "edgechromium": EdgeChromium, "edge": Edge, "edge_webdriver": EdgeWebDriver, "ie": InternetExplorer,
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_edge_chromium.txt b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_edge_chromium.txt new file mode 100644 index 0000000..470aaf9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_edge_chromium.txt
@@ -0,0 +1 @@ +mozprocess==1.0.0
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/__init__.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/__init__.py index fdedda4..a98604fe 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/__init__.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/__init__.py
@@ -24,6 +24,7 @@ product_list = ["chrome", "chrome_android", + "edgechromium", "edge", "edge_webdriver", "fennec",
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py new file mode 100644 index 0000000..64850165 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py
@@ -0,0 +1,116 @@ +from .base import Browser, ExecutorBrowser, require_arg +from .base import get_timeout_multiplier # noqa: F401 +from ..webdriver_server import EdgeChromiumDriverServer +from ..executors import executor_kwargs as base_executor_kwargs +from ..executors.executorwebdriver import (WebDriverTestharnessExecutor, # noqa: F401 + WebDriverRefTestExecutor) # noqa: F401 +from ..executors.executoredgechromium import EdgeChromiumDriverWdspecExecutor # noqa: F401 + + +__wptrunner__ = {"product": "edgechromium", + "check_args": "check_args", + "browser": "EdgeChromiumBrowser", + "executor": {"testharness": "WebDriverTestharnessExecutor", + "reftest": "WebDriverRefTestExecutor", + "wdspec": "EdgeChromiumDriverWdspecExecutor"}, + "browser_kwargs": "browser_kwargs", + "executor_kwargs": "executor_kwargs", + "env_extras": "env_extras", + "env_options": "env_options", + "timeout_multiplier": "get_timeout_multiplier",} + + +def check_args(**kwargs): + require_arg(kwargs, "webdriver_binary") + + +def browser_kwargs(test_type, run_info_data, config, **kwargs): + return {"binary": kwargs["binary"], + "webdriver_binary": kwargs["webdriver_binary"], + "webdriver_args": kwargs.get("webdriver_args")} + + +def executor_kwargs(test_type, server_config, cache_manager, run_info_data, + **kwargs): + executor_kwargs = base_executor_kwargs(test_type, server_config, + cache_manager, run_info_data, + **kwargs) + executor_kwargs["close_after_done"] = True + executor_kwargs["supports_eager_pageload"] = False + + capabilities = { + "goog:chromeOptions": { + "prefs": { + "profile": { + "default_content_setting_values": { + "popups": 1 + } + } + }, + "useAutomationExtension": False, + "excludeSwitches": ["enable-automation"], + "w3c": True + } + } + + if test_type == "testharness": + capabilities["pageLoadStrategy"] = "none" + + for (kwarg, capability) in [("binary", "binary"), ("binary_args", "args")]: + if kwargs[kwarg] is not None: + capabilities["goog:chromeOptions"][capability] = kwargs[kwarg] + + if kwargs["headless"]: + if "args" not in capabilities["goog:chromeOptions"]: + capabilities["goog:chromeOptions"]["args"] = [] + if "--headless" not in capabilities["goog:chromeOptions"]["args"]: + capabilities["goog:chromeOptions"]["args"].append("--headless") + + executor_kwargs["capabilities"] = capabilities + + return executor_kwargs + + +def env_extras(**kwargs): + return [] + + +def env_options(): + return {} + + +class EdgeChromiumBrowser(Browser): + """MicrosoftEdge is backed by MSEdgeDriver, which is supplied through + ``wptrunner.webdriver.EdgeChromiumDriverServer``. + """ + + def __init__(self, logger, binary, webdriver_binary="msedgedriver", + webdriver_args=None): + """Creates a new representation of MicrosoftEdge. The `binary` argument gives + the browser binary to use for testing.""" + Browser.__init__(self, logger) + self.binary = binary + self.server = EdgeChromiumDriverServer(self.logger, + binary=webdriver_binary, + args=webdriver_args) + + def start(self, **kwargs): + self.server.start(block=False) + + def stop(self, force=False): + self.server.stop(force=force) + + def pid(self): + return self.server.pid + + def is_alive(self): + # TODO(ato): This only indicates the driver is alive, + # and doesn't say anything about whether a browser session + # is active. + return self.server.is_alive() + + def cleanup(self): + self.stop() + + def executor_browser(self): + return ExecutorBrowser, {"webdriver_url": self.server.url}
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executoredgechromium.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executoredgechromium.py new file mode 100644 index 0000000..f47ecbf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executoredgechromium.py
@@ -0,0 +1,10 @@ +from ..webdriver_server import EdgeChromiumDriverServer +from .base import WdspecExecutor, WebDriverProtocol + + +class EdgeChromiumDriverProtocol(WebDriverProtocol): + server_cls = EdgeChromiumDriverServer + + +class EdgeChromiumDriverWdspecExecutor(WdspecExecutor): + protocol_cls = EdgeChromiumDriverProtocol
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/webdriver_server.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/webdriver_server.py index 4ec415c..d8d9f339 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/webdriver_server.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/webdriver_server.py
@@ -9,7 +9,7 @@ import mozprocess -__all__ = ["SeleniumServer", "ChromeDriverServer", "OperaDriverServer", +__all__ = ["SeleniumServer", "ChromeDriverServer", "EdgeChromiumDriverServer", "OperaDriverServer", "GeckoDriverServer", "InternetExplorerDriverServer", "EdgeDriverServer", "ServoDriverServer", "WebKitDriverServer", "WebDriverServer"] @@ -134,6 +134,17 @@ cmd_arg("port", str(self.port)), cmd_arg("url-base", self.base_path) if self.base_path else ""] + self._args +class EdgeChromiumDriverServer(WebDriverServer): + def __init__(self, logger, binary="msedgedriver", port=None, + base_path="", args=None): + WebDriverServer.__init__( + self, logger, binary, port=port, base_path=base_path, args=args) + + def make_command(self): + return [self.binary, + cmd_arg("port", str(self.port)), + cmd_arg("url-base", self.base_path) if self.base_path else ""] + self._args + class EdgeDriverServer(WebDriverServer): def __init__(self, logger, binary="microsoftwebdriver.exe", port=None, base_path="", host="localhost", args=None):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py index 0a17fd48..b2c4490b 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wpttest.py
@@ -472,10 +472,12 @@ value.remove(atom_reset) values = {} for key, data in value: - if len(key) == 3: + if isinstance(key, (tuple, list)): + key = list(key) key[0] = urljoin(self.url, key[0]) key[1] = urljoin(self.url, key[1]) - else: + key = tuple(key) + elif key: # Key is just a relative url to a ref key = urljoin(self.url, key) values[key] = data
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/idlharness.window-expected.txt index 44fc6cee..75523c9 100644 --- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/idlharness.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/idlharness.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 54 tests; 42 PASS, 12 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 54 tests; 45 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Animation interface. PASS Animation interface: existence and properties of interface object PASS Animation interface object length @@ -25,7 +25,7 @@ PASS Animation interface: operation finish() PASS Animation interface: operation play() PASS Animation interface: operation pause() -FAIL Animation interface: operation updatePlaybackRate(double) assert_own_property: interface prototype object missing non-static operation expected property "updatePlaybackRate" missing +PASS Animation interface: operation updatePlaybackRate(double) PASS Animation interface: operation reverse() FAIL Animation interface: operation persist() assert_own_property: interface prototype object missing non-static operation expected property "persist" missing FAIL Animation interface: operation commitStyles() assert_own_property: interface prototype object missing non-static operation expected property "commitStyles" missing @@ -49,8 +49,8 @@ PASS Animation interface: new Animation() must inherit property "finish()" with the proper type PASS Animation interface: new Animation() must inherit property "play()" with the proper type PASS Animation interface: new Animation() must inherit property "pause()" with the proper type -FAIL Animation interface: new Animation() must inherit property "updatePlaybackRate(double)" with the proper type assert_inherits: property "updatePlaybackRate" not found in prototype chain -FAIL Animation interface: calling updatePlaybackRate(double) on new Animation() with too few arguments must throw TypeError assert_inherits: property "updatePlaybackRate" not found in prototype chain +PASS Animation interface: new Animation() must inherit property "updatePlaybackRate(double)" with the proper type +PASS Animation interface: calling updatePlaybackRate(double) on new Animation() with too few arguments must throw TypeError PASS Animation interface: new Animation() must inherit property "reverse()" with the proper type FAIL Animation interface: new Animation() must inherit property "persist()" with the proper type assert_inherits: property "persist" not found in prototype chain FAIL Animation interface: new Animation() must inherit property "commitStyles()" with the proper type assert_inherits: property "commitStyles" not found in prototype chain
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/style-change-events-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/style-change-events-expected.txt index ccf7731..8d21e2d8 100644 --- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/style-change-events-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animation/style-change-events-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -FAIL All property keys are recognized assert_in_array: Test property 'updatePlaybackRate' should be one of the properties on Animation value "updatePlaybackRate" not in array ["effect", "startTime", "currentTime", "playbackRate", "playState", "pending", "id", "onfinish", "oncancel", "finish", "play", "pause", "reverse", "cancel", "finished", "ready", "timeline", "Animation constructor"] +PASS All property keys are recognized PASS Animation.effect does NOT trigger a style change event PASS Animation.startTime does NOT trigger a style change event PASS Animation.currentTime does NOT trigger a style change event @@ -13,6 +13,7 @@ PASS Animation.play does NOT trigger a style change event PASS Animation.pause does NOT trigger a style change event PASS Animation.reverse does NOT trigger a style change event +PASS Animation.updatePlaybackRate does NOT trigger a style change event PASS Animation.cancel does NOT trigger a style change event PASS Animation.finished does NOT trigger a style change event PASS Animation.ready does NOT trigger a style change event
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/finishing-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/finishing-an-animation-expected.txt deleted file mode 100644 index 83e59e0..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/finishing-an-animation-expected.txt +++ /dev/null
@@ -1,22 +0,0 @@ -This is a testharness.js-based test. -PASS Finishing an animation with a zero playback rate throws -PASS Finishing an infinite animation throws -PASS Finishing an animation seeks to the end time -PASS Finishing an animation with a current time past the effect end jumps back to the end -PASS Finishing a reversed animation jumps to zero time -PASS Finishing a reversed animation with a current time less than zero makes it jump back to zero -PASS Finishing a paused animation resolves the start time -PASS Finishing a pause-pending animation resolves the pending task immediately and update the start time -PASS Finishing a pause-pending animation with negative playback rate resolves the pending task immediately -PASS Finishing an animation while play-pending resolves the pending task immediately -PASS Finishing an animation during an aborted pause makes it finished immediately -PASS Finishing an animation resolves the finished promise synchronously -PASS Finishing an animation without a target resolves the finished promise synchronously -PASS A pending ready promise is resolved and not replaced when the animation is finished -FAIL A pending playback rate should be applied immediately when an animation is finished promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL An exception should be thrown if the effective playback rate is zero promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL An exception should be thrown when finishing if the effective playback rate is positive and the target effect end is infinity promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL An exception is NOT thrown when finishing if the effective playback rate is negative and the target effect end is infinity promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -PASS Finishing an animation fires finish event on orphaned element -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/play-states-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/play-states-expected.txt deleted file mode 100644 index bbfed266..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/play-states-expected.txt +++ /dev/null
@@ -1,19 +0,0 @@ -This is a testharness.js-based test. -PASS reports 'idle' for an animation with an unresolved current time and no pending tasks -PASS reports 'paused' for an animation with a pending pause task -PASS reports 'paused' for an animation with a resolved current time and unresolved start time -PASS reports 'running' for an animation with a resolved start time and current time -PASS reports 'finished' when playback rate > 0 and current time = target effect end -PASS reports 'running' when playback rate = 0 and current time = target effect end -PASS reports 'running' when playback rate < 0 and current time = target effect end -PASS reports 'running' when playback rate > 0 and current time = 0 -PASS reports 'running' when playback rate = 0 and current time = 0 -PASS reports 'finished' when playback rate < 0 and current time = 0 -PASS reports 'finished' when playback rate > 0 and current time = target effect end and there is a pending play task -PASS reports 'running' when playback rate > 0 and current time < target effect end and there is a pending play task -PASS reports 'running' for a play-pending animation -PASS reports 'paused' for a pause-pending animation -PASS reports 'finished' for a finished-pending animation -FAIL reports the play state based on the pending playback rate animation.updatePlaybackRate is not a function -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/playing-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/playing-an-animation-expected.txt deleted file mode 100644 index 8662ffc..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/playing-an-animation-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This is a testharness.js-based test. -PASS Playing a running animation leaves the current time unchanged -PASS Playing a finished animation seeks back to the start -PASS Playing a finished and reversed animation seeks to end -PASS Playing a pause-pending but previously finished animation seeks back to to the start -PASS Playing a finished animation clears the start time -PASS The ready promise should be replaced if the animation is not already pending -PASS A pending ready promise should be resolved and not replaced when the animation enters the running state -PASS Resuming an animation from paused calculates start time from hold time -PASS If a pause operation is interrupted, the ready promise is reused -FAIL A pending playback rate is used when determining auto-rewind behavior promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/reversing-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/reversing-an-animation-expected.txt index ec75490f..227a28ac 100644 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/reversing-an-animation-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/reversing-an-animation-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -FAIL Reversing an animation inverts the playback rate assert_equals: Playback rate should not have changed expected 1 but got -1 +PASS Reversing an animation inverts the playback rate PASS Reversing an animation plays a pausing animation PASS Reversing an animation maintains the same current time PASS Reversing an animation does not cause it to leave the pending state @@ -9,13 +9,13 @@ PASS Reversing an animation when playbackRate < 0 and currentTime < 0 should make it play from the start PASS Reversing an animation when playbackRate < 0 and currentTime > effect end should make it play from the start PASS Reversing an animation when playbackRate > 0 and currentTime < 0 and the target effect end is positive infinity should throw an exception -FAIL When reversing throws an exception, the playback rate remains unchanged assert_equals: playbackRate is unchanged expected 1 but got -1 +PASS When reversing throws an exception, the playback rate remains unchanged PASS Reversing animation when playbackRate = 0 and currentTime < 0 and the target effect end is positive infinity should NOT throw an exception PASS Reversing an animation when playbackRate < 0 and currentTime < 0 and the target effect end is positive infinity should make it play from the start PASS Reversing when when playbackRate == 0 should preserve the current time and playback rate PASS Reversing an idle animation from starts playing the animation FAIL Reversing an animation without an active timeline throws an InvalidStateError assert_throws: function "() => { animation.reverse(); }" did not throw -FAIL Reversing should use the negative pending playback rate promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL When reversing fails, it should restore any previous pending playback rate promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" +PASS Reversing should use the negative pending playback rate +PASS When reversing fails, it should restore any previous pending playback rate Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation-expected.txt deleted file mode 100644 index 1b74426..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/seamlessly-updating-the-playback-rate-of-an-animation-expected.txt +++ /dev/null
@@ -1,12 +0,0 @@ -This is a testharness.js-based test. -FAIL Updating the playback rate maintains the current time promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL Updating the playback rate while running makes the animation pending promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL Updating the playback rate on a play-pending animation maintains the current time promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL Updating the playback rate on a pause-pending animation maintains the current time promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL If a pending playback rate is set multiple times, the latest wins promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL In the idle state, the playback rate is applied immediately animation.updatePlaybackRate is not a function -FAIL In the paused state, the playback rate is applied immediately promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL Updating the playback rate on a finished animation maintains the current time promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -FAIL Updating the playback rate to zero on a finished animation maintains the current time promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-current-time-of-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-current-time-of-an-animation-expected.txt deleted file mode 100644 index f54bd1a5..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-current-time-of-an-animation-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -PASS Setting the current time of a pending animation to unresolved does not throw a TypeError -PASS Setting the current time of a playing animation to unresolved throws a TypeError -PASS Setting the current time of a paused animation to unresolved throws a TypeError -FAIL Setting the current time of a pausing animation applies a pending playback rate promise_test: Unhandled rejection with value: object "TypeError: anim.updatePlaybackRate is not a function" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation-expected.txt deleted file mode 100644 index 5bc5bed..0000000 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-playback-rate-of-an-animation-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -PASS The playback rate affects the rate of progress of the current time -PASS Setting the playback rate while play-pending preserves the current time -PASS Setting the playback rate while playing preserves the current time -FAIL Setting the playback rate should clear any pending playback rate promise_test: Unhandled rejection with value: object "TypeError: animation.updatePlaybackRate is not a function" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation-expected.txt index cd7eb65..5f0650b0 100644 --- a/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-animations/timing-model/animations/setting-the-target-effect-of-an-animation-expected.txt
@@ -5,6 +5,6 @@ PASS The pending play task should be rescheduled even after temporarily setting the effect to null FAIL When setting the effect of an animation to the effect of an existing animation, the existing animation's target effect should be set to null. assert_equals: expected "finished" but got "idle" PASS After setting the target effect of animation to the target effect of an existing animation, the target effect's timing is updated to reflect the current time of the new animation. -FAIL Setting the target effect to null causes a pending playback rate to be applied promise_test: Unhandled rejection with value: object "TypeError: anim.updatePlaybackRate is not a function" +PASS Setting the target effect to null causes a pending playback rate to be applied Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel-expected.txt b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel-expected.txt new file mode 100644 index 0000000..85e66d4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel-expected.txt
@@ -0,0 +1,60 @@ +This is a testharness.js-based test. +Found 56 tests; 51 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS # AUDIT TASK RUNNER STARTED. +PASS > [initialize] +PASS Initialized values contains only the constant -1. +PASS < [initialize] All assertions passed. (total 1 assertions) +PASS > [copyFrom-exceptions] +PASS AudioBuffer.prototype.copyFromChannel does exist. +PASS 0: buffer = context.createBuffer(3, 16, context.sampleRate) did not throw an exception. +PASS 1: buffer.copyFromChannel(null, 0) threw TypeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': parameter 1 is not of type 'Float32Array'.". +PASS 2: buffer.copyFromChannel(context, 0) threw TypeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': parameter 1 is not of type 'Float32Array'.". +PASS 3: buffer.copyFromChannel(x, -1) threw IndexSizeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': The channelNumber provided (-1) is outside the range [0, 2].". +PASS 4: buffer.copyFromChannel(x, 3) threw IndexSizeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': The channelNumber provided (3) is outside the range [0, 2].". +PASS 5: buffer.copyFromChannel(x, 0, -1) threw IndexSizeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': The startInChannel provided (4294967295) is outside the range [0, 16).". +FAIL X 6: buffer.copyFromChannel(x, 0, 16) incorrectly threw IndexSizeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': The startInChannel provided (16) is outside the range [0, 16).". assert_true: expected true got false +PASS 7: buffer.copyFromChannel(x, 3) threw IndexSizeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': The channelNumber provided (3) is outside the range [0, 2].". +PASS 8: buffer.copyFromChannel(SharedArrayBuffer view, 0) threw TypeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': The provided ArrayBufferView value must not be shared.". +PASS 9: buffer.copyFromChannel(SharedArrayBuffer view, 0, 0) threw TypeError: "Failed to execute 'copyFromChannel' on 'AudioBuffer': The provided ArrayBufferView value must not be shared.". +FAIL < [copyFrom-exceptions] 1 out of 11 assertions were failed. assert_true: expected true got false +PASS > [copyTo-exceptions] +PASS AudioBuffer.prototype.copyToChannel does exist. +PASS 0: buffer.copyToChannel(null, 0) threw TypeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': parameter 1 is not of type 'Float32Array'.". +PASS 1: buffer.copyToChannel(context, 0) threw TypeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': parameter 1 is not of type 'Float32Array'.". +PASS 2: buffer.copyToChannel(x, -1) threw IndexSizeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': The channelNumber provided (-1) is outside the range [0, 2].". +PASS 3: buffer.copyToChannel(x, 3) threw IndexSizeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': The channelNumber provided (3) is outside the range [0, 2].". +PASS 4: buffer.copyToChannel(x, 0, -1) threw IndexSizeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': The startInChannel provided (4294967295) is outside the range [0, 16).". +FAIL X 5: buffer.copyToChannel(x, 0, 16) incorrectly threw IndexSizeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': The startInChannel provided (16) is outside the range [0, 16).". assert_true: expected true got false +PASS 6: buffer.copyToChannel(x, 3) threw IndexSizeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': The channelNumber provided (3) is outside the range [0, 2].". +PASS 7: buffer.copyToChannel(SharedArrayBuffer view, 0) threw TypeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': The provided ArrayBufferView value must not be shared.". +PASS 8: buffer.copyToChannel(SharedArrayBuffer view, 0, 0) threw TypeError: "Failed to execute 'copyToChannel' on 'AudioBuffer': The provided ArrayBufferView value must not be shared.". +FAIL < [copyTo-exceptions] 1 out of 10 assertions were failed. assert_true: expected true got false +PASS > [copyFrom-validate] +PASS buffer.copyFromChannel(dst8, 0) is identical to the array [1,2,3,4,5,6,7,8]. +PASS buffer.copyFromChannel(dst8, 1) is identical to the array [2,3,4,5,6,7,8,9]. +PASS buffer.copyFromChannel(dst8, 2) is identical to the array [3,4,5,6,7,8,9,10]. +PASS buffer.copyFromChannel(dst8, 0, 1) is identical to the array [2,3,4,5,6,7,8,9]. +PASS buffer.copyFromChannel(dst8, 1, 1) is identical to the array [3,4,5,6,7,8,9,10]. +PASS buffer.copyFromChannel(dst8, 2, 1) is identical to the array [4,5,6,7,8,9,10,11]. +PASS buffer.copyFromChannel(dst8, 0, 11) is identical to the array [12,13,14,15,16,-1,-1,-1]. +PASS buffer.copyFromChannel(dst8, 1, 11) is identical to the array [13,14,15,16,17,-1,-1,-1]. +PASS buffer.copyFromChannel(dst8, 2, 11) is identical to the array [14,15,16,17,18,-1,-1,-1]. +PASS buffer.copyFromChannel(dst26, 0) is identical to the array [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16...]. +PASS buffer.copyFromChannel(dst26, 1) is identical to the array [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17...]. +PASS buffer.copyFromChannel(dst26, 2) is identical to the array [3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18...]. +PASS < [copyFrom-validate] All assertions passed. (total 12 assertions) +PASS > [copyTo-validate] +PASS buffer = createConstantBuffer(context, 16, [-1,-1,-1]) did not throw an exception. +PASS buffer.copyToChannel(src, 0) is identical to the array [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16...]. +PASS buffer.copyToChannel(src, 1) is identical to the array [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16...]. +PASS buffer.copyToChannel(src, 2) is identical to the array [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16...]. +PASS buffer.copyToChannel(src10, 0) is identical to the array [1,2,3,4,5,6,7,8,9,10,-1,-1,-1,-1,-1,-1...]. +PASS buffer.copyToChannel(src10, 1) is identical to the array [1,2,3,4,5,6,7,8,9,10,-1,-1,-1,-1,-1,-1...]. +PASS buffer.copyToChannel(src10, 2) is identical to the array [1,2,3,4,5,6,7,8,9,10,-1,-1,-1,-1,-1,-1...]. +PASS buffer.copyToChannel(src10, 0, 5) is identical to the array [-1,-1,-1,-1,-1,1,2,3,4,5,6,7,8,9,10,-1...]. +PASS buffer.copyToChannel(src10, 1, 5) is identical to the array [-1,-1,-1,-1,-1,1,2,3,4,5,6,7,8,9,10,-1...]. +PASS buffer.copyToChannel(src10, 2, 5) is identical to the array [-1,-1,-1,-1,-1,1,2,3,4,5,6,7,8,9,10,-1...]. +PASS < [copyTo-validate] All assertions passed. (total 10 assertions) +FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 5 tasks were failed. assert_true: expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html index e035995..a1a5f3fc 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html
@@ -143,7 +143,7 @@ buffer.copyFromChannel(x, 0, bufferLength); }, '6: buffer.copyFromChannel(x, 0, ' + bufferLength + ')') - .throw(DOMException, 'IndexSizeError'); + .notThrow(); should(() => { buffer.copyFromChannel(x, 3); @@ -198,7 +198,7 @@ buffer.copyToChannel(x, 0, bufferLength); }, '5: buffer.copyToChannel(x, 0, ' + bufferLength + ')') - .throw(DOMException, 'IndexSizeError'); + .notThrow(); should(() => { buffer.copyToChannel(x, 3); @@ -321,7 +321,6 @@ 'buffer.copyToChannel(src10, ' + c + ', ' + startInChannel + ')', buffer.getChannelData(c), 1, src10.length, startInChannel); } - task.done(); });
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDTMFSender-helper.js b/third_party/blink/web_tests/external/wpt/webrtc/RTCDTMFSender-helper.js index 84cc771..87f7ae1 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCDTMFSender-helper.js +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDTMFSender-helper.js
@@ -78,13 +78,24 @@ Test description. */ function test_tone_change_events(testFunc, toneChanges, desc) { - async_test(t => { + // Convert to cumulative time + let cumulativeTime = 0; + const cumulativeToneChanges = toneChanges.map(c => { + cumulativeTime += c[2]; + return [c[0], c[1], cumulativeTime]; + }); + + // Wait for same duration as last expected duration + 100ms + // before passing test in case there are new tone events fired, + // in which case the test should fail. + const lastWait = toneChanges.pop()[2] + 100; + + promise_test(async t => { const pc = new RTCPeerConnection(); + const dtmfSender = await createDtmfSender(pc); + const start = Date.now(); - createDtmfSender(pc) - .then(dtmfSender => { - let lastEventTime = Date.now(); - + const allEventsReceived = new Promise(resolve => { const onToneChange = t.step_func(ev => { assert_true(ev instanceof RTCDTMFToneChangeEvent, 'Expect tone change event object to be an RTCDTMFToneChangeEvent'); @@ -93,12 +104,12 @@ assert_equals(typeof tone, 'string', 'Expect event.tone to be the tone string'); - assert_greater_than(toneChanges.length, 0, + assert_greater_than(cumulativeToneChanges.length, 0, 'More tonechange event is fired than expected'); const [ - expectedTone, expectedToneBuffer, expectedDuration - ] = toneChanges.shift(); + expectedTone, expectedToneBuffer, expectedTime + ] = cumulativeToneChanges.shift(); assert_equals(tone, expectedTone, `Expect current event.tone to be ${expectedTone}`); @@ -106,37 +117,24 @@ assert_equals(dtmfSender.toneBuffer, expectedToneBuffer, `Expect dtmfSender.toneBuffer to be updated to ${expectedToneBuffer}`); - const now = Date.now(); - const duration = now - lastEventTime; - - // We check that the delay is at least the expected one, but - // system load may cause random delay, so we do not put any - // realistic upper bound on the timing of the event. - assert_between_inclusive(duration, expectedDuration, - expectedDuration + 4000, - `Expect tonechange event for "${tone}" to be fired approximately after ${expectedDuration} milliseconds`); - - lastEventTime = now; - - if (toneChanges.length === 0) { - // Wait for same duration as last expected duration + 100ms - // before passing test in case there are new tone events fired, - // in which case the test should fail. - t.step_timeout( - t.step_func(() => { - t.done(); - pc.close(); - pc.otherPc.close(); - }), expectedDuration + 100); + // We check that the cumulative delay is at least the expected one, but + // system load may cause random delays, so we do not put any + // realistic upper bound on the timing of the events. + assert_between_inclusive(Date.now() - start, expectedTime, + expectedTime + 4000, + `Expect tonechange event for "${tone}" to be fired approximately after ${expectedTime} milliseconds`); + if (cumulativeToneChanges.length === 0) { + resolve(); } }); dtmfSender.addEventListener('tonechange', onToneChange); - testFunc(t, dtmfSender, pc); - }) - .catch(t.step_func(err => { - assert_unreached(`Unexpected promise rejection: ${err}`); - })); + }); + + testFunc(t, dtmfSender, pc); + await allEventsReceived; + const wait = ms => new Promise(resolve => t.step_timeout(resolve, ms)); + await wait(lastWait); }, desc); }
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html index c4c6b4f..9f220157 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html
@@ -100,8 +100,28 @@ await unmutePromise; const mutePromise = muteWatcher.wait_for('mute'); - pc2.close(); + localTransceiver.stop(); await mutePromise; -}, 'pc.close() mutes remote tracks'); +}, 'transceiver.stop() on one side (without renegotiation) causes mute events on the other'); + +promise_test(async t => { + const pc1 = createPeerConnectionWithCleanup(t); + const pc1Sender = pc1.addTrack(...await createTrackAndStreamWithCleanup(t)); + const localTransceiver = findTransceiverForSender(pc1, pc1Sender); + const pc2 = createPeerConnectionWithCleanup(t); + exchangeIceCandidates(pc1, pc2); + + const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2); + // Need to wait for the initial unmute event before closing, otherwise + // there will be no transition from unmuted->muted. + const muteWatcher = new EventWatcher(t, e.track, ['mute', 'unmute']); + const unmutePromise = muteWatcher.wait_for('unmute'); + await exchangeAnswer(pc1, pc2); + await unmutePromise; + + const mutePromise = muteWatcher.wait_for('mute'); + pc1.close(); + await mutePromise; +}, 'pc.close() on one side causes mute events on the other'); </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html index eca86441..4c65daab 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCTrackEvent-fire.html
@@ -47,6 +47,12 @@ a=ssrc:3 msid:3 2 `; +const sdp4 = sdp1.replace('msid-semantic', 'unknownattr'); + +const sdp5 = sdpBase + ` +a=msid:- +`; + async function applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp) { const testTrackPromise = new Promise(resolve => { @@ -60,6 +66,14 @@ const pc = new RTCPeerConnection(); test.add_cleanup(() => pc.close()); + const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0); + assert_equals(streams.length, 1, "track event has a stream"); +}, "When a=msid is absent, the track should still be associated with a stream"); + +promise_test(async test => { + const pc = new RTCPeerConnection(); + test.add_cleanup(() => pc.close()); + const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1); assert_equals(streams.length, 1, "track event has a stream"); assert_equals(streams[0].id, "1", "msid should match"); @@ -93,6 +107,23 @@ const pc = new RTCPeerConnection(); test.add_cleanup(() => pc.close()); + const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp4); + assert_equals(streams.length, 1, "track event has a stream"); + assert_equals(streams[0].id, "1", "msid should match"); +}, "stream ids should be found even if msid-semantic is absent"); + +promise_test(async test => { + const pc = new RTCPeerConnection(); + test.add_cleanup(() => pc.close()); + + const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp5); + assert_equals(streams.length, 0, "track event has no stream"); +}, "a=msid:- should result in a track event with no streams"); + +promise_test(async test => { + const pc = new RTCPeerConnection(); + test.add_cleanup(() => pc.close()); + const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1); assert_equals(streams.length, 1, "track event has a stream"); assert_equals(streams[0].id, "1", "msid should match");
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-focus-rect-contains-links.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-focus-rect-contains-links.html new file mode 100644 index 0000000..6f9fa560 --- /dev/null +++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-focus-rect-contains-links.html
@@ -0,0 +1,45 @@ +<!doctype html> +<a id="outerA" href="www" style="margin-left: 150px">outerA</a> +<div id="containerA" style="width: 300px; height: 300px; background: pink; position: relative; margin: 20px" tabindex="0"> + <div id="containerB" style="width: 270px; height: 270px; background: yellow; position: relative; top: 15px; left: 15px" tabindex="0"> + <!-- The focusables' DOM order is not the same as their layout order. + SpatNav should prioritize layout order. --> + <a id="innerB" href="www" style="position: absolute; top: 150px; left: 20px">innerB</a> + <a id="innerC" href="www" style="position: absolute; top: 150px; left: 170px">innerC</a> + <a id="innerD" href="www" style="position: absolute; top: 230px; left: 130px">innerD</a> + <a id="innerA" href="www" style="position: absolute; top: 20px; left: 130px">innerA</a> + </div> +</div> +<a id="outerB" href="www" style="margin-left: 150px">outerB</a> + +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/snav-testharness.js"></script> +<script> + var resultMap = [ + ["Down", "outerA"], + ["Down", "containerA"], + ["Down", "containerB"], + ["Down", "innerA"], + ["Down", "innerC"], + ["Down", "innerD"], + ["Down", "outerB"], + ["Up", "containerA"], + ["Up", "containerB"], + ["Up", "innerD"], + ["Up", "innerC"], + ["Up", "innerA"], + ["Up", "outerA"], + ]; + snav.assertFocusMoves(resultMap); +</script> + +<p><em>Manual test instruction: Ensure that all links are reachable. Especially, when the +yellow "container" is focused, ensure that its "inner" focusables can be reached.</em></p> + +<p>Once the bottommost inner node gets focus, we exit the complete stack of +containers at once (moving to #outerB from #innerD). Note that we don't go back to +one of the containers because that would create focus traps.</p> + +<p>Also, when holding one of the four directional keys, ensure that the page is fully scrolled +in that direction. Especially, ensure that focus does not get stuck inside the container.</p> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-focusable-at-top-of-document.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-focusable-at-top-of-document.html new file mode 100644 index 0000000..60274a2 --- /dev/null +++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-focusable-at-top-of-document.html
@@ -0,0 +1,16 @@ +<!doctype html> +<style> + body {margin: 0;} + #top-of-root {background: green; width: 100%; height: 20px;} +</style> + +<div id="top-of-root" class="top" tabindex="0"></div> + +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/snav-testharness.js"></script> +<script> + snav.assertFocusMoves([["Down", "top-of-root"]]); +</script> + +<p><em>Manual test instruction: Ensure the div is reachable even though it sits at the very top of the document.</em></p> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-focusable-at-top-of-scroller.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-focusable-at-top-of-scroller.html new file mode 100644 index 0000000..7550572 --- /dev/null +++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-focusable-at-top-of-scroller.html
@@ -0,0 +1,22 @@ +<!doctype html> +<style> + #scroller {background: yellow; width: 130px; height: 80px; overflow: scroll;} + #insider-at-top {background: purple; width: 130px; height: 20px; margin-bottom: 300px} +</style> + +<div id="scroller"> + <div id="insider-at-top" class="top" tabindex="0">at top of scroller</div> +</div> + +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/snav-testharness.js"></script> +<script> + var resultMap = [ + ["Down", "scroller"], + ["Down", "insider-at-top"] + ]; + snav.assertFocusMoves(resultMap); +</script> + +<p><em>Manual test instruction: Ensure the insider is reachable even though it sits at the very top of the scroller.</em></p>
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-fragmented-link.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-fragmented-link.html new file mode 100644 index 0000000..d0fc180c --- /dev/null +++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-fragmented-link.html
@@ -0,0 +1,76 @@ +<!doctype html> +<p>Here are two links that (due to their parent divs' limited width) split over two lines:</p> + +<div style="font: 6px Ahem;"> + <a id="start" href="www">Random start link</a>. + <div style="width: 230px; background: yellow; position: relative; margin-left: 20px;"> + <a id="fragmentedA" href="www">This is a long bla bla bla fragmented link.</a> + Hey <a id="now_reachableA" href="www">previously</a> <a id="now_reachableB" href="www">unreachable</a>. + + <div style="position: absolute; right: -100px; top: 0px; width: 100px"> + <a id="anotherA" href="www">AnotherA random link</a> + </div> + <div style="position: absolute; left: -15px; top: 0px; width: 100px"> + <a id="B" href="www">B</a> + </div> + </div> + <br> + <div style="width: 230px; background: yellow; position: relative; margin-left: 20px;"> + This is a <a id="short" href="www">short</a> bla bla <a id="fragmentedB" href="www">fragmented liiiiiink.</a> + Hey now <a id="now_reachableC" href="www">reachable</a>. + + <div style="position: absolute; right: -100px; top: 0px; width: 100px"> + <a id="anotherC" href="www">AnotherC random link</a> + </div> + <div style="position: absolute; left: -15px; top: 0px; width: 100px"> + <a id="D" href="www">D</a> + </div> + </div> + <a id="end" href="www">Random end link</a>. +</div> + +<p>The yellow background highlights a fragmented link's bounding box</em>.<br> +This bounding box covers another link. Here we test that SpatNav can reach that link.</p> + +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/snav-testharness.js"></script> +<script> + var resultMap = [ + ["Down", "start"], + ["Down", "fragmentedA"], + ["Right", "now_reachableA"], // We searched *inside* #fragmentedA's box. + ["Right", "now_reachableB"], + ["Right", "anotherA"], + ["Down", "anotherC"], // #anotherA and #anotherC are perfectly aligned. + ["Up", "anotherA"], + ["Left", "fragmentedA"], + ["Left", "now_reachableB"], // We searched *inside* #fragmentedA's box. + ["Left", "now_reachableA"], + ["Left", "B"], // We don't go to the enclosing #fragmentedA. If we did, holding + // Left would cause a loop inside #fragmentedA's bounding box. + ["Right", "fragmentedA"], + ["Down", "now_reachableA"], // We searched *inside* #fragmentedA's box. + ["Down", "short"], + ["Right", "now_reachableC"], + ["Right", "anotherC"], // We don't go to #fragmentedB because Right from #fragmentedB goes back to #short. + // This avoids an endless loop between #fragmentedB and #short if Right is held. + ["Left", "fragmentedB"], + ["Right", "short"], // We searched *inside* #fragmentedB's box. + ["Down", "end"], // This avoids an endless loop between #fragmentedB and #short if Down is held. + ["Up", "fragmentedB"], + ["Down", "short"], // We searched *inside* #fragmentedB's box. + ["Right", "now_reachableC"], + ["Right", "anotherC"], + ["Left", "fragmentedB"], + ["Left", "now_reachableC"], // We searched *inside* #fragmentedB's box. + ["Down", "end"] + ]; + snav.assertFocusMoves(resultMap); +</script> + +<p><em>Manual test instruction: Ensure that all links are reachable.</em></p> + +<p>Also, when holding one of the four directional keys, ensure that the page is fully +scrolled in that direction. Especially, ensure that focus does not get stuck inside the +fragmented link's bounding box.</p> \ No newline at end of file
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..5ba48ab --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 662 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..27b9727 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 26 but got 19 +FAIL grid assert_equals: clientWidth expected 26 but got 19 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..f754c06 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 665 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..cba380a --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 26 but got 20 +FAIL grid assert_equals: clientWidth expected 26 but got 20 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..5caab58 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 664 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..5e878d0f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 28 but got 21 +FAIL grid assert_equals: clientWidth expected 28 but got 21 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..5caab58 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 664 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..5e878d0f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 28 but got 21 +FAIL grid assert_equals: clientWidth expected 28 but got 21 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..5caab58 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 664 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..5e878d0f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 28 but got 21 +FAIL grid assert_equals: clientWidth expected 28 but got 21 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..5caab58 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 664 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..5e878d0f --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 28 but got 21 +FAIL grid assert_equals: clientWidth expected 28 but got 21 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..5ba48ab --- /dev/null +++ b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 662 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..27b9727 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 26 but got 19 +FAIL grid assert_equals: clientWidth expected 26 but got 19 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/win/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt new file mode 100644 index 0000000..5ba48ab --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/external/wpt/html/rendering/widgets/button-layout/abspos-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL abspos button with auto width, non-auto left/right (rtl) assert_equals: offsetLeft expected 662 but got 100 +PASS abspos button with auto width, non-auto left/right (ltr) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt new file mode 100644 index 0000000..27b9727 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/external/wpt/html/rendering/widgets/button-layout/grid-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL inline-grid assert_equals: clientWidth expected 26 but got 19 +FAIL grid assert_equals: clientWidth expected 26 but got 19 +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt new file mode 100644 index 0000000..5a1e4fb --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/external/wpt/webrtc/RTCTrackEvent-fire-expected.txt
@@ -0,0 +1,11 @@ +This is a testharness.js-based test. +PASS When a=msid is absent, the track should still be associated with a stream +PASS Source-level msid should be ignored if media-level msid is present +PASS Source-level msid should be parsed if media-level msid is absent +PASS Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present +PASS stream ids should be found even if msid-semantic is absent +FAIL a=msid:- should result in a track event with no streams promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=msid:- Expects 2 fields." +PASS Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream +PASS Applying a remote description with a new msid should trigger firing an event with populated streams +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html index 2364b16..5956f8694 100644 --- a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html +++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html
@@ -32,7 +32,7 @@ } </style> -<div tabindex="0"> +<div tabindex="0" id="outer"> Outer Target <div id="clip" tabindex="0"> Clip @@ -41,16 +41,30 @@ </div> <script> + const outer = document.getElementById("outer"); + const clip = document.getElementById("clip"); const target = document.getElementById("target"); // This test checks that the spatial navigation overlap testing works // correctly in the presence of clipping. The spatial navigation algorithm - // attempts to prioritize the inner element when one valid target is fully - // contained by another valid target. This test ensures the inner is - // considered fully contained even if it has clipped overflow that would - // spill outside the outer target. + // attempts to prioritize inner elements that are fully contained by another + // valid target. + // + // The spatial navigation algorithm focuses "containers" from the outside and + // in. This test ensures that also clipped "insiders" are reachable. test(() => { assert_true(!!window.internals); + + snav.triggerMove('Down'); + assert_equals(window.internals.interestedElement, + outer, + "Expected interest to move to |outer| element."); + + snav.triggerMove('Down'); + assert_equals(window.internals.interestedElement, + clip, + "Expected interest to move to |clip| element."); + snav.triggerMove('Down'); assert_equals(window.internals.interestedElement, target,
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-fully-contained-input.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-fully-contained-input.html index f4d6436..88da5b3 100644 --- a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-fully-contained-input.html +++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-fully-contained-input.html
@@ -19,24 +19,32 @@ } </style> -<div tabindex="0"> +<div tabindex="0" id="container"> <input id="input" type="text" value="second"></input> </div> +<a href="www" id="outsider">Outsider</a> <script> + const container = document.getElementById("container"); const input = document.getElementById("input"); + const outsider = document.getElementById("outsider"); - // Spatial navigation attempts to determine when one valid target fully - // contains another. In this case, the contained "inner" target should be - // selected. This is done by performing a hit test. + // Spatial navigation attempts to determine when one valid focusable fully + // contains another. In this case, the contained, "inner" target should be + // selected when we start from the container div. // - // This test ensures the hit test works correctly on an input box. This - // requires special attention because the hit element will be in the input's - // shadow dom. + // This test ensures the "is contained"-test works correctly on an <input>. + // This requires special attention because the focusable node is in the + // the <input>'s Shadow DOM. test(() => { assert_true(!!window.internals); snav.triggerMove('Down'); assert_equals(window.internals.interestedElement, + container, + "Expected interest to move to the surrounding div."); + + snav.triggerMove('Down'); + assert_equals(window.internals.interestedElement, input, "Expected interest to move to input box."); }, "Navigation to fully contained input box.");
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index ae06df7..8ddaa66e 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -56,6 +56,7 @@ method pause method play method reverse + method updatePlaybackRate setter currentTime setter effect setter id
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt index f2bcb704..c40eae3 100644 --- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDTMFSender-ontonechange.https-expected.txt
@@ -5,7 +5,7 @@ PASS insertDTMF() with duration less than 40 should be clamped to 40 PASS insertDTMF() with interToneGap less than 30 should be clamped to 30 PASS insertDTMF with comma should delay next tonechange event for a constant 2000ms -FAIL insertDTMF() with transceiver stopped in the middle should stop future tonechange events from firing assert_unreached: Unexpected promise rejection: Error: assert_equals: Expect there to be only one tranceiver in pc expected 1 but got 0 Reached unreachable code +FAIL insertDTMF() with transceiver stopped in the middle should stop future tonechange events from firing assert_equals: Expect there to be only one tranceiver in pc expected 1 but got 0 PASS Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones PASS Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones PASS Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 195b031..8add08bf 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -188,6 +188,7 @@ method pause method play method reverse + method updatePlaybackRate setter currentTime setter effect setter id
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block-ref.html new file mode 100644 index 0000000..31998cb --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block-ref.html
@@ -0,0 +1,15 @@ +<!doctype HTML> +<html> +<meta charset="utf8"> +<title>Display Locking: contain: size block layout (reference)</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://github.com/WICG/display-locking"> + +<style> +#border { + border: 1px solid black; + width: min-content; +} +</style> +<div id="border"></div> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block.html b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block.html new file mode 100644 index 0000000..d5d6562 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-block.html
@@ -0,0 +1,34 @@ +<!doctype HTML> +<html class="reftest-wait"> +<meta charset="utf8"> +<title>Display Locking: contain: size block layout</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://github.com/WICG/display-locking"> +<link rel="match" href="contain-size-block-ref.html"> +<script src="/common/reftest-wait.js"></script> + +<style> +#border { + border: 1px solid black; + width: min-content; +} +#container { + contain: style layout size; +} +</style> + +<div id="border"> + <div id="container"></div> +</div> + +<script> +function runTest() { + const container = document.getElementById("container"); + container.displayLock.acquire({ timeout: Infinity, size: [123, 345] }).then(() => { + takeScreenshot(); + }); +} + +window.onload = runTest; +</script> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex-ref.html new file mode 100644 index 0000000..4b5ac45 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex-ref.html
@@ -0,0 +1,32 @@ +<!doctype HTML> +<html> +<meta charset="utf8"> +<title>Display Locking: contain: size flex layout (reference)</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://github.com/WICG/display-locking"> + +<style> +#flexer { + display: flex; + flex-direction: row; + justify-content: space-around; + width: 200px; + height: 200px; + background: lightgreen; +} +#container { + contain: style layout size; +} +.item { + width: 50px; + height: 60px; + background: blue; +} +</style> + +<div id="flexer"> + <div class="item"></div> + <div id="container"></div> + <div class="item"></div> +</div> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex.html b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex.html new file mode 100644 index 0000000..d8d9076d --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-flex.html
@@ -0,0 +1,44 @@ +<!doctype HTML> +<html class="reftest-wait"> +<meta charset="utf8"> +<title>Display Locking: contain: size flex layout</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://github.com/WICG/display-locking"> +<link rel="match" href="contain-size-flex-ref.html"> +<script src="/common/reftest-wait.js"></script> + +<style> +#flexer { + display: flex; + flex-direction: row; + justify-content: space-around; + width: 200px; + height: 200px; + background: lightgreen; +} +#container { + contain: style layout size; +} +.item { + width: 50px; + height: 60px; + background: blue; +} +</style> + +<div id="flexer"> + <div class="item"></div> + <div id="container"></div> + <div class="item"></div> +</div> + +<script> +async function runTest() { + const container = document.getElementById("container"); + await container.displayLock.acquire({ timeout: Infinity, size: [12, 34] }); + takeScreenshot(); +} + +window.onload = runTest; +</script> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced-ref.html b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced-ref.html new file mode 100644 index 0000000..c1500c7 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced-ref.html
@@ -0,0 +1,22 @@ +<!doctype HTML> +<html> +<meta charset="utf8"> +<title>Display Locking: contain: size replaced layout (reference)</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://github.com/WICG/display-locking"> + +<style> +#border { + border: 1px solid blue; + width: max-content; +} +img { + contain: style layout size; + visibility: hidden; +} +</style> + +<div id="border"> + <img src="resources/blue-100.png"> +</div> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced.html b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced.html new file mode 100644 index 0000000..66645358 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/display-lock/sizing/contain-size-replaced.html
@@ -0,0 +1,33 @@ +<!doctype HTML> +<html class="reftest-wait"> +<meta charset="utf8"> +<title>Display Locking: contain: size replaced layout</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://github.com/WICG/display-locking"> +<link rel="match" href="contain-size-replaced-ref.html"> +<script src="/common/reftest-wait.js"></script> + +<style> +#border { + border: 1px solid blue; + width: max-content; +} +img { + contain: style layout size; +} +</style> + +<div id="border"> + <img id="element" src="resources/blue-100.png"> +</div> + +<script> +async function runTest() { + const element = document.getElementById("element"); + await element.displayLock.acquire({ timeout: Infinity, size: [12, 34] }); + takeScreenshot(); +} + +window.onload = () => requestAnimationFrame(runTest); +</script> +</html>
diff --git a/third_party/custom_tabs_client/testing_with_chromium.md b/third_party/custom_tabs_client/testing_with_chromium.md new file mode 100644 index 0000000..e71f18c --- /dev/null +++ b/third_party/custom_tabs_client/testing_with_chromium.md
@@ -0,0 +1,42 @@ +# Testing Chrome Custom Tabs with Chromium + +[TOC] + +Chrome Custom Tabs (CCT) allow an app to customize how Chrome looks and feels. +It gives an app more control over the web experience without having to use +WebView. + +## What is Chrome Custom Tabs? + +For more information on Chrome Custom Tabs, refer to +[this blog post](https://developer.chrome.com/multidevice/android/customtabs). +If you want to use Chrome Custom Tabs in your own app, the instructions are +[here](/third_party/custom_tabs_client/src/Using.md). + +## Building + +These instruction assume that you have already built Chromium for Android. If +not, instructions for building Chromium for Android are +[here](/docs/android_build_instructions.md). Details below assume that the +build is setup in out/Default. + +### Build Chrome Custom Tabs example + +```shell +$ autoninja -C out/Default custom_tabs_client_example_apk +``` + +### Install Chrome Custom Tabs example + +```shell +# Install the example +$ out/Default/bin/custom_tabs_client_example_apk install +``` + +## Start running the app + +**That it!** The example app should be installed and available. Once you +launch "Chrome Custom Tabs Example" ("Chrome C..." in apps), you should be +able to switch to use Chromium by changing "Package" to Chromium (or any +version of Chrome installed on the device). Then simply click "Launch URL +in a Chrome Custom Tab"
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium index 42e9c5bd..49d684c 100644 --- a/third_party/libvpx/README.chromium +++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@ License File: source/libvpx/LICENSE Security Critical: yes -Date: Friday May 10 2019 +Date: Monday May 13 2019 Branch: master -Commit: 4d0fe85c1957cea215085e7da41ee797e6a51f01 +Commit: 78c44e2dc26e383fdc54eb4bf406a76e52ea361e Description: Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h index 929299d..09d82e09 100644 --- a/third_party/libvpx/source/config/vpx_version.h +++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,7 +2,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 8 #define VERSION_PATCH 0 -#define VERSION_EXTRA "485-g4d0fe85c19" +#define VERSION_EXTRA "488-g78c44e2dc2" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.8.0-485-g4d0fe85c19" -#define VERSION_STRING " v1.8.0-485-g4d0fe85c19" +#define VERSION_STRING_NOSP "v1.8.0-488-g78c44e2dc2" +#define VERSION_STRING " v1.8.0-488-g78c44e2dc2"
diff --git a/third_party/sqlite/BUILD.gn b/third_party/sqlite/BUILD.gn index d099d89..096c158 100644 --- a/third_party/sqlite/BUILD.gn +++ b/third_party/sqlite/BUILD.gn
@@ -279,14 +279,11 @@ visibility = [ ":*" ] public = [ - "patched/src/recover.h", "sqlite3.h", ] sources = [ "amalgamation/sqlite3.h", - "patched/src/recover.c", - "patched/src/recover_varint.c", "sqlite3_shim.c", ]
diff --git a/tools/binary_size/libsupersize/static/tree-worker.js b/tools/binary_size/libsupersize/static/tree-worker.js index 8d7b692..c2e274c 100644 --- a/tools/binary_size/libsupersize/static/tree-worker.js +++ b/tools/binary_size/libsupersize/static/tree-worker.js
@@ -139,6 +139,8 @@ * attached to the tree. * @param {(symbolNode: TreeNode) => boolean} options.highlightTest Called to * see if a symbol should be highlighted. + * @param {boolean} options.methodCountMode Whether we're in "method count" + * mode. * @param {string} options.sep Path seperator used to find parent names. * @param {Meta} options.meta Metadata associated with this tree. */ @@ -146,6 +148,7 @@ this._getPath = options.getPath; this._filterTest = options.filterTest; this._highlightTest = options.highlightTest; + this._methodCountMode = options.methodCountMode; this._sep = options.sep || _PATH_SEP; this._meta = options.meta; @@ -416,6 +419,12 @@ const numAliases = _KEYS.NUM_ALIASES in symbol ? symbol[_KEYS.NUM_ALIASES] : 1; + // Skip methods that have changed in size but not count when in + // "method count" mode. + if (this._methodCountMode && count === 0) { + continue; + } + const symbolNode = createNode({ // Join file path to symbol name with a ":" idPath: `${idPath}:${symbol[_KEYS.SYMBOL_NAME]}`, @@ -720,7 +729,7 @@ highlightTest = () => false; } - return {groupBy, filterTest, highlightTest, url}; + return {groupBy, filterTest, highlightTest, url, methodCountMode}; } /** @type {TreeBuilder | null} */ @@ -734,10 +743,12 @@ * each symbol is tested against * @param {(symbolNode: TreeNode) => boolean} highlightTest Filter function that * each symbol's flags are tested against + * @param {boolean} methodCountMode * @param {(msg: TreeProgress) => void} onProgress * @returns {Promise<TreeProgress>} */ -async function buildTree(groupBy, filterTest, highlightTest, onProgress) { +async function buildTree( + groupBy, filterTest, highlightTest, methodCountMode, onProgress) { /** @type {Meta | null} Object from the first line of the data file */ let meta = null; @@ -802,6 +813,7 @@ getPath: getPathMap[groupBy], filterTest, highlightTest, + methodCountMode, sep: groupBy === 'component' ? '>' : _PATH_SEP, meta, }); @@ -835,7 +847,8 @@ const actions = { /** @param {{input:string|null,options:string}} param0 */ load({input, options}) { - const {groupBy, filterTest, highlightTest, url} = parseOptions(options); + const {groupBy, filterTest, highlightTest, url, methodCountMode} = + parseOptions(options); if (input === 'from-url://' && url) { // Display the data from the `load_url` query parameter console.info('Displaying data from', url); @@ -845,10 +858,11 @@ fetcher.setInput(input); } - return buildTree(groupBy, filterTest, highlightTest, progress => { - // @ts-ignore - self.postMessage(progress); - }); + return buildTree( + groupBy, filterTest, highlightTest, methodCountMode, progress => { + // @ts-ignore + self.postMessage(progress); + }); }, /** @param {string} path */ async open(path) {
diff --git a/tools/grit/grit/format/resource_map.py b/tools/grit/grit/format/resource_map.py index 12880c8..c9a73c46 100644 --- a/tools/grit/grit/format/resource_map.py +++ b/tools/grit/grit/format/resource_map.py
@@ -19,12 +19,6 @@ return partial(_FormatSource, _GetItemPath) if type == 'resource_map_source': return partial(_FormatSource, _GetItemName) - if type == 'gzipped_resource_map_header': - return partial(_FormatHeader, include_gzipped=True) - if type == 'gzipped_resource_file_map_source': - return partial(_FormatSource, _GetItemPath, include_gzipped=True) - if type == 'gzipped_resource_map_source': - return partial(_FormatSource, _GetItemName, include_gzipped=True) def GetMapName(root): @@ -50,7 +44,7 @@ return 'k' + filename -def _FormatHeader(root, lang='en', output_dir='.', include_gzipped=False): +def _FormatHeader(root, lang='en', output_dir='.'): '''Create the header file for the resource mapping. This file just declares an array of name/value pairs.''' return '''\ @@ -58,24 +52,20 @@ #include <stddef.h> -#ifndef %(macro_prefix)sGRIT_RESOURCE_MAP_STRUCT_ -#define %(macro_prefix)sGRIT_RESOURCE_MAP_STRUCT_ -struct %(struct_prefix)sGritResourceMap { +#ifndef GRIT_RESOURCE_MAP_STRUCT_ +#define GRIT_RESOURCE_MAP_STRUCT_ +struct GritResourceMap { const char* const name; - int value;%(maybe_gzipped_bool)s + int value; }; -#endif // %(macro_prefix)sGRIT_RESOURCE_MAP_STRUCT_ +#endif // GRIT_RESOURCE_MAP_STRUCT_ -extern const %(struct_prefix)sGritResourceMap %(map_name)s[]; +extern const GritResourceMap %(map_name)s[]; extern const size_t %(map_name)sSize; -''' % { 'map_name': GetMapName(root), - 'maybe_gzipped_bool': '\n bool gzipped;' if include_gzipped else '', - 'struct_prefix': 'Gzipped' if include_gzipped else '', - 'macro_prefix': 'GZIPPED_' if include_gzipped else '', - } +''' % { 'map_name': GetMapName(root) } -def _FormatSourceHeader(root, output_dir, include_gzipped): +def _FormatSourceHeader(root, output_dir): '''Create the header of the C++ source file for the resource mapping.''' rc_header_file = None map_header_file = None @@ -84,12 +74,12 @@ if 'rc_header' == type: rc_header_file = util.MakeRelativePath(output_dir, output.GetOutputFilename()) - elif 'resource_map_header' == type or 'gzipped_resource_map_header' == type: + elif 'resource_map_header' == type: map_header_file = util.MakeRelativePath(output_dir, output.GetOutputFilename()) if not rc_header_file or not map_header_file: raise Exception('resource_map_source output type requires ' - 'a *resource_map_header and rc_header outputs') + 'a resource_map_header and rc_header outputs') return '''\ // This file is automatically generated by GRIT. Do not edit. @@ -101,11 +91,10 @@ #include "%(rc_header_file)s" -const %(struct_prefix)sGritResourceMap %(map_name)s[] = { +const GritResourceMap %(map_name)s[] = { ''' % { 'map_header_file': map_header_file, 'rc_header_file': rc_header_file, 'map_name': GetMapName(root), - 'struct_prefix': 'Gzipped' if include_gzipped else '', } @@ -118,10 +107,10 @@ ''' % { 'map_name': GetMapName(root) } -def _FormatSource(get_key, root, lang, output_dir, include_gzipped=False): +def _FormatSource(get_key, root, lang, output_dir): from grit.node import include, structure, message id_map = root.GetIdMap() - yield _FormatSourceHeader(root, output_dir, include_gzipped) + yield _FormatSourceHeader(root, output_dir) seen = set() for item in root.ActiveDescendants(): if not item.IsResourceMapSource(): @@ -131,11 +120,7 @@ if tid not in id_map or key in seen: continue seen.add(key) - if include_gzipped: - gzipped = item.attrs.get('compress', '') == 'gzip' - yield ' {"%s", %s, %s},\n' % (key, tid, 'true' if gzipped else 'false') - else: - yield ' {"%s", %s},\n' % (key, tid) + yield ' {"%s", %s},\n' % (key, tid) yield _FormatSourceFooter(root)
diff --git a/tools/grit/grit/format/resource_map_unittest.py b/tools/grit/grit/format/resource_map_unittest.py index c39f4cf..cd290a71 100755 --- a/tools/grit/grit/format/resource_map_unittest.py +++ b/tools/grit/grit/format/resource_map_unittest.py
@@ -88,14 +88,14 @@ }; const size_t kTheRcHeaderSize = base::size(kTheRcHeader);''', output) - def testGzippedMapFileSourceWithGeneratedFile(self): + def testFormatResourceMapWithGeneratedFile(self): os.environ["root_gen_dir"] = "gen" grd = util.ParseGrdForUnittest('''\ <outputs> <output type="rc_header" filename="the_rc_header.h" /> - <output type="gzipped_resource_map_header" - filename="gzipped_resource_map_header.h" /> + <output type="resource_map_header" + filename="resource_map_header.h" /> </outputs> <release seq="3"> <includes first_id="10000"> @@ -107,67 +107,19 @@ </includes> </release>''', run_gatherers=True) - formatter = resource_map.GetFormatter('gzipped_resource_file_map_source') + formatter = resource_map.GetFormatter('resource_file_map_source') output = util.StripBlankLinesAndComments(''.join(formatter(grd, 'en', '.'))) expected = '''\ -#include "gzipped_resource_map_header.h" +#include "resource_map_header.h" #include <stddef.h> #include "base/stl_util.h" #include "the_rc_header.h" -const GzippedGritResourceMap kTheRcHeader[] = { - {"@out_folder@/gen/foo/bar/baz.js", IDR_FOO_BAR_BAZ_JS, true}, +const GritResourceMap kTheRcHeader[] = { + {"@out_folder@/gen/foo/bar/baz.js", IDR_FOO_BAR_BAZ_JS}, }; const size_t kTheRcHeaderSize = base::size(kTheRcHeader);''' self.assertEqual(expected, output) - def testGzippedMapHeaderAndFileSource(self): - grd = util.ParseGrdForUnittest('''\ - <outputs> - <output type="rc_header" filename="the_rc_header.h" /> - <output type="gzipped_resource_map_header" - filename="gzipped_resource_map_header.h" /> - </outputs> - <release seq="3"> - <structures first_id="300"> - <structure type="menu" name="IDC_KLONKMENU" compress="gzip" - file="grit\\testdata\\klonk.rc" encoding="utf-16" /> - </structures> - <includes first_id="10000"> - <include type="foo" file="abc" name="IDS_FIRSTPRESENT" - compress="" /> - <if expr="False"> - <include type="foo" file="def" name="IDS_MISSING" - compress="garbage" /> - </if> - </includes> - </release>''', run_gatherers=True) - formatter = resource_map.GetFormatter('gzipped_resource_map_header') - output = util.StripBlankLinesAndComments(''.join(formatter(grd, 'en', '.'))) - self.assertEqual('''\ -#include <stddef.h> -#ifndef GZIPPED_GRIT_RESOURCE_MAP_STRUCT_ -#define GZIPPED_GRIT_RESOURCE_MAP_STRUCT_ -struct GzippedGritResourceMap { - const char* const name; - int value; - bool gzipped; -}; -#endif // GZIPPED_GRIT_RESOURCE_MAP_STRUCT_ -extern const GzippedGritResourceMap kTheRcHeader[]; -extern const size_t kTheRcHeaderSize;''', output) - formatter = resource_map.GetFormatter('gzipped_resource_file_map_source') - output = util.StripBlankLinesAndComments(''.join(formatter(grd, 'en', '.'))) - self.assertEqual('''\ -#include "gzipped_resource_map_header.h" -#include <stddef.h> -#include "base/stl_util.h" -#include "the_rc_header.h" -const GzippedGritResourceMap kTheRcHeader[] = { - {"grit/testdata/klonk.rc", IDC_KLONKMENU, true}, - {"abc", IDS_FIRSTPRESENT, false}, -}; -const size_t kTheRcHeaderSize = base::size(kTheRcHeader);''', output) - def testFormatResourceMapWithOutputAllEqualsFalseForStructures(self): grd = util.ParseGrdForUnittest(''' <outputs>
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py index 46ea4ba..fc7490ab 100644 --- a/tools/grit/grit/tool/build.py +++ b/tools/grit/grit/tool/build.py
@@ -30,9 +30,6 @@ 'c_format': 'c_format', 'chrome_messages_json': 'chrome_messages_json', 'data_package': 'data_pack', - 'gzipped_resource_file_map_source': 'resource_map', - 'gzipped_resource_map_header': 'resource_map', - 'gzipped_resource_map_source': 'resource_map', 'js_map_format': 'js_map_format', 'policy_templates': 'policy_templates_json', 'rc_all': 'rc', @@ -328,11 +325,7 @@ # files (no UTF-8), so we make all RC files UTF-16 to support all # character sets. if output_type in ('rc_header', 'resource_file_map_source', - 'resource_map_header', 'resource_map_source', - 'gzipped_resource_file_map_source', - 'gzipped_resource_map_header', - 'gzipped_resource_map_source', - ): + 'resource_map_header', 'resource_map_source'): return 'cp1252' if output_type in ('android', 'c_format', 'js_map_format', 'plist', 'plist_strings', 'doc', 'json', 'android_policy',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 5688881..cabaec8a 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -23217,6 +23217,7 @@ <int value="2896" label="PaymentRequestShippingAddressChange"/> <int value="2897" label="PaymentRequestShippingOptionChange"/> <int value="2898" label="PaymentRequestPaymentMethodChange"/> + <int value="2899" label="V8Animation_UpdatePlaybackRate_Method"/> </enum> <enum name="FeaturePolicyFeature"> @@ -32627,6 +32628,7 @@ <int value="-2133892372" label="ResamplingInputEvents:disabled"/> <int value="-2133277113" label="CCTModuleCustomHeader:disabled"/> <int value="-2132591642" label="enable-input-view"/> + <int value="-2132161378" label="SendTabToSelfHistory:disabled"/> <int value="-2131746498" label="AutofillUseImprovedLabelDisambiguation:enabled"/> <int value="-2129940395" label="WebAssemblySimd:disabled"/> @@ -33481,6 +33483,7 @@ label="AutofillRationalizeRepeatedServerPredictions:disabled"/> <int value="-928138978" label="IPH_DemoMode:disabled"/> <int value="-926422468" label="disable-embedded-shared-worker"/> + <int value="-926236394" label="SendTabToSelfHistory:enabled"/> <int value="-920204598" label="ScrollAnchorSerialization:enabled"/> <int value="-918900957" label="AutofillCreditCardAssist:disabled"/> <int value="-918618075" label="enable-service-worker"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 2aab9f8..4b782e4 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -38009,13 +38009,40 @@ </histogram> <histogram name="Extensions.InstallPrompt.Accepted" enum="BooleanAccepted" - expires_after="M77"> + expires_after="2019-05-13"> + <obsolete> + Obsolete as of 2019-05 as it can be derived by comparing the aggregate + counts of Extensions.InstallPrompt.TimeToInstall and + Extensions.InstallPrompt.TimeToInstall. + </obsolete> <owner>meacer@chromium.org</owner> <summary> Whether the user accepted or aborted an extension installation. </summary> </histogram> +<histogram name="Extensions.InstallPrompt.TimeToCancel" units="ms" + expires_after="M85"> + <owner>kelvinjiang@chromium.org</owner> + <owner>extensions-core@chromium.org</owner> + <summary> + Time from first display of the extension installation prompt until the user + aborts the installation through clicking the cancel button or dismissing the + dialog. + </summary> +</histogram> + +<histogram name="Extensions.InstallPrompt.TimeToInstall" units="ms" + expires_after="M85"> + <owner>kelvinjiang@chromium.org</owner> + <owner>extensions-core@chromium.org</owner> + <summary> + Time from first display of the extension installation prompt until the user + accepts the installation. Will always be greater than 500ms as the install + option is enabled after that time has elapsed. + </summary> +</histogram> + <histogram name="Extensions.InstallPrompt.Type" enum="ExtensionInstallPromptType" expires_after="M77"> <owner>meacer@chromium.org</owner> @@ -81465,8 +81492,9 @@ </histogram> <histogram name="OfflinePages.LastN.IsSavingSamePage" - enum="OfflinePagesLastNIsSavingSamePageEnum" expires_after="2019-05-31"> + enum="OfflinePagesLastNIsSavingSamePageEnum" expires_after="2020-05-31"> <owner>carlosk@chromium.org</owner> + <owner>offline-dev@chromium.org</owner> <summary> Upon starting saving a new last_n offline page snapshot, report if that is being done for a page that is new (a navigation happened) or for one that @@ -81598,6 +81626,7 @@ enum="OfflinePagesOfflineUsage" expires_after="2020-05-31"> <owner>carlosk@chromium.org</owner> <owner>dimich@chromium.org</owner> + <owner>offline-dev@chromium.org</owner> <summary> Counts user-days when Chrome was used in specific ways regarding navigation to online and offline content. Buckets are mutually exclusive so that only @@ -82041,9 +82070,10 @@ </histogram> <histogram base="true" name="OfflinePages.SavePage.AddPageTime" units="ms" - expires_after="2019-05-31"> + expires_after="2020-05-31"> <owner>carlosk@chromium.org</owner> <owner>dimich@chromium.org</owner> + <owner>offline-dev@chromium.org</owner> <summary> Time taken to successfully create the store metadata entry for an offline page archive during the process of saving an offline page. @@ -82051,9 +82081,10 @@ </histogram> <histogram base="true" name="OfflinePages.SavePage.ComputeDigestTime" - units="ms" expires_after="2019-05-31"> + units="ms" expires_after="2020-05-31"> <owner>carlosk@chromium.org</owner> <owner>dimich@chromium.org</owner> + <owner>offline-dev@chromium.org</owner> <summary> Time taken to successfully compute the digest of an offline page archive during the process of saving an offline page. @@ -82061,9 +82092,10 @@ </histogram> <histogram base="true" name="OfflinePages.SavePage.CreateArchiveTime" - units="ms" expires_after="2019-05-31"> + units="ms" expires_after="2020-05-31"> <owner>carlosk@chromium.org</owner> <owner>dimich@chromium.org</owner> + <owner>offline-dev@chromium.org</owner> <summary> Time taken to successfully create an offline page archive during the process of saving an offline page. @@ -82108,9 +82140,10 @@ </histogram> <histogram base="true" name="OfflinePages.SavePage.PublishArchiveTime" - units="ms" expires_after="2019-05-31"> + units="ms" expires_after="2020-05-31"> <owner>carlosk@chromium.org</owner> <owner>dimich@chromium.org</owner> + <owner>offline-dev@chromium.org</owner> <summary> Time taken to successfully move an offline page archive to the public downloads folder during the process of saving an offline page. @@ -117347,7 +117380,10 @@ </histogram> <histogram name="Signin.AccountTracker.DeprecatedServiceFlagDeleted" - enum="BooleanDeletedOrNot" expires_after="M76"> + enum="BooleanDeletedOrNot" expires_after="2019-05-30"> + <obsolete> + Instrumentation code has been removed as the conversion has been completed. + </obsolete> <owner>msarda@chromium.org</owner> <owner>sdefresne@chromium.org</owner> <summary>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py index 055b670..c1e4604d 100755 --- a/tools/perf/core/perf_data_generator.py +++ b/tools/perf/core/perf_data_generator.py
@@ -815,23 +815,23 @@ # that live in tools/perf/core. We need to verify off of that list. def get_telemetry_tests_in_performance_test_suite(): tests = set() - for platform in bot_platforms.OFFICIAL_PLATFORMS: - add_benchmarks_from_sharding_map( - tests, platform.shards_map_file_path) + add_benchmarks_from_sharding_map( + tests, "shard_maps/linux-perf_map.json") + add_benchmarks_from_sharding_map( + tests, "shard_maps/android-pixel2-perf_map.json") return tests -def add_benchmarks_from_sharding_map(tests, shard_map_path): - if not os.path.exists(shard_map_path): - raise RuntimeError( - 'Platform does not have a shard map at %s.' % shard_map_path) - with open(shard_map_path) as f: - shard_map = json.load(f) - for shard, benchmarks in shard_map.iteritems(): - if "extra_infos" in shard: - continue - for benchmark, _ in benchmarks['benchmarks'].iteritems(): - tests.add(benchmark) +def add_benchmarks_from_sharding_map(tests, shard_map_name): + path = os.path.join(os.path.dirname(__file__), shard_map_name) + if os.path.exists(path): + with open(path) as f: + sharding_map = json.load(f) + for shard, benchmarks in sharding_map.iteritems(): + if "extra_infos" in shard: + continue + for benchmark, _ in benchmarks['benchmarks'].iteritems(): + tests.add(benchmark) def get_scheduled_non_telemetry_benchmarks(perf_waterfall_file):
diff --git a/tools/win/pe_summarize.py b/tools/win/pe_summarize.py index 13e4a4b2..fa74d9e9 100644 --- a/tools/win/pe_summarize.py +++ b/tools/win/pe_summarize.py
@@ -71,13 +71,6 @@ print r'Sample: %s chrome.dll original\chrome.dll' % sys.argv[0] return 0 - # Add to the path so that dumpbin can run. - vs_dir = r'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64' - if not os.path.exists(os.path.join(vs_dir, 'dumpbin.exe')): - print "Couldn't find dumpbin.exe. Visual Studio 2015 must be installed." - return 0 - os.environ['PATH'] = vs_dir + ';' + os.environ["PATH"] - # Track the name of the last PE (Portable Executable) file to be processed - # file name only, without the path. last_pe_filepart = "" @@ -92,32 +85,43 @@ print '%10s: %9s , %9s' % ('name', 'mem size', 'disk size') sections = None - command = 'dumpbin.exe /headers "%s"' % pe_path - for line in subprocess.check_output(command).splitlines(): - if line.startswith('SECTION HEADER #'): - sections = [] - elif type(sections) == type([]): - # We must be processing a section header. - sections.append(line.strip()) - # When we've accumulated four lines of data, process them. - if len(sections) == 4: - name, memory_size, _, disk_size = sections - assert name.count('name') == 1 - assert memory_size.count('virtual size') == 1 - assert disk_size.count('size of raw data') == 1 - name = name.split()[0] - memory_size = int(memory_size.split()[0], 16) - disk_size = int(disk_size.split()[0], 16) - # Print the sizes in decimal MB. This makes large numbers easier to - # understand - 33.199959 is easier to read than 33199959. Decimal MB - # is used to allow simple conversions to a precise number of bytes. - if abs(memory_size - disk_size) < 512: - print '%10s: %9.6f MB' % (name, memory_size / 1e6) - else: - print '%10s: %9.6f MB, %9.6f MB' % (name, memory_size / 1e6, - disk_size / 1e6) - results.append((name, memory_size)) - sections = None + # Pass the undocumented /nopdb header to avoid hitting symbol servers for + # the entrypoint name. + command = 'dumpbin.exe /nopdb /headers "%s"' % pe_path + try: + for line in subprocess.check_output(command).splitlines(): + if line.startswith('SECTION HEADER #'): + sections = [] + elif type(sections) == type([]): + # We must be processing a section header. + sections.append(line.strip()) + # When we've accumulated four lines of data, process them. + if len(sections) == 4: + name, memory_size, _, disk_size = sections + assert name.count('name') == 1 + assert memory_size.count('virtual size') == 1 + assert disk_size.count('size of raw data') == 1 + name = name.split()[0] + memory_size = int(memory_size.split()[0], 16) + disk_size = int(disk_size.split()[0], 16) + # Print the sizes in decimal MB. This makes large numbers easier to + # understand - 33.199959 is easier to read than 33199959. Decimal MB + # is used to allow simple conversions to a precise number of bytes. + if abs(memory_size - disk_size) < 512: + print '%10s: %9.6f MB' % (name, memory_size / 1e6) + else: + print '%10s: %9.6f MB, %9.6f MB' % (name, memory_size / 1e6, + disk_size / 1e6) + results.append((name, memory_size)) + sections = None + except WindowsError as error: + if error.winerror == 2: + print (r'Cannot find dumpbin. Run "C:\Program Files (x86)\Microsoft ' + r'Visual Studio\2017\Professional\VC\Auxiliary\Build' + r'\vcvarsall.bat amd64" or similar to add dumpbin to the path.') + else: + print error + break print pe_filepart = os.path.split(pe_path)[1]
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc index 5854db3..55697a51 100644 --- a/ui/accessibility/ax_event_generator.cc +++ b/ui/accessibility/ax_event_generator.cc
@@ -208,6 +208,9 @@ case ax::mojom::StringAttribute::kLanguage: AddEvent(node, Event::LANGUAGE_CHANGED); break; + case ax::mojom::StringAttribute::kLiveRelevant: + AddEvent(node, Event::LIVE_RELEVANT_CHANGED); + break; case ax::mojom::StringAttribute::kLiveStatus: AddEvent(node, Event::LIVE_STATUS_CHANGED);
diff --git a/ui/accessibility/ax_event_generator.h b/ui/accessibility/ax_event_generator.h index 32c216b..31137cb 100644 --- a/ui/accessibility/ax_event_generator.h +++ b/ui/accessibility/ax_event_generator.h
@@ -52,6 +52,7 @@ LIVE_REGION_CHANGED, // Fired on the root of a live region. LIVE_REGION_CREATED, LIVE_REGION_NODE_CHANGED, // Fired on a node within a live region. + LIVE_RELEVANT_CHANGED, LIVE_STATUS_CHANGED, LOAD_COMPLETE, LOAD_START,
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc index f0fe7a7..dc7e20d 100644 --- a/ui/accessibility/ax_event_generator_unittest.cc +++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -107,6 +107,9 @@ case AXEventGenerator::Event::LIVE_REGION_NODE_CHANGED: event_name = "LIVE_REGION_NODE_CHANGED"; break; + case AXEventGenerator::Event::LIVE_RELEVANT_CHANGED: + event_name = "LIVE_RELEVANT_CHANGED"; + break; case AXEventGenerator::Event::LIVE_STATUS_CHANGED: event_name = "LIVE_STATUS_CHANGED"; break; @@ -1286,7 +1289,7 @@ EXPECT_EQ("ATOMIC_CHANGED on 1", DumpEvents(&event_generator)); } -TEST(AXEventGeneratorTest, PopupChanged) { +TEST(AXEventGeneratorTest, HasPopupChanged) { AXTreeUpdate initial_state; initial_state.root_id = 1; initial_state.nodes.resize(1); @@ -1301,6 +1304,22 @@ EXPECT_EQ("HASPOPUP_CHANGED on 1", DumpEvents(&event_generator)); } +TEST(AXEventGeneratorTest, LiveRelevantChanged) { + AXTreeUpdate initial_state; + initial_state.root_id = 1; + initial_state.nodes.resize(1); + initial_state.nodes[0].id = 1; + + AXTree tree(initial_state); + AXEventGenerator event_generator(&tree); + AXTreeUpdate update = initial_state; + + update.nodes[0].AddStringAttribute(ax::mojom::StringAttribute::kLiveRelevant, + "all"); + EXPECT_TRUE(tree.Unserialize(update)); + EXPECT_EQ("LIVE_RELEVANT_CHANGED on 1", DumpEvents(&event_generator)); +} + TEST(AXEventGeneratorTest, MultilineStateChanged) { AXTreeUpdate initial_state; initial_state.root_id = 1;
diff --git a/ui/native_theme/caption_style_mac.mm b/ui/native_theme/caption_style_mac.mm index d237eaff..75af604 100644 --- a/ui/native_theme/caption_style_mac.mm +++ b/ui/native_theme/caption_style_mac.mm
@@ -37,12 +37,14 @@ // 4) The only useful domain to retrieve attributes from is kUserDomain; the // system domain's values never change. -std::string GetMAForegroundColorAsCSSColor() { +std::string GetMAForegroundColorAndOpacityAsCSSColor() { base::ScopedCFTypeRef<CGColorRef> cg_color( MACaptionAppearanceCopyForegroundColor(kUserDomain, nullptr)); + float opacity = MACaptionAppearanceGetForegroundOpacity(kUserDomain, nullptr); - return color_utils::SkColorToRgbaString( - skia::CGColorRefToSkColor(cg_color.get())); + SkColor rgba_color = + SkColorSetA(skia::CGColorRefToSkColor(cg_color.get()), 0xff * opacity); + return color_utils::SkColorToRgbaString(rgba_color); } std::string GetMABackgroundColorAndOpacityAsCSSColor() { @@ -124,7 +126,7 @@ CaptionStyle CaptionStyle::FromSystemSettings() { CaptionStyle style; - style.text_color = GetMAForegroundColorAsCSSColor(); + style.text_color = GetMAForegroundColorAndOpacityAsCSSColor(); style.background_color = GetMABackgroundColorAndOpacityAsCSSColor(); style.text_size = GetMATextScaleAsCSSPercent(); style.text_shadow = GetMATextEdgeStyleAsCSSShadow();
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc index c336edd..34d4412 100644 --- a/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc +++ b/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc
@@ -56,11 +56,10 @@ gfx::NativePixmapHandle handle, std::unique_ptr<GbmBuffer>* buffer, scoped_refptr<DrmFramebuffer>* framebuffer) { - PostSyncTask( - drm_thread_.task_runner(), - base::BindOnce(&DrmThread::CreateBufferFromHandle, - base::Unretained(&drm_thread_), widget, size, format, - base::Passed(std::move(handle)), buffer, framebuffer)); + PostSyncTask(drm_thread_.task_runner(), + base::BindOnce(&DrmThread::CreateBufferFromHandle, + base::Unretained(&drm_thread_), widget, size, + format, std::move(handle), buffer, framebuffer)); } void DrmThreadProxy::SetClearOverlayCacheCallback(
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc index 7235a36..847c0fe9 100644 --- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc +++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -35,7 +35,7 @@ widget_(widget) {} GbmPixmapWayland::~GbmPixmapWayland() { - if (gbm_bo_) + if (gbm_bo_ && widget_ != gfx::kNullAcceleratedWidget) connection_->DestroyZwpLinuxDmabuf(widget_, GetUniqueId()); } @@ -80,7 +80,10 @@ return false; } - CreateZwpLinuxDmabuf(); + // The pixmap can be created as a staging buffer and not be mapped to any of + // the existing widgets. + if (widget_ != gfx::kNullAcceleratedWidget) + CreateZwpLinuxDmabuf(); return true; }
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc index 524c9af..724d1e0 100644 --- a/ui/views/bubble/bubble_frame_view.cc +++ b/ui/views/bubble/bubble_frame_view.cc
@@ -177,6 +177,8 @@ int BubbleFrameView::NonClientHitTest(const gfx::Point& point) { if (!bounds().Contains(point)) return HTNOWHERE; + if (hit_test_transparent_) + return HTTRANSPARENT; if (close_->visible() && close_->GetMirroredBounds().Contains(point)) return HTCLOSE;
diff --git a/ui/views/bubble/bubble_frame_view.h b/ui/views/bubble/bubble_frame_view.h index 7f43899..a3b91eb0 100644 --- a/ui/views/bubble/bubble_frame_view.h +++ b/ui/views/bubble/bubble_frame_view.h
@@ -97,6 +97,11 @@ preferred_arrow_adjustment_ = adjustment; } + bool hit_test_transparent() const { return hit_test_transparent_; } + void set_hit_test_transparent(bool hit_test_transparent) { + hit_test_transparent_ = hit_test_transparent; + } + // Get/set the corner radius of the bubble border. int corner_radius() const { return bubble_border_ ? bubble_border_->corner_radius() : 0; @@ -219,6 +224,10 @@ PreferredArrowAdjustment preferred_arrow_adjustment_ = PreferredArrowAdjustment::kMirror; + // If true the view is transparent to all hit tested events (i.e. click and + // hover). + bool hit_test_transparent_ = false; + DISALLOW_COPY_AND_ASSIGN(BubbleFrameView); };