diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 83e59cbb..03b6249 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1170,6 +1170,7 @@ "frame/caption_buttons/frame_size_button_unittest.cc", "frame/custom_frame_view_ash_unittest.cc", "frame/default_header_painter_unittest.cc", + "ime/ime_controller_unittest.cc", "laser/laser_pointer_controller_unittest.cc", "laser/laser_pointer_points_unittest.cc", "laser/laser_segment_utils_unittest.cc",
diff --git a/ash/ime/ime_controller.cc b/ash/ime/ime_controller.cc index 95121b5..03c820f 100644 --- a/ash/ime/ime_controller.cc +++ b/ash/ime/ime_controller.cc
@@ -4,7 +4,8 @@ #include "ash/ime/ime_controller.h" -#include "ash/public/interfaces/ime_info.mojom.h" +#include "ash/shell.h" +#include "ash/system/tray/system_tray_notifier.h" namespace ash { @@ -12,20 +13,23 @@ ImeController::~ImeController() = default; -mojom::ImeInfo ImeController::GetCurrentIme() const { - return mojom::ImeInfo(); +void ImeController::RefreshIme( + const mojom::ImeInfo& current_ime, + const std::vector<mojom::ImeInfo>& available_imes, + const std::vector<mojom::ImeMenuItem>& menu_items) { + current_ime_ = current_ime; + available_imes_ = available_imes; + current_ime_menu_items_ = menu_items; + Shell::Get()->system_tray_notifier()->NotifyRefreshIME(); } -std::vector<mojom::ImeInfo> ImeController::GetAvailableImes() const { - return std::vector<mojom::ImeInfo>(); +void ImeController::SetImesManagedByPolicy(bool managed) { + managed_by_policy_ = managed; + Shell::Get()->system_tray_notifier()->NotifyRefreshIME(); } -bool ImeController::IsImeManaged() const { - return false; -} - -std::vector<mojom::ImeMenuItem> ImeController::GetCurrentImeMenuItems() const { - return std::vector<mojom::ImeMenuItem>(); +void ImeController::ShowImeMenuOnShelf(bool show) { + Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(show); } } // namespace ash
diff --git a/ash/ime/ime_controller.h b/ash/ime/ime_controller.h index 22312602..96183636 100644 --- a/ash/ime/ime_controller.h +++ b/ash/ime/ime_controller.h
@@ -8,37 +8,55 @@ #include <vector> #include "ash/ash_export.h" +#include "ash/public/interfaces/ime_info.mojom.h" #include "base/macros.h" namespace ash { -namespace mojom { -class ImeInfo; -class ImeMenuItem; -} // namespace mojom - // Connects ash IME users (e.g. the system tray) to the IME implementation, // which might live in Chrome browser or in a separate mojo service. // TODO(jamescook): Convert to use mojo IME interface to Chrome browser. class ASH_EXPORT ImeController { public: ImeController(); - virtual ~ImeController(); + ~ImeController(); - // Returns the currently selected IME. - virtual mojom::ImeInfo GetCurrentIme() const; + const mojom::ImeInfo& current_ime() const { return current_ime_; } - // Returns a list of available IMEs. "Available" IMEs are both installed and - // enabled by the user in settings. - virtual std::vector<mojom::ImeInfo> GetAvailableImes() const; + const std::vector<mojom::ImeInfo>& available_imes() const { + return available_imes_; + } - // Returns true if the available IMEs are managed by enterprise policy. - virtual bool IsImeManaged() const; + bool managed_by_policy() const { return managed_by_policy_; } - // Returns additional menu items for properties of the currently selected IME. - virtual std::vector<mojom::ImeMenuItem> GetCurrentImeMenuItems() const; + const std::vector<mojom::ImeMenuItem>& current_ime_menu_items() const { + return current_ime_menu_items_; + } + + // Updates the cached IME information and refreshes the UI. + // TODO(jamescook): This should take an ID for current_ime. + void RefreshIme(const mojom::ImeInfo& current_ime, + const std::vector<mojom::ImeInfo>& available_imes, + const std::vector<mojom::ImeMenuItem>& menu_items); + + void SetImesManagedByPolicy(bool managed); + + // Shows the IME menu on the shelf instead of inside the system tray menu. + void ShowImeMenuOnShelf(bool show); private: + mojom::ImeInfo current_ime_; + + // "Available" IMEs are both installed and enabled by the user in settings. + std::vector<mojom::ImeInfo> available_imes_; + + // True if the available IMEs are currently managed by enterprise policy. + // For example, can occur at the login screen with device-level policy. + bool managed_by_policy_ = false; + + // Additional menu items for properties of the currently selected IME. + std::vector<mojom::ImeMenuItem> current_ime_menu_items_; + DISALLOW_COPY_AND_ASSIGN(ImeController); };
diff --git a/ash/ime/ime_controller_unittest.cc b/ash/ime/ime_controller_unittest.cc new file mode 100644 index 0000000..e235e6a4 --- /dev/null +++ b/ash/ime/ime_controller_unittest.cc
@@ -0,0 +1,86 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/ime/ime_controller.h" + +#include <vector> + +#include "ash/public/interfaces/ime_info.mojom.h" +#include "ash/shell.h" +#include "ash/system/ime/ime_observer.h" +#include "ash/system/tray/system_tray_notifier.h" +#include "ash/test/ash_test_base.h" + +namespace ash { +namespace { + +class TestImeObserver : public IMEObserver { + public: + TestImeObserver() = default; + ~TestImeObserver() override = default; + + // IMEObserver: + void OnIMERefresh() override { refresh_count_++; } + void OnIMEMenuActivationChanged(bool is_active) override { + ime_menu_active_ = is_active; + } + + int refresh_count_ = 0; + bool ime_menu_active_ = false; +}; + +using ImeControllerTest = test::AshTestBase; + +TEST_F(ImeControllerTest, RefreshIme) { + ImeController* controller = Shell::Get()->ime_controller(); + TestImeObserver observer; + Shell::Get()->system_tray_notifier()->AddIMEObserver(&observer); + + mojom::ImeInfo ime1; + ime1.id = "ime1"; + mojom::ImeInfo ime2; + ime2.id = "ime2"; + + mojom::ImeMenuItem item1; + item1.key = "key1"; + + controller->RefreshIme(ime1, {ime1, ime2}, {item1}); + + // Cached data was updated. + EXPECT_EQ("ime1", controller->current_ime().id); + ASSERT_EQ(2u, controller->available_imes().size()); + EXPECT_EQ("ime1", controller->available_imes()[0].id); + EXPECT_EQ("ime2", controller->available_imes()[1].id); + ASSERT_EQ(1u, controller->current_ime_menu_items().size()); + EXPECT_EQ("key1", controller->current_ime_menu_items()[0].key); + + // Observer was notified. + EXPECT_EQ(1, observer.refresh_count_); +} + +TEST_F(ImeControllerTest, SetImesManagedByPolicy) { + ImeController* controller = Shell::Get()->ime_controller(); + TestImeObserver observer; + Shell::Get()->system_tray_notifier()->AddIMEObserver(&observer); + + // Defaults to false. + EXPECT_FALSE(controller->managed_by_policy()); + + // Setting the value notifies observers. + controller->SetImesManagedByPolicy(true); + EXPECT_TRUE(controller->managed_by_policy()); + EXPECT_EQ(1, observer.refresh_count_); +} + +TEST_F(ImeControllerTest, ShowImeMenuOnShelf) { + ImeController* controller = Shell::Get()->ime_controller(); + TestImeObserver observer; + Shell::Get()->system_tray_notifier()->AddIMEObserver(&observer); + + controller->ShowImeMenuOnShelf(true); + EXPECT_TRUE(observer.ime_menu_active_); +} + +} // namespace +} // namespace ash
diff --git a/ash/mojo_interface_factory.cc b/ash/mojo_interface_factory.cc index 78ea5f4c..10aec6ab 100644 --- a/ash/mojo_interface_factory.cc +++ b/ash/mojo_interface_factory.cc
@@ -19,6 +19,7 @@ #include "ash/shutdown_controller.h" #include "ash/system/locale/locale_notification_controller.h" #include "ash/system/network/vpn_list.h" +#include "ash/system/night_light/night_light_controller.h" #include "ash/system/tray/system_tray_controller.h" #include "ash/tray_action/tray_action.h" #include "ash/wallpaper/wallpaper_controller.h" @@ -82,6 +83,12 @@ Shell::Get()->new_window_controller()->BindRequest(std::move(request)); } +void BindNightLightControllerRequestOnMainThread( + const service_manager::BindSourceInfo& source_info, + mojom::NightLightControllerRequest request) { + Shell::Get()->night_light_controller()->BindRequest(std::move(request)); +} + void BindSessionControllerRequestOnMainThread( const service_manager::BindSourceInfo& source_info, mojom::SessionControllerRequest request) { @@ -157,6 +164,11 @@ registry->AddInterface( base::Bind(&BindNewWindowControllerRequestOnMainThread), main_thread_task_runner); + if (NightLightController::IsFeatureEnabled()) { + registry->AddInterface( + base::Bind(&BindNightLightControllerRequestOnMainThread), + main_thread_task_runner); + } registry->AddInterface(base::Bind(&BindSessionControllerRequestOnMainThread), main_thread_task_runner); registry->AddInterface(base::Bind(&BindShelfRequestOnMainThread),
diff --git a/ash/mus/manifest.json b/ash/mus/manifest.json index 3a864e38..32e927d5 100644 --- a/ash/mus/manifest.json +++ b/ash/mus/manifest.json
@@ -14,6 +14,7 @@ "ash::mojom::LockScreen", "ash::mojom::MediaController", "ash::mojom::NewWindowController", + "ash::mojom::NightLightController", "ash::mojom::SessionController", "ash::mojom::ShelfController", "ash::mojom::ShutdownController",
diff --git a/ash/mus/shell_delegate_mus.cc b/ash/mus/shell_delegate_mus.cc index e6a79c8..744ec66 100644 --- a/ash/mus/shell_delegate_mus.cc +++ b/ash/mus/shell_delegate_mus.cc
@@ -87,10 +87,6 @@ return new SystemTrayDelegateMus(); } -ImeController* ShellDelegateMus::GetImeController() { - return &stub_ime_controller_; -} - std::unique_ptr<WallpaperDelegate> ShellDelegateMus::CreateWallpaperDelegate() { return base::MakeUnique<WallpaperDelegateMus>(); }
diff --git a/ash/mus/shell_delegate_mus.h b/ash/mus/shell_delegate_mus.h index 4c9f266..7736d37 100644 --- a/ash/mus/shell_delegate_mus.h +++ b/ash/mus/shell_delegate_mus.h
@@ -7,7 +7,6 @@ #include <memory> -#include "ash/ime/ime_controller.h" #include "ash/shell_delegate.h" #include "base/macros.h" @@ -37,7 +36,6 @@ void ShelfInit() override; void ShelfShutdown() override; SystemTrayDelegate* CreateSystemTrayDelegate() override; - ImeController* GetImeController() override; std::unique_ptr<WallpaperDelegate> CreateWallpaperDelegate() override; AccessibilityDelegate* CreateAccessibilityDelegate() override; std::unique_ptr<PaletteDelegate> CreatePaletteDelegate() override; @@ -55,7 +53,6 @@ private: // |connector_| may be null in tests. service_manager::Connector* connector_; - ImeController stub_ime_controller_; DISALLOW_COPY_AND_ASSIGN(ShellDelegateMus); };
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn index 9c2c920b..623b242 100644 --- a/ash/public/interfaces/BUILD.gn +++ b/ash/public/interfaces/BUILD.gn
@@ -22,6 +22,7 @@ "lock_screen.mojom", "media.mojom", "new_window.mojom", + "night_light_controller.mojom", "session_controller.mojom", "shelf.mojom", "shutdown.mojom",
diff --git a/ash/public/interfaces/night_light_controller.mojom b/ash/public/interfaces/night_light_controller.mojom new file mode 100644 index 0000000..2da100f --- /dev/null +++ b/ash/public/interfaces/night_light_controller.mojom
@@ -0,0 +1,50 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module ash.mojom; + +// Represents a geolocation position fix. It's "simple" because it doesn't +// expose all the parameters of the position interface as defined by the +// Geolocation API Specification: +// (https://dev.w3.org/geo/api/spec-source.html#position_interface). +// The NightLightController is only interested in valid latitude and longitude. +// It also doesn't require any specific accuracy. The more accurate the +// positions, the more accurate sunset and sunrise times calculations. However, +// an IP-based geoposition is considered good enough. +struct SimpleGeoposition { + double latitude; + double longitude; +}; + +// Used by a client (e.g. Chrome) to provide the current user's geoposition. +interface NightLightController { + enum ScheduleType { + // Automatic toggling of NightLight is turned off. + kNone = 0, + + // Turned automatically on at the user's local sunset time, and off at the + // user's local sunrise time. + kSunsetToSunrise = 1, + + // Toggled automatically based on the custom set start and end times + // selected by the user from the system settings. + kCustom = 2, + }; + + // Sets the client that will be notified of changes in the Night Light + // schedule type. + SetClient(NightLightClient client); + + // Provides the NightLightController with the user's geoposition so that it + // can calculate the sunset and sunrise times. This should only be called when + // the schedule type is set to "Sunset to Sunrise". + SetCurrentGeoposition(SimpleGeoposition position); +}; + +// Used by ash to notify a client (e.g. Chrome) of the changes in the Night +// Light schedule type. +interface NightLightClient { + // Notifies the client with the new schedule type whenever it changes. + OnScheduleTypeChanged(NightLightController.ScheduleType new_type); +}; \ No newline at end of file
diff --git a/ash/shell.cc b/ash/shell.cc index 8600cd4..ba18b54 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -571,7 +571,7 @@ base::MakeUnique<system::BrightnessControllerChromeos>()), cast_config_(base::MakeUnique<CastConfigController>()), focus_cycler_(base::MakeUnique<FocusCycler>()), - ime_controller_(shell_delegate->GetImeController()), + ime_controller_(base::MakeUnique<ImeController>()), immersive_context_(base::MakeUnique<ImmersiveContextAsh>()), keyboard_brightness_control_delegate_( base::MakeUnique<KeyboardBrightnessController>()), @@ -597,7 +597,6 @@ native_cursor_manager_(nullptr), simulate_modal_window_open_for_testing_(false), is_touch_hud_projection_enabled_(false) { - DCHECK(ime_controller_); // TODO(sky): better refactor cash/mash dependencies. Perhaps put all cash // state on ShellPortClassic. http://crbug.com/671246.
diff --git a/ash/shell.h b/ash/shell.h index 1150b456..5c2ad3c 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -324,7 +324,7 @@ } ::wm::CompoundEventFilter* env_filter() { return env_filter_.get(); } FocusCycler* focus_cycler() { return focus_cycler_.get(); } - ImeController* ime_controller() { return ime_controller_; } + ImeController* ime_controller() { return ime_controller_.get(); } KeyboardBrightnessControlDelegate* keyboard_brightness_control_delegate() { return keyboard_brightness_control_delegate_.get(); } @@ -693,7 +693,7 @@ std::unique_ptr<CastConfigController> cast_config_; std::unique_ptr<DragDropController> drag_drop_controller_; std::unique_ptr<FocusCycler> focus_cycler_; - ImeController* const ime_controller_; + std::unique_ptr<ImeController> ime_controller_; std::unique_ptr<ImmersiveContextAsh> immersive_context_; std::unique_ptr<KeyboardBrightnessControlDelegate> keyboard_brightness_control_delegate_;
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index 5dc0147..81001e1a 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc
@@ -110,10 +110,6 @@ return new SystemTrayDelegate; } -ImeController* ShellDelegateImpl::GetImeController() { - return &stub_ime_controller_; -} - std::unique_ptr<WallpaperDelegate> ShellDelegateImpl::CreateWallpaperDelegate() { return base::MakeUnique<DefaultWallpaperDelegate>();
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h index ba873a7..0074e50c 100644 --- a/ash/shell/shell_delegate_impl.h +++ b/ash/shell/shell_delegate_impl.h
@@ -8,7 +8,6 @@ #include <memory> #include <string> -#include "ash/ime/ime_controller.h" #include "ash/shell_delegate.h" #include "base/macros.h" @@ -39,7 +38,6 @@ void ShelfInit() override; void ShelfShutdown() override; SystemTrayDelegate* CreateSystemTrayDelegate() override; - ImeController* GetImeController() override; std::unique_ptr<WallpaperDelegate> CreateWallpaperDelegate() override; AccessibilityDelegate* CreateAccessibilityDelegate() override; std::unique_ptr<PaletteDelegate> CreatePaletteDelegate() override; @@ -55,8 +53,6 @@ void UpdateTouchscreenStatusFromPrefs() override; private: - ImeController stub_ime_controller_; - DISALLOW_COPY_AND_ASSIGN(ShellDelegateImpl); };
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h index 583a852..f5c62c3b 100644 --- a/ash/shell_delegate.h +++ b/ash/shell_delegate.h
@@ -39,7 +39,6 @@ class AccessibilityDelegate; class GPUSupport; -class ImeController; class PaletteDelegate; class Shelf; struct ShelfItem; @@ -99,9 +98,6 @@ // Creates a system-tray delegate. Shell takes ownership of the delegate. virtual SystemTrayDelegate* CreateSystemTrayDelegate() = 0; - // TODO(jamescook): Remove in favor of chrome using a mojo interface on ash. - virtual ImeController* GetImeController() = 0; - // Creates a wallpaper delegate. Shell takes ownership of the delegate. virtual std::unique_ptr<WallpaperDelegate> CreateWallpaperDelegate() = 0;
diff --git a/ash/system/ime/tray_ime_chromeos.cc b/ash/system/ime/tray_ime_chromeos.cc index d481c19b..d79c7642 100644 --- a/ash/system/ime/tray_ime_chromeos.cc +++ b/ash/system/ime/tray_ime_chromeos.cc
@@ -112,7 +112,7 @@ } void CreateExtraTitleRowButtons() override { - if (ime_controller_->IsImeManaged()) { + if (ime_controller_->managed_by_policy()) { controlled_setting_icon_ = TrayPopupUtils::CreateMainImageView(); controlled_setting_icon_->SetImage( gfx::CreateVectorIcon(kSystemMenuBusinessIcon, kMenuIconColor)); @@ -180,14 +180,16 @@ } void TrayIME::Update() { - UpdateTrayLabel(current_ime_, ime_list_.size()); + size_t ime_count = ime_controller_->available_imes().size(); + UpdateTrayLabel(ime_controller_->current_ime(), ime_count); if (default_) { default_->SetVisible(ShouldDefaultViewBeVisible()); - default_->UpdateLabel(GetDefaultViewLabel(ime_list_.size() > 1)); + default_->UpdateLabel(GetDefaultViewLabel(ime_count > 1)); } if (detailed_) { - detailed_->Update(ime_list_, property_items_, ShouldShowKeyboardToggle(), - GetSingleImeBehavior()); + detailed_->Update(ime_controller_->available_imes(), + ime_controller_->current_ime_menu_items(), + ShouldShowKeyboardToggle(), GetSingleImeBehavior()); } } @@ -215,7 +217,7 @@ base::string16 TrayIME::GetDefaultViewLabel(bool show_ime_label) { if (show_ime_label) { - return ime_controller_->GetCurrentIme().name; + return ime_controller_->current_ime().name; } else { // Display virtual keyboard status instead. int id = keyboard::IsKeyboardEnabled() @@ -239,7 +241,8 @@ views::View* TrayIME::CreateDefaultView(LoginStatus status) { CHECK(default_ == nullptr); default_ = new tray::IMEDefaultView( - this, GetDefaultViewLabel(ShouldShowImeTrayItem(ime_list_.size()))); + this, GetDefaultViewLabel(ShouldShowImeTrayItem( + ime_controller_->available_imes().size()))); default_->SetVisible(ShouldDefaultViewBeVisible()); return default_; } @@ -264,30 +267,23 @@ } void TrayIME::OnIMERefresh() { - // Caches the current ime state. - current_ime_ = ime_controller_->GetCurrentIme(); - property_items_ = ime_controller_->GetCurrentImeMenuItems(); - ime_list_ = ime_controller_->GetAvailableImes(); - Update(); } void TrayIME::OnIMEMenuActivationChanged(bool is_active) { is_visible_ = !is_active; - if (is_visible_) - OnIMERefresh(); - else - Update(); + Update(); } bool TrayIME::IsIMEManaged() { - return ime_controller_->IsImeManaged(); + return ime_controller_->managed_by_policy(); } bool TrayIME::ShouldDefaultViewBeVisible() { return is_visible_ && - (ShouldShowImeTrayItem(ime_list_.size()) || - property_items_.size() > 1 || ShouldShowKeyboardToggle()); + (ShouldShowImeTrayItem(ime_controller_->available_imes().size()) || + ime_controller_->current_ime_menu_items().size() > 1 || + ShouldShowKeyboardToggle()); } bool TrayIME::ShouldShowImeTrayItem(size_t ime_count) {
diff --git a/ash/system/ime/tray_ime_chromeos.h b/ash/system/ime/tray_ime_chromeos.h index 3e330e5..2e27f42 100644 --- a/ash/system/ime/tray_ime_chromeos.h +++ b/ash/system/ime/tray_ime_chromeos.h
@@ -87,12 +87,9 @@ TrayItemView* tray_label_; tray::IMEDefaultView* default_; tray::IMEDetailedView* detailed_; + // Whether the virtual keyboard is suppressed. bool keyboard_suppressed_; - // Cached IME info. - std::vector<mojom::ImeInfo> ime_list_; - mojom::ImeInfo current_ime_; - std::vector<mojom::ImeMenuItem> property_items_; // Whether the IME label and tray items should be visible. bool is_visible_;
diff --git a/ash/system/ime/tray_ime_chromeos_unittest.cc b/ash/system/ime/tray_ime_chromeos_unittest.cc index b13a4b46..4496c08 100644 --- a/ash/system/ime/tray_ime_chromeos_unittest.cc +++ b/ash/system/ime/tray_ime_chromeos_unittest.cc
@@ -4,6 +4,9 @@ #include "ash/system/ime/tray_ime_chromeos.h" +#include <memory> +#include <vector> + #include "ash/accessibility_delegate.h" #include "ash/accessibility_types.h" #include "ash/ime/ime_controller.h" @@ -17,31 +20,6 @@ #include "ui/keyboard/keyboard_util.h" namespace ash { -namespace { - -class TestImeController : public ImeController { - public: - TestImeController() = default; - ~TestImeController() override = default; - - // ImeController: - std::vector<mojom::ImeInfo> GetAvailableImes() const override { - return available_imes_; - } - bool IsImeManaged() const override { return is_ime_managed_; } - std::vector<mojom::ImeMenuItem> GetCurrentImeMenuItems() const override { - return current_ime_menu_items_; - } - - std::vector<mojom::ImeMenuItem> current_ime_menu_items_; - std::vector<mojom::ImeInfo> available_imes_; - bool is_ime_managed_ = false; - - private: - DISALLOW_COPY_AND_ASSIGN(TestImeController); -}; - -} // namespace class TrayIMETest : public test::AshTestBase { public: @@ -67,7 +45,7 @@ views::View* GetImeManagedIcon(); - void AddMenuItemForCurrentIme(mojom::ImeMenuItem item); + void SetCurrentImeMenuItems(const std::vector<mojom::ImeMenuItem>& items); void SuppressKeyboard(); void RestoreKeyboard(); @@ -77,7 +55,6 @@ void TearDown() override; private: - TestImeController test_ime_controller_; std::unique_ptr<TrayIME> tray_; std::unique_ptr<views::View> default_view_; std::unique_ptr<views::View> detailed_view_; @@ -86,6 +63,10 @@ std::vector<ui::TouchscreenDevice> touchscreen_devices_to_restore_; std::vector<ui::InputDevice> keyboard_devices_to_restore_; + mojom::ImeInfo current_ime_; + std::vector<mojom::ImeInfo> available_imes_; + std::vector<mojom::ImeMenuItem> menu_items_; + DISALLOW_COPY_AND_ASSIGN(TrayIMETest); }; @@ -99,12 +80,9 @@ } void TrayIMETest::SetActiveImeCount(int count) { - test_ime_controller_.available_imes_.clear(); - mojom::ImeInfo ime; - for (int i = 0; i < count; i++) { - test_ime_controller_.available_imes_.push_back(ime); - } - tray_->OnIMERefresh(); + available_imes_.resize(count); + Shell::Get()->ime_controller()->RefreshIme(current_ime_, available_imes_, + menu_items_); } views::View* TrayIMETest::GetToggleView() const { @@ -113,17 +91,18 @@ } void TrayIMETest::SetImeManaged(bool managed) { - test_ime_controller_.is_ime_managed_ = true; - tray_->OnIMERefresh(); + Shell::Get()->ime_controller()->SetImesManagedByPolicy(managed); } views::View* TrayIMETest::GetImeManagedIcon() { return tray_->GetControlledSettingIconForTesting(); } -void TrayIMETest::AddMenuItemForCurrentIme(mojom::ImeMenuItem property) { - test_ime_controller_.current_ime_menu_items_.push_back(property); - tray_->OnIMERefresh(); +void TrayIMETest::SetCurrentImeMenuItems( + const std::vector<mojom::ImeMenuItem>& items) { + menu_items_ = items; + Shell::Get()->ime_controller()->RefreshIme(current_ime_, available_imes_, + menu_items_); } void TrayIMETest::SuppressKeyboard() { @@ -159,7 +138,6 @@ void TrayIMETest::SetUp() { test::AshTestBase::SetUp(); tray_.reset(new TrayIME(GetPrimarySystemTray())); - tray_->ime_controller_ = &test_ime_controller_; default_view_.reset(tray_->CreateDefaultView(LoginStatus::USER)); detailed_view_.reset(tray_->CreateDetailedView(LoginStatus::USER)); } @@ -204,11 +182,12 @@ EXPECT_FALSE(default_view()->visible()); mojom::ImeMenuItem item1; - AddMenuItemForCurrentIme(item1); + mojom::ImeMenuItem item2; + + SetCurrentImeMenuItems({item1}); EXPECT_FALSE(default_view()->visible()); - mojom::ImeMenuItem item2; - AddMenuItemForCurrentIme(item2); + SetCurrentImeMenuItems({item1, item2}); EXPECT_TRUE(default_view()->visible()); }
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc index 6b01718..83c692b 100644 --- a/ash/system/ime_menu/ime_list_view.cc +++ b/ash/system/ime_menu/ime_list_view.cc
@@ -196,10 +196,9 @@ void ImeListView::Init(bool show_keyboard_toggle, SingleImeBehavior single_ime_behavior) { ImeController* ime_controller = Shell::Get()->ime_controller(); - std::vector<mojom::ImeInfo> list = ime_controller->GetAvailableImes(); - std::vector<mojom::ImeMenuItem> property_items = - ime_controller->GetCurrentImeMenuItems(); - Update(list, property_items, show_keyboard_toggle, single_ime_behavior); + Update(ime_controller->available_imes(), + ime_controller->current_ime_menu_items(), show_keyboard_toggle, + single_ime_behavior); } void ImeListView::Update(const std::vector<mojom::ImeInfo>& list,
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc index e354c595..de4071a6 100644 --- a/ash/system/ime_menu/ime_menu_tray.cc +++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -412,8 +412,8 @@ // 4) password input client. return InputMethodManager::Get() && InputMethodManager::Get()->IsEmojiHandwritingVoiceOnImeMenuEnabled() && - !current_ime_.third_party && !IsInLoginOrLockScreen() && - !IsInPasswordInputContext(); + !ime_controller_->current_ime().third_party && + !IsInLoginOrLockScreen() && !IsInPasswordInputContext(); } bool ImeMenuTray::ShouldShowKeyboardToggle() const { @@ -445,10 +445,8 @@ void ImeMenuTray::OnIMERefresh() { UpdateTrayLabel(); if (bubble_ && ime_list_view_) { - std::vector<mojom::ImeInfo> imes = ime_controller_->GetAvailableImes(); - std::vector<mojom::ImeMenuItem> property_items = - ime_controller_->GetCurrentImeMenuItems(); - ime_list_view_->Update(imes, property_items, false, + ime_list_view_->Update(ime_controller_->available_imes(), + ime_controller_->current_ime_menu_items(), false, ImeListView::SHOW_SINGLE_IME); } } @@ -534,13 +532,13 @@ } void ImeMenuTray::UpdateTrayLabel() { - current_ime_ = ime_controller_->GetCurrentIme(); + const mojom::ImeInfo& current_ime = ime_controller_->current_ime(); // Updates the tray label based on the current input method. - if (current_ime_.third_party) - label_->SetText(current_ime_.short_name + base::UTF8ToUTF16("*")); + if (current_ime.third_party) + label_->SetText(current_ime.short_name + base::UTF8ToUTF16("*")); else - label_->SetText(current_ime_.short_name); + label_->SetText(current_ime.short_name); } void ImeMenuTray::DisableVirtualKeyboard() {
diff --git a/ash/system/ime_menu/ime_menu_tray.h b/ash/system/ime_menu/ime_menu_tray.h index 41b86d9..39867fb 100644 --- a/ash/system/ime_menu/ime_menu_tray.h +++ b/ash/system/ime_menu/ime_menu_tray.h
@@ -103,7 +103,6 @@ ImeListView* ime_list_view_; views::Label* label_; - mojom::ImeInfo current_ime_; bool show_keyboard_; bool force_show_keyboard_; bool keyboard_suppressed_;
diff --git a/ash/system/ime_menu/ime_menu_tray_unittest.cc b/ash/system/ime_menu/ime_menu_tray_unittest.cc index 2cc21c0..7602ac3 100644 --- a/ash/system/ime_menu/ime_menu_tray_unittest.cc +++ b/ash/system/ime_menu/ime_menu_tray_unittest.cc
@@ -11,7 +11,6 @@ #include "ash/shell.h" #include "ash/system/ime_menu/ime_list_view.h" #include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray_notifier.h" #include "ash/test/ash_test_base.h" #include "ash/test/status_area_widget_test_helper.h" #include "base/run_loop.h" @@ -29,28 +28,16 @@ namespace ash { namespace { -class TestImeController : public ImeController { - public: - TestImeController() = default; - ~TestImeController() override = default; - - // ImeController: - mojom::ImeInfo GetCurrentIme() const override { return current_ime_; } - std::vector<mojom::ImeInfo> GetAvailableImes() const override { - return available_imes_; - } - - mojom::ImeInfo current_ime_; - std::vector<mojom::ImeInfo> available_imes_; - - private: - DISALLOW_COPY_AND_ASSIGN(TestImeController); -}; - ImeMenuTray* GetTray() { return StatusAreaWidgetTestHelper::GetStatusAreaWidget()->ime_menu_tray(); } +void SetCurrentIme(mojom::ImeInfo current_ime, + const std::vector<mojom::ImeInfo>& available_imes) { + Shell::Get()->ime_controller()->RefreshIme(current_ime, available_imes, + std::vector<mojom::ImeMenuItem>()); +} + } // namespace class ImeMenuTrayTest : public test::AshTestBase { @@ -58,12 +45,6 @@ ImeMenuTrayTest() {} ~ImeMenuTrayTest() override {} - // test::AshTestBase: - void SetUp() override { - test::AshTestBase::SetUp(); - GetTray()->ime_controller_ = &test_ime_controller_; - } - protected: // Returns true if the IME menu tray is visible. bool IsVisible() { return GetTray()->visible(); } @@ -109,17 +90,7 @@ ui::IMEBridge::Get()->SetCurrentInputContext(input_context); } - void SetCurrentIme(mojom::ImeInfo ime) { - test_ime_controller_.current_ime_ = ime; - } - - void SetAvailableImes(const std::vector<mojom::ImeInfo>& imes) { - test_ime_controller_.available_imes_ = imes; - } - private: - TestImeController test_ime_controller_; - DISALLOW_COPY_AND_ASSIGN(ImeMenuTrayTest); }; @@ -128,40 +99,41 @@ TEST_F(ImeMenuTrayTest, ImeMenuTrayVisibility) { ASSERT_FALSE(IsVisible()); - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); EXPECT_TRUE(IsVisible()); - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(false); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(false); EXPECT_FALSE(IsVisible()); } // Tests that IME menu tray shows the right info of the current IME. TEST_F(ImeMenuTrayTest, TrayLabelTest) { - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); ASSERT_TRUE(IsVisible()); - // Changes the input method to "ime1". mojom::ImeInfo info1; info1.id = "ime1"; info1.name = UTF8ToUTF16("English"); info1.medium_name = UTF8ToUTF16("English"); info1.short_name = UTF8ToUTF16("US"); info1.third_party = false; - info1.selected = true; - SetCurrentIme(info1); - Shell::Get()->system_tray_notifier()->NotifyRefreshIME(); - EXPECT_EQ(UTF8ToUTF16("US"), GetTrayText()); - // Changes the input method to a third-party IME extension. mojom::ImeInfo info2; info2.id = "ime2"; info2.name = UTF8ToUTF16("English UK"); info2.medium_name = UTF8ToUTF16("English UK"); info2.short_name = UTF8ToUTF16("UK"); info2.third_party = true; + + // Changes the input method to "ime1". + info1.selected = true; + SetCurrentIme(info1, {info1, info2}); + EXPECT_EQ(UTF8ToUTF16("US"), GetTrayText()); + + // Changes the input method to a third-party IME extension. + info1.selected = false; info2.selected = true; - SetCurrentIme(info2); - Shell::Get()->system_tray_notifier()->NotifyRefreshIME(); + SetCurrentIme(info2, {info1, info2}); EXPECT_EQ(UTF8ToUTF16("UK*"), GetTrayText()); } @@ -170,7 +142,7 @@ // menu feature. Also makes sure that the shelf won't autohide as long as the // IME menu is open. TEST_F(ImeMenuTrayTest, PerformAction) { - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); ASSERT_TRUE(IsVisible()); ASSERT_FALSE(IsTrayBackgroundActive()); StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); @@ -194,7 +166,7 @@ // element will be deactivated. GetTray()->PerformAction(tap); EXPECT_TRUE(IsTrayBackgroundActive()); - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(false); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(false); EXPECT_FALSE(IsVisible()); EXPECT_FALSE(IsBubbleShown()); EXPECT_FALSE(IsTrayBackgroundActive()); @@ -236,17 +208,15 @@ std::vector<mojom::ImeInfo> ime_info_list{info1, info2, info3}; - SetAvailableImes(ime_info_list); - SetCurrentIme(info1); - Shell::Get()->system_tray_notifier()->NotifyRefreshIME(); + // Switch to ime1. + SetCurrentIme(info1, ime_info_list); EXPECT_EQ(UTF8ToUTF16("US"), GetTrayText()); ExpectValidImeList(ime_info_list, info1); + // Switch to ime3. ime_info_list[0].selected = false; ime_info_list[2].selected = true; - SetAvailableImes(ime_info_list); - SetCurrentIme(info3); - Shell::Get()->system_tray_notifier()->NotifyRefreshIME(); + SetCurrentIme(info3, ime_info_list); EXPECT_EQ(UTF8ToUTF16("拼"), GetTrayText()); ExpectValidImeList(ime_info_list, info3); @@ -258,7 +228,7 @@ // Tests that quits Chrome with IME menu openned will not crash. TEST_F(ImeMenuTrayTest, QuitChromeWithMenuOpen) { - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); ASSERT_TRUE(IsVisible()); ASSERT_FALSE(IsTrayBackgroundActive()); @@ -271,7 +241,7 @@ // Tests using 'Alt+Shift+K' to open the menu. TEST_F(ImeMenuTrayTest, TestAccelerator) { - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); ASSERT_TRUE(IsVisible()); ASSERT_FALSE(IsTrayBackgroundActive()); @@ -288,7 +258,7 @@ } TEST_F(ImeMenuTrayTest, ShowEmojiKeyset) { - Shell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + Shell::Get()->ime_controller()->ShowImeMenuOnShelf(true); ASSERT_TRUE(IsVisible()); ASSERT_FALSE(IsTrayBackgroundActive());
diff --git a/ash/system/night_light/night_light_controller.cc b/ash/system/night_light/night_light_controller.cc index 7b82a77d..e5f68eaa 100644 --- a/ash/system/night_light/night_light_controller.cc +++ b/ash/system/night_light/night_light_controller.cc
@@ -38,15 +38,16 @@ class NightLightControllerDelegateImpl : public NightLightController::Delegate { public: - NightLightControllerDelegateImpl() { - // TODO(afakhry): Implement geolocation position retrieval. - } + NightLightControllerDelegateImpl() = default; ~NightLightControllerDelegateImpl() override = default; // ash::NightLightController::Delegate: base::Time GetNow() const override { return base::Time::Now(); } base::Time GetSunsetTime() const override { return GetSunRiseSet(false); } base::Time GetSunriseTime() const override { return GetSunRiseSet(true); } + void SetGeoposition(mojom::SimpleGeopositionPtr position) override { + position_ = std::move(position); + } private: base::Time GetSunRiseSet(bool sunrise) const { @@ -55,7 +56,7 @@ : TimeOfDay(kDefaultStartTimeOffsetMinutes).ToTimeToday(); } - icu::CalendarAstronomer astro(longitude_, latitude_); + icu::CalendarAstronomer astro(position_->longitude, position_->latitude); // For sunset and sunrise times calculations to be correct, the time of the // icu::CalendarAstronomer object should be set to a time near local noon. // This avoids having the computation flopping over into an adjacent day. @@ -68,14 +69,9 @@ return base::Time::FromDoubleT(sun_rise_set_ms / 1000.0); } - bool ValidatePosition() const { - // TODO(afakhry): Replace with geoposition APIs. - return false; - } + bool ValidatePosition() const { return !!position_; } - // Stub values to be replaced by actual geoposition APIs. - double latitude_ = 0.0; - double longitude_ = 0.0; + mojom::SimpleGeopositionPtr position_; DISALLOW_COPY_AND_ASSIGN(NightLightControllerDelegateImpl); }; @@ -102,7 +98,9 @@ NightLightController::NightLightController( SessionController* session_controller) - : session_controller_(session_controller) { + : session_controller_(session_controller), + delegate_(base::MakeUnique<NightLightControllerDelegateImpl>()), + binding_(this) { session_controller_->AddObserver(this); } @@ -129,6 +127,11 @@ kDefaultEndTimeOffsetMinutes); } +void NightLightController::BindRequest( + mojom::NightLightControllerRequest request) { + binding_.Bind(std::move(request)); +} + void NightLightController::AddObserver(Observer* observer) { observers_.AddObserver(observer); } @@ -226,10 +229,30 @@ // Initial login and user switching in multi profiles. pref_change_registrar_.reset(); active_user_pref_service_ = Shell::Get()->GetActiveUserPrefService(); - delegate_ = base::MakeUnique<NightLightControllerDelegateImpl>(); InitFromUserPrefs(); } +void NightLightController::SetCurrentGeoposition( + mojom::SimpleGeopositionPtr position) { + delegate_->SetGeoposition(std::move(position)); + + // If the schedule type is sunset to sunrise, then a potential change in the + // geoposition might mean a change in the start and end times. In this case, + // we must trigger a refresh. + if (GetScheduleType() == ScheduleType::kSunsetToSunrise) + Refresh(true /* did_schedule_change */); +} + +void NightLightController::SetClient(mojom::NightLightClientPtr client) { + client_ = std::move(client); + + if (client_) { + client_.set_connection_error_handler(base::Bind( + &NightLightController::SetClient, base::Unretained(this), nullptr)); + NotifyClientWithScheduleChange(); + } +} + void NightLightController::SetDelegateForTesting( std::unique_ptr<Delegate> delegate) { delegate_ = std::move(delegate); @@ -265,15 +288,15 @@ base::Unretained(this))); pref_change_registrar_->Add( prefs::kNightLightScheduleType, - base::Bind(&NightLightController::OnScheduleParamsPrefsChanged, + base::Bind(&NightLightController::OnScheduleTypePrefChanged, base::Unretained(this))); pref_change_registrar_->Add( prefs::kNightLightCustomStartTime, - base::Bind(&NightLightController::OnScheduleParamsPrefsChanged, + base::Bind(&NightLightController::OnCustomSchedulePrefsChanged, base::Unretained(this))); pref_change_registrar_->Add( prefs::kNightLightCustomEndTime, - base::Bind(&NightLightController::OnScheduleParamsPrefsChanged, + base::Bind(&NightLightController::OnCustomSchedulePrefsChanged, base::Unretained(this))); } @@ -286,6 +309,7 @@ StartWatchingPrefsChanges(); Refresh(true /* did_schedule_change */); NotifyStatusChanged(); + NotifyClientWithScheduleChange(); } void NightLightController::NotifyStatusChanged() { @@ -293,6 +317,11 @@ observer.OnNightLightEnabledChanged(GetEnabled()); } +void NightLightController::NotifyClientWithScheduleChange() { + if (client_) + client_->OnScheduleTypeChanged(GetScheduleType()); +} + void NightLightController::OnEnabledPrefChanged() { DCHECK(active_user_pref_service_); Refresh(false /* did_schedule_change */); @@ -304,7 +333,13 @@ RefreshLayersTemperature(); } -void NightLightController::OnScheduleParamsPrefsChanged() { +void NightLightController::OnScheduleTypePrefChanged() { + DCHECK(active_user_pref_service_); + NotifyClientWithScheduleChange(); + Refresh(true /* did_schedule_change */); +} + +void NightLightController::OnCustomSchedulePrefsChanged() { DCHECK(active_user_pref_service_); Refresh(true /* did_schedule_change */); }
diff --git a/ash/system/night_light/night_light_controller.h b/ash/system/night_light/night_light_controller.h index b9eef8f..2e9b5c7 100644 --- a/ash/system/night_light/night_light_controller.h +++ b/ash/system/night_light/night_light_controller.h
@@ -8,12 +8,14 @@ #include <memory> #include "ash/ash_export.h" +#include "ash/public/interfaces/night_light_controller.mojom.h" #include "ash/session/session_observer.h" #include "ash/system/night_light/time_of_day.h" #include "base/observer_list.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "components/prefs/pref_change_registrar.h" +#include "mojo/public/cpp/bindings/binding.h" class PrefRegistrySimple; class PrefService; @@ -24,20 +26,11 @@ // Controls the NightLight feature that adjusts the color temperature of the // screen. -class ASH_EXPORT NightLightController : public SessionObserver { +class ASH_EXPORT NightLightController + : public NON_EXPORTED_BASE(mojom::NightLightController), + public SessionObserver { public: - enum class ScheduleType : int { - // Automatic toggling of NightLight is turned off. - kNone = 0, - - // Turned automatically on at the user's local sunset time, and off at the - // user's local sunrise time. - kSunsetToSunrise = 1, - - // Toggled automatically based on the custom set start and end times - // selected by the user from the system settings. - kCustom = 2, - }; + using ScheduleType = mojom::NightLightController::ScheduleType; enum class AnimationDuration { // Short animation (2 seconds) used for manual changes of NightLight status @@ -64,6 +57,10 @@ // Gets the sunset and sunrise times. virtual base::Time GetSunsetTime() const = 0; virtual base::Time GetSunriseTime() const = 0; + + // Provides the delegate with the geoposition so that it can be used to + // calculate sunset and sunrise times. + virtual void SetGeoposition(mojom::SimpleGeopositionPtr position) = 0; }; class Observer { @@ -89,6 +86,8 @@ } const base::OneShotTimer& timer() const { return timer_; } + void BindRequest(mojom::NightLightControllerRequest request); + void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); @@ -113,6 +112,10 @@ // ash::SessionObserver: void OnActiveUserSessionChanged(const AccountId& account_id) override; + // ash::mojom::NightLightController: + void SetCurrentGeoposition(mojom::SimpleGeopositionPtr position) override; + void SetClient(mojom::NightLightClientPtr client) override; + void SetDelegateForTesting(std::unique_ptr<Delegate> delegate); private: @@ -124,15 +127,20 @@ void NotifyStatusChanged(); + void NotifyClientWithScheduleChange(); + // Called when the user pref for the enabled status of NightLight is changed. void OnEnabledPrefChanged(); // Called when the user pref for the color temperature is changed. void OnColorTemperaturePrefChanged(); - // Called when any of the schedule related prefs (schedule type, custom start - // and end times) are changed. - void OnScheduleParamsPrefsChanged(); + // Called when the user pref for the schedule type is changed. + void OnScheduleTypePrefChanged(); + + // Called when either of the custom schedule prefs (custom start or end times) + // are changed. + void OnCustomSchedulePrefsChanged(); // Refreshes the state of NightLight according to the currently set // parameters. |did_schedule_change| is true when Refresh() is called as a @@ -182,6 +190,10 @@ base::ObserverList<Observer> observers_; + mojo::Binding<mojom::NightLightController> binding_; + + mojom::NightLightClientPtr client_; + DISALLOW_COPY_AND_ASSIGN(NightLightController); };
diff --git a/ash/system/night_light/night_light_controller_unittest.cc b/ash/system/night_light/night_light_controller_unittest.cc index 267e325e..3745641 100644 --- a/ash/system/night_light/night_light_controller_unittest.cc +++ b/ash/system/night_light/night_light_controller_unittest.cc
@@ -66,6 +66,16 @@ DISALLOW_COPY_AND_ASSIGN(TestObserver); }; +constexpr double kFakePosition1_Latitude = 23.5; +constexpr double kFakePosition1_Longitude = 35.88; +constexpr int kFakePosition1_SunsetOffset = 20 * 60; +constexpr int kFakePosition1_SunriseOffset = 4 * 60; + +constexpr double kFakePosition2_Latitude = 37.5; +constexpr double kFakePosition2_Longitude = -100.5; +constexpr int kFakePosition2_SunsetOffset = 17 * 60; +constexpr int kFakePosition2_SunriseOffset = 3 * 60; + class TestDelegate : public NightLightController::Delegate { public: TestDelegate() = default; @@ -79,6 +89,19 @@ base::Time GetNow() const override { return fake_now_; } base::Time GetSunsetTime() const override { return fake_sunset_; } base::Time GetSunriseTime() const override { return fake_sunrise_; } + void SetGeoposition(mojom::SimpleGeopositionPtr position) override { + if (position.Equals(mojom::SimpleGeoposition::New( + kFakePosition1_Latitude, kFakePosition1_Longitude))) { + // Set sunset and sunrise times associated with fake position 1. + SetFakeSunset(TimeOfDay(kFakePosition1_SunsetOffset)); + SetFakeSunrise(TimeOfDay(kFakePosition1_SunriseOffset)); + } else if (position.Equals(mojom::SimpleGeoposition::New( + kFakePosition2_Latitude, kFakePosition2_Longitude))) { + // Set sunset and sunrise times associated with fake position 2. + SetFakeSunset(TimeOfDay(kFakePosition2_SunsetOffset)); + SetFakeSunrise(TimeOfDay(kFakePosition2_SunriseOffset)); + } + } private: base::Time fake_now_; @@ -480,7 +503,7 @@ return; } - // 16:00 18:00 20:00 22:00 5:00 + // 16:00 18:00 20:00 22:00 5:00 // <----- + ----------- + ------- + -------- + --------------- + -------> // | | | | | // now custom start sunset custom end sunrise @@ -529,6 +552,79 @@ controller->timer().GetCurrentDelay()); } +// Tests the behavior of the sunset to sunrise automatic schedule type when the +// client sets the geoposition. +TEST_F(NightLightTest, TestSunsetSunriseGeoposition) { + if (Shell::GetAshConfig() == Config::MASH) { + // PrefChangeRegistrar doesn't work on mash. crbug.com/721961. + return; + } + + // Position 1 sunset and sunrise times. + // + // 16:00 20:00 4:00 + // <----- + --------- + ---------------- + -------> + // | | | + // now sunset sunrise + // + NightLightController* controller = GetController(); + delegate()->SetFakeNow(TimeOfDay(16 * 60)); // 4:00 PM. + controller->SetCurrentGeoposition(mojom::SimpleGeoposition::New( + kFakePosition1_Latitude, kFakePosition1_Longitude)); + + // Expect that timer is running and the start is scheduled after 4 hours. + controller->SetScheduleType( + NightLightController::ScheduleType::kSunsetToSunrise); + EXPECT_FALSE(controller->GetEnabled()); + EXPECT_TRUE(TestLayersTemperature(0.0f)); + EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_EQ(base::TimeDelta::FromHours(4), + controller->timer().GetCurrentDelay()); + + // Simulate reaching sunset. + delegate()->SetFakeNow(TimeOfDay(20 * 60)); // Now is 8:00 PM. + controller->timer().user_task().Run(); + EXPECT_TRUE(controller->GetEnabled()); + EXPECT_TRUE(TestLayersTemperature(controller->GetColorTemperature())); + EXPECT_EQ(NightLightController::AnimationDuration::kLong, + controller->last_animation_duration()); + // Timer is running scheduling the end at sunrise. + EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_EQ(base::TimeDelta::FromHours(8), + controller->timer().GetCurrentDelay()); + + // Now simulate user changing position. + // Position 2 sunset and sunrise times. + // + // 17:00 20:00 3:00 + // <----- + --------- + ---------------- + -------> + // | | | + // sunset now sunrise + // + controller->SetCurrentGeoposition(mojom::SimpleGeoposition::New( + kFakePosition2_Latitude, kFakePosition2_Longitude)); + + // Expect that the scheduled end delay has been updated, and the status hasn't + // changed. + EXPECT_TRUE(controller->GetEnabled()); + EXPECT_TRUE(TestLayersTemperature(controller->GetColorTemperature())); + EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_EQ(base::TimeDelta::FromHours(7), + controller->timer().GetCurrentDelay()); + + // Simulate reaching sunrise. + delegate()->SetFakeNow(TimeOfDay(3 * 60)); // Now is 5:00 AM. + controller->timer().user_task().Run(); + EXPECT_FALSE(controller->GetEnabled()); + EXPECT_TRUE(TestLayersTemperature(0.0f)); + EXPECT_EQ(NightLightController::AnimationDuration::kLong, + controller->last_animation_duration()); + // Timer is running scheduling the start at the next sunset. + EXPECT_TRUE(controller->timer().IsRunning()); + EXPECT_EQ(base::TimeDelta::FromHours(14), + controller->timer().GetCurrentDelay()); +} + } // namespace } // namespace ash
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc index e010d9f..df7ef25 100644 --- a/ash/test/test_shell_delegate.cc +++ b/ash/test/test_shell_delegate.cc
@@ -105,10 +105,6 @@ return new SystemTrayDelegate; } -ImeController* TestShellDelegate::GetImeController() { - return &stub_ime_controller_; -} - std::unique_ptr<WallpaperDelegate> TestShellDelegate::CreateWallpaperDelegate() { return base::MakeUnique<TestWallpaperDelegate>();
diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h index 84e1131..a5a0467 100644 --- a/ash/test/test_shell_delegate.h +++ b/ash/test/test_shell_delegate.h
@@ -8,7 +8,6 @@ #include <memory> #include <string> -#include "ash/ime/ime_controller.h" #include "ash/shell_delegate.h" #include "base/macros.h" @@ -51,7 +50,6 @@ void ShelfShutdown() override; void OpenUrlFromArc(const GURL& url) override; SystemTrayDelegate* CreateSystemTrayDelegate() override; - ImeController* GetImeController() override; std::unique_ptr<WallpaperDelegate> CreateWallpaperDelegate() override; AccessibilityDelegate* CreateAccessibilityDelegate() override; std::unique_ptr<PaletteDelegate> CreatePaletteDelegate() override; @@ -82,7 +80,6 @@ bool touchscreen_enabled_in_local_pref_ = true; bool media_sessions_suspended_ = false; std::unique_ptr<ShelfInitializer> shelf_initializer_; - ImeController stub_ime_controller_; PrefService* active_user_pref_service_ = nullptr; // Not owned. DISALLOW_COPY_AND_ASSIGN(TestShellDelegate);
diff --git a/cc/base/rtree.cc b/cc/base/rtree.cc index 0859fcc..852bdce 100644 --- a/cc/base/rtree.cc +++ b/cc/base/rtree.cc
@@ -133,4 +133,10 @@ return root_.bounds; } +void RTree::Reset() { + num_data_elements_ = 0; + nodes_.clear(); + root_.bounds = gfx::Rect(); +} + } // namespace cc
diff --git a/cc/base/rtree.h b/cc/base/rtree.h index 3d4d742..a5ac5a13 100644 --- a/cc/base/rtree.h +++ b/cc/base/rtree.h
@@ -103,6 +103,8 @@ // Returns the total bounds of all items in this rtree. gfx::Rect GetBounds() const; + void Reset(); + private: // These values were empirically determined to produce reasonable performance // in most cases.
diff --git a/cc/base/rtree_unittest.cc b/cc/base/rtree_unittest.cc index 487d0c4..b6adc8a 100644 --- a/cc/base/rtree_unittest.cc +++ b/cc/base/rtree_unittest.cc
@@ -109,7 +109,7 @@ TEST(RTreeTest, GetBoundsEmpty) { RTree rtree; - ASSERT_EQ(gfx::Rect(), rtree.GetBounds()); + EXPECT_EQ(gfx::Rect(), rtree.GetBounds()); } TEST(RTreeTest, GetBoundsNonOverlapping) { @@ -120,7 +120,7 @@ RTree rtree; rtree.Build(rects); - ASSERT_EQ(gfx::Rect(5, 6, 19, 20), rtree.GetBounds()); + EXPECT_EQ(gfx::Rect(5, 6, 19, 20), rtree.GetBounds()); } TEST(RTreeTest, GetBoundsOverlapping) { @@ -131,7 +131,26 @@ RTree rtree; rtree.Build(rects); - ASSERT_EQ(gfx::Rect(0, 0, 10, 10), rtree.GetBounds()); + EXPECT_EQ(gfx::Rect(0, 0, 10, 10), rtree.GetBounds()); +} + +TEST(RTreeTest, BuildAfterReset) { + std::vector<gfx::Rect> rects; + rects.push_back(gfx::Rect(0, 0, 10, 10)); + rects.push_back(gfx::Rect(0, 0, 10, 10)); + rects.push_back(gfx::Rect(0, 0, 10, 10)); + rects.push_back(gfx::Rect(0, 0, 10, 10)); + + RTree rtree; + rtree.Build(rects); + + // Resetting should give the same as an empty rtree. + rtree.Reset(); + EXPECT_EQ(gfx::Rect(), rtree.GetBounds()); + + // Should be able to rebuild from a reset rtree. + rtree.Build(rects); + EXPECT_EQ(gfx::Rect(0, 0, 10, 10), rtree.GetBounds()); } } // namespace cc
diff --git a/cc/paint/discardable_image_map.cc b/cc/paint/discardable_image_map.cc index 4b6c58240..475c7cc7 100644 --- a/cc/paint/discardable_image_map.cc +++ b/cc/paint/discardable_image_map.cc
@@ -59,4 +59,10 @@ image_map_->EndGeneratingMetadata(); } +void DiscardableImageMap::Reset() { + all_images_.clear(); + image_id_to_rect_.clear(); + images_rtree_.Reset(); +} + } // namespace cc
diff --git a/cc/paint/discardable_image_map.h b/cc/paint/discardable_image_map.h index f705e89..0509473 100644 --- a/cc/paint/discardable_image_map.h +++ b/cc/paint/discardable_image_map.h
@@ -51,6 +51,8 @@ std::vector<DrawImage>* images) const; gfx::Rect GetRectForImage(PaintImage::Id image_id) const; + void Reset(); + private: friend class ScopedMetadataGenerator; friend class DiscardableImageMapTest;
diff --git a/cc/paint/discardable_image_map_unittest.cc b/cc/paint/discardable_image_map_unittest.cc index 4d8368b..c6eb10c 100644 --- a/cc/paint/discardable_image_map_unittest.cc +++ b/cc/paint/discardable_image_map_unittest.cc
@@ -695,9 +695,11 @@ display_list->EndPaintOfUnpaired(gfx::Rect(100, 100, 100, 100)); display_list->Finalize(); + sk_sp<PaintRecord> record2 = display_list->ReleaseAsRecord(); + PaintOpBuffer root_buffer; root_buffer.push<DrawRecordOp>(internal_record); - root_buffer.push<DrawDisplayItemListOp>(display_list); + root_buffer.push<DrawRecordOp>(record2); DiscardableImageMap image_map_; { DiscardableImageMap::ScopedMetadataGenerator generator(&image_map_,
diff --git a/cc/paint/discardable_image_store.cc b/cc/paint/discardable_image_store.cc index 4f635fd6..25fc05a7 100644 --- a/cc/paint/discardable_image_store.cc +++ b/cc/paint/discardable_image_store.cc
@@ -107,10 +107,6 @@ 2 * circle_op->radius, 2 * circle_op->radius); AddImageFromFlags(rect, circle_op->flags); } break; - case PaintOpType::DrawDisplayItemList: { - auto* list_op = static_cast<DrawDisplayItemListOp*>(op); - list_op->list->GatherDiscardableImages(this); - } break; case PaintOpType::DrawImage: { auto* image_op = static_cast<DrawImageOp*>(op); const SkImage* sk_image = image_op->image.sk_image().get();
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc index cccc2f61..1e4b6c0 100644 --- a/cc/paint/display_item_list.cc +++ b/cc/paint/display_item_list.cc
@@ -69,8 +69,6 @@ // If this fails we had more calls to EndPaintOfPairedBegin() than // to EndPaintOfPairedEnd(). DCHECK_EQ(0, in_paired_begin_count_); - DCHECK_EQ(visual_rects_range_starts_.size(), visual_rects_.size()); - DCHECK_GE(paint_op_buffer_.size(), visual_rects_.size()); paint_op_buffer_.ShrinkToFit(); rtree_.Build(visual_rects_); @@ -198,4 +196,28 @@ return image_map_.GetRectForImage(image_id); } +void DisplayItemList::Reset() { + DCHECK(!in_painting_); + DCHECK_EQ(0, in_paired_begin_count_); + + rtree_.Reset(); + image_map_.Reset(); + paint_op_buffer_.Reset(); + visual_rects_.clear(); + visual_rects_range_starts_.clear(); + begin_paired_indices_.clear(); + current_range_start_ = 0; + in_paired_begin_count_ = 0; + in_painting_ = false; + op_count_ = 0u; +} + +sk_sp<PaintRecord> DisplayItemList::ReleaseAsRecord() { + sk_sp<PaintRecord> record = + sk_make_sp<PaintOpBuffer>(std::move(paint_op_buffer_)); + + Reset(); + return record; +} + } // namespace cc
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h index b48a19d..f74456e 100644 --- a/cc/paint/display_item_list.h +++ b/cc/paint/display_item_list.h
@@ -125,12 +125,18 @@ return paint_op_buffer_.HasDiscardableImages(); } + // Generate a PaintRecord from this DisplayItemList, leaving |this| in + // an empty state. + sk_sp<PaintRecord> ReleaseAsRecord(); + private: FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithNoOps); FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithOps); ~DisplayItemList(); + void Reset(); + std::unique_ptr<base::trace_event::TracedValue> CreateTracedValue( bool include_items) const;
diff --git a/cc/paint/paint_canvas.h b/cc/paint/paint_canvas.h index ca2b0bd..556be62 100644 --- a/cc/paint/paint_canvas.h +++ b/cc/paint/paint_canvas.h
@@ -15,7 +15,6 @@ namespace cc { -class DisplayItemList; class PaintFlags; class PaintOpBuffer; @@ -165,9 +164,6 @@ SkScalar y, const PaintFlags& flags) = 0; - virtual void drawDisplayItemList( - scoped_refptr<DisplayItemList> display_item_list) = 0; - // Unlike SkCanvas::drawPicture, this only plays back the PaintRecord and does // not add an additional clip. This is closer to SkPicture::playback. virtual void drawPicture(sk_sp<const PaintRecord> record) = 0;
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc index 0689974..5f08b50 100644 --- a/cc/paint/paint_op_buffer.cc +++ b/cc/paint/paint_op_buffer.cc
@@ -21,7 +21,6 @@ M(DrawArcOp) \ M(DrawCircleOp) \ M(DrawColorOp) \ - M(DrawDisplayItemListOp) \ M(DrawDRRectOp) \ M(DrawImageOp) \ M(DrawImageRectOp) \ @@ -127,16 +126,6 @@ NOTREACHED(); } }; -template <bool HasFlags> -struct Rasterizer<DrawDisplayItemListOp, HasFlags> { - static void RasterWithAlpha(const DrawDisplayItemListOp* op, - SkCanvas* canvas, - const SkRect& bounds, - uint8_t alpha) { - NOTREACHED(); - } -}; - // TODO(enne): partially specialize RasterWithAlpha for draw color? static constexpr size_t kNumOpTypes = @@ -270,13 +259,6 @@ canvas->drawColor(op->color, op->mode); } -void DrawDisplayItemListOp::Raster(const PaintOp* base_op, - SkCanvas* canvas, - const SkMatrix& original_ctm) { - auto* op = static_cast<const DrawDisplayItemListOp*>(base_op); - op->list->Raster(canvas); -} - void DrawDRRectOp::RasterWithFlags(const PaintOpWithFlags* base_op, const PaintFlags* flags, SkCanvas* canvas, @@ -472,10 +454,6 @@ return antialias && !path.isConvex() ? 1 : 0; } -int DrawDisplayItemListOp::CountSlowPaths() const { - return list->NumSlowPaths(); -} - int DrawLineOp::CountSlowPaths() const { if (const SkPathEffect* effect = flags.getPathEffect()) { SkPathEffect::DashInfo info; @@ -522,26 +500,6 @@ AnnotateOp::~AnnotateOp() = default; -DrawDisplayItemListOp::DrawDisplayItemListOp( - scoped_refptr<DisplayItemList> list) - : list(list) {} - -size_t DrawDisplayItemListOp::AdditionalBytesUsed() const { - return list->BytesUsed(); -} - -bool DrawDisplayItemListOp::HasDiscardableImages() const { - return list->HasDiscardableImages(); -} - -DrawDisplayItemListOp::DrawDisplayItemListOp(const DrawDisplayItemListOp& op) = - default; - -DrawDisplayItemListOp& DrawDisplayItemListOp::operator=( - const DrawDisplayItemListOp& op) = default; - -DrawDisplayItemListOp::~DrawDisplayItemListOp() = default; - DrawImageOp::DrawImageOp(const PaintImage& image, SkScalar left, SkScalar top, @@ -606,10 +564,29 @@ PaintOpBuffer::PaintOpBuffer() = default; +PaintOpBuffer::PaintOpBuffer(PaintOpBuffer&& other) { + *this = std::move(other); +} + PaintOpBuffer::~PaintOpBuffer() { Reset(); } +void PaintOpBuffer::operator=(PaintOpBuffer&& other) { + data_ = std::move(other.data_); + used_ = other.used_; + reserved_ = other.reserved_; + op_count_ = other.op_count_; + num_slow_paths_ = other.num_slow_paths_; + subrecord_bytes_used_ = other.subrecord_bytes_used_; + has_discardable_images_ = other.has_discardable_images_; + + // Make sure the other pob can destruct safely. + other.used_ = 0; + other.op_count_ = 0; + other.reserved_ = 0; +} + void PaintOpBuffer::Reset() { for (auto* op : Iterator(this)) { auto func = g_destructor_functions[op->type]; @@ -682,13 +659,7 @@ if (!op->IsDrawOp()) return nullptr; - while (op->GetType() == PaintOpType::DrawRecord || - op->GetType() == PaintOpType::DrawDisplayItemList) { - if (op->GetType() == PaintOpType::DrawDisplayItemList) { - // TODO(danakj): If we could inspect the PaintOpBuffer here, then - // we could see if it is a single draw op. - return nullptr; - } + while (op->GetType() == PaintOpType::DrawRecord) { auto* draw_record_op = static_cast<const DrawRecordOp*>(op); if (draw_record_op->record->size() > 1) { // If there's more than one op, then we need to keep the
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h index ae40cad4..abda0c6 100644 --- a/cc/paint/paint_op_buffer.h +++ b/cc/paint/paint_op_buffer.h
@@ -23,7 +23,6 @@ // See: third_party/skia/src/core/SkLiteDL.h. namespace cc { -class DisplayItemList; class CC_PAINT_EXPORT ThreadsafeMatrix : public SkMatrix { public: @@ -48,7 +47,6 @@ DrawArc, DrawCircle, DrawColor, - DrawDisplayItemList, DrawDRRect, DrawImage, DrawImageRect, @@ -364,26 +362,6 @@ SkBlendMode mode; }; -struct CC_PAINT_EXPORT DrawDisplayItemListOp final : PaintOp { - static constexpr PaintOpType kType = PaintOpType::DrawDisplayItemList; - static constexpr bool kIsDrawOp = true; - explicit DrawDisplayItemListOp(scoped_refptr<DisplayItemList> list); - // Windows wants to generate these when types are exported, so - // provide them here explicitly so that DisplayItemList doesn't have - // to be defined in this header. - DrawDisplayItemListOp(const DrawDisplayItemListOp& op); - DrawDisplayItemListOp& operator=(const DrawDisplayItemListOp& op); - ~DrawDisplayItemListOp(); - static void Raster(const PaintOp* op, - SkCanvas* canvas, - const SkMatrix& original_ctm); - size_t AdditionalBytesUsed() const; - bool HasDiscardableImages() const; - int CountSlowPaths() const; - - scoped_refptr<DisplayItemList> list; -}; - struct CC_PAINT_EXPORT DrawDRRectOp final : PaintOpWithFlags { static constexpr PaintOpType kType = PaintOpType::DrawDRRect; static constexpr bool kIsDrawOp = true; @@ -781,8 +759,11 @@ static constexpr size_t PaintOpAlign = alignof(DrawDRRectOp); PaintOpBuffer(); + PaintOpBuffer(PaintOpBuffer&& other); ~PaintOpBuffer() override; + void operator=(PaintOpBuffer&& other); + void Reset(); void playback(SkCanvas* canvas,
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc index 42b2984e..1e6e18cb 100644 --- a/cc/paint/paint_op_buffer_unittest.cc +++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -26,46 +26,125 @@ EXPECT_EQ(buffer.size(), 0u); EXPECT_EQ(buffer.bytes_used(), sizeof(PaintOpBuffer)); EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); + + PaintOpBuffer buffer2(std::move(buffer)); + EXPECT_EQ(buffer.size(), 0u); + EXPECT_EQ(buffer.bytes_used(), sizeof(PaintOpBuffer)); + EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); + EXPECT_EQ(buffer2.size(), 0u); + EXPECT_EQ(buffer2.bytes_used(), sizeof(PaintOpBuffer)); + EXPECT_EQ(PaintOpBuffer::Iterator(&buffer2), false); } -TEST(PaintOpBufferTest, SimpleAppend) { - SkRect rect = SkRect::MakeXYWH(2, 3, 4, 5); - PaintFlags flags; - flags.setColor(SK_ColorMAGENTA); - flags.setAlpha(100); - SkColor draw_color = SK_ColorRED; - SkBlendMode blend = SkBlendMode::kSrc; +class PaintOpAppendTest : public ::testing::Test { + public: + PaintOpAppendTest() { + rect_ = SkRect::MakeXYWH(2, 3, 4, 5); + flags_.setColor(SK_ColorMAGENTA); + flags_.setAlpha(100); + } + void PushOps(PaintOpBuffer* buffer) { + buffer->push<SaveLayerOp>(&rect_, &flags_); + buffer->push<SaveOp>(); + buffer->push<DrawColorOp>(draw_color_, blend_); + buffer->push<RestoreOp>(); + EXPECT_EQ(buffer->size(), 4u); + } + + void VerifyOps(PaintOpBuffer* buffer) { + EXPECT_EQ(buffer->size(), 4u); + + PaintOpBuffer::Iterator iter(buffer); + ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer); + SaveLayerOp* save_op = static_cast<SaveLayerOp*>(*iter); + EXPECT_EQ(save_op->bounds, rect_); + EXPECT_TRUE(save_op->flags == flags_); + ++iter; + + ASSERT_EQ(iter->GetType(), PaintOpType::Save); + ++iter; + + ASSERT_EQ(iter->GetType(), PaintOpType::DrawColor); + DrawColorOp* op = static_cast<DrawColorOp*>(*iter); + EXPECT_EQ(op->color, draw_color_); + EXPECT_EQ(op->mode, blend_); + ++iter; + + ASSERT_EQ(iter->GetType(), PaintOpType::Restore); + ++iter; + + EXPECT_FALSE(iter); + } + + private: + SkRect rect_; + PaintFlags flags_; + SkColor draw_color_ = SK_ColorRED; + SkBlendMode blend_ = SkBlendMode::kSrc; +}; + +TEST_F(PaintOpAppendTest, SimpleAppend) { PaintOpBuffer buffer; - buffer.push<SaveLayerOp>(&rect, &flags); - buffer.push<SaveOp>(); - buffer.push<DrawColorOp>(draw_color, blend); - buffer.push<RestoreOp>(); + PushOps(&buffer); + VerifyOps(&buffer); - EXPECT_EQ(buffer.size(), 4u); - - PaintOpBuffer::Iterator iter(&buffer); - ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer); - SaveLayerOp* save_op = static_cast<SaveLayerOp*>(*iter); - EXPECT_EQ(save_op->bounds, rect); - EXPECT_TRUE(save_op->flags == flags); - ++iter; - - ASSERT_EQ(iter->GetType(), PaintOpType::Save); - ++iter; - - ASSERT_EQ(iter->GetType(), PaintOpType::DrawColor); - DrawColorOp* op = static_cast<DrawColorOp*>(*iter); - EXPECT_EQ(op->color, draw_color); - EXPECT_EQ(op->mode, blend); - ++iter; - - ASSERT_EQ(iter->GetType(), PaintOpType::Restore); - ++iter; - - EXPECT_FALSE(iter); + buffer.Reset(); + PushOps(&buffer); + VerifyOps(&buffer); } +TEST_F(PaintOpAppendTest, MoveThenDestruct) { + PaintOpBuffer original; + PushOps(&original); + VerifyOps(&original); + + PaintOpBuffer destination(std::move(original)); + VerifyOps(&destination); + + // Original should be empty, and safe to destruct. + EXPECT_EQ(original.size(), 0u); + EXPECT_EQ(original.bytes_used(), sizeof(PaintOpBuffer)); + EXPECT_EQ(PaintOpBuffer::Iterator(&original), false); +} + +TEST_F(PaintOpAppendTest, MoveThenDestructOperatorEq) { + PaintOpBuffer original; + PushOps(&original); + VerifyOps(&original); + + PaintOpBuffer destination; + destination = std::move(original); + VerifyOps(&destination); + + // Original should be empty, and safe to destruct. + EXPECT_EQ(original.size(), 0u); + EXPECT_EQ(original.bytes_used(), sizeof(PaintOpBuffer)); + EXPECT_EQ(PaintOpBuffer::Iterator(&original), false); +} + +TEST_F(PaintOpAppendTest, MoveThenReappend) { + PaintOpBuffer original; + PushOps(&original); + + PaintOpBuffer destination(std::move(original)); + + // Should be possible to reappend to the original and get the same result. + PushOps(&original); + VerifyOps(&original); +} + +TEST_F(PaintOpAppendTest, MoveThenReappendOperatorEq) { + PaintOpBuffer original; + PushOps(&original); + + PaintOpBuffer destination; + destination = std::move(original); + + // Should be possible to reappend to the original and get the same result. + PushOps(&original); + VerifyOps(&original); +} // Verify that PaintOps with data are stored properly. TEST(PaintOpBufferTest, PaintOpData) { @@ -341,28 +420,6 @@ EXPECT_TRUE(buffer.HasDiscardableImages()); } -TEST(PaintOpBufferTest, DiscardableImagesTracking_NestedDrawOp) { - sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>(); - PaintImage image = PaintImage(PaintImage::GetNextId(), - CreateDiscardableImage(gfx::Size(100, 100))); - record->push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0), nullptr); - - PaintOpBuffer buffer; - buffer.push<DrawRecordOp>(record); - EXPECT_TRUE(buffer.HasDiscardableImages()); - - scoped_refptr<DisplayItemList> list = new DisplayItemList; - { - PaintOpBuffer* buffer = list->StartPaint(); - buffer->push<DrawRecordOp>(record); - list->EndPaintOfUnpaired(gfx::Rect(100, 100)); - } - list->Finalize(); - PaintOpBuffer new_buffer; - new_buffer.push<DrawDisplayItemListOp>(list); - EXPECT_TRUE(new_buffer.HasDiscardableImages()); -} - TEST(PaintOpBufferTest, DiscardableImagesTracking_OpWithFlags) { PaintOpBuffer buffer; PaintFlags flags; @@ -424,27 +481,6 @@ EXPECT_EQ(2, buffer2->numSlowPaths()); buffer2->push<DrawRecordOp>(buffer); EXPECT_EQ(4, buffer2->numSlowPaths()); - - // Drawing an empty display item list doesn't change anything. - auto empty_list = base::MakeRefCounted<DisplayItemList>(); - buffer2->push<DrawDisplayItemListOp>(empty_list); - EXPECT_EQ(4, buffer2->numSlowPaths()); - - // Drawing a display item list adds the items from that list. - auto slow_path_list = base::MakeRefCounted<DisplayItemList>(); - { - PaintOpBuffer* display_list_buffer = slow_path_list->StartPaint(); - EXPECT_EQ(0, display_list_buffer->numSlowPaths()); - display_list_buffer->push<DrawRecordOp>(buffer); - EXPECT_EQ(2, display_list_buffer->numSlowPaths()); - display_list_buffer->push<DrawRecordOp>(buffer); - EXPECT_EQ(4, display_list_buffer->numSlowPaths()); - display_list_buffer->push<DrawRecordOp>(buffer); - EXPECT_EQ(6, display_list_buffer->numSlowPaths()); - slow_path_list->EndPaintOfUnpaired(gfx::Rect(30, 30)); - } - buffer2->push<DrawDisplayItemListOp>(slow_path_list); - EXPECT_EQ(10, buffer2->numSlowPaths()); } TEST(PaintOpBufferTest, ContiguousRanges) {
diff --git a/cc/paint/record_paint_canvas.cc b/cc/paint/record_paint_canvas.cc index a4596bf22..97a9f8d 100644 --- a/cc/paint/record_paint_canvas.cc +++ b/cc/paint/record_paint_canvas.cc
@@ -320,11 +320,6 @@ buffer_->push<DrawTextBlobOp>(blob, x, y, flags); } -void RecordPaintCanvas::drawDisplayItemList( - scoped_refptr<DisplayItemList> list) { - buffer_->push<DrawDisplayItemListOp>(list); -} - void RecordPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) { // TODO(enne): If this is small, maybe flatten it? buffer_->push<DrawRecordOp>(record);
diff --git a/cc/paint/record_paint_canvas.h b/cc/paint/record_paint_canvas.h index 8730bd7a..d5b6d898 100644 --- a/cc/paint/record_paint_canvas.h +++ b/cc/paint/record_paint_canvas.h
@@ -113,9 +113,6 @@ SkScalar y, const PaintFlags& flags) override; - void drawDisplayItemList( - scoped_refptr<DisplayItemList> display_item_list) override; - void drawPicture(sk_sp<const PaintRecord> record) override; bool isClipEmpty() const override;
diff --git a/cc/paint/skia_paint_canvas.cc b/cc/paint/skia_paint_canvas.cc index f2231e74..65a86c9a 100644 --- a/cc/paint/skia_paint_canvas.cc +++ b/cc/paint/skia_paint_canvas.cc
@@ -255,11 +255,6 @@ canvas_->drawTextBlob(blob.get(), x, y, ToSkPaint(flags)); } -void SkiaPaintCanvas::drawDisplayItemList( - scoped_refptr<DisplayItemList> display_item_list) { - display_item_list->Raster(canvas_); -} - void SkiaPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) { record->playback(canvas_); }
diff --git a/cc/paint/skia_paint_canvas.h b/cc/paint/skia_paint_canvas.h index 15690a2..f3df753 100644 --- a/cc/paint/skia_paint_canvas.h +++ b/cc/paint/skia_paint_canvas.h
@@ -121,9 +121,6 @@ SkScalar y, const PaintFlags& flags) override; - void drawDisplayItemList( - scoped_refptr<DisplayItemList> display_item_list) override; - void drawPicture(sk_sp<const PaintRecord> record) override; bool isClipEmpty() const override;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index ea7ec748..4076f147 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -2776,11 +2776,7 @@ EXPECT_TRUE(sent_gesture_); EXPECT_EQ(gfx::Vector2dF(50, 50), inner); EXPECT_EQ(2, scale_delta); - } - void DidCommit() override { - if (!sent_gesture_) - return; auto* scroll_layer = layer_tree_host()->inner_viewport_scroll_layer(); EXPECT_EQ(gfx::ScrollOffset(50, 50), scroll_layer->scroll_offset()); EndTest(); @@ -2791,8 +2787,7 @@ bool sent_gesture_; }; -// Disabled for flakiness, http://crbug.com/733001 -// MULTI_THREAD_TEST_F(ViewportDeltasAppliedDuringPinch); +MULTI_THREAD_TEST_F(ViewportDeltasAppliedDuringPinch); class LayerTreeHostTestSetVisible : public LayerTreeHostTest { public:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index b001e96..e9f79858 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1095,7 +1095,7 @@ // We send this intent so that we can enter WebVr presentation mode if needed. This // call doesn't consume the intent because it also has the url that we need to load. - VrShellDelegate.onNewIntent(intent); + VrShellDelegate.onNewIntent(ChromeTabbedActivity.this, intent); TabModel tabModel = getCurrentTabModel(); boolean fromLauncherShortcut = IntentUtils.safeGetBooleanExtra(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java index c51fdb5..7746751 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -12,6 +12,7 @@ import android.view.ViewGroup; import org.chromium.base.ContextUtils; +import org.chromium.base.Log; import org.chromium.base.ObserverList; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; @@ -48,6 +49,7 @@ /** Bridges the user's download history and the UI used to display it. */ public class DownloadHistoryAdapter extends DateDividedAdapter implements DownloadUiObserver, DownloadSharedPreferenceHelper.Observer { + private static final String TAG = "DownloadAdapter"; /** Alerted about changes to internal state. */ static interface TestObserver { @@ -439,7 +441,13 @@ // changed. This prevents the RecyclerView from detaching and immediately // reattaching the same view, causing janky animations. for (DownloadItemView view : mViews) { - if (TextUtils.equals(item.getId(), view.getItem().getId())) { + DownloadHistoryItemWrapper wrapper = view.getItem(); + if (wrapper == null) { + // TODO(qinmin): remove this once crbug.com/731789 is fixed. + Log.e(TAG, "DownloadItemView contains empty DownloadHistoryItemWrapper"); + continue; + } + if (TextUtils.equals(item.getId(), wrapper.getId())) { view.displayItem(mBackendProvider, existingWrapper); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java index 214fb2ec..7156ed1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ChromeHomeNewTabPageBase.java
@@ -37,7 +37,7 @@ final OverviewModeObserver mOverviewModeObserver; @Nullable final LayoutManagerChrome mLayoutManager; - final BottomSheet mBottomSheet; + BottomSheet mBottomSheet; final String mTitle; private boolean mShowOverviewOnClose; @@ -96,9 +96,12 @@ // If the NTP is loading, the sheet state will be set to SHEET_STATE_HALF. if (TextUtils.equals(tab.getUrl(), getUrl())) return; - mBottomSheet.getBottomSheetMetrics().setSheetCloseReason( - BottomSheetMetrics.CLOSED_BY_NAVIGATION); - mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true); + mBottomSheet = mTab.getActivity().getBottomSheet(); + if (mBottomSheet != null) { + mBottomSheet.getBottomSheetMetrics().setSheetCloseReason( + BottomSheetMetrics.CLOSED_BY_NAVIGATION); + mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true); + } } }; mTab.addObserver(mTabObserver); @@ -108,9 +111,11 @@ boolean tabAlreadyShowing = mTabModelSelector.getCurrentTab() == mTab; if (tabAlreadyShowing) onNewTabPageShown(); - mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_HALF, true); - mBottomSheet.getBottomSheetMetrics().recordSheetOpenReason( - BottomSheetMetrics.OPENED_BY_NEW_TAB_CREATION); + if (mBottomSheet != null) { + mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_HALF, true); + mBottomSheet.getBottomSheetMetrics().recordSheetOpenReason( + BottomSheetMetrics.OPENED_BY_NEW_TAB_CREATION); + } // TODO(twellington): disallow moving the NTP to the other window in Android N+ // multi-window mode. @@ -168,9 +173,13 @@ mCloseButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - mBottomSheet.getBottomSheetMetrics().setSheetCloseReason( - BottomSheetMetrics.CLOSED_BY_NTP_CLOSE_BUTTON); - mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true); + mBottomSheet = mTab.getActivity().getBottomSheet(); + if (mBottomSheet != null) { + mBottomSheet.getBottomSheetMetrics().setSheetCloseReason( + BottomSheetMetrics.CLOSED_BY_NTP_CLOSE_BUTTON); + mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true); + } + if (mShowOverviewOnClose && getLayoutManager() != null) { getLayoutManager().showOverview(false); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java index 482cf95..2c89dc8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -676,13 +676,12 @@ /** * This is called every time ChromeActivity gets a new intent. */ - public static void onNewIntent(Intent intent) { + public static void onNewIntent(ChromeActivity activity, Intent intent) { if (IntentUtils.safeGetBooleanExtra(intent, DAYDREAM_VR_EXTRA, false) && ChromeFeatureList.isEnabled(ChromeFeatureList.WEBVR_AUTOPRESENT) - && activitySupportsAutopresentation( - ApplicationStatus.getLastTrackedFocusedActivity()) + && activitySupportsAutopresentation(activity) && IntentHandler.isIntentFromTrustedApp(intent, DAYDREAM_HOME_PACKAGE)) { - VrShellDelegate instance = getInstance(); + VrShellDelegate instance = getInstance(activity); if (instance == null) return; instance.onAutopresentIntent(); }
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc index 9d09439d..54524a6 100644 --- a/chrome/app/chrome_main.cc +++ b/chrome/app/chrome_main.cc
@@ -107,10 +107,8 @@ #endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) #if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING) - if (command_line->GetSwitchValueASCII(switches::kProcessType) == - "profiling") { + if (command_line->HasSwitch(switches::kMemlog)) return profiling::ProfilingMain(*command_line); - } #endif // ENABLE_OOP_HEAP_PROFILING #if defined(OS_CHROMEOS) && BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index ee6fff5a..c97c865 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -9152,11 +9152,7 @@ Send feedback to help us fix this issue. </message> <message name="IDS_PROFILE_ERROR_FEEDBACK_DESCRIPTION" desc="The prepopulated text filled in the feedback report reporting a profile error. The triple single quotes are needed to preserve the line break."> -Tell us what happened exactly before you got the profile error message: -''' - </message> - <message name="IDS_PROFILE_ERROR_FEEDBACK_DIAGNOSTICS_LINE" desc="The prepopulated text filled in the feedback report reporting a profile error, above any diagnostics information. The triple single quotes are needed to preserve the line break."> -****Please do not change below this line**** +Please help our engineers fix this problem. Tell us what happened right before you got the profile error message: ''' </message> <message name="IDS_COULDNT_STARTUP_PROFILE_ERROR" desc="Error displayed when Chrome cannot start because profiles were not opened correctly.">
diff --git a/chrome/browser/android/vr_shell/ui_element_renderer.h b/chrome/browser/android/vr_shell/ui_element_renderer.h index b14af75..24fd174 100644 --- a/chrome/browser/android/vr_shell/ui_element_renderer.h +++ b/chrome/browser/android/vr_shell/ui_element_renderer.h
@@ -5,9 +5,13 @@ #ifndef CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENT_RENDERER_H_ #define CHROME_BROWSER_ANDROID_VR_SHELL_UI_ELEMENT_RENDERER_H_ -#include "device/vr/vr_types.h" #include "third_party/skia/include/core/SkColor.h" +namespace gfx { +class RectF; +class Transform; +} // namespace gfx + namespace vr_shell { // This is the interface offered by VrShell's GL system to UI elements. @@ -16,11 +20,11 @@ virtual ~UiElementRenderer() {} virtual void DrawTexturedQuad(int texture_data_handle, - const vr::Mat4f& view_proj_matrix, + const gfx::Transform& view_proj_matrix, const gfx::RectF& copy_rect, float opacity) = 0; - virtual void DrawGradientQuad(const vr::Mat4f& view_proj_matrix, + virtual void DrawGradientQuad(const gfx::Transform& view_proj_matrix, const SkColor edge_color, const SkColor center_color, float opacity) = 0;
diff --git a/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc b/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc index 26b25da..9e1a034 100644 --- a/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc +++ b/chrome/browser/android/vr_shell/ui_elements/screen_dimmer.cc
@@ -6,7 +6,6 @@ #include "chrome/browser/android/vr_shell/color_scheme.h" #include "chrome/browser/android/vr_shell/ui_element_renderer.h" -#include "device/vr/vr_math.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/quaternion.h" #include "ui/gfx/transform.h" @@ -33,7 +32,7 @@ // Always use normal scheme for dimmer. const ColorScheme& color_scheme = ColorScheme::GetColorScheme(ColorScheme::kModeNormal); - renderer->DrawGradientQuad(vr::ToMat4F(m), color_scheme.dimmer_outer, + renderer->DrawGradientQuad(m, color_scheme.dimmer_outer, color_scheme.dimmer_inner, kDimmerOpacity); }
diff --git a/chrome/browser/android/vr_shell/ui_elements/textured_element.cc b/chrome/browser/android/vr_shell/ui_elements/textured_element.cc index 842d09f3..b4a065a 100644 --- a/chrome/browser/android/vr_shell/ui_elements/textured_element.cc +++ b/chrome/browser/android/vr_shell/ui_elements/textured_element.cc
@@ -8,7 +8,6 @@ #include "cc/paint/skia_paint_canvas.h" #include "chrome/browser/android/vr_shell/textures/ui_texture.h" #include "chrome/browser/android/vr_shell/ui_element_renderer.h" -#include "device/vr/vr_math.h" #include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/geometry/rect_f.h" @@ -48,8 +47,8 @@ gfx::SizeF drawn_size = GetTexture()->GetDrawnSize(); gfx::RectF copy_rect(0, 0, drawn_size.width() / texture_size_.width(), drawn_size.height() / texture_size_.height()); - renderer->DrawTexturedQuad(texture_handle_, vr::ToMat4F(view_proj_matrix), - copy_rect, opacity()); + renderer->DrawTexturedQuad(texture_handle_, view_proj_matrix, copy_rect, + opacity()); } void TexturedElement::Flush(SkSurface* surface) {
diff --git a/chrome/browser/android/vr_shell/ui_scene.cc b/chrome/browser/android/vr_shell/ui_scene.cc index d67a011c..a1b7574 100644 --- a/chrome/browser/android/vr_shell/ui_scene.cc +++ b/chrome/browser/android/vr_shell/ui_scene.cc
@@ -13,7 +13,6 @@ #include "chrome/browser/android/vr_shell/animation.h" #include "chrome/browser/android/vr_shell/easing.h" #include "chrome/browser/android/vr_shell/ui_elements/ui_element.h" -#include "device/vr/vr_math.h" namespace vr_shell { @@ -251,17 +250,15 @@ ApplyAnchoring(*parent, element->x_anchoring(), element->y_anchoring(), inheritable); ApplyRecursiveTransforms(parent); - vr::Mat4f product; - vr::MatrixMul(vr::ToMat4F(parent->inheritable_transform().to_world), - vr::ToMat4F(inheritable->to_world), &product); - inheritable->to_world = vr::ToTransform(product); + inheritable->to_world.ConcatTransform( + parent->inheritable_transform().to_world); element->set_computed_opacity(element->computed_opacity() * parent->opacity()); element->set_computed_lock_to_fov(parent->lock_to_fov()); } - transform->to_world = inheritable->to_world * transform->to_world; + transform->to_world.ConcatTransform(inheritable->to_world); element->set_dirty(false); }
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.h b/chrome/browser/android/vr_shell/ui_scene_manager.h index 94630e3..d83b4a72 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.h +++ b/chrome/browser/android/vr_shell/ui_scene_manager.h
@@ -13,7 +13,6 @@ #include "chrome/browser/android/vr_shell/color_scheme.h" #include "chrome/browser/android/vr_shell/ui_interface.h" #include "chrome/browser/android/vr_shell/ui_unsupported_mode.h" -#include "device/vr/vr_types.h" namespace vr_shell {
diff --git a/chrome/browser/android/vr_shell/ui_scene_unittest.cc b/chrome/browser/android/vr_shell/ui_scene_unittest.cc index 7e5ea2c..b806a76 100644 --- a/chrome/browser/android/vr_shell/ui_scene_unittest.cc +++ b/chrome/browser/android/vr_shell/ui_scene_unittest.cc
@@ -14,8 +14,6 @@ #include "chrome/browser/android/vr_shell/animation.h" #include "chrome/browser/android/vr_shell/easing.h" #include "chrome/browser/android/vr_shell/ui_elements/ui_element.h" -#include "device/vr/vr_math.h" -#include "device/vr/vr_types.h" #include "testing/gtest/include/gtest/gtest.h" #define TOLERANCE 0.0001 @@ -133,16 +131,14 @@ scene.AddUiElement(std::move(element)); const UiElement* child = scene.GetUiElementById(1); - const gfx::Vector3dF origin(0, 0, 0); - const gfx::Vector3dF point(1, 0, 0); + gfx::Point3F origin(0, 0, 0); + gfx::Point3F point(1, 0, 0); scene.OnBeginFrame(usToTicks(0)); - auto new_origin = - vr::MatrixVectorMul(vr::ToMat4F(child->TransformMatrix()), origin); - auto new_point = - vr::MatrixVectorMul(vr::ToMat4F(child->TransformMatrix()), point); - EXPECT_VEC3F_NEAR(gfx::Vector3dF(6, 10, 0), new_origin); - EXPECT_VEC3F_NEAR(gfx::Vector3dF(0, 10, 0), new_point); + child->TransformMatrix().TransformPoint(&origin); + child->TransformMatrix().TransformPoint(&point); + EXPECT_VEC3F_NEAR(gfx::Point3F(6, 10, 0), origin); + EXPECT_VEC3F_NEAR(gfx::Point3F(0, 10, 0), point); } TEST(UiScene, Opacity) {
diff --git a/chrome/browser/android/vr_shell/vr_controller.cc b/chrome/browser/android/vr_shell/vr_controller.cc index 42864a5..1898cb3b 100644 --- a/chrome/browser/android/vr_shell/vr_controller.cc +++ b/chrome/browser/android/vr_shell/vr_controller.cc
@@ -11,12 +11,14 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/time/time.h" +#include "cc/base/math_util.h" #include "chrome/browser/android/vr_shell/elbow_model.h" #include "device/vr/vr_math.h" #include "third_party/WebKit/public/platform/WebGestureEvent.h" #include "third_party/WebKit/public/platform/WebInputEvent.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_controller.h" +#include "ui/gfx/transform.h" namespace vr_shell { @@ -49,8 +51,8 @@ constexpr float kLaserStartDisplacement = 0.045; void ClampTouchpadPosition(gfx::Vector2dF* position) { - position->set_x(vr::Clampf(position->x(), 0.0f, 1.0f)); - position->set_y(vr::Clampf(position->y(), 0.0f, 1.0f)); + position->set_x(cc::MathUtil::ClampToRange(position->x(), 0.0f, 1.0f)); + position->set_y(cc::MathUtil::ClampToRange(position->y(), 0.0f, 1.0f)); } float DeltaTimeSeconds(int64_t last_timestamp_nanos) { @@ -109,17 +111,16 @@ pad.timestamp = controller_state_->GetLastOrientationTimestamp(); pad.touch_pos.set_x(TouchPosX()); pad.touch_pos.set_y(TouchPosY()); - pad.orientation = Orientation(); + pad.orientation = vr::ToVRQuatF(Orientation()); // Use orientation to rotate acceleration/gyro into seated space. - vr::Mat4f pose_mat; - vr::QuatToMatrix(pad.orientation, &pose_mat); + gfx::Transform pose_mat(Orientation()); const gvr::Vec3f& accel = controller_state_->GetAccel(); const gvr::Vec3f& gyro = controller_state_->GetGyro(); - pad.accel = - vr::MatrixVectorMul(pose_mat, gfx::Vector3dF(accel.x, accel.y, accel.z)); - pad.gyro = - vr::MatrixVectorMul(pose_mat, gfx::Vector3dF(gyro.x, gyro.y, gyro.z)); + pad.accel = gfx::Vector3dF(accel.x, accel.y, accel.z); + pose_mat.TransformVector(&pad.accel); + pad.gyro = gfx::Vector3dF(gyro.x, gyro.y, gyro.z); + pose_mat.TransformVector(&pad.gyro); pad.is_touching = controller_state_->IsTouching(); pad.controller_button_pressed = @@ -141,15 +142,16 @@ return controller_state_->GetTouchPos().y; } -vr::Quatf VrController::Orientation() const { +gfx::Quaternion VrController::Orientation() const { const gvr::Quatf& orientation = controller_state_->GetOrientation(); - return *reinterpret_cast<vr::Quatf*>(const_cast<gvr::Quatf*>(&orientation)); + return gfx::Quaternion(orientation.qx, orientation.qy, orientation.qz, + orientation.qw); } -void VrController::GetTransform(vr::Mat4f* out) const { - QuatToMatrix(vr::ToVRQuatF(elbow_model_->GetControllerRotation()), out); - auto position = elbow_model_->GetControllerPosition(); - vr::TranslateM(*out, vr::ToVector(position), out); +void VrController::GetTransform(gfx::Transform* out) const { + *out = gfx::Transform(elbow_model_->GetControllerRotation()); + gfx::Point3F p = elbow_model_->GetControllerPosition(); + out->matrix().postTranslate(p.x(), p.y(), p.z()); } float VrController::GetOpacity() const { @@ -157,12 +159,11 @@ } gfx::Point3F VrController::GetPointerStart() const { - auto controller_position = elbow_model_->GetControllerPosition(); + gfx::Point3F controller_position = elbow_model_->GetControllerPosition(); gfx::Vector3dF pointer_direction{0.0f, -sin(kErgoAngleOffset), -cos(kErgoAngleOffset)}; - vr::Mat4f rotation_mat; - vr::QuatToMatrix(Orientation(), &rotation_mat); - pointer_direction = vr::MatrixVectorRotate(rotation_mat, pointer_direction); + gfx::Transform rotation_mat(Orientation()); + rotation_mat.TransformVector(&pointer_direction); return controller_position + gfx::ScaleVector3d(pointer_direction, kLaserStartDisplacement); } @@ -215,7 +216,7 @@ } const gvr::Vec3f& gvr_gyro = controller_state_->GetGyro(); - elbow_model_->Update({IsConnected(), vr::ToQuaternion(Orientation()), + elbow_model_->Update({IsConnected(), Orientation(), gfx::Vector3dF(gvr_gyro.x, gvr_gyro.y, gvr_gyro.z), head_direction, DeltaTimeSeconds(last_timestamp_nanos_)});
diff --git a/chrome/browser/android/vr_shell/vr_controller.h b/chrome/browser/android/vr_shell/vr_controller.h index 25b5fc1..de6d03b7 100644 --- a/chrome/browser/android/vr_shell/vr_controller.h +++ b/chrome/browser/android/vr_shell/vr_controller.h
@@ -11,13 +11,20 @@ #include "base/macros.h" #include "chrome/browser/android/vr_shell/vr_controller_model.h" #include "device/vr/android/gvr/gvr_gamepad_data_provider.h" -#include "device/vr/vr_types.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h" +#include "ui/gfx/geometry/point3_f.h" +#include "ui/gfx/geometry/quaternion.h" +#include "ui/gfx/geometry/vector2d_f.h" +#include "ui/gfx/geometry/vector3d_f.h" namespace blink { class WebGestureEvent; } +namespace gfx { +class Transform; +} + namespace gvr { class ControllerState; } @@ -56,8 +63,8 @@ float TouchPosY(); - vr::Quatf Orientation() const; - void GetTransform(vr::Mat4f* out) const; + gfx::Quaternion Orientation() const; + void GetTransform(gfx::Transform* out) const; float GetOpacity() const; gfx::Point3F GetPointerStart() const;
diff --git a/chrome/browser/android/vr_shell/vr_gl_util.cc b/chrome/browser/android/vr_shell/vr_gl_util.cc index 1c68ee1..e087b892 100644 --- a/chrome/browser/android/vr_shell/vr_gl_util.cc +++ b/chrome/browser/android/vr_shell/vr_gl_util.cc
@@ -4,20 +4,15 @@ #include "chrome/browser/android/vr_shell/vr_gl_util.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/transform.h" + namespace vr_shell { // This code is adapted from the GVR Treasure Hunt demo source. -std::array<float, 16> MatrixToGLArray(const vr::Mat4f& matrix) { - // Note that this performs a *transpose* to a column-major matrix array, as - // expected by GL. The input matrix has translation components at [i][3] for - // use with row vectors and premultiplied transforms. In the output, the - // translation elements are at the end at positions 3*4+i. +std::array<float, 16> MatrixToGLArray(const gfx::Transform& transform) { std::array<float, 16> result; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result[j * 4 + i] = matrix[i][j]; - } - } + transform.matrix().asColMajorf(result.data()); return result; }
diff --git a/chrome/browser/android/vr_shell/vr_gl_util.h b/chrome/browser/android/vr_shell/vr_gl_util.h index 59052929..ff0b2e6 100644 --- a/chrome/browser/android/vr_shell/vr_gl_util.h +++ b/chrome/browser/android/vr_shell/vr_gl_util.h
@@ -8,12 +8,18 @@ #include <array> #include <string> -#include "device/vr/vr_types.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gl/gl_bindings.h" +namespace gfx { +class RectF; +class Size; +class Transform; +} // namespace gfx + namespace vr_shell { -std::array<float, 16> MatrixToGLArray(const vr::Mat4f& matrix); +std::array<float, 16> MatrixToGLArray(const gfx::Transform& matrix); gfx::Rect CalculatePixelSpaceRect(const gfx::Size& texture_size, const gfx::RectF& texture_rect);
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc index 40d60d7f..b7b761d 100644 --- a/chrome/browser/android/vr_shell/vr_shell_gl.cc +++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -103,33 +103,46 @@ gfx::PointF(std::numeric_limits<float>::max(), std::numeric_limits<float>::max()); +static constexpr float kEpsilon = 1e-6f; + +gfx::Point3F GetRayPoint(const gfx::Point3F& rayOrigin, + const gfx::Vector3dF& rayVector, + float scale) { + return rayOrigin + gfx::ScaleVector3d(rayVector, scale); +} + +// Provides the direction the head is looking towards as a 3x1 unit vector. +gfx::Vector3dF GetForwardVector(const gfx::Transform& head_pose) { + // Same as multiplying the inverse of the rotation component of the matrix by + // (0, 0, -1, 0). + return gfx::Vector3dF(-head_pose.matrix().get(2, 0), + -head_pose.matrix().get(2, 1), + -head_pose.matrix().get(2, 2)); +} + // Generate a quaternion representing the rotation from the negative Z axis // (0, 0, -1) to a specified vector. This is an optimized version of a more // general vector-to-vector calculation. -vr::Quatf GetRotationFromZAxis(gfx::Vector3dF vec) { - vr::NormalizeVector(&vec); - vr::Quatf quat; - quat.qw = 1.0f - vec.z(); - if (quat.qw < 1e-6f) { +gfx::Quaternion GetRotationFromZAxis(gfx::Vector3dF vec) { + vec.GetNormalized(&vec); + gfx::Quaternion quat; + quat.set_w(1.0f - vec.z()); + if (quat.w() < kEpsilon) { // Degenerate case: vectors are exactly opposite. Replace by an // arbitrary 180 degree rotation to avoid invalid normalization. - quat.qx = 1.0f; - quat.qy = 0.0f; - quat.qz = 0.0f; - quat.qw = 0.0f; - } else { - quat.qx = vec.y(); - quat.qy = -vec.x(); - quat.qz = 0.0f; - vr::NormalizeQuat(&quat); + return gfx::Quaternion(1, 0, 0, 0); } - return quat; + + quat.set_x(vec.y()); + quat.set_y(-vec.x()); + quat.set_z(0.0); + return quat.Normalized(); } -gvr::Mat4f PerspectiveMatrixFromView(const gvr::Rectf& fov, - float z_near, - float z_far) { - gvr::Mat4f result; +gfx::Transform PerspectiveMatrixFromView(const gvr::Rectf& fov, + float z_near, + float z_far) { + gfx::Transform result; const float x_left = -std::tan(fov.left * M_PI / 180.0f) * z_near; const float x_right = std::tan(fov.right * M_PI / 180.0f) * z_near; const float y_bottom = -std::tan(fov.bottom * M_PI / 180.0f) * z_near; @@ -144,18 +157,16 @@ const float C = (z_near + z_far) / (z_near - z_far); const float D = (2 * z_near * z_far) / (z_near - z_far); - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - result.m[i][j] = 0.0f; - } - } - result.m[0][0] = X; - result.m[0][2] = A; - result.m[1][1] = Y; - result.m[1][2] = B; - result.m[2][2] = C; - result.m[2][3] = D; - result.m[3][2] = -1; + // The gfx::Transform default ctor initializes the transform to the identity, + // so we must zero out a few values along the diagonal here. + result.matrix().set(0, 0, X); + result.matrix().set(0, 2, A); + result.matrix().set(1, 1, Y); + result.matrix().set(1, 2, B); + result.matrix().set(2, 2, C); + result.matrix().set(2, 3, D); + result.matrix().set(3, 2, -1); + result.matrix().set(3, 3, 0); return result; } @@ -178,21 +189,20 @@ return mouse_event; } - -void MatfToGvrMat(const vr::Mat4f& in, gvr::Mat4f* out) { - // If our std::array implementation doesn't have any non-data members, we can - // just cast the gvr matrix to an std::array. - static_assert(sizeof(in) == sizeof(*out), - "Cannot reinterpret gvr::Mat4f as vr::Matf"); - *out = *reinterpret_cast<gvr::Mat4f*>(const_cast<vr::Mat4f*>(&in)); +void TransformToGvrMat(const gfx::Transform& in, gvr::Mat4f* out) { + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + out->m[i][j] = in.matrix().get(i, j); + } + } } -void GvrMatToMatf(const gvr::Mat4f& in, vr::Mat4f* out) { - // If our std::array implementation doesn't have any non-data members, we can - // just cast the gvr matrix to an std::array. - static_assert(sizeof(in) == sizeof(*out), - "Cannot reinterpret gvr::Mat4f as vr::Matf"); - *out = *reinterpret_cast<vr::Mat4f*>(const_cast<gvr::Mat4f*>(&in)); +void GvrMatToTransform(const gvr::Mat4f& in, gfx::Transform* out) { + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + out->matrix().set(i, j, in.m[i][j]); + } + } } gvr::Rectf UVFromGfxRect(gfx::RectF rect) { @@ -450,8 +460,10 @@ void VrShellGl::InitializeRenderer() { gvr_api_->InitializeGl(); - vr::Mat4f head_pose; - device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); + gfx::Transform head_pose; + vr::Mat4f from_gvr; + device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &from_gvr); + head_pose = vr::ToTransform(from_gvr); webvr_head_pose_.assign(kPoseRingBufferSize, head_pose); webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks()); webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks()); @@ -557,10 +569,9 @@ controller_quat_ = controller_->Orientation(); } - vr::Mat4f mat; - QuatToMatrix(controller_quat_, &mat); - gfx::Vector3dF controller_direction = - vr::MatrixVectorMul(mat, ergo_neutral_pose); + gfx::Transform mat(controller_quat_); + gfx::Vector3dF controller_direction = ergo_neutral_pose; + mat.TransformVector(&controller_direction); HandleControllerAppButtonActivity(controller_direction); @@ -857,10 +868,9 @@ // that the sphere is centered at the controller, rather than the eye, for // simplicity. float distance = scene_->GetBackgroundDistance(); - target_point = - vr::GetRayPoint(pointer_start_, controller_direction, distance); + target_point = GetRayPoint(pointer_start_, controller_direction, distance); eye_to_target = target_point - kOrigin; - vr::NormalizeVector(&eye_to_target); + eye_to_target.GetNormalized(&eye_to_target); // Determine which UI element (if any) intersects the line between the eyes // and the controller target position. @@ -898,7 +908,7 @@ if (distance_to_plane < 0 || distance_to_plane >= max_distance_to_plane) return false; - target_point = vr::GetRayPoint(kOrigin, eye_to_target, distance_to_plane); + target_point = GetRayPoint(kOrigin, eye_to_target, distance_to_plane); gfx::PointF unit_xy_point = element.GetUnitRectangleCoordinates(target_point); target_local_point.set_x(0.5f + unit_xy_point.x()); @@ -922,9 +932,13 @@ // TODO(asimjour1): We need to refactor the gesture recognition outside of // VrShellGl. UiInterface::Direction direction = UiInterface::NONE; - float gesture_xz_angle; - if (vr::XZAngle(controller_start_direction_, controller_direction, - &gesture_xz_angle)) { + gfx::Vector3dF a = controller_start_direction_; + gfx::Vector3dF b = controller_direction; + a.set_y(0); + b.set_y(0); + if (a.LengthSquared() * b.LengthSquared() > 0.0) { + float gesture_xz_angle = + acos(gfx::DotProduct(a, b) / a.Length() / b.Length()); if (fabs(gesture_xz_angle) > kMinAppButtonGestureAngleRad) { direction = gesture_xz_angle < 0 ? UiInterface::LEFT : UiInterface::RIGHT; @@ -1024,7 +1038,7 @@ DrawWebVr(); } - vr::Mat4f head_pose; + gfx::Transform head_pose; // When using async reprojection, we need to know which pose was // used in the WebVR app for drawing this frame and supply it when @@ -1036,7 +1050,9 @@ "kPoseRingBufferSize must be a power of 2"); head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; } else { - device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); + vr::Mat4f from_gvr; + device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &from_gvr); + head_pose = vr::ToTransform(from_gvr); } // Update the render position of all UI elements (including desktop). @@ -1046,7 +1062,7 @@ // TODO(crbug.com/704690): Acquire controller state in a way that's timely // for both the gamepad API and UI input handling. TRACE_EVENT0("gpu", "VrShellGl::UpdateController"); - auto head_direction = vr::GetForwardVector(head_pose); + gfx::Vector3dF head_direction = GetForwardVector(head_pose); UpdateController(head_direction); HandleControllerInput(head_direction); } @@ -1081,7 +1097,7 @@ void VrShellGl::DrawFrameSubmitWhenReady(int16_t frame_index, gvr_frame* frame_ptr, - const vr::Mat4f& head_pose, + const gfx::Transform& head_pose, std::unique_ptr<gl::GLFence> fence) { if (fence && !fence->HasCompleted()) { task_runner_->PostDelayedTask( @@ -1098,7 +1114,7 @@ gvr::Frame frame(frame_ptr); gvr::Mat4f mat; - MatfToGvrMat(head_pose, &mat); + TransformToGvrMat(head_pose, &mat); frame.Submit(*buffer_viewport_list_, mat); // No need to swap buffers for surfaceless rendering. @@ -1137,7 +1153,7 @@ TRACE_COUNTER1("gpu", "WebVR FPS", fps_meter_->GetFPS()); } -void VrShellGl::DrawWorldElements(const vr::Mat4f& head_pose) { +void VrShellGl::DrawWorldElements(const gfx::Transform& head_pose) { TRACE_EVENT0("gpu", "VrShellGl::DrawWorldElements"); if (ShouldDrawWebVr()) { @@ -1167,7 +1183,7 @@ kViewportListPrimaryOffset, draw_reticle); } -void VrShellGl::DrawOverlayElements(const vr::Mat4f& head_pose) { +void VrShellGl::DrawOverlayElements(const gfx::Transform& head_pose) { std::vector<const UiElement*> elements = scene_->GetOverlayElements(); if (elements.empty()) return; @@ -1199,13 +1215,12 @@ glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - vr::Mat4f identity_matrix; - vr::SetIdentityM(&identity_matrix); + gfx::Transform identity_matrix; DrawUiView(identity_matrix, elements, render_size_headlocked_, kViewportListHeadlockedOffset, false); } -void VrShellGl::DrawUiView(const vr::Mat4f& head_pose, +void VrShellGl::DrawUiView(const gfx::Transform& head_pose, const std::vector<const UiElement*>& elements, const gfx::Size& render_size, int viewport_offset, @@ -1218,23 +1233,18 @@ buffer_viewport_list_->GetBufferViewport(eye + viewport_offset, buffer_viewport_.get()); - vr::Mat4f eye_view_matrix; - vr::Mat4f eye_matrix; - GvrMatToMatf(gvr_api_->GetEyeFromHeadMatrix(eye), &eye_matrix); - vr::MatrixMul(eye_matrix, head_pose, &eye_view_matrix); + gfx::Transform eye_matrix; + GvrMatToTransform(gvr_api_->GetEyeFromHeadMatrix(eye), &eye_matrix); + gfx::Transform eye_view_matrix = eye_matrix * head_pose; const gfx::RectF& rect = GfxRectFromUV(buffer_viewport_->GetSourceUv()); const gfx::Rect& pixel_rect = CalculatePixelSpaceRect(render_size, rect); glViewport(pixel_rect.x(), pixel_rect.y(), pixel_rect.width(), pixel_rect.height()); - vr::Mat4f view_proj_matrix; - vr::Mat4f perspective_matrix; - GvrMatToMatf(PerspectiveMatrixFromView(buffer_viewport_->GetSourceFov(), - kZNear, kZFar), - &perspective_matrix); - - vr::MatrixMul(perspective_matrix, eye_view_matrix, &view_proj_matrix); + gfx::Transform perspective_matrix = PerspectiveMatrixFromView( + buffer_viewport_->GetSourceFov(), kZNear, kZFar); + gfx::Transform view_proj_matrix = perspective_matrix * eye_view_matrix; DrawElements(view_proj_matrix, sorted_elements, draw_reticle); if (draw_reticle) { @@ -1244,7 +1254,7 @@ } } -void VrShellGl::DrawElements(const vr::Mat4f& view_proj_matrix, +void VrShellGl::DrawElements(const gfx::Transform& view_proj_matrix, const std::vector<const UiElement*>& elements, bool draw_reticle) { if (elements.empty()) @@ -1269,11 +1279,9 @@ vr_shell_renderer_->Flush(); } -void VrShellGl::DrawElement(const vr::Mat4f& view_proj_matrix, +void VrShellGl::DrawElement(const gfx::Transform& view_proj_matrix, const UiElement& element) { - vr::Mat4f transform; - vr::MatrixMul(view_proj_matrix, vr::ToMat4F(element.TransformMatrix()), - &transform); + gfx::Transform transform = view_proj_matrix * element.TransformMatrix(); switch (element.fill()) { case Fill::OPAQUE_GRADIENT: { @@ -1297,7 +1305,7 @@ break; } case Fill::SELF: { - element.Render(vr_shell_renderer_.get(), vr::ToTransform(transform)); + element.Render(vr_shell_renderer_.get(), transform); break; } default: @@ -1306,7 +1314,7 @@ } std::vector<const UiElement*> VrShellGl::GetElementsInDrawOrder( - const vr::Mat4f& view_matrix, + const gfx::Transform& view_matrix, const std::vector<const UiElement*>& elements) { std::vector<const UiElement*> sorted_elements = elements; @@ -1321,32 +1329,23 @@ if (first->draw_phase() != second->draw_phase()) { return first->draw_phase() < second->draw_phase(); } else { - const float first_depth = - vr::GetTranslation(vr::ToMat4F(first->TransformMatrix())) - .z(); - const float second_depth = - vr::GetTranslation(vr::ToMat4F(second->TransformMatrix())) - .z(); - return first_depth < second_depth; + return first->TransformMatrix().matrix().get(2, 3) < + second->TransformMatrix().matrix().get(2, 3); } }); return sorted_elements; } -void VrShellGl::DrawReticle(const vr::Mat4f& render_matrix) { - vr::Mat4f mat; - vr::SetIdentityM(&mat); - +void VrShellGl::DrawReticle(const gfx::Transform& render_matrix) { // Scale the reticle to have a fixed FOV size at any distance. const float eye_to_target = std::sqrt(target_point_.SquaredDistanceTo(kOrigin)); - vr::ScaleM( - mat, - {kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1.0f}, - &mat); - vr::Quatf rotation; + gfx::Transform mat; + mat.Scale3d(kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1); + + gfx::Quaternion rotation; if (reticle_render_target_ != nullptr) { // Make the reticle planar to the element it's hitting. rotation = GetRotationFromZAxis(reticle_render_target_->GetNormal()); @@ -1354,74 +1353,67 @@ // Rotate the reticle to directly face the eyes. rotation = GetRotationFromZAxis(target_point_ - kOrigin); } - vr::Mat4f rotation_mat; - vr::QuatToMatrix(rotation, &rotation_mat); - vr::MatrixMul(rotation_mat, mat, &mat); + gfx::Transform rotation_mat(rotation); + mat = rotation_mat * mat; gfx::Point3F target_point = ScalePoint(target_point_, kReticleOffset); // Place the pointer slightly in front of the plane intersection point. - vr::TranslateM(mat, target_point - kOrigin, &mat); + mat.matrix().postTranslate(target_point.x(), target_point.y(), + target_point.z()); - vr::Mat4f transform; - vr::MatrixMul(render_matrix, mat, &transform); + gfx::Transform transform = render_matrix * mat; vr_shell_renderer_->GetReticleRenderer()->Draw(transform); } -void VrShellGl::DrawLaser(const vr::Mat4f& render_matrix) { +void VrShellGl::DrawLaser(const gfx::Transform& render_matrix) { gfx::Point3F target_point = ScalePoint(target_point_, kReticleOffset); // Find the length of the beam (from hand to target). const float laser_length = std::sqrt(pointer_start_.SquaredDistanceTo(target_point)); - vr::Mat4f mat; // Build a beam, originating from the origin. - vr::SetIdentityM(&mat); + gfx::Transform mat; // Move the beam half its height so that its end sits on the origin. - vr::TranslateM(mat, {0.0f, 0.5f, 0.0f}, &mat); - vr::ScaleM(mat, {kLaserWidth, laser_length, 1}, &mat); + mat.matrix().postTranslate(0.0f, 0.5f, 0.0f); + mat.matrix().postScale(kLaserWidth, laser_length, 1); // Tip back 90 degrees to flat, pointing at the scene. - const vr::Quatf quat = vr::QuatFromAxisAngle({1.0f, 0.0f, 0.0f, -M_PI / 2}); - vr::Mat4f rotation_mat; - vr::QuatToMatrix(quat, &rotation_mat); - vr::MatrixMul(rotation_mat, mat, &mat); + const gfx::Quaternion quat(gfx::Vector3dF(1.0f, 0.0f, 0.0f), -M_PI / 2); + gfx::Transform rotation_mat(quat); + mat = rotation_mat * mat; const gfx::Vector3dF beam_direction = target_point_ - pointer_start_; - vr::Mat4f beam_direction_mat; - vr::QuatToMatrix(GetRotationFromZAxis(beam_direction), &beam_direction_mat); + gfx::Transform beam_direction_mat(GetRotationFromZAxis(beam_direction)); float opacity = controller_->GetOpacity(); // Render multiple faces to make the laser appear cylindrical. const int faces = 4; - vr::Mat4f face_transform; - vr::Mat4f transform; + gfx::Transform face_transform; + gfx::Transform transform; for (int i = 0; i < faces; i++) { // Rotate around Z. const float angle = M_PI * 2 * i / faces; - const vr::Quatf rot = vr::QuatFromAxisAngle({0.0f, 0.0f, 1.0f, angle}); - vr::QuatToMatrix(rot, &face_transform); - vr::MatrixMul(face_transform, mat, &face_transform); - // Orient according to target direction. - vr::MatrixMul(beam_direction_mat, face_transform, &face_transform); + const gfx::Quaternion rot({0.0f, 0.0f, 1.0f}, angle); + face_transform = beam_direction_mat * gfx::Transform(rot) * mat; // Move the beam origin to the hand. - vr::TranslateM(face_transform, pointer_start_ - kOrigin, &face_transform); - vr::MatrixMul(render_matrix, face_transform, &transform); + face_transform.matrix().postTranslate( + pointer_start_.x(), pointer_start_.y(), pointer_start_.z()); + transform = render_matrix * face_transform; vr_shell_renderer_->GetLaserRenderer()->Draw(opacity, transform); } } -void VrShellGl::DrawController(const vr::Mat4f& view_proj_matrix) { +void VrShellGl::DrawController(const gfx::Transform& view_proj_matrix) { if (!vr_shell_renderer_->GetControllerRenderer()->IsSetUp()) return; auto state = controller_->GetModelState(); auto opacity = controller_->GetOpacity(); - vr::Mat4f controller_transform; + gfx::Transform controller_transform; controller_->GetTransform(&controller_transform); - vr::Mat4f transform; - vr::MatrixMul(view_proj_matrix, controller_transform, &transform); + gfx::Transform transform = view_proj_matrix * controller_transform; vr_shell_renderer_->GetControllerRenderer()->Draw(state, opacity, transform); } @@ -1610,10 +1602,12 @@ int64_t prediction_nanos = GetPredictedFrameTimeNanos(); - vr::Mat4f head_mat; + gfx::Transform head_mat; + vr::Mat4f from_gvr; device::mojom::VRPosePtr pose = - device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, + device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &from_gvr, prediction_nanos); + head_mat = vr::ToTransform(from_gvr); webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now();
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.h b/chrome/browser/android/vr_shell/vr_shell_gl.h index 6ea66a9..57252186 100644 --- a/chrome/browser/android/vr_shell/vr_shell_gl.h +++ b/chrome/browser/android/vr_shell/vr_shell_gl.h
@@ -18,10 +18,11 @@ #include "chrome/browser/android/vr_shell/vr_controller.h" #include "chrome/browser/android/vr_shell/vr_controller_model.h" #include "device/vr/vr_service.mojom.h" -#include "device/vr/vr_types.h" #include "mojo/public/cpp/bindings/binding.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h" +#include "ui/gfx/geometry/quaternion.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/native_widget_types.h" namespace blink { @@ -117,26 +118,27 @@ void DrawFrame(int16_t frame_index); void DrawFrameSubmitWhenReady(int16_t frame_index, gvr_frame* frame_ptr, - const vr::Mat4f& head_pose, + const gfx::Transform& head_pose, std::unique_ptr<gl::GLFence> fence); - void DrawWorldElements(const vr::Mat4f& head_pose); - void DrawOverlayElements(const vr::Mat4f& head_pose); + void DrawWorldElements(const gfx::Transform& head_pose); + void DrawOverlayElements(const gfx::Transform& head_pose); void DrawHeadLockedElements(); - void DrawUiView(const vr::Mat4f& head_pose, + void DrawUiView(const gfx::Transform& head_pose, const std::vector<const UiElement*>& elements, const gfx::Size& render_size, int viewport_offset, bool draw_cursor); - void DrawElements(const vr::Mat4f& view_proj_matrix, + void DrawElements(const gfx::Transform& view_proj_matrix, const std::vector<const UiElement*>& elements, bool draw_cursor); - void DrawElement(const vr::Mat4f& view_proj_matrix, const UiElement& element); + void DrawElement(const gfx::Transform& view_proj_matrix, + const UiElement& element); std::vector<const UiElement*> GetElementsInDrawOrder( - const vr::Mat4f& view_matrix, + const gfx::Transform& view_matrix, const std::vector<const UiElement*>& elements); - void DrawReticle(const vr::Mat4f& view_proj_matrix); - void DrawLaser(const vr::Mat4f& view_proj_matrix); - void DrawController(const vr::Mat4f& view_proj_matrix); + void DrawReticle(const gfx::Transform& view_proj_matrix); + void DrawLaser(const gfx::Transform& view_proj_matrix); + void DrawController(const gfx::Transform& view_proj_matrix); bool ShouldDrawWebVr(); void DrawWebVr(); bool WebVrPoseByteIsValid(int pose_index_byte); @@ -229,7 +231,7 @@ bool cardboard_ = false; bool touch_pending_ = false; - vr::Quatf controller_quat_; + gfx::Quaternion controller_quat_; gfx::Point3F target_point_; @@ -250,9 +252,11 @@ gfx::Size content_tex_physical_size_ = {0, 0}; gfx::Size webvr_surface_size_ = {0, 0}; - std::vector<vr::Mat4f> webvr_head_pose_; std::vector<base::TimeTicks> webvr_time_pose_; std::vector<base::TimeTicks> webvr_time_js_submit_; + + std::vector<gfx::Transform> webvr_head_pose_; + bool web_vr_mode_; bool ready_to_draw_ = false; bool surfaceless_rendering_;
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.cc b/chrome/browser/android/vr_shell/vr_shell_renderer.cc index df3705c8..f43a98a5 100644 --- a/chrome/browser/android/vr_shell/vr_shell_renderer.cc +++ b/chrome/browser/android/vr_shell/vr_shell_renderer.cc
@@ -11,6 +11,7 @@ #include "base/memory/ptr_util.h" #include "base/trace_event/trace_event.h" #include "chrome/browser/android/vr_shell/vr_gl_util.h" +#include "ui/gfx/geometry/rect_f.h" namespace { @@ -337,7 +338,7 @@ BaseQuadRenderer::~BaseQuadRenderer() = default; void BaseQuadRenderer::PrepareToDraw(GLuint view_proj_matrix_handle, - const vr::Mat4f& view_proj_matrix) { + const gfx::Transform& view_proj_matrix) { glUseProgram(program_handle_); // Pass in model view project matrix. @@ -381,7 +382,7 @@ } void ExternalTexturedQuadRenderer::Draw(int texture_data_handle, - const vr::Mat4f& view_proj_matrix, + const gfx::Transform& view_proj_matrix, const gfx::RectF& copy_rect, float opacity) { PrepareToDraw(model_view_proj_matrix_handle_, view_proj_matrix); @@ -419,7 +420,7 @@ } void TexturedQuadRenderer::AddQuad(int texture_data_handle, - const vr::Mat4f& view_proj_matrix, + const gfx::Transform& view_proj_matrix, const gfx::RectF& copy_rect, float opacity) { SkiaQuad quad; @@ -562,7 +563,7 @@ glGetUniformLocation(program_handle_, "mid_ring_opacity"); } -void ReticleRenderer::Draw(const vr::Mat4f& view_proj_matrix) { +void ReticleRenderer::Draw(const gfx::Transform& view_proj_matrix) { PrepareToDraw(model_view_proj_matrix_handle_, view_proj_matrix); glUniform4f(color_handle_, kReticleColor[0], kReticleColor[1], @@ -604,7 +605,8 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } -void LaserRenderer::Draw(float opacity, const vr::Mat4f& view_proj_matrix) { +void LaserRenderer::Draw(float opacity, + const gfx::Transform& view_proj_matrix) { PrepareToDraw(model_view_proj_matrix_handle_, view_proj_matrix); // Link texture data with texture unit. @@ -688,7 +690,7 @@ void ControllerRenderer::Draw(VrControllerModel::State state, float opacity, - const vr::Mat4f& view_proj_matrix) { + const gfx::Transform& view_proj_matrix) { glUseProgram(program_handle_); glUniform1f(opacity_handle_, opacity); @@ -730,7 +732,7 @@ opacity_handle_ = glGetUniformLocation(program_handle_, "u_Opacity"); } -void GradientQuadRenderer::Draw(const vr::Mat4f& view_proj_matrix, +void GradientQuadRenderer::Draw(const gfx::Transform& view_proj_matrix, SkColor edge_color, SkColor center_color, float opacity) { @@ -765,7 +767,7 @@ lines_count_handle_ = glGetUniformLocation(program_handle_, "u_LinesCount"); } -void GradientGridRenderer::Draw(const vr::Mat4f& view_proj_matrix, +void GradientGridRenderer::Draw(const gfx::Transform& view_proj_matrix, SkColor edge_color, SkColor center_color, SkColor grid_color, @@ -807,14 +809,14 @@ VrShellRenderer::~VrShellRenderer() = default; void VrShellRenderer::DrawTexturedQuad(int texture_data_handle, - const vr::Mat4f& view_proj_matrix, + const gfx::Transform& view_proj_matrix, const gfx::RectF& copy_rect, float opacity) { GetTexturedQuadRenderer()->AddQuad(texture_data_handle, view_proj_matrix, copy_rect, opacity); } -void VrShellRenderer::DrawGradientQuad(const vr::Mat4f& view_proj_matrix, +void VrShellRenderer::DrawGradientQuad(const gfx::Transform& view_proj_matrix, const SkColor edge_color, const SkColor center_color, float opacity) {
diff --git a/chrome/browser/android/vr_shell/vr_shell_renderer.h b/chrome/browser/android/vr_shell/vr_shell_renderer.h index 85791ab1..eb11c06e 100644 --- a/chrome/browser/android/vr_shell/vr_shell_renderer.h +++ b/chrome/browser/android/vr_shell/vr_shell_renderer.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "chrome/browser/android/vr_shell/ui_element_renderer.h" #include "chrome/browser/android/vr_shell/vr_controller_model.h" -#include "device/vr/vr_types.h" +#include "ui/gfx/transform.h" #include "ui/gl/gl_bindings.h" namespace vr_shell { @@ -61,7 +61,7 @@ struct SkiaQuad { int texture_data_handle; - vr::Mat4f view_proj_matrix; + gfx::Transform view_proj_matrix; RectF copy_rect; float opacity; }; @@ -89,7 +89,7 @@ protected: void PrepareToDraw(GLuint view_proj_matrix_handle, - const vr::Mat4f& view_proj_matrix); + const gfx::Transform& view_proj_matrix); static GLuint vertex_buffer_; @@ -103,7 +103,7 @@ // Draw the content rect in the texture quad. void Draw(int texture_data_handle, - const vr::Mat4f& view_proj_matrix, + const gfx::Transform& view_proj_matrix, const gfx::RectF& copy_rect, float opacity); @@ -123,7 +123,7 @@ // Draw the content rect in the texture quad. void AddQuad(int texture_data_handle, - const vr::Mat4f& view_proj_matrix, + const gfx::Transform& view_proj_matrix, const gfx::RectF& copy_rect, float opacity); @@ -159,7 +159,7 @@ ReticleRenderer(); ~ReticleRenderer() override; - void Draw(const vr::Mat4f& view_proj_matrix); + void Draw(const gfx::Transform& view_proj_matrix); private: GLuint model_view_proj_matrix_handle_; @@ -179,7 +179,7 @@ LaserRenderer(); ~LaserRenderer() override; - void Draw(float opacity, const vr::Mat4f& view_proj_matrix); + void Draw(float opacity, const gfx::Transform& view_proj_matrix); private: GLuint model_view_proj_matrix_handle_; @@ -201,7 +201,7 @@ void SetUp(std::unique_ptr<VrControllerModel> model); void Draw(VrControllerModel::State state, float opacity, - const vr::Mat4f& view_proj_matrix); + const gfx::Transform& view_proj_matrix); bool IsSetUp() const { return setup_; } private: @@ -233,7 +233,7 @@ GradientQuadRenderer(); ~GradientQuadRenderer() override; - void Draw(const vr::Mat4f& view_proj_matrix, + void Draw(const gfx::Transform& view_proj_matrix, SkColor edge_color, SkColor center_color, float opacity); @@ -253,7 +253,7 @@ GradientGridRenderer(); ~GradientGridRenderer() override; - void Draw(const vr::Mat4f& view_proj_matrix, + void Draw(const gfx::Transform& view_proj_matrix, SkColor edge_color, SkColor center_color, SkColor grid_color, @@ -279,10 +279,10 @@ // UiElementRenderer interface (exposed to UI elements). void DrawTexturedQuad(int texture_data_handle, - const vr::Mat4f& view_proj_matrix, + const gfx::Transform& view_proj_matrix, const gfx::RectF& copy_rect, float opacity) override; - void DrawGradientQuad(const vr::Mat4f& view_proj_matrix, + void DrawGradientQuad(const gfx::Transform& view_proj_matrix, const SkColor edge_color, const SkColor center_color, float opacity) override;
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc index 5cd67754..156fb72 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -92,8 +92,7 @@ check_webapk_compatibility_(check_webapk_compatibility), is_waiting_for_web_application_info_(true), is_installable_check_complete_(false), - is_icon_saved_(false), - is_ready_(false) { + is_icon_saved_(false) { DCHECK(minimum_icon_size_in_px <= ideal_icon_size_in_px); DCHECK(minimum_splash_image_size_in_px <= ideal_splash_image_size_in_px); @@ -344,6 +343,5 @@ is_icon_saved_ = true; primary_icon_ = primary_icon; - is_ready_ = true; weak_observer_->OnDataAvailable(shortcut_info_, primary_icon_, badge_icon_); }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h index e70c0f9..fa237db 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -86,7 +86,6 @@ // Accessors, etc. void set_weak_observer(Observer* observer) { weak_observer_ = observer; } - bool is_ready() const { return is_ready_; } const SkBitmap& badge_icon() const { return badge_icon_; } const SkBitmap& primary_icon() const { return primary_icon_; } ShortcutInfo& shortcut_info() { return shortcut_info_; } @@ -146,7 +145,6 @@ bool is_waiting_for_web_application_info_; bool is_installable_check_complete_; bool is_icon_saved_; - bool is_ready_; DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcher); };
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc index 7ee2f60e..f5e8ecd 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -42,8 +42,7 @@ } AddToHomescreenManager::AddToHomescreenManager(JNIEnv* env, jobject obj) - : add_shortcut_pending_(false), - is_webapk_compatible_(false) { + : is_webapk_compatible_(false) { java_ref_.Reset(env, obj); } @@ -61,18 +60,24 @@ JNIEnv* env, const JavaParamRef<jobject>& obj, const JavaParamRef<jstring>& j_user_title) { - add_shortcut_pending_ = true; + content::WebContents* web_contents = data_fetcher_->web_contents(); + if (!web_contents) + return; base::string16 user_title = base::android::ConvertJavaStringToUTF16(env, j_user_title); if (!user_title.empty()) data_fetcher_->shortcut_info().user_title = user_title; - if (data_fetcher_->is_ready()) { - // If the fetcher isn't ready yet, the shortcut will be added when it is - // via OnDataAvailable(); - AddShortcut(data_fetcher_->shortcut_info(), data_fetcher_->primary_icon()); - } + RecordAddToHomescreen(); + ShortcutHelper::AddToLauncherWithSkBitmap(web_contents, + data_fetcher_->shortcut_info(), + data_fetcher_->primary_icon()); + + // Fire the appinstalled event. + banners::AppBannerManagerAndroid* app_banner_manager = + banners::AppBannerManagerAndroid::FromWebContents(web_contents); + app_banner_manager->OnInstall(); } void AddToHomescreenManager::Start(content::WebContents* web_contents) { @@ -105,26 +110,6 @@ Java_AddToHomescreenManager_showDialog(env, java_ref_); } -void AddToHomescreenManager::AddShortcut(const ShortcutInfo& info, - const SkBitmap& icon) { - DCHECK(add_shortcut_pending_); - if (!add_shortcut_pending_) - return; - add_shortcut_pending_ = false; - - content::WebContents* web_contents = data_fetcher_->web_contents(); - if (!web_contents) - return; - - RecordAddToHomescreen(); - ShortcutHelper::AddToLauncherWithSkBitmap(web_contents, info, icon); - - // Fire the appinstalled event. - banners::AppBannerManagerAndroid* app_banner_manager = - banners::AppBannerManagerAndroid::FromWebContents(web_contents); - app_banner_manager->OnInstall(); -} - void AddToHomescreenManager::RecordAddToHomescreen() { // Record that the shortcut has been added, so no banners will be shown // for this app. @@ -181,9 +166,6 @@ JNIEnv* env = base::android::AttachCurrentThread(); Java_AddToHomescreenManager_onReadyToAdd(env, java_ref_, java_bitmap); - - if (add_shortcut_pending_) - AddShortcut(info, primary_icon); } void AddToHomescreenManager::CreateInfoBarForWebApk(
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.h b/chrome/browser/android/webapps/add_to_homescreen_manager.h index 36de2b12..3d7af4d 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_manager.h +++ b/chrome/browser/android/webapps/add_to_homescreen_manager.h
@@ -47,10 +47,6 @@ void ShowDialog(); // Called only when the AddToHomescreenDataFetcher has retrieved all of the - // data needed to add the shortcut. - void AddShortcut(const ShortcutInfo& info, const SkBitmap& icon); - - // Called only when the AddToHomescreenDataFetcher has retrieved all of the // data needed to install a WebAPK. void CreateInfoBarForWebApk(const ShortcutInfo& info, const SkBitmap& primary_icon, @@ -71,10 +67,6 @@ // Points to the Java object. base::android::ScopedJavaGlobalRef<jobject> java_ref_; - // Whether the user has requested that a shortcut be added while a fetch was - // in progress. - bool add_shortcut_pending_; - // Whether the site is WebAPK-compatible. bool is_webapk_compatible_;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index df18b88..ed80234 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1661,6 +1661,9 @@ *base::CommandLine::ForCurrentProcess(); static const char* const kCommonSwitchNames[] = { +#if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING) + switches::kMemlogPipe, +#endif switches::kUserAgent, switches::kUserDataDir, // Make logs go to the right file. };
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index bee6bdb1..0c2e3f2 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1069,6 +1069,8 @@ "net/wake_on_wifi_connection_observer.h", "net/wake_on_wifi_manager.cc", "net/wake_on_wifi_manager.h", + "night_light/night_light_client.cc", + "night_light/night_light_client.h", "note_taking_helper.cc", "note_taking_helper.h", "options/cert_library.cc", @@ -1727,6 +1729,7 @@ "net/network_throttling_observer_unittest.cc", "net/tether_notification_presenter_unittest.cc", "net/wake_on_wifi_manager_unittest.cc", + "night_light/night_light_client_unittest.cc", "note_taking_helper_unittest.cc", "options/network_property_ui_data_unittest.cc", "ownership/fake_owner_settings_service.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index 01148fcd..136cc7c 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "ash/ash_switches.h" #include "ash/shell.h" #include "ash/sticky_keys/sticky_keys_controller.h" #include "base/bind.h" @@ -70,6 +71,7 @@ #include "chrome/browser/chromeos/net/network_pref_state_observer.h" #include "chrome/browser/chromeos/net/network_throttling_observer.h" #include "chrome/browser/chromeos/net/wake_on_wifi_manager.h" +#include "chrome/browser/chromeos/night_light/night_light_client.h" #include "chrome/browser/chromeos/note_taking_helper.h" #include "chrome/browser/chromeos/options/cert_library.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" @@ -988,6 +990,13 @@ // fetch of the initial CrosSettings DeviceRebootOnShutdown policy. shutdown_policy_forwarder_ = base::MakeUnique<ShutdownPolicyForwarder>(); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + ash::switches::kAshEnableNightLight)) { + night_light_client_ = base::MakeUnique<NightLightClient>( + g_browser_process->system_request_context()); + night_light_client_->Start(); + } + ChromeBrowserMainPartsLinux::PostBrowserStart(); }
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h index e14676b..e002708c 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -14,6 +14,8 @@ #include "chrome/browser/memory/memory_kills_monitor.h" #include "chromeos/system/version_loader.h" +class NightLightClient; + namespace lock_screen_apps { class StateController; } @@ -111,6 +113,8 @@ std::unique_ptr<lock_screen_apps::StateController> lock_screen_apps_state_controller_; + std::unique_ptr<NightLightClient> night_light_client_; + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsChromeos); };
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc index d3be1d3..2c2eff8 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -62,19 +62,6 @@ namespace { -InputMethodManagerImpl* g_instance = nullptr; - -ash::mojom::ImeInfo GetAshImeInfo(const InputMethodDescriptor& ime, - const InputMethodUtil& util) { - ash::mojom::ImeInfo info; - info.id = ime.id(); - info.name = util.GetInputMethodLongName(ime); - info.medium_name = util.GetInputMethodMediumName(ime); - info.short_name = util.GetInputMethodShortName(ime); - info.third_party = extension_ime_util::IsExtensionIME(ime.id()); - return info; -} - enum InputMethodCategory { INPUT_METHOD_CATEGORY_UNKNOWN = 0, INPUT_METHOD_CATEGORY_XKB, // XKB input methods @@ -962,25 +949,14 @@ component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor(); util_.ResetInputMethods(descriptors); chromeos::UserAddingScreen::Get()->AddObserver(this); - - DCHECK(!g_instance); - g_instance = this; } InputMethodManagerImpl::~InputMethodManagerImpl() { - DCHECK_EQ(g_instance, this); - g_instance = nullptr; - if (candidate_window_controller_.get()) candidate_window_controller_->RemoveObserver(this); chromeos::UserAddingScreen::Get()->RemoveObserver(this); } -// static -InputMethodManagerImpl* InputMethodManagerImpl::Get() { - return g_instance; -} - void InputMethodManagerImpl::RecordInputMethodUsage( const std::string& input_method_id) { UMA_HISTOGRAM_ENUMERATION("InputMethod.Category", @@ -1369,56 +1345,5 @@ return base::FeatureList::IsEnabled(features::kEHVInputOnImeMenu); } -ash::mojom::ImeInfo InputMethodManagerImpl::GetCurrentIme() const { - if (!state_) - return ash::mojom::ImeInfo(); - - InputMethodDescriptor ime = state_->GetCurrentInputMethod(); - ash::mojom::ImeInfo info = GetAshImeInfo(ime, util_); - info.selected = true; - return info; -} - -std::vector<ash::mojom::ImeInfo> InputMethodManagerImpl::GetAvailableImes() - const { - if (!state_) - return std::vector<ash::mojom::ImeInfo>(); - - std::vector<ash::mojom::ImeInfo> imes; - std::string current_ime_id = state_->GetCurrentInputMethod().id(); - std::unique_ptr<InputMethodDescriptors> descriptors = - state_->GetActiveInputMethods(); - for (const InputMethodDescriptor& descriptor : *descriptors) { - ash::mojom::ImeInfo info = GetAshImeInfo(descriptor, util_); - info.selected = descriptor.id() == current_ime_id; - imes.push_back(info); - } - return imes; -} - -bool InputMethodManagerImpl::IsImeManaged() const { - if (!state_) - return false; - - // Having a non-empty "allowed" list indicates that IMEs are managed. - return !state_->GetAllowedInputMethods().empty(); -} - -std::vector<ash::mojom::ImeMenuItem> -InputMethodManagerImpl::GetCurrentImeMenuItems() const { - std::vector<ash::mojom::ImeMenuItem> items; - ui::ime::InputMethodMenuItemList menu_list = - ui::ime::InputMethodMenuManager::GetInstance() - ->GetCurrentInputMethodMenuItemList(); - for (size_t i = 0; i < menu_list.size(); ++i) { - ash::mojom::ImeMenuItem property; - property.key = menu_list[i].key; - property.label = base::UTF8ToUTF16(menu_list[i].label); - property.checked = menu_list[i].is_selection_item_checked; - items.push_back(property); - } - return items; -} - } // namespace input_method } // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h index db5247b..dfd8fdc4 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -12,7 +12,6 @@ #include <string> #include <vector> -#include "ash/ime/ime_controller.h" #include "base/macros.h" #include "base/observer_list.h" #include "base/threading/thread_checker.h" @@ -36,9 +35,7 @@ class ImeKeyboard; // The implementation of InputMethodManager. -// TODO(jamescook): Replace ash::ImeController with mojo interface. class InputMethodManagerImpl : public InputMethodManager, - public ash::ImeController, public CandidateWindowController::Observer, public UserAddingScreen::Observer { public: @@ -167,8 +164,6 @@ bool enable_extension_loading); ~InputMethodManagerImpl() override; - static InputMethodManagerImpl* Get(); - // Receives notification of an InputMethodManager::UISessionState transition. void SetUISessionState(UISessionState new_ui_session); @@ -196,12 +191,6 @@ void OverrideKeyboardUrlRef(const std::string& keyset) override; bool IsEmojiHandwritingVoiceOnImeMenuEnabled() override; - // ash::ImeController: - ash::mojom::ImeInfo GetCurrentIme() const override; - std::vector<ash::mojom::ImeInfo> GetAvailableImes() const override; - bool IsImeManaged() const override; - std::vector<ash::mojom::ImeMenuItem> GetCurrentImeMenuItems() const override; - // chromeos::UserAddingScreen: void OnUserAddingStarted() override; void OnUserAddingFinished() override;
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc index a74dc0d..3ce9aec 100644 --- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc +++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -10,6 +10,8 @@ #include <memory> #include <utility> +#include "ash/ime/ime_controller.h" +#include "ash/shell.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/compiler_specific.h" @@ -20,6 +22,7 @@ #include "chrome/browser/chromeos/input_method/mock_candidate_window_controller.h" #include "chrome/browser/chromeos/input_method/mock_input_method_engine.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/ash/ime_controller_client.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" @@ -66,6 +69,14 @@ return extension_ime_util::GetInputMethodIDByEngineID(id); } +std::string GetCurrentImeIdFromAsh() { + return ash::Shell::Get()->ime_controller()->current_ime().id; +} + +size_t GetAvailableImeCountFromAsh() { + return ash::Shell::Get()->ime_controller()->available_imes().size(); +} + class TestObserver : public InputMethodManager::Observer, public ui::ime::InputMethodMenuManager::Observer { public: @@ -1560,5 +1571,45 @@ ImeIdFromEngineId("xkb:fr::fra"))); } +// Verifies that the combination of InputMethodManagerImpl and +// ImeControllerClient sends the correct data to ash. +TEST_F(InputMethodManagerImplTest, IntegrationWithAsh) { + ImeControllerClient ime_controller_client(manager_.get()); + + InitComponentExtension(); + manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); + std::vector<std::string> ids; + ids.push_back(ImeIdFromEngineId("xkb:us:dvorak:eng")); + ids.push_back(ImeIdFromEngineId(kExt2Engine2Id)); + ids.push_back(ImeIdFromEngineId(kExt2Engine1Id)); + EXPECT_TRUE(manager_->GetActiveIMEState()->ReplaceEnabledInputMethods(ids)); + + EXPECT_EQ(3u, GetAvailableImeCountFromAsh()); + EXPECT_EQ(ImeIdFromEngineId(ids[0]), GetCurrentImeIdFromAsh()); + + // Switch to Mozc. + manager_->GetActiveIMEState()->SwitchToNextInputMethod(); + EXPECT_EQ(ImeIdFromEngineId(ids[1]), GetCurrentImeIdFromAsh()); + + // Lock screen + scoped_refptr<input_method::InputMethodManager::State> saved_ime_state = + manager_->GetActiveIMEState(); + manager_->SetState(saved_ime_state->Clone()); + manager_->GetActiveIMEState()->EnableLockScreenLayouts(); + manager_->SetUISessionState(InputMethodManager::STATE_LOCK_SCREEN); + EXPECT_EQ(2u, GetAvailableImeCountFromAsh()); // Qwerty+Dvorak. + EXPECT_EQ(ImeIdFromEngineId("xkb:us:dvorak:eng"), GetCurrentImeIdFromAsh()); + + manager_->GetActiveIMEState()->SwitchToNextInputMethod(); + EXPECT_EQ(ImeIdFromEngineId("xkb:us::eng"), // The hardware keyboard layout. + GetCurrentImeIdFromAsh()); + + // Unlock screen. The original state, pinyin-dv, is restored. + manager_->SetState(saved_ime_state); + manager_->SetUISessionState(InputMethodManager::STATE_BROWSER_SCREEN); + EXPECT_EQ(3u, GetAvailableImeCountFromAsh()); // Dvorak and 2 IMEs. + EXPECT_EQ(ImeIdFromEngineId(ids[1]), GetCurrentImeIdFromAsh()); +} + } // namespace input_method } // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc index 1b49fe0e..599314a 100644 --- a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc +++ b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/memory/ptr_util.h" #include "ui/base/ime/chromeos/input_method_util.h" namespace chromeos { @@ -24,12 +25,8 @@ std::unique_ptr<InputMethodDescriptors> MockInputMethodManagerImpl::State::GetActiveInputMethods() const { - std::unique_ptr<InputMethodDescriptors> result; -#if _LIBCPP_STD_VER > 11 - result = std::make_unique<InputMethodDescriptors>(); -#else - result.reset(new InputMethodDescriptors); -#endif + std::unique_ptr<InputMethodDescriptors> result = + base::MakeUnique<InputMethodDescriptors>(); result->push_back(InputMethodUtil::GetFallbackInputMethodDescriptor()); return result; } @@ -64,24 +61,29 @@ MockInputMethodManagerImpl::State::~State() {} MockInputMethodManagerImpl::MockInputMethodManagerImpl() - : state_(new State(this)), - add_observer_count_(0), - remove_observer_count_(0), - util_(new InputMethodUtil(&delegate_)), - mod3_used_(false) {} + : state_(new State(this)), util_(new InputMethodUtil(&delegate_)) {} -MockInputMethodManagerImpl::~MockInputMethodManagerImpl() {} +MockInputMethodManagerImpl::~MockInputMethodManagerImpl() = default; void MockInputMethodManagerImpl::AddObserver( InputMethodManager::Observer* observer) { ++add_observer_count_; } +void MockInputMethodManagerImpl::AddImeMenuObserver(ImeMenuObserver* observer) { + ++add_menu_observer_count_; +} + void MockInputMethodManagerImpl::RemoveObserver( InputMethodManager::Observer* observer) { ++remove_observer_count_; } +void MockInputMethodManagerImpl::RemoveImeMenuObserver( + ImeMenuObserver* observer) { + ++remove_menu_observer_count_; +} + std::unique_ptr<InputMethodDescriptors> MockInputMethodManagerImpl::GetSupportedInputMethods() const { std::unique_ptr<InputMethodDescriptors> result;
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h index 5e6f61a..31516da 100644 --- a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h +++ b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h
@@ -51,7 +51,9 @@ // MockInputMethodManager: void AddObserver(InputMethodManager::Observer* observer) override; + void AddImeMenuObserver(ImeMenuObserver* observer) override; void RemoveObserver(InputMethodManager::Observer* observer) override; + void RemoveImeMenuObserver(ImeMenuObserver* observer) override; std::unique_ptr<InputMethodDescriptors> GetSupportedInputMethods() const override; bool IsISOLevel5ShiftUsedByCurrentInputMethod() const override; @@ -78,17 +80,22 @@ int add_observer_count() const { return add_observer_count_; } int remove_observer_count() const { return remove_observer_count_; } + int add_menu_observer_count() const { return add_menu_observer_count_; } + int remove_menu_observer_count() const { return remove_menu_observer_count_; } + protected: scoped_refptr<State> state_; private: // TODO(yusukes): Add more variables for counting the numbers of the API calls - int add_observer_count_; - int remove_observer_count_; + int add_observer_count_ = 0; + int remove_observer_count_ = 0; + int add_menu_observer_count_ = 0; + int remove_menu_observer_count_ = 0; FakeInputMethodDelegate delegate_; // used by util_ std::unique_ptr<InputMethodUtil> util_; FakeImeKeyboard keyboard_; - bool mod3_used_; + bool mod3_used_ = false; std::unique_ptr<ComponentExtensionIMEManager> comp_ime_manager_; DISALLOW_COPY_AND_ASSIGN(MockInputMethodManagerImpl);
diff --git a/chrome/browser/chromeos/login/lock_screen_utils.cc b/chrome/browser/chromeos/login/lock_screen_utils.cc index 6b681bd..c9d856f 100644 --- a/chrome/browser/chromeos/login/lock_screen_utils.cc +++ b/chrome/browser/chromeos/login/lock_screen_utils.cc
@@ -7,6 +7,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/language_preferences.h" #include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/ui/ash/ime_controller_client.h" #include "chrome/common/pref_names.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/signin/core/account_id/account_id.h" @@ -114,6 +115,16 @@ chromeos::input_method::InputMethodManager* imm = chromeos::input_method::InputMethodManager::Get(); imm->GetActiveIMEState()->SetAllowedInputMethods(allowed_input_methods); + ImeControllerClient::Get()->SetImesManagedByPolicy(true); +} + +void StopEnforcingPolicyInputMethods() { + // Empty means all input methods are allowed + std::vector<std::string> allowed_input_methods; + chromeos::input_method::InputMethodManager* imm = + chromeos::input_method::InputMethodManager::Get(); + imm->GetActiveIMEState()->SetAllowedInputMethods(allowed_input_methods); + ImeControllerClient::Get()->SetImesManagedByPolicy(false); } void SetKeyboardSettings(const AccountId& account_id) {
diff --git a/chrome/browser/chromeos/login/lock_screen_utils.h b/chrome/browser/chromeos/login/lock_screen_utils.h index 1fe58cb..bf481bca 100644 --- a/chrome/browser/chromeos/login/lock_screen_utils.h +++ b/chrome/browser/chromeos/login/lock_screen_utils.h
@@ -29,6 +29,9 @@ // by policy. void EnforcePolicyInputMethods(std::string user_input_method); +// Remove any policy limitations on allowed IMEs. +void StopEnforcingPolicyInputMethods(); + // Update the keyboard settings for |account_id|. void SetKeyboardSettings(const AccountId& account_id);
diff --git a/chrome/browser/chromeos/login/ui/login_feedback.cc b/chrome/browser/chromeos/login/ui/login_feedback.cc index 6b216df..3906002 100644 --- a/chrome/browser/chromeos/login/ui/login_feedback.cc +++ b/chrome/browser/chromeos/login/ui/login_feedback.cc
@@ -253,7 +253,7 @@ extensions::FeedbackPrivateAPI* api = extensions::FeedbackPrivateAPI::GetFactoryInstance()->Get(profile_); api->RequestFeedbackForFlow( - description_, "Login", GURL(), + description_, "Login", std::string(), GURL(), extensions::api::feedback_private::FeedbackFlow::FEEDBACK_FLOW_LOGIN); // Make sure there is a feedback app window opened.
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.cc b/chrome/browser/chromeos/net/network_portal_detector_impl.cc index d16ab571..37b92dd5 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_impl.cc
@@ -498,7 +498,18 @@ attempt_completed_report_.Report(); } - state_ = STATE_IDLE; + // If Chrome portal detection successfully returns portal state, mark the + // state so that Chrome won't schedule detection actively by self. + // The exception is when portal side session expires, shill doesn't report + // network connection state changed from online to portal. Thus we enable + // Chrome's detection by still marking |state_| to STATE_IDLE. + if (result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL && + response_code == 200 && + (!network || network->connection_state() != shill::kStateOnline)) { + state_ = STATE_BEHIND_PORTAL_IDLE; + } else { + state_ = STATE_IDLE; + } attempt_timeout_.Cancel(); CaptivePortalState state;
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl.h b/chrome/browser/chromeos/net/network_portal_detector_impl.h index 042f6bd..c28afefd 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl.h +++ b/chrome/browser/chromeos/net/network_portal_detector_impl.h
@@ -84,6 +84,8 @@ STATE_PORTAL_CHECK_PENDING, // Portal check is in progress. STATE_CHECKING_FOR_PORTAL, + // No portal check when successfully behind portal. + STATE_BEHIND_PORTAL_IDLE, }; struct DetectionAttemptCompletedReport { @@ -170,6 +172,9 @@ bool is_checking_for_portal() const { return state_ == STATE_CHECKING_FOR_PORTAL; } + bool is_behind_portal_idle() const { + return state_ == STATE_BEHIND_PORTAL_IDLE; + } int same_detection_result_count_for_testing() const { return same_detection_result_count_;
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc index b64467b..c02149e 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc
@@ -206,6 +206,9 @@ bool is_state_checking_for_portal() { return (NetworkPortalDetectorImpl::STATE_CHECKING_FOR_PORTAL == state()); } + bool is_state_behind_portal_idle() { + return (NetworkPortalDetectorImpl::STATE_BEHIND_PORTAL_IDLE == state()); + } const base::TimeDelta& next_attempt_delay() { return network_portal_detector()->next_attempt_delay_for_testing(); @@ -508,7 +511,7 @@ CompleteURLFetch(net::OK, 200, nullptr); - ASSERT_FALSE(is_state_idle()); + ASSERT_TRUE(is_state_behind_portal_idle()); CheckPortalState( NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1); @@ -526,7 +529,7 @@ CompleteURLFetch(net::OK, 200, nullptr); - ASSERT_FALSE(is_state_idle()); + ASSERT_TRUE(is_state_behind_portal_idle()); CheckPortalState( NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
diff --git a/chrome/browser/chromeos/night_light/night_light_client.cc b/chrome/browser/chromeos/night_light/night_light_client.cc new file mode 100644 index 0000000..0b8941b --- /dev/null +++ b/chrome/browser/chromeos/night_light/night_light_client.cc
@@ -0,0 +1,112 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/night_light/night_light_client.h" + +#include "ash/public/interfaces/constants.mojom.h" +#include "content/public/common/service_manager_connection.h" +#include "services/service_manager/public/cpp/connector.h" + +namespace { + +// Delay to wait for a response to our geolocation request, if we get a response +// after which, we will consider the request a failure. +constexpr base::TimeDelta kGeolocationRequestTimeout = + base::TimeDelta::FromSeconds(60); + +// Minimum delay to wait to fire a new request after a previous one failing. +constexpr base::TimeDelta kMinimumDelayAfterFailure = + base::TimeDelta::FromSeconds(60); + +// Delay to wait to fire a new request after a previous one succeeding. +constexpr base::TimeDelta kNextRequestDelayAfterSuccess = + base::TimeDelta::FromDays(1); + +} // namespace + +NightLightClient::NightLightClient( + net::URLRequestContextGetter* url_context_getter) + : provider_( + url_context_getter, + chromeos::SimpleGeolocationProvider::DefaultGeolocationProviderURL()), + binding_(this), + backoff_delay_(kMinimumDelayAfterFailure) {} + +NightLightClient::~NightLightClient() {} + +void NightLightClient::Start() { + if (!night_light_controller_) { + service_manager::Connector* connector = + content::ServiceManagerConnection::GetForProcess()->GetConnector(); + connector->BindInterface(ash::mojom::kServiceName, + &night_light_controller_); + } + ash::mojom::NightLightClientPtr client; + binding_.Bind(mojo::MakeRequest(&client)); + night_light_controller_->SetClient(std::move(client)); +} + +void NightLightClient::OnScheduleTypeChanged( + ash::mojom::NightLightController::ScheduleType new_type) { + if (new_type == + ash::mojom::NightLightController::ScheduleType::kSunsetToSunrise) { + // Schedule an immediate request. + using_geoposition_ = true; + ScheduleNextRequest(base::TimeDelta::FromSeconds(0)); + } else { + using_geoposition_ = false; + timer_.Stop(); + } +} + +void NightLightClient::SetNightLightControllerPtrForTesting( + ash::mojom::NightLightControllerPtr controller) { + night_light_controller_ = std::move(controller); +} + +void NightLightClient::FlushNightLightControllerForTesting() { + night_light_controller_.FlushForTesting(); +} + +void NightLightClient::OnGeoposition(const chromeos::Geoposition& position, + bool server_error, + const base::TimeDelta elapsed) { + if (!using_geoposition_) { + // A response might arrive after the schedule type is no longer "sunset to + // sunrise", which means we should not push any positions to the + // NightLightController. + return; + } + + if (server_error || !position.Valid() || + elapsed > kGeolocationRequestTimeout) { + // Don't send invalid positions to ash. + // On failure, we schedule another request after the current backoff delay. + ScheduleNextRequest(backoff_delay_); + + // If another failure occurs next, our backoff delay should double. + backoff_delay_ *= 2; + return; + } + + night_light_controller_->SetCurrentGeoposition( + ash::mojom::SimpleGeoposition::New(position.latitude, + position.longitude)); + + // On success, reset the backoff delay to its minimum value, and schedule + // another request. + backoff_delay_ = kMinimumDelayAfterFailure; + ScheduleNextRequest(kNextRequestDelayAfterSuccess); +} + +void NightLightClient::ScheduleNextRequest(base::TimeDelta delay) { + timer_.Start(FROM_HERE, delay, this, &NightLightClient::RequestGeoposition); +} + +void NightLightClient::RequestGeoposition() { + provider_.RequestGeolocation( + kGeolocationRequestTimeout, false /* send_wifi_access_points */, + false /* send_cell_towers */, + base::Bind(&NightLightClient::OnGeoposition, base::Unretained(this))); +}
diff --git a/chrome/browser/chromeos/night_light/night_light_client.h b/chrome/browser/chromeos/night_light/night_light_client.h new file mode 100644 index 0000000..0f8580d --- /dev/null +++ b/chrome/browser/chromeos/night_light/night_light_client.h
@@ -0,0 +1,73 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_NIGHT_LIGHT_NIGHT_LIGHT_CLIENT_H_ +#define CHROME_BROWSER_CHROMEOS_NIGHT_LIGHT_NIGHT_LIGHT_CLIENT_H_ + +#include "ash/public/interfaces/night_light_controller.mojom.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "chromeos/geolocation/simple_geolocation_provider.h" +#include "mojo/public/cpp/bindings/binding.h" + +namespace net { +class URLRequestContextGetter; +} + +// Periodically requests the IP-based geolocation and provides it to the +// NightLightController running in ash. +class NightLightClient + : public NON_EXPORTED_BASE(ash::mojom::NightLightClient) { + public: + explicit NightLightClient(net::URLRequestContextGetter* url_context_getter); + ~NightLightClient() override; + + // Starts watching changes in the Night Light schedule type in order to begin + // periodically pushing user's IP-based geoposition to NightLightController as + // long as the type is set to "sunset to sunrise". + void Start(); + + // ash::mojom::NightLightClient: + void OnScheduleTypeChanged( + ash::mojom::NightLightController::ScheduleType new_type) override; + + bool using_geoposition() const { return using_geoposition_; } + + void SetNightLightControllerPtrForTesting( + ash::mojom::NightLightControllerPtr controller); + + void FlushNightLightControllerForTesting(); + + protected: + void OnGeoposition(const chromeos::Geoposition& position, + bool server_error, + const base::TimeDelta elapsed); + + private: + void ScheduleNextRequest(base::TimeDelta delay); + + // Virtual so that it can be overriden by a fake implementation in unit tests + // that doesn't request actual geopositions. + virtual void RequestGeoposition(); + + // The IP-based geolocation provider. + chromeos::SimpleGeolocationProvider provider_; + + ash::mojom::NightLightControllerPtr night_light_controller_; + mojo::Binding<ash::mojom::NightLightClient> binding_; + + // Delay after which a new request is retried after a failed one. + base::TimeDelta backoff_delay_; + + base::OneShotTimer timer_; + + // True as long as the schedule type is set to "sunset to sunrise", which + // means this client will be retrieving the IP-based geoposition once per day. + bool using_geoposition_ = false; + + DISALLOW_COPY_AND_ASSIGN(NightLightClient); +}; + +#endif // CHROME_BROWSER_CHROMEOS_NIGHT_LIGHT_NIGHT_LIGHT_CLIENT_H_
diff --git a/chrome/browser/chromeos/night_light/night_light_client_unittest.cc b/chrome/browser/chromeos/night_light/night_light_client_unittest.cc new file mode 100644 index 0000000..bfe124b --- /dev/null +++ b/chrome/browser/chromeos/night_light/night_light_client_unittest.cc
@@ -0,0 +1,147 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/night_light/night_light_client.h" + +#include "ash/public/interfaces/night_light_controller.mojom.h" +#include "base/test/scoped_task_environment.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +using ScheduleType = ash::mojom::NightLightController::ScheduleType; + +// A fake implementation of NightLightController for testing. +class FakeNightLightController : public ash::mojom::NightLightController { + public: + FakeNightLightController() : binding_(this) {} + ~FakeNightLightController() override = default; + + int position_pushes_num() const { return position_pushes_num_; } + + ash::mojom::NightLightControllerPtr CreateInterfacePtrAndBind() { + ash::mojom::NightLightControllerPtr ptr; + binding_.Bind(mojo::MakeRequest(&ptr)); + return ptr; + } + + // ash::mojom::NightLightController: + void SetCurrentGeoposition( + ash::mojom::SimpleGeopositionPtr position) override { + position_ = std::move(position); + ++position_pushes_num_; + } + + void SetClient(ash::mojom::NightLightClientPtr client) override { + client_ = std::move(client); + } + + void NotifyScheduleTypeChanged(ScheduleType type) { + client_->OnScheduleTypeChanged(type); + client_.FlushForTesting(); + } + + private: + ash::mojom::SimpleGeopositionPtr position_; + ash::mojom::NightLightClientPtr client_; + mojo::Binding<ash::mojom::NightLightController> binding_; + + // The number of times a new position is pushed to this controller. + int position_pushes_num_ = 0; + + DISALLOW_COPY_AND_ASSIGN(FakeNightLightController); +}; + +// A fake implementation of NightLightClient that doesn't perform any actual +// geoposition requests. +class FakeNightLightClient : public NightLightClient { + public: + FakeNightLightClient() : NightLightClient(nullptr /* url_context_getter */) {} + ~FakeNightLightClient() override = default; + + void set_position_to_send(const chromeos::Geoposition& position) { + position_to_send_ = position; + } + + private: + // night_light::NightLightClient: + void RequestGeoposition() override { + OnGeoposition(position_to_send_, false, base::TimeDelta()); + } + + // The position to send to the controller the next time OnGeoposition is + // invoked. + chromeos::Geoposition position_to_send_; + + DISALLOW_COPY_AND_ASSIGN(FakeNightLightClient); +}; + +// Base test fixture. +class NightLightClientTest : public testing::Test { + public: + NightLightClientTest() = default; + ~NightLightClientTest() override = default; + + void SetUp() override { + client_.SetNightLightControllerPtrForTesting( + controller_.CreateInterfacePtrAndBind()); + client_.Start(); + client_.FlushNightLightControllerForTesting(); + } + + base::test::ScopedTaskEnvironment scoped_task_environment_; + + FakeNightLightController controller_; + FakeNightLightClient client_; + + private: + DISALLOW_COPY_AND_ASSIGN(NightLightClientTest); +}; + +// Test that the client is retrieving geoposition periodically only when the +// schedule type is "sunset to sunrise". +TEST_F(NightLightClientTest, TestClientRunningOnlyWhenSunsetToSunriseSchedule) { + EXPECT_FALSE(client_.using_geoposition()); + controller_.NotifyScheduleTypeChanged(ScheduleType::kNone); + EXPECT_FALSE(client_.using_geoposition()); + controller_.NotifyScheduleTypeChanged(ScheduleType::kCustom); + controller_.NotifyScheduleTypeChanged(ScheduleType::kSunsetToSunrise); + scoped_task_environment_.RunUntilIdle(); + client_.FlushNightLightControllerForTesting(); + EXPECT_TRUE(client_.using_geoposition()); + + // Client should stop retrieving geopositions when schedule type changes to + // something else. + controller_.NotifyScheduleTypeChanged(ScheduleType::kNone); + EXPECT_FALSE(client_.using_geoposition()); +} + +// Test that client only pushes valid positions. +TEST_F(NightLightClientTest, TestPositionPushes) { + // Start with a valid position, and expect it to be delivered to the + // controller. + EXPECT_EQ(0, controller_.position_pushes_num()); + chromeos::Geoposition position; + position.latitude = 32.0; + position.longitude = 31.0; + position.status = chromeos::Geoposition::STATUS_OK; + position.accuracy = 10; + position.timestamp = base::Time::Now(); + client_.set_position_to_send(position); + controller_.NotifyScheduleTypeChanged(ScheduleType::kSunsetToSunrise); + scoped_task_environment_.RunUntilIdle(); + client_.FlushNightLightControllerForTesting(); + EXPECT_EQ(1, controller_.position_pushes_num()); + + // Invalid positions should not be sent. + position.status = chromeos::Geoposition::STATUS_TIMEOUT; + client_.set_position_to_send(position); + controller_.NotifyScheduleTypeChanged(ScheduleType::kSunsetToSunrise); + scoped_task_environment_.RunUntilIdle(); + client_.FlushNightLightControllerForTesting(); + EXPECT_EQ(1, controller_.position_pushes_num()); +} + +} // namespace
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc b/chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc index 78d9b7b..2c5385e 100644 --- a/chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc +++ b/chrome/browser/extensions/api/feedback_private/feedback_browsertest.cc
@@ -54,10 +54,11 @@ extensions::api::feedback_private::OnFeedbackRequested::kEventName); } - void StartFeedbackUI(FeedbackFlow flow) { + void StartFeedbackUI(FeedbackFlow flow, + const std::string& extra_diagnostics) { base::Closure callback = base::Bind(&StopMessageLoopCallback); extensions::FeedbackPrivateGetStringsFunction::set_test_callback(&callback); - InvokeFeedbackUI(flow); + InvokeFeedbackUI(flow, extra_diagnostics); content::RunMessageLoop(); extensions::FeedbackPrivateGetStringsFunction::set_test_callback(NULL); } @@ -73,12 +74,14 @@ } private: - void InvokeFeedbackUI(FeedbackFlow flow) { + void InvokeFeedbackUI(FeedbackFlow flow, + const std::string& extra_diagnostics) { extensions::FeedbackPrivateAPI* api = extensions::FeedbackPrivateAPI::GetFactoryInstance()->Get( browser()->profile()); api->RequestFeedbackForFlow("Test description", "Test tag", - GURL("http://www.test.com"), flow); + extra_diagnostics, GURL("http://www.test.com"), + flow); } }; @@ -86,7 +89,7 @@ WaitForExtensionViewsToLoad(); ASSERT_TRUE(IsFeedbackAppAvailable()); - StartFeedbackUI(FeedbackFlow::FEEDBACK_FLOW_REGULAR); + StartFeedbackUI(FeedbackFlow::FEEDBACK_FLOW_REGULAR, std::string()); VerifyFeedbackAppLaunch(); } @@ -94,7 +97,7 @@ WaitForExtensionViewsToLoad(); ASSERT_TRUE(IsFeedbackAppAvailable()); - StartFeedbackUI(FeedbackFlow::FEEDBACK_FLOW_LOGIN); + StartFeedbackUI(FeedbackFlow::FEEDBACK_FLOW_LOGIN, std::string()); VerifyFeedbackAppLaunch(); AppWindow* const window = @@ -118,7 +121,7 @@ WaitForExtensionViewsToLoad(); ASSERT_TRUE(IsFeedbackAppAvailable()); - StartFeedbackUI(FeedbackFlow::FEEDBACK_FLOW_REGULAR); + StartFeedbackUI(FeedbackFlow::FEEDBACK_FLOW_REGULAR, std::string()); VerifyFeedbackAppLaunch(); AppWindow* const window = @@ -143,4 +146,37 @@ EXPECT_TRUE(bool_result); } +// Ensures that when extra diagnostics are provided with feedback, they are +// injected properly in the system information. +IN_PROC_BROWSER_TEST_F(FeedbackTest, ExtraDiagnostics) { + WaitForExtensionViewsToLoad(); + + ASSERT_TRUE(IsFeedbackAppAvailable()); + StartFeedbackUI(FeedbackFlow::FEEDBACK_FLOW_REGULAR, "Some diagnostics"); + VerifyFeedbackAppLaunch(); + + AppWindow* const window = + PlatformAppBrowserTest::GetFirstAppWindowForBrowser(browser()); + ASSERT_TRUE(window); + content::WebContents* const content = window->web_contents(); + + bool bool_result = false; + ASSERT_TRUE(content::ExecuteScriptAndExtractBool( + content, + "domAutomationController.send(" + " ((function() {" + " var sysInfo = feedbackInfo.systemInformation;" + " for (var info in sysInfo) {" + " if (sysInfo[info].key == 'EXTRA_DIAGNOSTICS' &&" + " sysInfo[info].value == 'Some diagnostics') {" + " return true;" + " }" + " }" + " return false;" + " })()));", + &bool_result)); + + EXPECT_TRUE(bool_result); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc index 47ce719d..73c305f 100644 --- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc +++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -114,6 +114,7 @@ void FeedbackPrivateAPI::RequestFeedback( const std::string& description_template, const std::string& category_tag, + const std::string& extra_diagnostics, const GURL& page_url) { #if defined(OS_WIN) // Show prompt for Software Removal Tool if the Reporter component has found @@ -121,18 +122,20 @@ if (base::FeatureList::IsEnabled(kSrtPromptOnFeedbackForm) && safe_browsing::ReporterFoundUws() && !safe_browsing::UserHasRunCleaner()) { - RequestFeedbackForFlow(description_template, category_tag, page_url, + RequestFeedbackForFlow(description_template, category_tag, + extra_diagnostics, page_url, FeedbackFlow::FEEDBACK_FLOW_SHOWSRTPROMPT); return; } #endif - RequestFeedbackForFlow(description_template, category_tag, page_url, - FeedbackFlow::FEEDBACK_FLOW_REGULAR); + RequestFeedbackForFlow(description_template, category_tag, extra_diagnostics, + page_url, FeedbackFlow::FEEDBACK_FLOW_REGULAR); } void FeedbackPrivateAPI::RequestFeedbackForFlow( const std::string& description_template, const std::string& category_tag, + const std::string& extra_diagnostics, const GURL& page_url, api::feedback_private::FeedbackFlow flow) { if (browser_context_ && EventRouter::Get(browser_context_)) { @@ -140,10 +143,19 @@ info.description = description_template; info.category_tag = base::MakeUnique<std::string>(category_tag); info.page_url = base::MakeUnique<std::string>(page_url.spec()); - info.system_information.reset(new SystemInformationList); + info.system_information = base::MakeUnique<SystemInformationList>(); + + // Any extra diagnostics information should be added to the sys info. + if (!extra_diagnostics.empty()) { + SystemInformation extra_info; + extra_info.key = "EXTRA_DIAGNOSTICS"; + extra_info.value = extra_diagnostics; + info.system_information->emplace_back(std::move(extra_info)); + } + // The manager is only available if tracing is enabled. if (TracingManager* manager = TracingManager::Get()) { - info.trace_id.reset(new int(manager->RequestTrace())); + info.trace_id = base::MakeUnique<int>(manager->RequestTrace()); } info.flow = flow; #if defined(OS_MACOSX)
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.h b/chrome/browser/extensions/api/feedback_private/feedback_private_api.h index b993acb..e39d263 100644 --- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.h +++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
@@ -34,10 +34,12 @@ void RequestFeedback(const std::string& description_template, const std::string& category_tag, + const std::string& extra_diagnostics, const GURL& page_url); void RequestFeedbackForFlow(const std::string& description_template, const std::string& category_tag, + const std::string& extra_diagnostics, const GURL& page_url, api::feedback_private::FeedbackFlow flow);
diff --git a/chrome/browser/extensions/extension_service_test_base.cc b/chrome/browser/extensions/extension_service_test_base.cc index 2e3b693..45ed898 100644 --- a/chrome/browser/extensions/extension_service_test_base.cc +++ b/chrome/browser/extensions/extension_service_test_base.cc
@@ -14,6 +14,7 @@ #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" +#include "chrome/browser/after_startup_task_utils.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_garbage_collector_factory.h" @@ -90,6 +91,11 @@ return; } data_dir_ = test_data_dir.AppendASCII("extensions"); + + // The extension subsystem posts logging tasks to be done after browser + // startup. There's no StartupObserver as there normally would be since we're + // in a unit test, so we have to explicitly note tasks should be processed. + AfterStartupTaskUtils::SetBrowserStartupIsCompleteForTesting(); } ExtensionServiceTestBase::~ExtensionServiceTestBase() {
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 04fcdd5a..189b8b41 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -41,7 +41,6 @@ #include "base/values.h" #include "base/version.h" #include "build/build_config.h" -#include "chrome/browser/after_startup_task_utils.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/blacklist.h" @@ -522,13 +521,7 @@ class ExtensionServiceTest : public extensions::ExtensionServiceTestWithInstall { public: - ExtensionServiceTest() { - // The extension subsystem posts logging tasks to be done after - // browser startup. There's no StartupObserver as there normally - // would be since we're in a unit test, so we have to explicitly - // note tasks should be processed. - AfterStartupTaskUtils::SetBrowserStartupIsCompleteForTesting(); - } + ExtensionServiceTest() = default; MockExternalProvider* AddMockExternalProvider(Manifest::Location location) { auto provider = base::MakeUnique<MockExternalProvider>(service(), location);
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc index b9967ab..f2f9466 100644 --- a/chrome/browser/feedback/show_feedback_page.cc +++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -21,7 +21,8 @@ void ShowFeedbackPage(Browser* browser, FeedbackSource source, const std::string& description_template, - const std::string& category_tag) { + const std::string& category_tag, + const std::string& extra_diagnostics) { GURL page_url; if (browser) { page_url = GetTargetTabUrl(browser->session_id().id(), @@ -47,7 +48,7 @@ extensions::FeedbackPrivateAPI::GetFactoryInstance()->Get(profile); api->RequestFeedbackForFlow( - description_template, category_tag, page_url, + description_template, category_tag, extra_diagnostics, page_url, source == kFeedbackSourceSadTabPage ? feedback_private::FeedbackFlow::FEEDBACK_FLOW_SADTABCRASH : feedback_private::FeedbackFlow::FEEDBACK_FLOW_REGULAR);
diff --git a/chrome/browser/hang_monitor/hang_crash_dump_win.cc b/chrome/browser/hang_monitor/hang_crash_dump_win.cc index 5943438..56b9f2ee 100644 --- a/chrome/browser/hang_monitor/hang_crash_dump_win.cc +++ b/chrome/browser/hang_monitor/hang_crash_dump_win.cc
@@ -96,31 +96,3 @@ TerminateProcess(hprocess, content::RESULT_CODE_HUNG); WaitForSingleObject(hprocess, kTerminateTimeoutMS); } - -void CrashDumpForHangDebugging(HANDLE hprocess) { - if (hprocess == GetCurrentProcess()) { - typedef void (__cdecl *DumpFunction)(); - DumpFunction request_dump = reinterpret_cast<DumpFunction>(GetProcAddress( - GetModuleHandle(chrome::kChromeElfDllName), "DumpProcessWithoutCrash")); - DCHECK(request_dump) << "Failed loading DumpProcessWithoutCrash: error " << - GetLastError(); - if (request_dump) - request_dump(); - } else { - typedef HANDLE (__cdecl *DumpFunction)(HANDLE); - DumpFunction request_dump = reinterpret_cast<DumpFunction>( - GetProcAddress(GetModuleHandle(chrome::kChromeElfDllName), - "InjectDumpForHangDebugging")); - DCHECK(request_dump) << "Failed loading InjectDumpForHangDebugging: error " - << GetLastError(); - if (request_dump) { - HANDLE remote_thread = request_dump(hprocess); - DCHECK(remote_thread) << "Failed creating remote thread: error " << - GetLastError(); - if (remote_thread) { - WaitForSingleObject(remote_thread, kGenerateDumpTimeoutMS); - CloseHandle(remote_thread); - } - } - } -}
diff --git a/chrome/browser/hang_monitor/hang_crash_dump_win.h b/chrome/browser/hang_monitor/hang_crash_dump_win.h index fdec2f3e..42a518b 100644 --- a/chrome/browser/hang_monitor/hang_crash_dump_win.h +++ b/chrome/browser/hang_monitor/hang_crash_dump_win.h
@@ -17,8 +17,4 @@ HANDLE hprocess, const base::StringPairs& additional_crash_keys); -// TODO(yzshen): Remove when enough information is collected and the hang rate -// of pepper/renderer processes is reduced. -void CrashDumpForHangDebugging(HANDLE hprocess); - #endif // CHROME_BROWSER_HANG_MONITOR_HANG_CRASH_DUMP_WIN_H_
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index fb717d2..3836d9d 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc
@@ -749,9 +749,9 @@ // This needs to happen (e.g. so that the appid is fixed and the // run-time Chrome icon is merged with the taskbar shortcut), but it is not an // urgent task. - base::PostTaskWithTraits(FROM_HERE, - {base::MayBlock(), base::TaskPriority::BACKGROUND}, - base::Bind(&MigrateTaskbarPinsCallback)); + base::CreateCOMSTATaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND}) + ->PostTask(FROM_HERE, base::Bind(&MigrateTaskbarPinsCallback)); } void GetIsPinnedToTaskbarState(
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc index a46e50e6b..f6843dbe 100644 --- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -1029,7 +1029,33 @@ std::vector<const char*>{"b", "d"}, {false, true}); } +IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, + NoConfiguration_AllowCreatingNewWindows) { + base::HistogramTester tester; + const char kWindowOpenPath[] = "/subresource_filter/window_open.html"; + GURL a_url(embedded_test_server()->GetURL("a.com", kWindowOpenPath)); + // Only configure |a_url| as a phishing URL. + ConfigureAsPhishingURL(a_url); + + // Only necessary so we have a valid ruleset. + ASSERT_NO_FATAL_FAILURE(SetRulesetWithRules(std::vector<proto::UrlRule>())); + + // Navigate to a_url, should not trigger the popup blocker. + ui_test_utils::NavigateToURL(browser(), a_url); + bool opened_window = false; + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_TRUE(content::ExecuteScriptAndExtractBool(web_contents, "openWindow()", + &opened_window)); + EXPECT_TRUE(opened_window); + EXPECT_FALSE(TabSpecificContentSettings::FromWebContents(web_contents) + ->IsContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS)); +} + IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, BlockCreatingNewWindows) { + Configuration config = Configuration::MakePresetForLiveRunOnPhishingSites(); + config.activation_options.should_strengthen_popup_blocker = true; + ResetConfiguration(std::move(config)); base::HistogramTester tester; const char kWindowOpenPath[] = "/subresource_filter/window_open.html"; GURL a_url(embedded_test_server()->GetURL("a.com", kWindowOpenPath)); @@ -1068,6 +1094,9 @@ } IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, BlockOpenURLFromTab) { + Configuration config = Configuration::MakePresetForLiveRunOnPhishingSites(); + config.activation_options.should_strengthen_popup_blocker = true; + ResetConfiguration(std::move(config)); base::HistogramTester tester; const char kWindowOpenPath[] = "/subresource_filter/window_open_spoof_click.html";
diff --git a/chrome/browser/supervised_user/supervised_user_interstitial.cc b/chrome/browser/supervised_user/supervised_user_interstitial.cc index 8765cd4..ca2da83 100644 --- a/chrome/browser/supervised_user/supervised_user_interstitial.cc +++ b/chrome/browser/supervised_user/supervised_user_interstitial.cc
@@ -262,7 +262,8 @@ #else chrome::ShowFeedbackPage(chrome::FindBrowserWithWebContents(web_contents_), chrome::kFeedbackSourceSupervisedUserInterstitial, - message, std::string() /* category_tag */); + message, std::string() /* category_tag */, + std::string() /* extra_diagnostics */); #endif return; }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 09addc8..598001d 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1159,6 +1159,8 @@ "app_list/search/launcher_search/launcher_search_provider.h", "app_list/search/launcher_search/launcher_search_result.cc", "app_list/search/launcher_search/launcher_search_result.h", + "ash/ime_controller_client.cc", + "ash/ime_controller_client.h", "ash/lock_screen_client.cc", "ash/lock_screen_client.h", "ash/session_controller_client.cc",
diff --git a/chrome/browser/ui/android/infobars/infobar_android.cc b/chrome/browser/ui/android/infobars/infobar_android.cc index 6c130164..b13a333 100644 --- a/chrome/browser/ui/android/infobars/infobar_android.cc +++ b/chrome/browser/ui/android/infobars/infobar_android.cc
@@ -55,6 +55,10 @@ return !java_info_bar_.is_null(); } +void InfoBarAndroid::PlatformSpecificHide(bool animate) { + CloseJavaInfoBar(); +} + int InfoBarAndroid::GetInfoBarIdentifier(JNIEnv* env, const JavaParamRef<jobject>& obj) { return delegate()->GetIdentifier();
diff --git a/chrome/browser/ui/android/infobars/infobar_android.h b/chrome/browser/ui/android/infobars/infobar_android.h index 0115ea6..dd54ab65 100644 --- a/chrome/browser/ui/android/infobars/infobar_android.h +++ b/chrome/browser/ui/android/infobars/infobar_android.h
@@ -42,6 +42,7 @@ const base::android::JavaRef<jobject>& java_info_bar); jobject GetJavaInfoBar(); bool HasSetJavaInfoBar() const; + void PlatformSpecificHide(bool animate) override; // Tells the Java-side counterpart of this InfoBar to point to the replacement // InfoBar instead of this one.
diff --git a/chrome/browser/ui/android/infobars/infobar_container_android.cc b/chrome/browser/ui/android/infobars/infobar_container_android.cc index 71a733a..3ac3e6af 100644 --- a/chrome/browser/ui/android/infobars/infobar_container_android.cc +++ b/chrome/browser/ui/android/infobars/infobar_container_android.cc
@@ -97,8 +97,8 @@ void InfoBarContainerAndroid::PlatformSpecificRemoveInfoBar( infobars::InfoBar* infobar) { - InfoBarAndroid* android_infobar = static_cast<InfoBarAndroid*>(infobar); - android_infobar->CloseJavaInfoBar(); + // The infobar will be closed by InfoBar::PlatformSpecificHide, this call + // is a noop on Android. }
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc index 616f3cf..db0e420 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -32,7 +32,6 @@ #include "chrome/browser/chromeos/background/ash_wallpaper_delegate.h" #include "chrome/browser/chromeos/display/display_configuration_observer.h" #include "chrome/browser/chromeos/display/display_preferences.h" -#include "chrome/browser/chromeos/input_method/input_method_manager_impl.h" #include "chrome/browser/chromeos/policy/display_rotation_default_handler.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/system/input_device_settings.h" @@ -73,7 +72,6 @@ #include "content/public/browser/notification_service.h" #include "content/public/common/service_manager_connection.h" #include "ui/aura/window.h" -#include "ui/base/ime/chromeos/input_method_manager.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -614,10 +612,6 @@ return chromeos::CreateSystemTrayDelegate(); } -ash::ImeController* ChromeShellDelegate::GetImeController() { - return chromeos::input_method::InputMethodManagerImpl::Get(); -} - std::unique_ptr<ash::WallpaperDelegate> ChromeShellDelegate::CreateWallpaperDelegate() { return base::WrapUnique(chromeos::CreateWallpaperDelegate());
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h index 34d5717..1002ad8 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.h +++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -45,7 +45,6 @@ void ShelfInit() override; void ShelfShutdown() override; ash::SystemTrayDelegate* CreateSystemTrayDelegate() override; - ash::ImeController* GetImeController() override; std::unique_ptr<ash::WallpaperDelegate> CreateWallpaperDelegate() override; ash::AccessibilityDelegate* CreateAccessibilityDelegate() override; std::unique_ptr<ash::PaletteDelegate> CreatePaletteDelegate() override;
diff --git a/chrome/browser/ui/ash/ime_controller_client.cc b/chrome/browser/ui/ash/ime_controller_client.cc new file mode 100644 index 0000000..54d6929e --- /dev/null +++ b/chrome/browser/ui/ash/ime_controller_client.cc
@@ -0,0 +1,138 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/ime_controller_client.h" + +#include <memory> +#include <vector> + +#include "ash/ime/ime_controller.h" +#include "ash/public/interfaces/ime_info.mojom.h" +#include "ash/shell.h" +#include "ash/system/tray/system_tray_notifier.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/ime/chromeos/extension_ime_util.h" +#include "ui/base/ime/chromeos/input_method_descriptor.h" +#include "ui/base/ime/chromeos/input_method_util.h" + +using chromeos::input_method::InputMethodDescriptor; +using chromeos::input_method::InputMethodManager; +using chromeos::input_method::InputMethodUtil; +using ui::ime::InputMethodMenuManager; + +namespace { + +ImeControllerClient* g_instance = nullptr; + +} // namespace + +ImeControllerClient::ImeControllerClient(InputMethodManager* manager) + : input_method_manager_(manager) { + DCHECK(input_method_manager_); + input_method_manager_->AddObserver(this); + input_method_manager_->AddImeMenuObserver(this); + InputMethodMenuManager::GetInstance()->AddObserver(this); + + // This does not need send the initial state to ash because that happens + // via observers when the InputMethodManager initializes its list of IMEs. + + DCHECK(!g_instance); + g_instance = this; +} + +ImeControllerClient::~ImeControllerClient() { + DCHECK_EQ(this, g_instance); + g_instance = nullptr; + + InputMethodMenuManager::GetInstance()->RemoveObserver(this); + input_method_manager_->RemoveImeMenuObserver(this); + input_method_manager_->RemoveObserver(this); +} + +// static +ImeControllerClient* ImeControllerClient::Get() { + return g_instance; +} + +void ImeControllerClient::SetImesManagedByPolicy(bool managed) { + ash::Shell::Get()->ime_controller()->SetImesManagedByPolicy(managed); +} + +// chromeos::input_method::InputMethodManager::Observer: +void ImeControllerClient::InputMethodChanged(InputMethodManager* manager, + Profile* profile, + bool show_message) { + RefreshIme(); +} + +// chromeos::input_method::InputMethodManager::ImeMenuObserver: +void ImeControllerClient::ImeMenuActivationChanged(bool is_active) { + ash::Shell::Get()->ime_controller()->ShowImeMenuOnShelf(is_active); +} + +void ImeControllerClient::ImeMenuListChanged() { + RefreshIme(); +} + +void ImeControllerClient::ImeMenuItemsChanged( + const std::string& engine_id, + const std::vector<InputMethodManager::MenuItem>& items) {} + +// ui::ime::InputMethodMenuManager::Observer: +void ImeControllerClient::InputMethodMenuItemChanged( + InputMethodMenuManager* manager) { + RefreshIme(); +} + +ash::mojom::ImeInfo ImeControllerClient::GetAshImeInfo( + const InputMethodDescriptor& ime) const { + InputMethodUtil* util = input_method_manager_->GetInputMethodUtil(); + ash::mojom::ImeInfo info; + info.id = ime.id(); + info.name = util->GetInputMethodLongName(ime); + info.medium_name = util->GetInputMethodMediumName(ime); + info.short_name = util->GetInputMethodShortName(ime); + info.third_party = chromeos::extension_ime_util::IsExtensionIME(ime.id()); + return info; +} + +void ImeControllerClient::RefreshIme() { + ash::ImeController* ime_controller = ash::Shell::Get()->ime_controller(); + InputMethodManager::State* state = + input_method_manager_->GetActiveIMEState().get(); + if (!state) { + ime_controller->RefreshIme(ash::mojom::ImeInfo(), + std::vector<ash::mojom::ImeInfo>(), + std::vector<ash::mojom::ImeMenuItem>()); + return; + } + + InputMethodDescriptor current_descriptor = state->GetCurrentInputMethod(); + ash::mojom::ImeInfo current_ime = GetAshImeInfo(current_descriptor); + current_ime.selected = true; + + std::vector<ash::mojom::ImeInfo> available_imes; + std::unique_ptr<std::vector<InputMethodDescriptor>> + available_ime_descriptors = state->GetActiveInputMethods(); + for (const InputMethodDescriptor& descriptor : *available_ime_descriptors) { + ash::mojom::ImeInfo info = GetAshImeInfo(descriptor); + info.selected = descriptor.id() == current_ime.id; + available_imes.push_back(info); + } + + std::vector<ash::mojom::ImeMenuItem> ash_menu_items; + ui::ime::InputMethodMenuItemList menu_list = + ui::ime::InputMethodMenuManager::GetInstance() + ->GetCurrentInputMethodMenuItemList(); + for (const ui::ime::InputMethodMenuItem& menu_item : menu_list) { + ash::mojom::ImeMenuItem ash_item; + ash_item.key = menu_item.key; + ash_item.label = base::UTF8ToUTF16(menu_item.label); + ash_item.checked = menu_item.is_selection_item_checked; + ash_menu_items.push_back(ash_item); + } + ash::Shell::Get()->ime_controller()->RefreshIme(current_ime, available_imes, + ash_menu_items); +}
diff --git a/chrome/browser/ui/ash/ime_controller_client.h b/chrome/browser/ui/ash/ime_controller_client.h new file mode 100644 index 0000000..e7f947a --- /dev/null +++ b/chrome/browser/ui/ash/ime_controller_client.h
@@ -0,0 +1,64 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ASH_IME_CONTROLLER_CLIENT_H_ +#define CHROME_BROWSER_UI_ASH_IME_CONTROLLER_CLIENT_H_ + +#include "base/macros.h" +#include "ui/base/ime/chromeos/input_method_manager.h" +#include "ui/chromeos/ime/input_method_menu_manager.h" + +namespace ash { +namespace mojom { +class ImeInfo; +} +} + +// Connects the ImeController in ash to the InputMethodManagerImpl in chrome. +// TODO(jamescook): Convert to using mojo interfaces. +class ImeControllerClient + : public chromeos::input_method::InputMethodManager::Observer, + public chromeos::input_method::InputMethodManager::ImeMenuObserver, + public ui::ime::InputMethodMenuManager::Observer { + public: + explicit ImeControllerClient( + chromeos::input_method::InputMethodManager* manager); + ~ImeControllerClient() override; + + static ImeControllerClient* Get(); + + // Sets whether the list of IMEs is managed by device policy. + void SetImesManagedByPolicy(bool managed); + + // chromeos::input_method::InputMethodManager::Observer: + void InputMethodChanged(chromeos::input_method::InputMethodManager* manager, + Profile* profile, + bool show_message) override; + + // chromeos::input_method::InputMethodManager::ImeMenuObserver: + void ImeMenuActivationChanged(bool is_active) override; + void ImeMenuListChanged() override; + void ImeMenuItemsChanged( + const std::string& engine_id, + const std::vector<chromeos::input_method::InputMethodManager::MenuItem>& + items) override; + + // ui::ime::InputMethodMenuManager::Observer: + void InputMethodMenuItemChanged( + ui::ime::InputMethodMenuManager* manager) override; + + private: + // Converts IME information from |descriptor| into the ash mojo format. + ash::mojom::ImeInfo GetAshImeInfo( + const chromeos::input_method::InputMethodDescriptor& descriptor) const; + + // Sends information about current and available IMEs to ash. + void RefreshIme(); + + chromeos::input_method::InputMethodManager* const input_method_manager_; + + DISALLOW_COPY_AND_ASSIGN(ImeControllerClient); +}; + +#endif // CHROME_BROWSER_UI_ASH_IME_CONTROLLER_CLIENT_H_
diff --git a/chrome/browser/ui/ash/ime_controller_client_unittest.cc b/chrome/browser/ui/ash/ime_controller_client_unittest.cc new file mode 100644 index 0000000..76317c51 --- /dev/null +++ b/chrome/browser/ui/ash/ime_controller_client_unittest.cc
@@ -0,0 +1,30 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/ime_controller_client.h" + +#include <memory> + +#include "base/memory/ptr_util.h" +#include "chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ImeControllerClientTest = testing::Test; + +TEST_F(ImeControllerClientTest, Basics) { + chromeos::input_method::MockInputMethodManagerImpl input_method_manager; + + std::unique_ptr<ImeControllerClient> client = + base::MakeUnique<ImeControllerClient>(&input_method_manager); + EXPECT_EQ(1, input_method_manager.add_observer_count()); + EXPECT_EQ(1, input_method_manager.add_menu_observer_count()); + + client.reset(); + EXPECT_EQ(1, input_method_manager.remove_observer_count()); + EXPECT_EQ(1, input_method_manager.remove_menu_observer_count()); +} + +// TODO(jamescook): When ImeControllerClient switches to using mojo add +// additional tests that the correct mojo interface methods are called to send +// data to ash.
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc index 093f814..f96eb3f 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -99,10 +99,6 @@ } void SystemTrayDelegateChromeOS::Initialize() { - input_method::InputMethodManager::Get()->AddObserver(this); - input_method::InputMethodManager::Get()->AddImeMenuObserver(this); - ui::ime::InputMethodMenuManager::GetInstance()->AddObserver(this); - BrowserList::AddObserver(this); DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this); @@ -117,9 +113,6 @@ // Unregister a11y status subscription. accessibility_subscription_.reset(); - input_method::InputMethodManager::Get()->RemoveObserver(this); - ui::ime::InputMethodMenuManager::GetInstance()->RemoveObserver(this); - BrowserList::RemoveObserver(this); StopObservingAppWindowRegistry(); @@ -339,20 +332,6 @@ GetSystemTrayNotifier()->NotifyTracingModeChanged(value); } -// Overridden from InputMethodManager::Observer. -void SystemTrayDelegateChromeOS::InputMethodChanged( - input_method::InputMethodManager* manager, - Profile* /* profile */, - bool show_message) { - GetSystemTrayNotifier()->NotifyRefreshIME(); -} - -// Overridden from InputMethodMenuManager::Observer. -void SystemTrayDelegateChromeOS::InputMethodMenuItemChanged( - ui::ime::InputMethodMenuManager* manager) { - GetSystemTrayNotifier()->NotifyRefreshIME(); -} - // Overridden from chrome::BrowserListObserver. void SystemTrayDelegateChromeOS::OnBrowserRemoved(Browser* browser) { NotifyIfLastWindowClosed(); @@ -372,16 +351,6 @@ OnAccessibilityModeChanged(details.notify); } -void SystemTrayDelegateChromeOS::ImeMenuActivationChanged(bool is_active) { - GetSystemTrayNotifier()->NotifyRefreshIMEMenu(is_active); -} - -void SystemTrayDelegateChromeOS::ImeMenuListChanged() {} - -void SystemTrayDelegateChromeOS::ImeMenuItemsChanged( - const std::string& engine_id, - const std::vector<input_method::InputMethodManager::MenuItem>& items) {} - void SystemTrayDelegateChromeOS::OnUpdateOverCellularTargetSet(bool success) { GetSystemTrayNotifier()->NotifyUpdateOverCellularTargetSet(success); }
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h index fa734088..f9712ac 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -24,8 +24,6 @@ #include "content/public/browser/notification_registrar.h" #include "extensions/browser/app_window/app_window_registry.h" #include "ui/base/ime/chromeos/ime_keyboard.h" -#include "ui/base/ime/chromeos/input_method_manager.h" -#include "ui/chromeos/ime/input_method_menu_manager.h" namespace ash { class SystemTrayNotifier; @@ -34,13 +32,10 @@ namespace chromeos { class SystemTrayDelegateChromeOS - : public ui::ime::InputMethodMenuManager::Observer, - public ash::SystemTrayDelegate, + : public ash::SystemTrayDelegate, public content::NotificationObserver, - public input_method::InputMethodManager::Observer, public chrome::BrowserListObserver, public extensions::AppWindowRegistry::Observer, - public input_method::InputMethodManager::ImeMenuObserver, public UpdateEngineClient::Observer { public: SystemTrayDelegateChromeOS(); @@ -86,15 +81,6 @@ void UpdatePerformanceTracing(); - // Overridden from InputMethodManager::Observer. - void InputMethodChanged(input_method::InputMethodManager* manager, - Profile* profile, - bool show_message) override; - - // Overridden from InputMethodMenuManager::Observer. - void InputMethodMenuItemChanged( - ui::ime::InputMethodMenuManager* manager) override; - // Overridden from chrome::BrowserListObserver: void OnBrowserRemoved(Browser* browser) override; @@ -104,14 +90,6 @@ void OnAccessibilityStatusChanged( const AccessibilityStatusEventDetails& details); - // input_method::InputMethodManager::ImeMenuObserver: - void ImeMenuActivationChanged(bool is_active) override; - void ImeMenuListChanged() override; - void ImeMenuItemsChanged( - const std::string& engine_id, - const std::vector<input_method::InputMethodManager::MenuItem>& items) - override; - // Overridden from UpdateEngineClient::Observer. void OnUpdateOverCellularTargetSet(bool success) override;
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc index da15e24..7f4d3e7 100644 --- a/chrome/browser/ui/browser_commands.cc +++ b/chrome/browser/ui/browser_commands.cc
@@ -1116,9 +1116,9 @@ void OpenFeedbackDialog(Browser* browser, FeedbackSource source) { base::RecordAction(UserMetricsAction("Feedback")); - chrome::ShowFeedbackPage(browser, source, - std::string() /* description_template */, - std::string() /* category_tag */); + chrome::ShowFeedbackPage( + browser, source, std::string() /* description_template */, + std::string() /* category_tag */, std::string() /* extra_diagnostics */); } void ToggleBookmarkBar(Browser* browser) {
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h index c698198e..0db324e 100644 --- a/chrome/browser/ui/chrome_pages.h +++ b/chrome/browser/ui/chrome_pages.h
@@ -66,7 +66,8 @@ void ShowFeedbackPage(Browser* browser, FeedbackSource source, const std::string& description_template, - const std::string& category_tag); + const std::string& category_tag, + const std::string& extra_diagnostics); void ShowHelp(Browser* browser, HelpSource source); void ShowHelpForProfile(Profile* profile, HelpSource source);
diff --git a/chrome/browser/ui/hung_plugin_tab_helper.cc b/chrome/browser/ui/hung_plugin_tab_helper.cc index e8fd91f2..dc93e19 100644 --- a/chrome/browser/ui/hung_plugin_tab_helper.cc +++ b/chrome/browser/ui/hung_plugin_tab_helper.cc
@@ -10,7 +10,6 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/process/process.h" -#include "base/rand_util.h" #include "build/build_config.h" #include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/chrome_notification_types.h" @@ -20,77 +19,23 @@ #include "chrome/grit/generated_resources.h" #include "components/infobars/core/confirm_infobar_delegate.h" #include "components/infobars/core/infobar.h" -#include "components/version_info/version_info.h" #include "content/public/browser/browser_child_process_host_iterator.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/plugin_service.h" -#include "content/public/browser/render_process_host.h" #include "content/public/common/process_type.h" #include "content/public/common/result_codes.h" #include "ui/base/l10n/l10n_util.h" #if defined(OS_WIN) -#include "base/win/scoped_handle.h" #include "chrome/browser/hang_monitor/hang_crash_dump_win.h" #endif namespace { -#if defined(OS_WIN) - -// OwnedHandleVector ---------------------------------------------------------- - -class OwnedHandleVector { - public: - typedef std::vector<HANDLE> Handles; - OwnedHandleVector(); - ~OwnedHandleVector(); - - Handles* data() { return &data_; } - - private: - Handles data_; - - DISALLOW_COPY_AND_ASSIGN(OwnedHandleVector); -}; - -OwnedHandleVector::OwnedHandleVector() { -} - -OwnedHandleVector::~OwnedHandleVector() { - for (Handles::iterator iter = data_.begin(); iter != data_.end(); ++iter) - ::CloseHandle(*iter); -} - - -// Helpers -------------------------------------------------------------------- - -const char kDumpChildProcessesSequenceName[] = "DumpChildProcesses"; - -void DumpBrowserInBlockingPool() { - CrashDumpForHangDebugging(::GetCurrentProcess()); -} - -void DumpRenderersInBlockingPool(OwnedHandleVector* renderer_handles) { - for (OwnedHandleVector::Handles::const_iterator iter = - renderer_handles->data()->begin(); - iter != renderer_handles->data()->end(); ++iter) { - CrashDumpForHangDebugging(*iter); - } -} - -void DumpAndTerminatePluginInBlockingPool( - base::win::ScopedHandle* plugin_handle) { - base::StringPairs crash_keys = {{crash_keys::kHungRendererReason, "plugin"}}; - CrashDumpAndTerminateHungChildProcess(plugin_handle->Get(), crash_keys); -} - -#endif // defined(OS_WIN) - // Called on the I/O thread to actually kill the plugin with the given child // ID. We specifically don't want this to be a member function since if the // user chooses to kill the plugin, we want to kill it even if they close the @@ -105,16 +50,9 @@ const content::ChildProcessData& data = iter.GetData(); if (data.id == child_id) { #if defined(OS_WIN) - HANDLE handle = NULL; - HANDLE current_process = ::GetCurrentProcess(); - ::DuplicateHandle(current_process, data.handle, current_process, &handle, - 0, FALSE, DUPLICATE_SAME_ACCESS); - // Run it in blocking pool so that it won't block the I/O thread. Besides, - // we would like to make sure that it happens after dumping renderers. - content::BrowserThread::PostBlockingPoolSequencedTask( - kDumpChildProcessesSequenceName, FROM_HERE, - base::Bind(&DumpAndTerminatePluginInBlockingPool, - base::Owned(new base::win::ScopedHandle(handle)))); + base::StringPairs crash_keys = { + {crash_keys::kHungRendererReason, "plugin"}}; + CrashDumpAndTerminateHungChildProcess(data.handle, crash_keys); #else base::Process process = base::Process::DeprecatedGetProcessFromHandle(data.handle); @@ -360,43 +298,6 @@ } void HungPluginTabHelper::KillPlugin(int child_id) { -#if defined(OS_WIN) - // Dump renderers that are sending or receiving pepper messages, in order to - // diagnose inter-process deadlocks. - // Only do that on the Canary channel, for 20% of pepper plugin hangs. - if (base::RandInt(0, 100) < 20) { - version_info::Channel channel = chrome::GetChannel(); - if (channel == version_info::Channel::CANARY) { - std::unique_ptr<OwnedHandleVector> renderer_handles( - new OwnedHandleVector); - HANDLE current_process = ::GetCurrentProcess(); - content::RenderProcessHost::iterator renderer_iter = - content::RenderProcessHost::AllHostsIterator(); - for (; !renderer_iter.IsAtEnd(); renderer_iter.Advance()) { - content::RenderProcessHost* host = renderer_iter.GetCurrentValue(); - HANDLE handle = NULL; - ::DuplicateHandle(current_process, host->GetHandle(), current_process, - &handle, 0, FALSE, DUPLICATE_SAME_ACCESS); - renderer_handles->data()->push_back(handle); - } - // If there are a lot of renderer processes, it is likely that we will - // generate too many crash dumps. They might not all be uploaded/recorded - // due to our crash dump uploading restrictions. So we just don't generate - // renderer crash dumps in that case. - if (renderer_handles->data()->size() > 0 && - renderer_handles->data()->size() < 4) { - content::BrowserThread::PostBlockingPoolSequencedTask( - kDumpChildProcessesSequenceName, FROM_HERE, - base::Bind(&DumpBrowserInBlockingPool)); - content::BrowserThread::PostBlockingPoolSequencedTask( - kDumpChildProcessesSequenceName, FROM_HERE, - base::Bind(&DumpRenderersInBlockingPool, - base::Owned(renderer_handles.release()))); - } - } - } -#endif - PluginStateMap::iterator found = hung_plugins_.find(child_id); DCHECK(found != hung_plugins_.end());
diff --git a/chrome/browser/ui/profile_error_dialog.cc b/chrome/browser/ui/profile_error_dialog.cc index ec31648..e6a63f03 100644 --- a/chrome/browser/ui/profile_error_dialog.cc +++ b/chrome/browser/ui/profile_error_dialog.cc
@@ -30,17 +30,10 @@ std::string feedback_description = l10n_util::GetStringUTF8(IDS_PROFILE_ERROR_FEEDBACK_DESCRIPTION); - if (!diagnostics.empty()) { - // TODO(afakhry): Add support to inject diagnostics to the feedback - // reports without adding them to the description. crbug.com/708511. - feedback_description += - "\n\n" + - l10n_util::GetStringUTF8(IDS_PROFILE_ERROR_FEEDBACK_DIAGNOSTICS_LINE) + - diagnostics; - } chrome::ShowFeedbackPage(nullptr, chrome::kFeedbackSourceProfileErrorDialog, - feedback_description, kProfileErrorFeedbackCategory); + feedback_description, kProfileErrorFeedbackCategory, + diagnostics); } #endif // !defined(OS_ANDROID)
diff --git a/chrome/browser/ui/sad_tab.cc b/chrome/browser/ui/sad_tab.cc index 8fb280c6..5ebf1c7 100644 --- a/chrome/browser/ui/sad_tab.cc +++ b/chrome/browser/ui/sad_tab.cc
@@ -231,7 +231,7 @@ l10n_util::GetStringUTF8(kind_ == SAD_TAB_KIND_CRASHED ? IDS_CRASHED_TAB_FEEDBACK_MESSAGE : IDS_KILLED_TAB_FEEDBACK_MESSAGE), - std::string(kCategoryTagCrash)); + std::string(kCategoryTagCrash), std::string()); } else { web_contents_->GetController().Reload(content::ReloadType::NORMAL, true);
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc index ff60812..9e6572e8f 100644 --- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc +++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ui/ash/cast_config_client_media_router.h" #include "chrome/browser/ui/ash/chrome_new_window_client.h" #include "chrome/browser/ui/ash/chrome_shell_content_state.h" +#include "chrome/browser/ui/ash/ime_controller_client.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" #include "chrome/browser/ui/ash/lock_screen_client.h" #include "chrome/browser/ui/ash/media_client.h" @@ -32,6 +33,7 @@ #include "chrome/browser/ui/views/select_file_dialog_extension_factory.h" #include "ui/aura/mus/property_converter.h" #include "ui/base/class_property.h" +#include "ui/base/ime/chromeos/input_method_manager.h" #include "ui/keyboard/content/keyboard.h" #include "ui/keyboard/keyboard_controller.h" #include "ui/views/mus/mus_client.h" @@ -86,6 +88,11 @@ // Must be available at login screen, so initialize before profile. system_tray_client_ = base::MakeUnique<SystemTrayClient>(); + // TODO(jamescook): Enable in mash once converted to mojo. + if (!ash_util::IsRunningInMash()) { + ime_controller_client_ = base::MakeUnique<ImeControllerClient>( + chromeos::input_method::InputMethodManager::Get()); + } new_window_client_ = base::MakeUnique<ChromeNewWindowClient>(); volume_controller_ = base::MakeUnique<VolumeController>(); vpn_list_forwarder_ = base::MakeUnique<VpnListForwarder>(); @@ -131,6 +138,7 @@ vpn_list_forwarder_.reset(); volume_controller_.reset(); new_window_client_.reset(); + ime_controller_client_.reset(); system_tray_client_.reset(); lock_screen_client_.reset(); media_client_.reset();
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h index 8337b50a..4ec4137 100644 --- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h +++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h
@@ -20,6 +20,7 @@ class ChromeNewWindowClient; class ChromeShellContentState; class LockScreenClient; +class ImeControllerClient; class ImmersiveContextMus; class ImmersiveHandlerFactoryMus; class MediaClient; @@ -50,6 +51,7 @@ std::unique_ptr<ImmersiveContextMus> immersive_context_; std::unique_ptr<SessionControllerClient> session_controller_client_; std::unique_ptr<SystemTrayClient> system_tray_client_; + std::unique_ptr<ImeControllerClient> ime_controller_client_; std::unique_ptr<ChromeNewWindowClient> new_window_client_; std::unique_ptr<VolumeController> volume_controller_; std::unique_ptr<VpnListForwarder> vpn_list_forwarder_;
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 56e0ab4d..8f9b594 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -198,14 +198,6 @@ return network->name(); } -void StopEnforcingPolicyInputMethods() { - // Empty means all input methods are allowed - std::vector<std::string> allowed_input_methods; - chromeos::input_method::InputMethodManager* imm = - chromeos::input_method::InputMethodManager::Get(); - imm->GetActiveIMEState()->SetAllowedInputMethods(allowed_input_methods); -} - } // namespace // LoginScreenContext implementation ------------------------------------------ @@ -301,7 +293,7 @@ chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard(); if (keyboard) keyboard->RemoveObserver(this); - StopEnforcingPolicyInputMethods(); + lock_screen_utils::StopEnforcingPolicyInputMethods(); weak_factory_.InvalidateWeakPtrs(); if (delegate_) delegate_->SetWebUIHandler(nullptr);
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 2a8196d..9a1b589 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -1122,6 +1122,14 @@ extern const char kEnableNewAppMenuIcon[] = "enable-new-app-menu-icon"; #endif +#if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING) +// Enables the out-of-process memory logging. +const char kMemlog[] = "memlog"; + +// Communicates the pipe name for out-of-process memory logging. +const char kMemlogPipe[] = "memlog-pipe"; +#endif + bool ExtensionsDisabled(const base::CommandLine& command_line) { return command_line.HasSwitch(switches::kDisableExtensions) || command_line.HasSwitch(switches::kDisableExtensionsExcept);
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index dec100fe..ca9b97d9 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -350,6 +350,11 @@ extern const char kEnableNewAppMenuIcon[]; #endif +#if BUILDFLAG(ENABLE_OOP_HEAP_PROFILING) +extern const char kMemlog[]; +extern const char kMemlogPipe[]; +#endif + bool ExtensionsDisabled(const base::CommandLine& command_line); bool ExtensionsDisabled(); bool MdFeedbackEnabled();
diff --git a/chrome/installer/setup/BUILD.gn b/chrome/installer/setup/BUILD.gn index c0bb689..e9720a5 100644 --- a/chrome/installer/setup/BUILD.gn +++ b/chrome/installer/setup/BUILD.gn
@@ -30,6 +30,8 @@ "//components/crash/content/app:app", "//components/crash/content/app:run_as_crashpad_handler", ] + + libs = [ "netapi32.lib" ] } static_library("lib") { @@ -60,6 +62,8 @@ "setup_util.h", "update_active_setup_version_work_item.cc", "update_active_setup_version_work_item.h", + "user_experiment.cc", + "user_experiment.h", "user_hive_visitor.cc", "user_hive_visitor.h", ] @@ -80,6 +84,7 @@ "//rlz:rlz_lib", "//third_party/bspatch", "//third_party/zlib", + "//ui/base:fullscreen_win", ] } @@ -103,6 +108,7 @@ "setup_util_unittest.cc", "setup_util_unittest.h", "update_active_setup_version_work_item_unittest.cc", + "user_experiment_unittest.cc", "user_hive_visitor_unittest.cc", ] @@ -124,5 +130,7 @@ "//chrome/installer/test/data/", "//chrome/test/data/installer/", ] + + libs = [ "netapi32.lib" ] } }
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index 2bb42f1..f6d9fd3 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc
@@ -11,11 +11,13 @@ #include <memory> #include <string> +#include "base/base_paths.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" +#include "base/path_service.h" #include "base/process/launch.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -29,6 +31,7 @@ #include "chrome/installer/setup/setup_constants.h" #include "chrome/installer/setup/setup_util.h" #include "chrome/installer/setup/update_active_setup_version_work_item.h" +#include "chrome/installer/setup/user_experiment.h" #include "chrome/installer/util/beacons.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/create_reg_key_work_item.h" @@ -664,14 +667,14 @@ // be increased for Active Setup to invoke this again for all users of this // install. It may also be invoked again when a system-level chrome install goes // through an OS upgrade. -void HandleActiveSetupForBrowser(const base::FilePath& installation_root, - const installer::Product& chrome, +void HandleActiveSetupForBrowser(const InstallerState& installer_state, bool force) { std::unique_ptr<WorkItemList> cleanup_list(WorkItem::CreateWorkItemList()); cleanup_list->set_log_message("Cleanup deprecated per-user registrations"); cleanup_list->set_rollback_enabled(false); cleanup_list->set_best_effort(true); - AddCleanupDeprecatedPerUserRegistrationsWorkItems(chrome, cleanup_list.get()); + AddCleanupDeprecatedPerUserRegistrationsWorkItems(installer_state.product(), + cleanup_list.get()); cleanup_list->Do(); // Only create shortcuts on Active Setup if the first run sentinel is not @@ -686,13 +689,28 @@ ? INSTALL_SHORTCUT_REPLACE_EXISTING : INSTALL_SHORTCUT_CREATE_EACH_IF_NO_SYSTEM_LEVEL; - // Read master_preferences copied beside chrome.exe at install. + // Read master_preferences copied beside chrome.exe at install for the sake of + // creating/updating shortcuts. + const base::FilePath installation_root = installer_state.target_path(); MasterPreferences prefs(installation_root.AppendASCII(kDefaultMasterPrefs)); base::FilePath chrome_exe(installation_root.Append(kChromeExe)); - CreateOrUpdateShortcuts( - chrome_exe, chrome, prefs, CURRENT_USER, install_operation); + CreateOrUpdateShortcuts(chrome_exe, installer_state.product(), prefs, + CURRENT_USER, install_operation); UpdateDefaultBrowserBeaconForPath(chrome_exe); + + // This install may have been selected into a study for a retention + // experiment following a successful update. In case the experiment was not + // able to run immediately after the update (e.g., no user was logged on at + // the time), try to run it now that the installer is running in the context + // of a user. + if (ShouldRunUserExperiment(installer_state)) { + base::FilePath setup_exe; + if (!base::PathService::Get(base::FILE_EXE, &setup_exe)) + LOG(ERROR) << "Failed to get path to setup.exe."; + else + BeginUserExperiment(installer_state, setup_exe, true /* user_context */); + } } } // namespace installer
diff --git a/chrome/installer/setup/install.h b/chrome/installer/setup/install.h index 20ebd55d..a0af5c2b 100644 --- a/chrome/installer/setup/install.h +++ b/chrome/installer/setup/install.h
@@ -124,14 +124,9 @@ const base::Version& installed_version); // Performs per-user installation-related tasks on Active Setup (ran on first -// login for each user post system-level Chrome install). -// |installation_root|: The root of this install (i.e. the directory in which -// chrome.exe is installed). -// Shortcut creation is skipped if the First Run beacon is present (unless -// |force| is set to true). -// |chrome| The installed product (must be a browser). -void HandleActiveSetupForBrowser(const base::FilePath& installation_root, - const Product& chrome, +// login for each user post system-level Chrome install). Shortcut creation is +// skipped if the First Run beacon is present (unless |force| is set to true). +void HandleActiveSetupForBrowser(const InstallerState& installer_state, bool force); } // namespace installer
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc index 0eeac1b2..9a62365 100644 --- a/chrome/installer/setup/install_worker.cc +++ b/chrome/installer/setup/install_worker.cc
@@ -28,6 +28,7 @@ #include "base/version.h" #include "base/win/registry.h" #include "chrome/install_static/install_details.h" +#include "chrome/install_static/install_modes.h" #include "chrome/install_static/install_util.h" #include "chrome/installer/setup/installer_state.h" #include "chrome/installer/setup/persistent_histogram_storage.h" @@ -659,6 +660,19 @@ post_install_task_list); } + // Add a best-effort item to create the ClientStateMedium key for system-level + // installs. This is ordinarily done by Google Update prior to running + // Chrome's installer. Do it here as well so that the key exists for manual + // installs. + if (install_static::kUseGoogleUpdateIntegration && + installer_state.system_install()) { + const base::string16 path = + install_static::InstallDetails::Get().GetClientStateMediumKeyPath(); + post_install_task_list + ->AddCreateRegKeyWorkItem(HKEY_LOCAL_MACHINE, path, KEY_WOW64_32KEY) + ->set_best_effort(true); + } + return true; }
diff --git a/chrome/installer/setup/setup_constants.cc b/chrome/installer/setup/setup_constants.cc index ffb70c3..e93f004 100644 --- a/chrome/installer/setup/setup_constants.cc +++ b/chrome/installer/setup/setup_constants.cc
@@ -32,6 +32,9 @@ const char kSetDisplayVersionProduct[] = "set-display-version-product"; const char kSetDisplayVersionValue[] = "set-display-version-value"; +// Run setup.exe to conduct a post-update experiment. +const char kUserExperiment[] = "user-experiment"; + } // namespace switches } // namespace installer
diff --git a/chrome/installer/setup/setup_constants.h b/chrome/installer/setup/setup_constants.h index c5c36b7..359ff06 100644 --- a/chrome/installer/setup/setup_constants.h +++ b/chrome/installer/setup/setup_constants.h
@@ -24,6 +24,7 @@ extern const char kDelay[]; extern const char kSetDisplayVersionProduct[]; extern const char kSetDisplayVersionValue[]; +extern const char kUserExperiment[]; } // namespace switches
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 1e8df55..064412f0 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc
@@ -57,6 +57,7 @@ #include "chrome/installer/setup/setup_singleton.h" #include "chrome/installer/setup/setup_util.h" #include "chrome/installer/setup/uninstall.h" +#include "chrome/installer/setup/user_experiment.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/delete_after_reboot_helper.h" #include "chrome/installer/util/delete_old_versions.h" @@ -871,13 +872,11 @@ // NOTE: Should the work done here, on kConfigureUserSettings, change: // kActiveSetupVersion in install_worker.cc needs to be increased for Active // Setup to invoke this again for all users of this install. - const Product& chrome_install = installer_state->product(); installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION; if (installer_state->system_install()) { bool force = cmd_line.HasSwitch(installer::switches::kForceConfigureUserSettings); - installer::HandleActiveSetupForBrowser(installer_state->target_path(), - chrome_install, force); + installer::HandleActiveSetupForBrowser(*installer_state, force); status = installer::INSTALL_REPAIRED; } else { LOG(DFATAL) @@ -979,6 +978,11 @@ << setup_exe.value(); } *exit_code = InstallUtil::GetInstallReturnCode(status); + } else if (cmd_line.HasSwitch(installer::switches::kUserExperiment)) { + installer::RunUserExperiment(cmd_line, + MasterPreferences::ForCurrentProcess(), + original_state, installer_state); + exit_code = 0; } else if (cmd_line.HasSwitch(installer::switches::kInactiveUserToast)) { // Launch the inactive user toast experiment. int flavor = -1; @@ -1480,6 +1484,15 @@ InstallProducts(original_state, setup_exe, cmd_line, prefs, &installer_state, &installer_directory); DoLegacyCleanups(installer_state, install_status); + + // It may be time to kick off an experiment if this was a successful update. + if ((install_status == installer::NEW_VERSION_UPDATED || + install_status == installer::IN_USE_UPDATED) && + installer::ShouldRunUserExperiment(installer_state)) { + installer::BeginUserExperiment( + installer_state, installer_directory.Append(setup_exe.BaseName()), + !system_install); + } } UMA_HISTOGRAM_ENUMERATION("Setup.Install.Result", install_status,
diff --git a/chrome/installer/setup/user_experiment.cc b/chrome/installer/setup/user_experiment.cc new file mode 100644 index 0000000..e7b51cce --- /dev/null +++ b/chrome/installer/setup/user_experiment.cc
@@ -0,0 +1,540 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/setup/user_experiment.h" + +#include <windows.h> + +#include <lm.h> +#include <shellapi.h> +#include <wtsapi32.h> + +#include <memory> + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/process/launch.h" +#include "base/process/process_info.h" +#include "base/rand_util.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/win/registry.h" +#include "base/win/scoped_handle.h" +#include "base/win/scoped_process_information.h" +#include "base/win/win_util.h" +#include "base/win/windows_version.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_version.h" +#include "chrome/install_static/install_modes.h" +#include "chrome/install_static/install_util.h" +#include "chrome/installer/setup/installer_state.h" +#include "chrome/installer/setup/setup_constants.h" +#include "chrome/installer/setup/setup_singleton.h" +#include "chrome/installer/setup/setup_util.h" +#include "chrome/installer/setup/update_active_setup_version_work_item.h" +#include "chrome/installer/util/experiment.h" +#include "chrome/installer/util/experiment_storage.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/google_update_settings.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/util_constants.h" +#include "ui/base/fullscreen_win.h" + +namespace installer { + +namespace { + +// The study currently being conducted. +constexpr ExperimentStorage::Study kCurrentStudy = ExperimentStorage::kStudyOne; + +// The primary group for study number two. +constexpr int kStudyTwoGroup = 0; + +// Test switches. +constexpr char kExperimentEnableForTesting[] = "experiment-enable-for-testing"; +constexpr char kExperimentEnterpriseBypass[] = "experiment-enterprise-bypass"; +constexpr char kExperimentParticipation[] = "experiment-participation"; +constexpr char kExperimentRetryDelay[] = "experiment-retry-delay"; + +// Returns true if the experiment is enabled for testing. +bool IsExperimentEnabledForTesting() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + kExperimentEnableForTesting); +} + +// Returns true if the install originated from the MSI or if the machine is +// joined to a domain. This check can be bypassed via +// --experiment-enterprise-bypass. +bool IsEnterpriseInstall(const InstallerState& installer_state) { + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + kExperimentEnterpriseBypass)) { + return false; + } + return installer_state.is_msi() || IsDomainJoined(); +} + +// Returns the delay to be used between presentation retries. The default (five +// minutes) can be overidden via --experiment-retry-delay=SECONDS. +base::TimeDelta GetRetryDelay() { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + base::string16 value = + command_line->GetSwitchValueNative(kExperimentRetryDelay); + int seconds; + if (!value.empty() && base::StringToInt(value, &seconds)) + return base::TimeDelta::FromSeconds(seconds); + return base::TimeDelta::FromMinutes(5); +} + +// Overrides the participation value for testing if a value is provided via +// --experiment-participation=value. "value" may be "one" or "two". Any other +// value (or none at all) results in clearing the persisted state for organic +// re-evaluation. +ExperimentStorage::Study HandleParticipationOverride( + ExperimentStorage::Study current_participation, + ExperimentStorage::Lock* lock) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(kExperimentParticipation)) + return current_participation; + + base::string16 participation_override = + command_line->GetSwitchValueNative(kExperimentParticipation); + ExperimentStorage::Study participation = ExperimentStorage::kNoStudySelected; + if (participation_override == L"one") + participation = ExperimentStorage::kStudyOne; + else if (participation_override == L"two") + participation = ExperimentStorage::kStudyTwo; + + if (participation != current_participation) + lock->WriteParticipation(participation); + + return participation; +} + +// This function launches setup as the currently logged-in interactive +// user, that is, the user whose logon session is attached to winsta0\default. +// It assumes that currently we are running as SYSTEM in a non-interactive +// window station. +// The function fails if there is no interactive session active, basically +// the computer is on but nobody has logged in locally. +// Remote Desktop sessions do not count as interactive sessions; running this +// method as a user logged in via remote desktop will do nothing. +bool LaunchSetupAsConsoleUser(const base::CommandLine& cmd_line) { + DWORD console_id = ::WTSGetActiveConsoleSessionId(); + if (console_id == 0xFFFFFFFF) { + PLOG(ERROR) << __func__ << " no session attached to the console"; + return false; + } + base::win::ScopedHandle user_token_handle; + { + HANDLE user_token; + if (!::WTSQueryUserToken(console_id, &user_token)) { + PLOG(ERROR) << __func__ << " failed to get user token for console_id " + << console_id; + return false; + } + user_token_handle.Set(user_token); + } + base::LaunchOptions options; + options.as_user = user_token_handle.Get(); + options.empty_desktop_name = true; + VLOG(1) << "Spawning experiment process: " << cmd_line.GetCommandLineString(); + if (base::LaunchProcess(cmd_line, options).IsValid()) + return true; + PLOG(ERROR) << "Failed"; + return false; +} + +// Returns true if the Windows shell indicates that the machine isn't in +// presentation mode, running a full-screen D3D app, or in a quiet period. +bool MayShowNotifications() { + QUERY_USER_NOTIFICATION_STATE state = {}; + HRESULT result = SHQueryUserNotificationState(&state); + if (FAILED(result)) + return true; + // Explicitly allow the acceptable states rather than the converse to be sure + // there are no surprises should new states be introduced. + return state == QUNS_NOT_PRESENT || // Locked/screensaver running. + state == QUNS_ACCEPTS_NOTIFICATIONS; // Go for it! +} + +bool UserSessionIsNotYoung() { + static constexpr base::TimeDelta kMinSessionLength = + base::TimeDelta::FromMinutes(5); + base::Time session_start_time = GetConsoleSessionStartTime(); + if (session_start_time.is_null()) + return true; + + base::TimeDelta session_length = base::Time::Now() - session_start_time; + return session_length >= kMinSessionLength; +} + +bool ActiveWindowIsNotFullscreen() { + return !ui::IsFullScreenMode(); +} + +// Blocks processing if conditions are not right for presentation. Returns true +// if presentation should continue, or false otherwise (e.g., another process +// requires the setup singleton). +bool WaitForPresentation( + const SetupSingleton& setup_singleton, + Experiment* experiment, + ExperimentStorage* storage, + std::unique_ptr<ExperimentStorage::Lock>* storage_lock) { + base::TimeDelta retry_delay = GetRetryDelay(); + bool first_sleep = true; + bool loop_again = true; + + do { + if (MayShowNotifications() && UserSessionIsNotYoung() && + ActiveWindowIsNotFullscreen()) { + return true; + } + + // Update the state accordingly if this is the first sleep. + if (first_sleep) { + experiment->SetState(ExperimentMetrics::kDeferringPresentation); + (*storage_lock)->StoreExperiment(*experiment); + first_sleep = false; + } + + // Release the storage lock and wait on the singleton for five minutes. + storage_lock->reset(); + // Break when another process needs the singleton. + loop_again = !setup_singleton.WaitForInterrupt(retry_delay); + *storage_lock = storage->AcquireLock(); + } while (loop_again); + + return false; +} + +} // namespace + +// Execution may be in the context of the system or a user on it, and no +// guarantee is made regarding the setup singleton. +bool ShouldRunUserExperiment(const InstallerState& installer_state) { + if (!install_static::kUseGoogleUpdateIntegration) + return false; + + if (!install_static::SupportsRetentionExperiments()) + return false; + + // The current experiment only applies to Windows 10 and newer. + if (base::win::GetVersion() < base::win::VERSION_WIN10) + return false; + + // Enterprise brand codes and domain joined machines are excluded. + if (IsEnterpriseInstall(installer_state)) + return false; + + // Gain exclusive access to the persistent experiment state. Only per-install + // state may be queried (participation and metrics are okay; Experiment itself + // is not). + ExperimentStorage storage; + auto lock = storage.AcquireLock(); + + // Bail out if this install is not selected into the fraction participating in + // the current study. + // NOTE: No clients will participate while this feature is under development. + if (!IsExperimentEnabledForTesting() || + !IsSelectedForStudy(lock.get(), kCurrentStudy)) { + return false; + } + + // Skip the experiment if a user on the machine has already reached a terminal + // state. + ExperimentMetrics metrics; + if (!lock->LoadMetrics(&metrics) || metrics.InTerminalState()) + return false; + + return true; +} + +// Execution is from the context of the installer immediately following a +// successful update. The setup singleton is held. +void BeginUserExperiment(const InstallerState& installer_state, + const base::FilePath& setup_path, + bool user_context) { + ExperimentStorage storage; + + // Prepare a command line to relaunch the installed setup.exe for the + // experiment. + base::CommandLine setup_command(setup_path); + InstallUtil::AppendModeSwitch(&setup_command); + if (installer_state.system_install()) + setup_command.AppendSwitch(switches::kSystemLevel); + if (installer_state.verbose_logging()) + setup_command.AppendSwitch(switches::kVerboseLogging); + setup_command.AppendSwitch(switches::kUserExperiment); + // Copy any test switches used by the spawned process. + static constexpr const char* kSwitchesToCopy[] = { + kExperimentRetryDelay, + }; + setup_command.CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(), + kSwitchesToCopy, arraysize(kSwitchesToCopy)); + + if (user_context) { + // This is either a per-user install or a per-machine install run via + // Active Setup as a normal user. + DCHECK(!installer_state.system_install() || + base::GetCurrentProcessIntegrityLevel() == base::MEDIUM_INTEGRITY); + VLOG(1) << "Spawning experiment process: " + << setup_command.GetCommandLineString(); + // The installer is already running in the context of an ordinary user. + // Relaunch directly to run the experiment. + base::LaunchOptions launch_options; + launch_options.force_breakaway_from_job_ = true; + if (!base::LaunchProcess(setup_command, launch_options).IsValid()) { + LOG(ERROR) << __func__ + << " failed to relaunch installer for user experiment,"; + WriteInitialState(&storage, ExperimentMetrics::kRelaunchFailed); + } + return; + } + + // The installer is running at high integrity, likely as SYSTEM. Relaunch as + // the console user at medium integrity. + VLOG(1) << "Attempting to spawn experiment as console user."; + if (LaunchSetupAsConsoleUser(setup_command)) { + return; + } + + // Trigger Active Setup to run on the next user logon if this machine has + // never participated in the experiment. This will be done at most once per + // machine, even across updates. Doing so more often risks having excessive + // active setup activity for some users. + auto storage_lock = storage.AcquireLock(); + ExperimentMetrics experiment_metrics; + if (storage_lock->LoadMetrics(&experiment_metrics) && + experiment_metrics.state == ExperimentMetrics::kUninitialized) { + UpdateActiveSetupVersionWorkItem item( + install_static::GetActiveSetupPath(), + UpdateActiveSetupVersionWorkItem::UPDATE_AND_BUMP_SELECTIVE_TRIGGER); + if (item.Do()) { + VLOG(1) << "Bumped Active Setup Version for user experiment"; + experiment_metrics.state = ExperimentMetrics::kWaitingForUserLogon; + storage_lock->StoreMetrics(experiment_metrics); + } else { + LOG(ERROR) << "Failed to bump Active Setup Version for user experiment."; + } + } +} + +// This function executes within the context of a signed-in user, even for the +// case of system-level installs. In particular, it may be run in a spawned +// setup.exe immediately after a successful update or following user logon as a +// result of Active Setup. +void RunUserExperiment(const base::CommandLine& command_line, + const MasterPreferences& master_preferences, + InstallationState* original_state, + InstallerState* installer_state) { + VLOG(1) << __func__; + + ExperimentStorage storage; + std::unique_ptr<SetupSingleton> setup_singleton(SetupSingleton::Acquire( + command_line, master_preferences, original_state, installer_state)); + if (!setup_singleton) { + VLOG(1) << "Timed out while waiting for setup singleton"; + WriteInitialState(&storage, ExperimentMetrics::kSingletonWaitTimeout); + return; + } + + Experiment experiment; + auto storage_lock = storage.AcquireLock(); + + // Determine the study in which this client participates. + ExperimentStorage::Study participation = ExperimentStorage::kNoStudySelected; + if (!storage_lock->ReadParticipation(&participation) || + participation == ExperimentStorage::kNoStudySelected) { + // ShouldRunUserExperiment should have brought this client into a particular + // study. Something is very wrong if it can't be determined here. + LOG(ERROR) << "Failed to read study participation."; + return; + } + + if (!storage_lock->LoadExperiment(&experiment)) { + // The metrics correspond to a different user on the machine; nothing to do. + VLOG(1) << "Another user is participating in the experiment."; + return; + } + + // There is nothing to do if the user has already reached a terminal state. + if (experiment.metrics().InTerminalState()) { + VLOG(1) << "Experiment has reached terminal state: " + << experiment.metrics().state; + return; + } + + // Now the fun begins. Assign this user to a group if this is the first time + // through. + if (experiment.metrics().InInitialState()) { + experiment.AssignGroup(PickGroup(participation)); + VLOG(1) << "Assigned user to experiment group: " + << experiment.metrics().group; + } + + // Chrome is considered actively used if it has been run within the last 28 + // days or if it was installed within the same time period. + int days_ago_last_run = GoogleUpdateSettings::GetLastRunTime(); + if ((days_ago_last_run >= 0 ? days_ago_last_run + : GetInstallAge(*installer_state)) <= 28) { + VLOG(1) << "Aborting experiment due to activity."; + experiment.SetState(ExperimentMetrics::kIsActive); + storage_lock->StoreExperiment(experiment); + return; + } + + // Check for a dormant user: one for which the machine has been off or the + // user has been signed out for more than 90% of the last 28 days. + if (false) { // TODO(grt): Implement this. + VLOG(1) << "Aborting experiment due to dormancy."; + experiment.SetState(ExperimentMetrics::kIsDormant); + storage_lock->StoreExperiment(experiment); + return; + } + + if (base::win::IsTabletDevice(nullptr)) { + VLOG(1) << "Aborting experiment due to tablet device."; + experiment.SetState(ExperimentMetrics::kIsTabletDevice); + storage_lock->StoreExperiment(experiment); + return; + } + + if (IsUpdateRenamePending()) { + VLOG(1) << "Aborting experiment due to Chrome update rename pending."; + experiment.SetState(ExperimentMetrics::kIsUpdateRenamePending); + storage_lock->StoreExperiment(experiment); + return; + } + + if (!WaitForPresentation(*setup_singleton, &experiment, &storage, + &storage_lock)) { + VLOG(1) << "Aborting experiment while waiting to present."; + experiment.SetState(ExperimentMetrics::kDeferredPresentationAborted); + storage_lock->StoreExperiment(experiment); + return; + } + + VLOG(1) << "Launching Chrome to show the toast."; + experiment.SetState(ExperimentMetrics::kLaunchingChrome); + storage_lock->StoreExperiment(experiment); + LaunchChrome(*installer_state, experiment); +} + +// Writes the initial state |state| to the registry if there is no existing +// state for this or another user. +void WriteInitialState(ExperimentStorage* storage, + ExperimentMetrics::State state) { + auto storage_lock = storage->AcquireLock(); + + // Write the state provided that there is either no existing state or that + // any that exists also represents an initial state. + ExperimentMetrics experiment_metrics; + if (storage_lock->LoadMetrics(&experiment_metrics) && + experiment_metrics.InInitialState()) { + experiment_metrics.state = state; + storage_lock->StoreMetrics(experiment_metrics); + } +} + +bool IsDomainJoined() { + LPWSTR buffer = nullptr; + NETSETUP_JOIN_STATUS buffer_type = NetSetupUnknownStatus; + bool is_joined = + ::NetGetJoinInformation(nullptr, &buffer, &buffer_type) == NERR_Success && + buffer_type == NetSetupDomainName; + if (buffer) + NetApiBufferFree(buffer); + + return is_joined; +} + +bool IsSelectedForStudy(ExperimentStorage::Lock* lock, + ExperimentStorage::Study current_study) { + ExperimentStorage::Study participation = ExperimentStorage::kNoStudySelected; + if (!lock->ReadParticipation(&participation)) + return false; + + participation = HandleParticipationOverride(participation, lock); + + if (participation == ExperimentStorage::kNoStudySelected) { + // This install has not been evaluated for participation. Do so now. Select + // a small population into the first study of the experiment. Everyone else + // gets the second study. + participation = base::RandDouble() <= 0.02756962532 + ? ExperimentStorage::kStudyOne + : ExperimentStorage::kStudyTwo; + if (!lock->WriteParticipation(participation)) + return false; + } + + return participation <= current_study; +} + +int PickGroup(ExperimentStorage::Study participation) { + DCHECK(participation == ExperimentStorage::kStudyOne || + participation == ExperimentStorage::kStudyTwo); + static constexpr int kHoldbackGroup = ExperimentMetrics::kNumGroups - 1; + + if (participation == ExperimentStorage::kStudyOne) { + // Evenly distrubute clients among the groups. + return base::RandInt(0, ExperimentMetrics::kNumGroups - 1); + } + + // 1% holdback, 99% in the winning group. + return base::RandDouble() < 0.01 ? kHoldbackGroup : kStudyTwoGroup; +} + +bool IsUpdateRenamePending() { + // Consider an update to be pending if an "opv" value is present in the + // registry or if Chrome's version as registered with Omaha doesn't match the + // current version. + base::string16 clients_key_path = + install_static::GetClientsKeyPath(install_static::GetAppGuid()); + const HKEY root = install_static::IsSystemInstall() ? HKEY_LOCAL_MACHINE + : HKEY_CURRENT_USER; + base::win::RegKey clients_key; + + // The failure modes below are generally indicitive of a run from a + // non-installed Chrome. Pretend that all is well. + if (clients_key.Open(root, clients_key_path.c_str(), + KEY_WOW64_64KEY | KEY_QUERY_VALUE) != ERROR_SUCCESS) { + return false; + } + if (clients_key.HasValue(google_update::kRegOldVersionField)) + return true; + base::string16 product_version; + if (clients_key.ReadValue(google_update::kRegVersionField, + &product_version) != ERROR_SUCCESS) { + return false; + } + return product_version != TEXT(CHROME_VERSION_STRING); +} + +void LaunchChrome(const InstallerState& installer_state, + const Experiment& experiment) { + const base::FilePath chrome_exe = + installer_state.target_path().Append(kChromeExe); + base::CommandLine command_line(chrome_exe); + command_line.AppendSwitchNative(::switches::kTryChromeAgain, + base::IntToString16(experiment.group())); + + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION temp_process_info = {}; + base::string16 writable_command_line_string( + command_line.GetCommandLineString()); + if (!::CreateProcess( + chrome_exe.value().c_str(), &writable_command_line_string[0], + nullptr /* lpProcessAttributes */, nullptr /* lpThreadAttributes */, + FALSE /* bInheritHandles */, CREATE_NO_WINDOW, + nullptr /* lpEnvironment */, nullptr /* lpCurrentDirectory */, + &startup_info, &temp_process_info)) { + PLOG(ERROR) << "Failed to launch: " << writable_command_line_string; + return; + } + + // Ensure that the thread and process handles of the new process are closed. + base::win::ScopedProcessInformation process_info(temp_process_info); +} + +} // namespace installer
diff --git a/chrome/installer/setup/user_experiment.h b/chrome/installer/setup/user_experiment.h new file mode 100644 index 0000000..3a72d78 --- /dev/null +++ b/chrome/installer/setup/user_experiment.h
@@ -0,0 +1,75 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_SETUP_USER_EXPERIMENT_H_ +#define CHROME_INSTALLER_SETUP_USER_EXPERIMENT_H_ + +#include "chrome/installer/util/experiment_metrics.h" +#include "chrome/installer/util/experiment_storage.h" +#include "chrome/installer/util/util_constants.h" + +namespace base { +class CommandLine; +class FilePath; +} // namespace base + +namespace installer { + +class Experiment; +class ExperimentStorage; +class InstallationState; +class InstallerState; +class MasterPreferences; + +// Returns true if a user of this Chrome install should participate in a +// post-update user experiment. +bool ShouldRunUserExperiment(const InstallerState& installer_state); + +// Initiates the user experiment for a user of the current install. May only be +// called if eligibility had previously been evaluated via +// ShouldRunUserExperiment. |setup_path| is the path to the version of setup.exe +// that will be spawned to run the experiment. If |user_context| is true, +// setup.exe will be spawned directly; otherwise, it will be either be run as +// the interactive console user or on the next login via Active Setup. +void BeginUserExperiment(const InstallerState& installer_state, + const base::FilePath& setup_path, + bool user_context); + +// Runs the experiment for the current user. +void RunUserExperiment(const base::CommandLine& command_line, + const MasterPreferences& master_preferences, + InstallationState* original_state, + InstallerState* installer_state); + +// Writes the initial state |state| to the registry if there is no existing +// state for this or another user. +void WriteInitialState(ExperimentStorage* storage, + ExperimentMetrics::State state); + +// Returns true if the install is associated with an enterprise brand code. +bool IsEnterpriseBrand(); + +// Returns true if the machine is joined to a Windows domain. +bool IsDomainJoined(); + +// Returns true if the machine is selected for participation in |current_study|. +// Dice are rolled on the first invocation to determine in which study the +// machine participates. +bool IsSelectedForStudy(ExperimentStorage::Lock* lock, + ExperimentStorage::Study current_study); + +// Returns a group number based on the study in which the client participates. +int PickGroup(ExperimentStorage::Study participation); + +// Returns true if the installed version of Chrome doesn't match the current +// executable's. +bool IsUpdateRenamePending(); + +// Launches Chrome to present the prompt. +void LaunchChrome(const InstallerState& installer_state, + const Experiment& experiment); + +} // namespace installer + +#endif // CHROME_INSTALLER_SETUP_USER_EXPERIMENT_H_
diff --git a/chrome/installer/setup/user_experiment_unittest.cc b/chrome/installer/setup/user_experiment_unittest.cc new file mode 100644 index 0000000..a5b81c3 --- /dev/null +++ b/chrome/installer/setup/user_experiment_unittest.cc
@@ -0,0 +1,194 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/setup/user_experiment.h" + +#include "base/macros.h" +#include "base/test/test_reg_util_win.h" +#include "base/win/registry.h" +#include "chrome/common/chrome_version.h" +#include "chrome/install_static/install_details.h" +#include "chrome/install_static/install_modes.h" +#include "chrome/install_static/install_util.h" +#include "chrome/install_static/test/scoped_install_details.h" +#include "chrome/installer/util/experiment_metrics.h" +#include "chrome/installer/util/experiment_storage.h" +#include "chrome/installer/util/google_update_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace installer { + +class UserExperimentTest : public ::testing::TestWithParam<bool> { + protected: + UserExperimentTest() + : system_level_(GetParam()), + root_(system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER), + install_details_(system_level_) {} + + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(registry_override_manager_.OverrideRegistry(root_)); + + // Create the ClientState key. + base::win::RegKey key; + ASSERT_EQ(key.Create(root_, + install_static::InstallDetails::Get() + .GetClientStateKeyPath() + .c_str(), + KEY_WOW64_64KEY | KEY_SET_VALUE), + ERROR_SUCCESS); + } + + void SetProductVersion(const base::char16* version) { + SetClientsValue(google_update::kRegVersionField, version); + } + + void SetOldProductVersion(const base::char16* version) { + SetClientsValue(google_update::kRegOldVersionField, version); + } + + private: + void SetClientsValue(const base::char16* value_name, + const base::char16* value_data) { + base::win::RegKey key( + root_, + install_static::GetClientsKeyPath(install_static::GetAppGuid()).c_str(), + KEY_WOW64_64KEY | KEY_SET_VALUE); + ASSERT_TRUE(key.Valid()); + ASSERT_EQ(key.WriteValue(value_name, value_data), ERROR_SUCCESS); + } + + const bool system_level_; + const HKEY root_; + registry_util::RegistryOverrideManager registry_override_manager_; + install_static::ScopedInstallDetails install_details_; + DISALLOW_COPY_AND_ASSIGN(UserExperimentTest); +}; + +TEST_P(UserExperimentTest, WriteInitialStateNoData) { + ExperimentStorage storage; + + // A first call should write the desired state. + WriteInitialState(&storage, ExperimentMetrics::kWaitingForUserLogon); + + ExperimentMetrics metrics = ExperimentMetrics(); + EXPECT_TRUE(storage.AcquireLock()->LoadMetrics(&metrics)); + EXPECT_EQ(metrics.state, ExperimentMetrics::kWaitingForUserLogon); + + // A subsequent should update it state. + WriteInitialState(&storage, ExperimentMetrics::kSingletonWaitTimeout); + + metrics = ExperimentMetrics(); + EXPECT_TRUE(storage.AcquireLock()->LoadMetrics(&metrics)); + EXPECT_EQ(metrics.state, ExperimentMetrics::kSingletonWaitTimeout); +} + +// Nothing should be written if the experiment is underway. +TEST_P(UserExperimentTest, WriteInitialStateInExperiment) { + ExperimentStorage storage; + + { + ExperimentMetrics metrics = ExperimentMetrics(); + metrics.state = ExperimentMetrics::kGroupAssigned; + storage.AcquireLock()->StoreMetrics(metrics); + } + + WriteInitialState(&storage, ExperimentMetrics::kSingletonWaitTimeout); + + ExperimentMetrics metrics = ExperimentMetrics(); + EXPECT_TRUE(storage.AcquireLock()->LoadMetrics(&metrics)); + EXPECT_EQ(metrics.state, ExperimentMetrics::kGroupAssigned); +} + +TEST_P(UserExperimentTest, IsDomainJoined) { + // Just make sure it doesn't crash or leak. + IsDomainJoined(); +} + +TEST_P(UserExperimentTest, IsSelectedForStudyFirstCall) { + ExperimentStorage storage; + auto lock = storage.AcquireLock(); + + // The first call will pick a study. + bool is_selected = + IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyOne); + + // A value must have been written. + ExperimentStorage::Study participation = ExperimentStorage::kNoStudySelected; + ASSERT_TRUE(lock->ReadParticipation(&participation)); + EXPECT_GE(participation, ExperimentStorage::kStudyOne); + EXPECT_LE(participation, ExperimentStorage::kStudyTwo); + + // is_selected should be set based on the value that was written. + if (participation == ExperimentStorage::kStudyOne) + EXPECT_TRUE(is_selected); + else + EXPECT_FALSE(is_selected); +} + +// A user selected into study one participates in both studies. +TEST_P(UserExperimentTest, IsSelectedForStudyOne) { + ExperimentStorage storage; + auto lock = storage.AcquireLock(); + + ASSERT_TRUE(lock->WriteParticipation(ExperimentStorage::kStudyOne)); + + EXPECT_TRUE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyOne)); + EXPECT_TRUE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyTwo)); +} + +// A user selected into study two only participates in that study. +TEST_P(UserExperimentTest, IsSelectedForStudyTwo) { + ExperimentStorage storage; + auto lock = storage.AcquireLock(); + + ASSERT_TRUE(lock->WriteParticipation(ExperimentStorage::kStudyTwo)); + + EXPECT_FALSE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyOne)); + EXPECT_TRUE(IsSelectedForStudy(lock.get(), ExperimentStorage::kStudyTwo)); +} + +// Ensure that group selection is within bounds. +TEST_P(UserExperimentTest, PickGroupStudyOne) { + int group = PickGroup(ExperimentStorage::kStudyOne); + EXPECT_GE(group, 0); + EXPECT_LT(group, ExperimentMetrics::kNumGroups); +} + +// Ensure that group selection is within bounds. +TEST_P(UserExperimentTest, PickGroupStudyTwo) { + int group = PickGroup(ExperimentStorage::kStudyTwo); + EXPECT_GE(group, 0); + EXPECT_LT(group, ExperimentMetrics::kNumGroups); +} + +// When there's nothing in the registry, default to false. +TEST_P(UserExperimentTest, IsUpdateRenamePendingNoRegistration) { + EXPECT_FALSE(IsUpdateRenamePending()); +} + +// No update is pending if "pv" matches the current version. +TEST_P(UserExperimentTest, IsUpdateRenamePendingNo) { + ASSERT_NO_FATAL_FAILURE(SetProductVersion(TEXT(CHROME_VERSION_STRING))); + EXPECT_FALSE(IsUpdateRenamePending()); +} + +// An update is pending if an old version needs to be restarted to be the +// current. +TEST_P(UserExperimentTest, IsUpdateRenamePendingYes) { + static constexpr base::char16 kSillyOldVersion[] = L"47.0.1.0"; + ASSERT_STRNE(kSillyOldVersion, TEXT(CHROME_VERSION_STRING)); + + ASSERT_NO_FATAL_FAILURE(SetProductVersion(TEXT(CHROME_VERSION_STRING))); + ASSERT_NO_FATAL_FAILURE(SetOldProductVersion(kSillyOldVersion)); + EXPECT_TRUE(IsUpdateRenamePending()); +} + +INSTANTIATE_TEST_CASE_P(UserLevel, + UserExperimentTest, + ::testing::Values(false)); +INSTANTIATE_TEST_CASE_P(SystemLevel, + UserExperimentTest, + ::testing::Values(true)); + +} // namespace installer
diff --git a/chrome/installer/util/experiment_metrics.h b/chrome/installer/util/experiment_metrics.h index fae52636..4b31d47 100644 --- a/chrome/installer/util/experiment_metrics.h +++ b/chrome/installer/util/experiment_metrics.h
@@ -26,24 +26,25 @@ // next logon via Active Setup. kWaitingForUserLogon = 1, - // Waiting in user context for the setup singleton. - kWaitingForSingleton = 2, - // Timed out waiting for the setup singleton. Will retry on next update. - kSingletonWaitTimeout = 3, + kSingletonWaitTimeout = 2, // A group has been assigned. The experiment has moved out of the initial // state at this point. This state is reached under the setup singleton. - kGroupAssigned = 4, + kGroupAssigned = 3, // The user is not participating on account of using a tablet-like device. - kIsTabletDevice = 5, + kIsTabletDevice = 4, // Chrome has been run within the last 28 days. - kIsActive = 6, + kIsActive = 5, // The user has not been active on the machine much in the last 28 days. - kIsDormant = 7, + kIsDormant = 6, + + // Chrome has received an in-use update for which the rename is pending. + // The UX cannot be shown. + kIsUpdateRenamePending = 7, // Deferring presentation until it's okay to show the toast. kDeferringPresentation = 8,
diff --git a/chrome/installer/util/experiment_storage.cc b/chrome/installer/util/experiment_storage.cc index 6f8fe0e..0fd9d3d 100644 --- a/chrome/installer/util/experiment_storage.cc +++ b/chrome/installer/util/experiment_storage.cc
@@ -157,7 +157,7 @@ DCHECK(result); } -bool ExperimentStorage::Lock::ReadParticipation(Participation* participation) { +bool ExperimentStorage::Lock::ReadParticipation(Study* participation) { base::win::RegKey key; // A failure to open the key likely indicates that this isn't running from a // real install of Chrome. @@ -166,28 +166,29 @@ DWORD value = 0; LONG result = key.ReadValueDW(kRegValueRetentionStudy, &value); - if (result != ERROR_SUCCESS) { - // This likely means that the value is not present. - *participation = Participation::kNotEvaluated; - } else if (value == 0) { - *participation = Participation::kNotParticipating; - } else { - *participation = Participation::kIsParticipating; - } + // An error most likely means that the value is not present. + if (result != ERROR_SUCCESS || value == 0) + *participation = kNoStudySelected; + else if (value == 1) + *participation = kStudyOne; + else + *participation = kStudyTwo; return true; } -bool ExperimentStorage::Lock::WriteParticipation(Participation participation) { +bool ExperimentStorage::Lock::WriteParticipation(Study participation) { + DCHECK(participation == kNoStudySelected || participation == kStudyOne || + participation == kStudyTwo); base::win::RegKey key; // A failure to open the key likely indicates that this isn't running from a // real install of Chrome. if (!OpenParticipationKey(true /* write_access */, &key)) return false; - if (participation == Participation::kNotEvaluated) + if (participation == kNoStudySelected) return key.DeleteValue(kRegValueRetentionStudy) == ERROR_SUCCESS; - const DWORD value = participation == Participation::kIsParticipating ? 1 : 0; - return key.WriteValue(kRegValueRetentionStudy, value) == ERROR_SUCCESS; + return key.WriteValue(kRegValueRetentionStudy, participation) == + ERROR_SUCCESS; } bool ExperimentStorage::Lock::LoadExperiment(Experiment* experiment) {
diff --git a/chrome/installer/util/experiment_storage.h b/chrome/installer/util/experiment_storage.h index 40ed1d2..081bbe8 100644 --- a/chrome/installer/util/experiment_storage.h +++ b/chrome/installer/util/experiment_storage.h
@@ -18,9 +18,9 @@ // Manages the storage of experiment state on the machine. // -// Participation is a per-install property evaluated one time to determine -// whether or not the install as a whole participates in the study. It is -// stored in the install's ClientState key. +// Participation is a per-install property evaluated one time to determine which +// study the client participates in. It is stored in the install's ClientState +// key. // // ExperimentMetrics are stored in a per-install experiment_label, while the // fine-grained Experiment data are stored in a per-user key in Chrome's @@ -38,15 +38,11 @@ // mutex is used for all reads and writes to ensure consistent state. class ExperimentStorage { public: - enum class Participation { - // No participation state was found for the install. - kNotEvaluated, - - // The client is not participating in the study. - kNotParticipating, - - // The client is participating in the study. - kIsParticipating, + // An identifier of which study the install participates in. + enum Study : uint32_t { + kNoStudySelected = 0, + kStudyOne = 1, + kStudyTwo = 2, }; // Grants the holder exclusive access to the data in the registry. Consumers @@ -56,12 +52,13 @@ ~Lock(); // Reads the participation state for the install. Returns false in case of - // error. - bool ReadParticipation(Participation* participation); + // error. |participation| is set to kNotEvaluated if no value is present; + // otherwise, it is set to the value found. + bool ReadParticipation(Study* participation); // Writes the participation state for the install. Returns false if the // write failed. - bool WriteParticipation(Participation participation); + bool WriteParticipation(Study participation); // Loads the experiment metrics and data from the registry. Returns false if // the state in the registry corresponds to a different user or could not be
diff --git a/chrome/installer/util/experiment_storage_unittest.cc b/chrome/installer/util/experiment_storage_unittest.cc index 5f4d2d3..f341ce9 100644 --- a/chrome/installer/util/experiment_storage_unittest.cc +++ b/chrome/installer/util/experiment_storage_unittest.cc
@@ -62,7 +62,7 @@ metrics.action_delay_bucket = 11; metrics.session_length_bucket = 36; base::string16 encoded_metrics(ExperimentStorage::EncodeMetrics(metrics)); - EXPECT_EQ(L"5BIMD4IA", encoded_metrics); + EXPECT_EQ(L"5BIMD2IA", encoded_metrics); ExperimentMetrics decoded_metrics; ASSERT_TRUE( ExperimentStorage::DecodeMetrics(encoded_metrics, &decoded_metrics)); @@ -124,10 +124,9 @@ TEST_P(ExperimentStorageTest, TestReadWriteParticipation) { ExperimentStorage storage; - ExperimentStorage::Participation expected = - ExperimentStorage::Participation::kIsParticipating; + ExperimentStorage::Study expected = ExperimentStorage::kStudyOne; ASSERT_TRUE(storage.AcquireLock()->WriteParticipation(expected)); - ExperimentStorage::Participation p; + ExperimentStorage::Study p; ASSERT_TRUE(storage.AcquireLock()->ReadParticipation(&p)); EXPECT_EQ(expected, p); } @@ -166,7 +165,7 @@ ASSERT_TRUE(storage.AcquireLock()->StoreMetrics(metrics)); ExperimentMetrics stored_metrics; ASSERT_TRUE(storage.AcquireLock()->LoadMetrics(&stored_metrics)); - EXPECT_EQ(L"5BIMD4IA", ExperimentStorage::EncodeMetrics(stored_metrics)); + EXPECT_EQ(L"5BIMD2IA", ExperimentStorage::EncodeMetrics(stored_metrics)); // Verify that expeirment labels are stored in registry. EXPECT_EQ(metrics, stored_metrics); }
diff --git a/chrome/profiling/BUILD.gn b/chrome/profiling/BUILD.gn index 5318bb21..097b41e 100644 --- a/chrome/profiling/BUILD.gn +++ b/chrome/profiling/BUILD.gn
@@ -7,6 +7,8 @@ if (enable_oop_heap_profiling) { static_library("profiling") { sources = [ + "profiling_globals.cc", + "profiling_globals.h", "profiling_main.cc", "profiling_main.h", ] @@ -14,6 +16,7 @@ deps = [ "//base", "//chrome/common", + "//mojo/edk/system", ] } } else {
diff --git a/chrome/profiling/DEPS b/chrome/profiling/DEPS new file mode 100644 index 0000000..177020e --- /dev/null +++ b/chrome/profiling/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/edk/embedder", +]
diff --git a/chrome/profiling/profiling_globals.cc b/chrome/profiling/profiling_globals.cc new file mode 100644 index 0000000..5cd552e --- /dev/null +++ b/chrome/profiling/profiling_globals.cc
@@ -0,0 +1,59 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/profiling/profiling_globals.h" + +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "build/build_config.h" + +namespace profiling { + +ProfilingGlobals::ProfilingGlobals() + : io_thread_("IO thread") { +#if defined(OS_WIN) + io_thread_.init_com_with_mta(true); +#endif + base::Thread::Options options; + options.message_loop_type = base::MessageLoop::TYPE_IO; + io_thread_.StartWithOptions(options); +} + +ProfilingGlobals::~ProfilingGlobals() {} + +// static +ProfilingGlobals* ProfilingGlobals::Get() { + static ProfilingGlobals singleton; + return &singleton; +} + +base::TaskRunner* ProfilingGlobals::GetIORunner() { + return io_thread_.task_runner().get(); +} + +scoped_refptr<base::SingleThreadTaskRunner> ProfilingGlobals::GetMainThread() + const { + CHECK(base::MessageLoop::current() == main_message_loop_); + return main_message_loop_->task_runner(); +} + +void ProfilingGlobals::RunMainMessageLoop() { + // TODO(brettw) if we never add anything interesting on the main thread here, + // we can change this so the main thread *is* the I/O thread. This will save + // some resources. + base::MessageLoopForUI message_loop; + DCHECK(!main_message_loop_); + main_message_loop_ = &message_loop; + + base::RunLoop run_loop; + run_loop.Run(); + + main_message_loop_ = nullptr; +} + +void ProfilingGlobals::QuitWhenIdle() { + main_message_loop_->QuitWhenIdle(); +} + +} // namespace profiling
diff --git a/chrome/profiling/profiling_globals.h b/chrome/profiling/profiling_globals.h new file mode 100644 index 0000000..84060a7 --- /dev/null +++ b/chrome/profiling/profiling_globals.h
@@ -0,0 +1,49 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_PROFILING_PROFILING_GLOBALS_H_ +#define CHROME_PROFILING_PROFILING_GLOBALS_H_ + +#include <memory> + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/threading/thread.h" + +namespace base { +class MessageLoopForUI; +class SingleThreadTaskRunner; +class TaskRunner; +} // namespace base + +namespace profiling { + +class ProfilingGlobals { + public: + static ProfilingGlobals* Get(); + + base::TaskRunner* GetIORunner(); + + // Returns non-null when inside RunMainMessageLoop. Call only on the + // main thread (otherwise there's a shutdown race). + scoped_refptr<base::SingleThreadTaskRunner> GetMainThread() const; + + void RunMainMessageLoop(); + void QuitWhenIdle(); + + private: + ProfilingGlobals(); + ~ProfilingGlobals(); + + // Non-null inside RunMainMessageLoop. + base::MessageLoopForUI* main_message_loop_ = nullptr; + + base::Thread io_thread_; + + DISALLOW_COPY_AND_ASSIGN(ProfilingGlobals); +}; + +} // namespace profiling + +#endif // CHROME_PROFILING_PROFILING_GLOBALS_H_
diff --git a/chrome/profiling/profiling_main.cc b/chrome/profiling/profiling_main.cc index fd582b6..ccc022b 100644 --- a/chrome/profiling/profiling_main.cc +++ b/chrome/profiling/profiling_main.cc
@@ -4,8 +4,22 @@ #include "chrome/profiling/profiling_main.h" +#include "base/base_paths.h" #include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/process/launch.h" +#include "base/process/process.h" +#include "base/process/process_metrics.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "build/build_config.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/profiling/profiling_globals.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/scoped_ipc_support.h" #if defined(OS_WIN) #include "base/win/win_util.h" @@ -13,8 +27,80 @@ namespace profiling { +namespace { + +base::CommandLine MakeBrowserCommandLine(const base::CommandLine& cmdline, + const std::string& pipe_id) { + const base::CommandLine::StringVector& our_argv = cmdline.argv(); + + base::CommandLine::StringVector browser_argv; + browser_argv.reserve(our_argv.size()); + + // Program name. + base::FilePath child_path; +#if defined(OS_LINUX) + // Use /proc/self/exe rather than our known binary path so updates + // can't swap out the binary from underneath us. + // When running under Valgrind, forking /proc/self/exe ends up forking the + // Valgrind executable, which then crashes. However, it's almost safe to + // assume that the updates won't happen while testing with Valgrind tools. + if (!RunningOnValgrind()) + child_path = base::FilePath(base::kProcSelfExe); +#endif + + if (child_path.empty()) + base::PathService::Get(base::FILE_EXE, &child_path); + browser_argv.push_back(child_path.value()); // Program name. + + // Remove all memlog flags. + for (size_t i = 1; i < our_argv.size(); i++) { + if (!base::StartsWith(our_argv[i], FILE_PATH_LITERAL("--memlog"), + base::CompareCase::SENSITIVE)) + browser_argv.push_back(our_argv[i]); + } + + // Append the pipe ID. + std::string pipe_switch("--"); + pipe_switch.append(switches::kMemlogPipe); + pipe_switch.push_back('='); + pipe_switch.append(pipe_id); +#if defined(OS_WIN) + browser_argv.push_back(base::ASCIIToUTF16(pipe_switch)); +#else + browser_argv.push_back(pipe_switch); +#endif + + return base::CommandLine(browser_argv); +} + +bool LaunchBrowser(const base::CommandLine& our_cmdline, + const std::string& pipe_id) { + base::CommandLine browser_cmdline = + MakeBrowserCommandLine(our_cmdline, pipe_id); + + base::LaunchOptions options; + base::Process process = base::LaunchProcess(browser_cmdline, options); + + return true; +} + +} // namespace + int ProfilingMain(const base::CommandLine& cmdline) { - // TODO(brettw) implement this. + ProfilingGlobals* globals = ProfilingGlobals::Get(); + + mojo::edk::Init(); + mojo::edk::ScopedIPCSupport ipc_support( + globals->GetIORunner(), + mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN); + + base::Process process = base::Process::Current(); + std::string pipe_id = base::IntToString(static_cast<int>(process.Pid())); + + if (!LaunchBrowser(cmdline, pipe_id)) + return 1; + + ProfilingGlobals::Get()->RunMainMessageLoop(); #if defined(OS_WIN) base::win::SetShouldCrashOnProcessDetach(false);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index a1c1262e..a9ec2bc 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4164,6 +4164,7 @@ # Ash implies the app list is enabled (only disabled on mobile). "../browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc", "../browser/ui/ash/chrome_screenshot_grabber_unittest.cc", + "../browser/ui/ash/ime_controller_client_unittest.cc", "../browser/ui/ash/launcher/arc_app_shelf_id_unittest.cc", "../browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc", "../browser/ui/ash/launcher/launcher_context_menu_unittest.cc",
diff --git a/chrome/tools/test/experiment_tool_win.py b/chrome/tools/test/experiment_tool_win.py new file mode 100755 index 0000000..2d942197 --- /dev/null +++ b/chrome/tools/test/experiment_tool_win.py
@@ -0,0 +1,212 @@ +#!/usr/bin/env python +# 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. + +"""A tool for working with state associated with the M60 Chrome on Windows 10 +retention experiment. + +For example: +experiment_tool_win.py --channel beta --system-level --operation prep +""" + +import argparse +import math +import sys +from datetime import datetime, timedelta +import win32api +import win32security +import _winreg + + +def GetUserSidString(): + """Returns the current user's SID string.""" + token_handle = win32security.OpenProcessToken(win32api.GetCurrentProcess(), + win32security.TOKEN_QUERY) + user_sid, _ = win32security.GetTokenInformation(token_handle, + win32security.TokenUser) + return win32security.ConvertSidToStringSid(user_sid) + + +def InternalTimeFromPyTime(pytime): + """Returns a Chromium internal time value representing a Python datetime.""" + # Microseconds since 1601-01-01 00:00:00 UTC + delta = pytime - datetime(1601, 1, 1) + return math.trunc(delta.total_seconds()) * 1000000 + delta.microseconds + + +class ChromeState: + """An object that provides mutations on Chrome's state relating to the + user experiment. + """ + _CHANNEL_CONFIGS = { + 'stable': { + 'guid': '{8A69D345-D564-463c-AFF1-A69D9E530F96}' + }, + 'beta': { + 'guid': '{8237E44A-0054-442C-B6B6-EA0509993955}' + }, + 'dev': { + 'guid': '{401C381F-E0DE-4B85-8BD8-3F3F14FBDA57}' + }, + 'canary': { + 'guid': '{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}' + }, + } + _GOOGLE_UPDATE_PATH = 'Software\\Google\\Update' + _ACTIVE_SETUP_PATH = 'Software\\Microsoft\\Active Setup\\Installed ' + \ + 'Components\\' + + def __init__(self, channel_name, system_level): + self._config = ChromeState._CHANNEL_CONFIGS[channel_name] + self._system_level = system_level + self._registry_root = _winreg.HKEY_LOCAL_MACHINE if self._system_level \ + else _winreg.HKEY_CURRENT_USER + + def SetRetentionStudyValue(self, study): + """Sets the RetentionStudy value for the install.""" + path = ChromeState._GOOGLE_UPDATE_PATH + '\\ClientState\\' + \ + self._config['guid'] + with _winreg.OpenKey(self._registry_root, path, 0, + _winreg.KEY_WOW64_32KEY | + _winreg.KEY_SET_VALUE) as key: + _winreg.SetValueEx(key, 'RetentionStudy', 0, _winreg.REG_DWORD, study) + + def DeleteRetentionStudyValue(self): + """Deletes the RetentionStudy value for the install.""" + path = ChromeState._GOOGLE_UPDATE_PATH + '\\ClientState\\' + \ + self._config['guid'] + try: + with _winreg.OpenKey(self._registry_root, path, 0, + _winreg.KEY_WOW64_32KEY | + _winreg.KEY_SET_VALUE) as key: + _winreg.DeleteValue(key, 'RetentionStudy') + except WindowsError as error: + if error.winerror != 2: + raise + + def DeleteExperimentLabelsValue(self): + """Deletes the experiment_labels for the install.""" + medium = 'Medium' if self._system_level else '' + path = ChromeState._GOOGLE_UPDATE_PATH + '\\ClientState' + medium + '\\' + \ + self._config['guid'] + try: + with _winreg.OpenKey(self._registry_root, path, 0, + _winreg.KEY_WOW64_32KEY | + _winreg.KEY_SET_VALUE) as key: + _winreg.DeleteValue(key, 'experiment_labels') + except WindowsError as error: + if error.winerror != 2: + raise + + def DeleteRentionKey(self): + """Deletes the Retention key for the current user.""" + medium = 'Medium' if self._system_level else '' + path = ChromeState._GOOGLE_UPDATE_PATH + '\\ClientState' + medium + '\\' + \ + self._config['guid'] + '\\Retention' + try: + if self._system_level: + _winreg.DeleteKeyEx(self._registry_root, + path + '\\' + GetUserSidString(), + _winreg.KEY_WOW64_32KEY) + _winreg.DeleteKeyEx(self._registry_root, path, _winreg.KEY_WOW64_32KEY) + except WindowsError as error: + if error.winerror != 2: + raise + + def SetLastRunTime(self, delta): + """Sets Chrome's lastrun time for the current user.""" + path = ChromeState._GOOGLE_UPDATE_PATH + '\\ClientState\\' + \ + self._config['guid'] + lastrun = InternalTimeFromPyTime(datetime.utcnow() - delta) + with _winreg.CreateKeyEx(_winreg.HKEY_CURRENT_USER, path, 0, + _winreg.KEY_WOW64_32KEY | + _winreg.KEY_SET_VALUE) as key: + _winreg.SetValueEx(key, 'lastrun', 0, _winreg.REG_SZ, str(lastrun)) + + def AdjustActiveSetupCommand(self): + """Adds --experiment-enterprise-bypass to system-level Chrome's Active Setup + command.""" + if not self._system_level: + return + enable_switch = '--experiment-enable-for-testing' + bypass_switch = '--experiment-enterprise-bypass' + for flag in [_winreg.KEY_WOW64_32KEY, _winreg.KEY_WOW64_64KEY]: + try: + with _winreg.OpenKey(self._registry_root, + ChromeState._ACTIVE_SETUP_PATH + + self._config['guid'], 0, + _winreg.KEY_SET_VALUE | _winreg.KEY_QUERY_VALUE | + flag) as key: + command, _ = _winreg.QueryValueEx(key, 'StubPath') + if not bypass_switch in command: + command += ' ' + bypass_switch + if not enable_switch in command: + command += ' ' + enable_switch + _winreg.SetValueEx(key, 'StubPath', 0, _winreg.REG_SZ, command) + except WindowsError as error: + if error.winerror != 2: + raise + + def ClearUserActiveSetup(self): + """Clears per-user state associated with Active Setup so that it will run + again on next login.""" + if not self._system_level: + return + paths = [ChromeState._ACTIVE_SETUP_PATH, + ChromeState._ACTIVE_SETUP_PATH.replace('Software\\', + 'Software\\Wow6432Node\\')] + for path in paths: + try: + _winreg.DeleteKeyEx(_winreg.HKEY_CURRENT_USER, + path + self._config['guid'], 0) + except WindowsError as error: + if error.winerror != 2: + raise + + +def DoClean(chrome_state): + """Deletes all state associated with the user experiment.""" + chrome_state.DeleteRetentionStudyValue() + chrome_state.DeleteExperimentLabelsValue() + chrome_state.DeleteRentionKey() + return 0 + + +def DoPrep(chrome_state): + """Prepares an install for participation in the experiment.""" + # Clear old state. + DoClean(chrome_state) + # Make Chrome appear to have been last run 30 days ago. + chrome_state.SetLastRunTime(timedelta(30)) + # Add the enterprise bypass switch to the Active Setup command. + chrome_state.AdjustActiveSetupCommand() + # Cause Active Setup to be run for the current user on next logon. + chrome_state.ClearUserActiveSetup() + # Put the machine into the first study. + chrome_state.SetRetentionStudyValue(1) + return 0 + + +def main(options): + chrome_state = ChromeState(options.channel, options.system_level) + if options.operation == 'clean': + return DoClean(chrome_state) + if options.operation == 'prep': + return DoPrep(chrome_state) + return 1 + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('--operation', required=True, choices=['clean', 'prep'], + help='The operation to be performed.') + parser.add_argument('--channel', default='stable', + choices=['stable', 'beta', 'dev', 'canary'], + help='The install on which to operate (stable by ' \ + 'default).') + parser.add_argument('--system-level', action='store_true', + help='Specify to operate on a system-level install ' \ + '(user-level by default).') + sys.exit(main(parser.parse_args()))
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index d6093d4a..e95ba4f9 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc
@@ -690,13 +690,24 @@ void NetworkStateHandler::SetTetherNetworkStateDisconnected( const std::string& guid) { - // TODO(khorimoto): Remove the Tether network as the default network. SetTetherNetworkStateConnectionState(guid, shill::kStateDisconnect); } void NetworkStateHandler::SetTetherNetworkStateConnecting( const std::string& guid) { - // TODO(khorimoto): Set the Tether network as the default network. + // The default network should only be set if there currently is no default + // network. Otherwise, the default network should not change unless the + // connection completes successfully and the newly-connected network is + // prioritized higher than the existing default network. Note that, in + // general, a connected Ethernet network is still considered the default + // network even if a Tether or Wi-Fi network becomes connected. + if (default_network_path_.empty()) { + NET_LOG(EVENT) << "Connecting to Tether network when there is currently no " + << "default network; setting as new default network. GUID: " + << guid; + default_network_path_ = guid; + } + SetTetherNetworkStateConnectionState(guid, shill::kStateConfiguration); } @@ -707,6 +718,9 @@ DCHECK(GetNetworkStateFromGuid(GetNetworkStateFromGuid(guid)->tether_guid()) ->tether_guid() == guid); + // At this point, there should be a default network set. + DCHECK(!default_network_path_.empty()); + SetTetherNetworkStateConnectionState(guid, shill::kStateOnline); } @@ -1259,6 +1273,17 @@ if (new_service_path == default_network_path_) return; + if (new_service_path.empty()) { + // If Shill reports that there is no longer a default network but there is + // still an active Tether connection corresponding to the default network, + // return early without changing |default_network_path_|. Observers will be + // notified of the default network change due to a subsequent call to + // SetTetherNetworkStateDisconnected(). + const NetworkState* old_default_network = DefaultNetwork(); + if (old_default_network && old_default_network->type() == kTypeTether) + return; + } + default_network_path_ = service_path; NET_LOG_EVENT("DefaultNetworkServiceChanged:", default_network_path_); const NetworkState* network = nullptr; @@ -1271,6 +1296,15 @@ << default_network_path_; return; } + if (!network->tether_guid().empty()) { + DCHECK(network->type() == shill::kTypeWifi); + + // If the new default network from Shill's point of view is a Wi-Fi + // network which corresponds to a hotspot for a Tether network, set the + // default network to be the associated Tether network instead. + default_network_path_ = network->tether_guid(); + return; + } } if (network && !network->IsConnectedState()) { if (network->IsConnectingState()) {
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc index ad8af8e..e6c467c0 100644 --- a/chromeos/network/network_state_handler_unittest.cc +++ b/chromeos/network/network_state_handler_unittest.cc
@@ -969,60 +969,268 @@ kTetherGuid1, kWifiGuid1)); } -TEST_F(NetworkStateHandlerTest, SetTetherNetworkStateConnectionState) { +TEST_F(NetworkStateHandlerTest, + SetTetherNetworkStateConnectionState_NoDefaultNetworkToStart) { network_state_handler_->SetTetherTechnologyState( NetworkStateHandler::TECHNOLOGY_ENABLED); + // Disconnect Ethernet and Wi-Fi so that there is no default network. For the + // purpose of this test, the default Wi-Fi network will serve as the Tether + // network's underlying Wi-Fi hotspot. + const std::string eth1 = kShillManagerClientStubDefaultService; + const std::string wifi1 = kShillManagerClientStubDefaultWifi; + service_test_->SetServiceProperty(eth1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(std::string(), test_observer_->default_network()); + + // Simulate a host scan, and reset the change counts for the connection flow. network_state_handler_->AddTetherNetworkState( kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1, kTetherSignalStrength1, kTetherHasConnectedToHost1); + test_observer_->reset_change_counts(); + test_observer_->reset_updates(); - // Add corresponding Wi-Fi network. - const std::string profile = "/profile/profile1"; - const std::string wifi_path = "/service/wifi_with_guid"; - AddService(wifi_path, kWifiGuid1, kWifiName1, shill::kTypeWifi, - shill::kStateOnline); - profile_test_->AddProfile(profile, "" /* userhash */); - EXPECT_TRUE(profile_test_->AddService(profile, wifi_path)); - UpdateManagerProperties(); + // Preconditions. + EXPECT_EQ(0, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(0, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + EXPECT_EQ("", test_observer_->default_network()); + EXPECT_EQ("", test_observer_->default_network_connection_state()); + EXPECT_EQ(nullptr, network_state_handler_->DefaultNetwork()); + + // Set the Tether network state to "connecting." This is expected to be called + // before the connection to the underlying hotspot Wi-Fi network begins. + const NetworkState* tether_network = + network_state_handler_->GetNetworkStateFromGuid(kTetherGuid1); + network_state_handler_->SetTetherNetworkStateConnecting(kTetherGuid1); + EXPECT_TRUE(tether_network->IsConnectingState()); + EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + EXPECT_EQ(tether_network, network_state_handler_->DefaultNetwork()); // Associate Tether and Wi-Fi networks. network_state_handler_->AssociateTetherNetworkStateWithWifiNetwork( - kTetherGuid1, kWifiGuid1); - - EXPECT_EQ(0, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); - EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(kTetherGuid1)); - - const NetworkState* tether_network = - network_state_handler_->GetNetworkStateFromGuid(kTetherGuid1); - - EXPECT_FALSE(tether_network->IsConnectingState()); - EXPECT_FALSE(tether_network->IsConnectedState()); - - network_state_handler_->SetTetherNetworkStateConnecting(kTetherGuid1); - EXPECT_TRUE(tether_network->IsConnectingState()); - + kTetherGuid1, "wifi1_guid"); EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + // Connect to the underlying Wi-Fi network. The default network should not + // change yet. + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateOnline)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + + // Now, set the Tether network state to "connected." This should result in a + // default network change event. network_state_handler_->SetTetherNetworkStateConnected(kTetherGuid1); EXPECT_TRUE(tether_network->IsConnectedState()); - EXPECT_EQ(2, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); EXPECT_EQ(3, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(1u, test_observer_->default_network_change_count()); + EXPECT_EQ(kTetherGuid1, test_observer_->default_network()); + EXPECT_EQ(shill::kStateOnline, + test_observer_->default_network_connection_state()); + EXPECT_EQ(tether_network, network_state_handler_->DefaultNetwork()); - network_state_handler_->SetTetherNetworkStateConnecting(kTetherGuid1); - EXPECT_TRUE(tether_network->IsReconnecting()); + // Disconnect from the underlying Wi-Fi network. The default network should + // not change yet. + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1u, test_observer_->default_network_change_count()); - EXPECT_EQ(3, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); - EXPECT_EQ(4, test_observer_->PropertyUpdatesForService(kTetherGuid1)); - + // Now, set the Tether network state to "disconnected." This should result in + // a default network change event. network_state_handler_->SetTetherNetworkStateDisconnected(kTetherGuid1); EXPECT_FALSE(tether_network->IsConnectingState()); EXPECT_FALSE(tether_network->IsConnectedState()); + EXPECT_EQ(3, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(4, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(2u, test_observer_->default_network_change_count()); + EXPECT_EQ("", test_observer_->default_network()); + EXPECT_EQ("", test_observer_->default_network_connection_state()); + EXPECT_EQ(nullptr, network_state_handler_->DefaultNetwork()); +} - EXPECT_EQ(4, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); - EXPECT_EQ(5, test_observer_->PropertyUpdatesForService(kTetherGuid1)); +TEST_F(NetworkStateHandlerTest, + SetTetherNetworkStateConnectionState_EthernetIsDefaultNetwork) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + + // The ethernet corresponding to |eth1| will be left connected this entire + // test. It should be expected to remain the default network during the Tether + // connection. + const std::string eth1 = kShillManagerClientStubDefaultService; + + // Disconnect the Wi-Fi network, which will serve as the underlying connection + // for the Tether network under test. + const std::string wifi1 = kShillManagerClientStubDefaultWifi; + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(eth1, test_observer_->default_network()); + + // Simulate a host scan, and reset the change counts for the connection flow. + network_state_handler_->AddTetherNetworkState( + kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1, + kTetherSignalStrength1, kTetherHasConnectedToHost1); + test_observer_->reset_change_counts(); + test_observer_->reset_updates(); + + // Preconditions. + EXPECT_EQ(0, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(0, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + EXPECT_EQ(eth1, test_observer_->default_network()); + EXPECT_EQ(shill::kStateOnline, + test_observer_->default_network_connection_state()); + + // Set the Tether network state to "connecting." This is expected to be called + // before the connection to the underlying hotspot Wi-Fi network begins. + const NetworkState* tether_network = + network_state_handler_->GetNetworkStateFromGuid(kTetherGuid1); + network_state_handler_->SetTetherNetworkStateConnecting(kTetherGuid1); + EXPECT_TRUE(tether_network->IsConnectingState()); + EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + + // Associate Tether and Wi-Fi networks. + network_state_handler_->AssociateTetherNetworkStateWithWifiNetwork( + kTetherGuid1, "wifi1_guid"); + EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + + // Connect to the underlying Wi-Fi network. + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateOnline)); + base::RunLoop().RunUntilIdle(); + + // Now, set the Tether network state to "connected." + network_state_handler_->SetTetherNetworkStateConnected(kTetherGuid1); + EXPECT_TRUE(tether_network->IsConnectedState()); + EXPECT_EQ(2, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(3, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + + // Disconnect from the underlying Wi-Fi network. + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + base::RunLoop().RunUntilIdle(); + + // Now, set the Tether network state to "disconnected." + network_state_handler_->SetTetherNetworkStateDisconnected(kTetherGuid1); + EXPECT_FALSE(tether_network->IsConnectingState()); + EXPECT_FALSE(tether_network->IsConnectedState()); + EXPECT_EQ(3, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(4, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + + // The Ethernet network should still be the default network, and no changes + // should have occurred during this test. + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + EXPECT_EQ(eth1, test_observer_->default_network()); + EXPECT_EQ(shill::kStateOnline, + test_observer_->default_network_connection_state()); +} + +TEST_F(NetworkStateHandlerTest, + SetTetherNetworkStateConnectionState_NoDefaultThenTetherThenEthernet) { + network_state_handler_->SetTetherTechnologyState( + NetworkStateHandler::TECHNOLOGY_ENABLED); + + // Disconnect Ethernet and Wi-Fi so that there is no default network. For the + // purpose of this test, the default Wi-Fi network will serve as the Tether + // network's underlying Wi-Fi hotspot. + const std::string eth1 = kShillManagerClientStubDefaultService; + const std::string wifi1 = kShillManagerClientStubDefaultWifi; + service_test_->SetServiceProperty(eth1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(std::string(), test_observer_->default_network()); + + // Simulate a host scan, and reset the change counts for the connection flow. + network_state_handler_->AddTetherNetworkState( + kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1, + kTetherSignalStrength1, kTetherHasConnectedToHost1); + test_observer_->reset_change_counts(); + test_observer_->reset_updates(); + + // Preconditions. + EXPECT_EQ(0, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(0, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + EXPECT_EQ("", test_observer_->default_network()); + EXPECT_EQ("", test_observer_->default_network_connection_state()); + EXPECT_EQ(nullptr, network_state_handler_->DefaultNetwork()); + + // Set the Tether network state to "connecting." This is expected to be called + // before the connection to the underlying hotspot Wi-Fi network begins. + const NetworkState* tether_network = + network_state_handler_->GetNetworkStateFromGuid(kTetherGuid1); + network_state_handler_->SetTetherNetworkStateConnecting(kTetherGuid1); + EXPECT_TRUE(tether_network->IsConnectingState()); + EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + EXPECT_EQ(tether_network, network_state_handler_->DefaultNetwork()); + + // Associate Tether and Wi-Fi networks. + network_state_handler_->AssociateTetherNetworkStateWithWifiNetwork( + kTetherGuid1, "wifi1_guid"); + EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + + // Connect to the underlying Wi-Fi network. The default network should not + // change yet. + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateOnline)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0u, test_observer_->default_network_change_count()); + + // Now, set the Tether network state to "connected." This should result in a + // default network change event. + network_state_handler_->SetTetherNetworkStateConnected(kTetherGuid1); + EXPECT_TRUE(tether_network->IsConnectedState()); + EXPECT_EQ(2, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(3, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(1u, test_observer_->default_network_change_count()); + EXPECT_EQ(kTetherGuid1, test_observer_->default_network()); + EXPECT_EQ(shill::kStateOnline, + test_observer_->default_network_connection_state()); + EXPECT_EQ(tether_network, network_state_handler_->DefaultNetwork()); + + // Now, connect the Ethernet network. This should be the new default network. + service_test_->SetServiceProperty(eth1, shill::kStateProperty, + base::Value(shill::kStateOnline)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, test_observer_->default_network_change_count()); + EXPECT_EQ(eth1, test_observer_->default_network()); + EXPECT_EQ(shill::kStateOnline, + test_observer_->default_network_connection_state()); + + // Disconnect from the underlying Wi-Fi network. The default network should + // still be the Ethernet network. + service_test_->SetServiceProperty(wifi1, shill::kStateProperty, + base::Value(shill::kStateIdle)); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, test_observer_->default_network_change_count()); + + // Now, set the Tether network state to "disconnected." The default network + // should still be the Ethernet network. + network_state_handler_->SetTetherNetworkStateDisconnected(kTetherGuid1); + EXPECT_FALSE(tether_network->IsConnectingState()); + EXPECT_FALSE(tether_network->IsConnectedState()); + EXPECT_EQ(3, test_observer_->ConnectionStateChangesForService(kTetherGuid1)); + EXPECT_EQ(4, test_observer_->PropertyUpdatesForService(kTetherGuid1)); + EXPECT_EQ(2u, test_observer_->default_network_change_count()); + EXPECT_EQ(eth1, test_observer_->default_network()); + EXPECT_EQ(shill::kStateOnline, + test_observer_->default_network_connection_state()); } TEST_F(NetworkStateHandlerTest, NetworkConnectionStateChanged) {
diff --git a/components/crash/content/app/breakpad_win.cc b/components/crash/content/app/breakpad_win.cc index c236230..3324f1f 100644 --- a/components/crash/content/app/breakpad_win.cc +++ b/components/crash/content/app/breakpad_win.cc
@@ -121,41 +121,13 @@ namespace { -// We need to prevent ICF from folding DumpForHangDebuggingThread() and -// DumpProcessWithoutCrashThread() together, since that makes them -// indistinguishable in crash dumps. We do this by making the function -// bodies unique, and prevent optimization from shuffling things around. -MSVC_DISABLE_OPTIMIZE() -MSVC_PUSH_DISABLE_WARNING(4748) - DWORD WINAPI DumpProcessWithoutCrashThread(void*) { DumpProcessWithoutCrash(); return 0; } -// The following two functions do exactly the same thing as the two above. But -// we want the signatures to be different so that we can easily track them in -// crash reports. -// TODO(yzshen): Remove when enough information is collected and the hang rate -// of pepper/renderer processes is reduced. -DWORD WINAPI DumpForHangDebuggingThread(void*) { - DumpProcessWithoutCrash(); - VLOG(1) << "dumped for hang debugging"; - return 0; -} - -MSVC_POP_WARNING() -MSVC_ENABLE_OPTIMIZE() - } // namespace -// Injects a thread into a remote process to dump state when there is no crash. -extern "C" HANDLE __declspec(dllexport) __cdecl InjectDumpProcessWithoutCrash( - HANDLE process) { - return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread, 0, - 0, NULL); -} - extern "C" HANDLE __declspec(dllexport) __cdecl InjectDumpForHungInput( HANDLE process, void* serialized_crash_keys) { @@ -174,12 +146,6 @@ 0, NULL); } -extern "C" HANDLE __declspec(dllexport) __cdecl -InjectDumpForHangDebugging(HANDLE process) { - return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread, - 0, 0, NULL); -} - // Returns a string containing a list of all modifiers for the loaded profile. std::wstring GetProfileType() { std::wstring profile_type;
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc index 6fdfd83d..77ccc323 100644 --- a/components/crash/content/app/crashpad_win.cc +++ b/components/crash/content/app/crashpad_win.cc
@@ -170,21 +170,13 @@ namespace { -// We need to prevent ICF from folding DumpForHangDebuggingThread(), -// DumpProcessForHungInputThread(), DumpProcessForHungInputNoCrashKeysThread() -// and DumpProcessWithoutCrashThread() together, since that makes them +// We need to prevent ICF from folding DumpProcessForHungInputThread(), +// DumpProcessForHungInputNoCrashKeysThread() together, since that makes them // indistinguishable in crash dumps. We do this by making the function // bodies unique, and prevent optimization from shuffling things around. MSVC_DISABLE_OPTIMIZE() MSVC_PUSH_DISABLE_WARNING(4748) -// Note that this function must be in a namespace for the [Renderer hang] -// annotations to work on the crash server. -DWORD WINAPI DumpProcessWithoutCrashThread(void*) { - DumpProcessWithoutCrash(); - return 0; -} - // TODO(dtapuska): Remove when enough information is gathered where the crash // reports without crash keys come from. DWORD WINAPI DumpProcessForHungInputThread(void* crash_keys_str) { @@ -213,14 +205,6 @@ return 0; } -// TODO(yzshen): Remove when enough information is collected and the hang rate -// of pepper/renderer processes is reduced. -DWORD WINAPI DumpForHangDebuggingThread(void*) { - DumpProcessWithoutCrash(); - VLOG(1) << "dumped for hang debugging"; - return 0; -} - MSVC_POP_WARNING() MSVC_ENABLE_OPTIMIZE() @@ -244,15 +228,6 @@ } // Injects a thread into a remote process to dump state when there is no crash. -HANDLE __declspec(dllexport) __cdecl InjectDumpProcessWithoutCrash( - HANDLE process) { - return CreateRemoteThread( - process, nullptr, 0, - crash_reporter::internal::DumpProcessWithoutCrashThread, nullptr, 0, - nullptr); -} - -// Injects a thread into a remote process to dump state when there is no crash. // |serialized_crash_keys| is a nul terminated string that represents serialized // crash keys sent from the browser. Keys and values are separated by ':', and // key/value pairs are separated by ','. All keys should be previously @@ -278,13 +253,6 @@ reinterpret_cast<void*>(reason), 0, nullptr); } -HANDLE __declspec(dllexport) __cdecl InjectDumpForHangDebugging( - HANDLE process) { - return CreateRemoteThread( - process, nullptr, 0, crash_reporter::internal::DumpForHangDebuggingThread, - 0, 0, nullptr); -} - #if defined(ARCH_CPU_X86_64) static int CrashForExceptionInNonABICompliantCodeRange(
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc index 663aa6e..ace2c7d 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -101,6 +101,10 @@ ActivationLevel::ENABLED); } +bool ContentSubresourceFilterDriverFactory::AllowStrongPopupBlocking() { + return activation_options_.should_strengthen_popup_blocker; +} + void ContentSubresourceFilterDriverFactory::DidStartNavigation( content::NavigationHandle* navigation_handle) { if (navigation_handle->IsInMainFrame() &&
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h index bbb2d6b..aafc7dd 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h +++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -69,6 +69,7 @@ // ContentSubresourceFilterThrottleManager::Delegate: void OnFirstSubresourceLoadDisallowed() override; + bool AllowStrongPopupBlocking() override; ContentSubresourceFilterThrottleManager* throttle_manager() { return throttle_manager_.get();
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc index e4cc209..6c1cff4 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc +++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -27,6 +27,11 @@ namespace subresource_filter { +bool ContentSubresourceFilterThrottleManager::Delegate:: + AllowStrongPopupBlocking() { + return false; +} + ContentSubresourceFilterThrottleManager:: ContentSubresourceFilterThrottleManager( Delegate* delegate, @@ -210,7 +215,8 @@ // subresource filter specific UI here. return state.activation_level == ActivationLevel::ENABLED && !state.filtering_disabled_for_document && - !state.generic_blocking_rules_disabled; + !state.generic_blocking_rules_disabled && + delegate_->AllowStrongPopupBlocking(); } std::unique_ptr<SubframeNavigationFilteringThrottle>
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h index 4240c57..7bde89b 100644 --- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h +++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -57,6 +57,7 @@ // The embedder may be interested in displaying UI to the user when the // first load is disallowed for a given page load. virtual void OnFirstSubresourceLoadDisallowed() {} + virtual bool AllowStrongPopupBlocking(); }; ContentSubresourceFilterThrottleManager(
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc index 6621c92..a1ca0b6 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -172,6 +172,10 @@ ParseBool(TakeVariationParamOrReturnEmpty( params, kWhitelistSiteOnReloadParameterName)); + configuration.activation_options.should_strengthen_popup_blocker = + ParseBool(TakeVariationParamOrReturnEmpty( + params, kStrengthenPopupBlockerParameterName)); + // GeneralSettings: configuration.general_settings.ruleset_flavor = TakeVariationParamOrReturnEmpty(params, kRulesetFlavorParameterName); @@ -259,6 +263,7 @@ "performance_measurement_rate"; const char kSuppressNotificationsParameterName[] = "suppress_notifications"; const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload"; +const char kStrengthenPopupBlockerParameterName[] = "strengthen_popup_blocker"; const char kRulesetFlavorParameterName[] = "ruleset_flavor"; @@ -310,6 +315,7 @@ config.activation_options.performance_measurement_rate, config.activation_options.should_whitelist_site_on_reload, config.activation_options.should_suppress_notifications, + config.activation_options.should_strengthen_popup_blocker, config.general_settings.ruleset_flavor); }; return tie(*this) == tie(rhs); @@ -335,6 +341,8 @@ activation_options.should_suppress_notifications); value->SetBoolean("should_whitelist_site_on_reload", activation_options.should_whitelist_site_on_reload); + value->SetBoolean("should_strengthen_popup_blocker", + activation_options.should_strengthen_popup_blocker); value->SetString("ruleset_flavor", StreamToString(general_settings.ruleset_flavor)); return value;
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.h b/components/subresource_filter/core/browser/subresource_filter_features.h index a828a4e..7fc4dca 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features.h +++ b/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -83,6 +83,9 @@ // Whether to whitelist a site when a page loaded from that site is // reloaded. bool should_whitelist_site_on_reload = false; + + // Whether to apply a more powerful popup blocker on pages with activation. + bool should_strengthen_popup_blocker = false; }; // General settings that apply outside of the scope of a navigation. @@ -201,6 +204,8 @@ extern const char kWhitelistSiteOnReloadParameterName[]; +extern const char kStrengthenPopupBlockerParameterName[]; + extern const char kRulesetFlavorParameterName[]; extern const char kEnablePresetsParameterName[];
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc index 6b7263d..5ab04be 100644 --- a/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc +++ b/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -428,6 +428,40 @@ } } +TEST(SubresourceFilterFeaturesTest, StrengthenPopupBlocker) { + const struct { + bool feature_enabled; + const char* strengthen_popup_blocker_param; + bool expected_strengthen_popup_blocker_value; + } kTestCases[] = {{false, "", false}, + {false, "true", false}, + {false, "false", false}, + {false, "invalid value", false}, + {true, "", false}, + {true, "false", false}, + {true, "invalid value", false}, + {true, "True", true}, + {true, "TRUE", true}, + {true, "true", true}}; + for (const auto& test_case : kTestCases) { + SCOPED_TRACE(::testing::Message("Enabled = ") << test_case.feature_enabled); + SCOPED_TRACE(::testing::Message("StrengthenPopupBlockerParam = \"") + << test_case.strengthen_popup_blocker_param << "\""); + + ScopedExperimentalStateToggle scoped_experimental_state( + test_case.feature_enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE + : base::FeatureList::OVERRIDE_USE_DEFAULT, + {{kStrengthenPopupBlockerParameterName, + test_case.strengthen_popup_blocker_param}}); + + Configuration actual_configuration; + ExpectAndRetrieveExactlyOneEnabledConfig(&actual_configuration); + EXPECT_EQ(test_case.expected_strengthen_popup_blocker_value, + actual_configuration.activation_options + .should_strengthen_popup_blocker); + } +} + TEST(SubresourceFilterFeaturesTest, RulesetFlavor) { const struct { bool feature_enabled;
diff --git a/content/browser/presentation/presentation_service_impl.h b/content/browser/presentation/presentation_service_impl.h index 5b63387..d23ad25 100644 --- a/content/browser/presentation/presentation_service_impl.h +++ b/content/browser/presentation/presentation_service_impl.h
@@ -65,40 +65,44 @@ const service_manager::BindSourceInfo& source_info, mojo::InterfaceRequest<blink::mojom::PresentationService> request); + // PresentationService implementation. + void SetDefaultPresentationUrls( + const std::vector<GURL>& presentation_urls) override; + void SetClient(blink::mojom::PresentationServiceClientPtr client) override; + void ListenForScreenAvailability(const GURL& url) override; + void StopListeningForScreenAvailability(const GURL& url) override; + void StartPresentation(const std::vector<GURL>& presentation_urls, + NewPresentationCallback callback) override; + void ReconnectPresentation(const std::vector<GURL>& presentation_urls, + const base::Optional<std::string>& presentation_id, + NewPresentationCallback callback) override; + void CloseConnection(const GURL& presentation_url, + const std::string& presentation_id) override; + void Terminate(const GURL& presentation_url, + const std::string& presentation_id) override; + void ListenForConnectionMessages( + const PresentationInfo& presentation_info) override; + void SetPresentationConnection( + const PresentationInfo& presentation_info, + blink::mojom::PresentationConnectionPtr controller_connection_ptr, + blink::mojom::PresentationConnectionRequest receiver_connection_request) + override; + private: friend class PresentationServiceImplTest; FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, Reset); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DidNavigateThisFrame); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - DidNavigateOtherFrame); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ThisRenderFrameDeleted); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, OtherRenderFrameDeleted); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DelegateFails); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - SetDefaultPresentationUrls); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - SetSameDefaultPresentationUrls); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - ClearDefaultPresentationUrls); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - ListenForDefaultPresentationStart); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - ListenForDefaultPresentationStartAfterSet); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - DefaultPresentationStartReset); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - ReceiveConnectionMessagesAfterReset); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - MaxPendingStartPresentationRequests); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - MaxPendingReconnectPresentationRequests); - FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ListenForConnectionStateChange); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ListenForConnectionClose); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, - SetPresentationConnection); + MaxPendingStartPresentationRequests); + FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, + MaxPendingReconnectPresentationRequests); FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ReceiverPresentationServiceDelegate); @@ -159,29 +163,6 @@ ControllerPresentationServiceDelegate* controller_delegate, ReceiverPresentationServiceDelegate* receiver_delegate); - // PresentationService implementation. - void SetDefaultPresentationUrls( - const std::vector<GURL>& presentation_urls) override; - void SetClient(blink::mojom::PresentationServiceClientPtr client) override; - void ListenForScreenAvailability(const GURL& url) override; - void StopListeningForScreenAvailability(const GURL& url) override; - void StartPresentation(const std::vector<GURL>& presentation_urls, - NewPresentationCallback callback) override; - void ReconnectPresentation(const std::vector<GURL>& presentation_urls, - const base::Optional<std::string>& presentation_id, - NewPresentationCallback callback) override; - void CloseConnection(const GURL& presentation_url, - const std::string& presentation_id) override; - void Terminate(const GURL& presentation_url, - const std::string& presentation_id) override; - void ListenForConnectionMessages( - const PresentationInfo& presentation_info) override; - void SetPresentationConnection( - const PresentationInfo& presentation_info, - blink::mojom::PresentationConnectionPtr controller_connection_ptr, - blink::mojom::PresentationConnectionRequest receiver_connection_request) - override; - // Creates a binding between this object and |request|. void Bind(blink::mojom::PresentationServiceRequest request);
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc index f6937ca5..fe47a55 100644 --- a/content/browser/presentation/presentation_service_impl_unittest.cc +++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -13,11 +13,8 @@ #include <utility> #include <vector> -#include "base/location.h" #include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/test/test_timeouts.h" -#include "base/threading/thread_task_runner_handle.h" +#include "base/test/mock_callback.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/presentation_service_delegate.h" #include "content/public/common/presentation_connection_message.h" @@ -29,19 +26,25 @@ #include "testing/gmock/include/gmock/gmock.h" using ::testing::_; -using ::testing::ByRef; using ::testing::Eq; -using ::testing::Invoke; -using ::testing::InvokeWithoutArgs; using ::testing::Mock; using ::testing::Return; using ::testing::SaveArg; -using ::testing::WithArgs; +using NewPresentationCallback = + content::PresentationServiceImpl::NewPresentationCallback; namespace content { namespace { +MATCHER(OptionalIsNotNull, "") { + return !!arg; +} + +MATCHER(OptionalIsNull, "") { + return !arg; +} + // Matches content::PresentationInfo. MATCHER_P(InfoEquals, expected, "") { return expected.presentation_url == arg.presentation_url && @@ -247,13 +250,11 @@ // when AppendChild is called. NavigateAndCommit(GURL("about:blank")); - auto request = mojo::MakeRequest(&service_ptr_); EXPECT_CALL(mock_delegate_, AddObserver(_, _, _)).Times(1); TestRenderFrameHost* render_frame_host = contents()->GetMainFrame(); render_frame_host->InitializeRenderFrameIfNeeded(); service_impl_.reset(new PresentationServiceImpl( render_frame_host, contents(), &mock_delegate_, nullptr)); - service_impl_->Bind(std::move(request)); blink::mojom::PresentationServiceClientPtr client_ptr; client_binding_.reset( @@ -266,7 +267,6 @@ } void TearDown() override { - service_ptr_.reset(); if (service_impl_.get()) { EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1); service_impl_.reset(); @@ -287,49 +287,25 @@ void ListenForScreenAvailabilityAndWait(const GURL& url, bool delegate_success) { - base::RunLoop run_loop; - // This will call to |service_impl_| via mojo. Process the message - // using RunLoop. - // The callback shouldn't be invoked since there is no availability - // result yet. EXPECT_CALL(mock_delegate_, AddScreenAvailabilityListener()) - .WillOnce(DoAll( - InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit), - Return(delegate_success))); - service_ptr_->ListenForScreenAvailability(url); - run_loop.Run(); + .WillOnce(Return(delegate_success)); + service_impl_->ListenForScreenAvailability(url); EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_delegate_)); } - void RunLoopFor(base::TimeDelta duration) { - base::RunLoop run_loop; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, run_loop.QuitClosure(), duration); - run_loop.Run(); - } - - void SaveQuitClosureAndRunLoop() { - base::RunLoop run_loop; - run_loop_quit_closure_ = run_loop.QuitClosure(); - run_loop.Run(); - run_loop_quit_closure_.Reset(); - } - void SimulateScreenAvailabilityChangeAndWait(const GURL& url, bool available) { auto listener_it = service_impl_->screen_availability_listeners_.find(url); ASSERT_TRUE(listener_it->second); - base::RunLoop run_loop; blink::mojom::ScreenAvailability expected_availability = available ? blink::mojom::ScreenAvailability::AVAILABLE : blink::mojom::ScreenAvailability::UNAVAILABLE; EXPECT_CALL(mock_client_, - OnScreenAvailabilityUpdated(url, expected_availability)) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); + OnScreenAvailabilityUpdated(url, expected_availability)); listener_it->second->OnScreenAvailabilityChanged(available); - run_loop.Run(); + base::RunLoop().RunUntilIdle(); } void ExpectReset() { @@ -343,44 +319,15 @@ service_impl_->screen_availability_listeners_.end()); } - void ExpectNewPresentationCallbackSuccess( - const base::Optional<PresentationInfo>& info, - const base::Optional<PresentationError>& error) { - EXPECT_TRUE(info); - EXPECT_FALSE(error); - if (!run_loop_quit_closure_.is_null()) - run_loop_quit_closure_.Run(); - } - - void ExpectNewPresentationCallbackError( - const base::Optional<PresentationInfo>& info, - const base::Optional<PresentationError>& error) { - EXPECT_FALSE(info); - EXPECT_TRUE(error); - if (!run_loop_quit_closure_.is_null()) - run_loop_quit_closure_.Run(); - } - - void ExpectConnectionMessages( - const std::vector<PresentationConnectionMessage>& expected_msgs, - const std::vector<PresentationConnectionMessage>& actual_msgs) { - EXPECT_EQ(expected_msgs.size(), actual_msgs.size()); - for (size_t i = 0; i < actual_msgs.size(); ++i) - EXPECT_EQ(expected_msgs[i], actual_msgs[i]); - } - MockPresentationServiceDelegate mock_delegate_; MockReceiverPresentationServiceDelegate mock_receiver_delegate_; std::unique_ptr<PresentationServiceImpl> service_impl_; - mojo::InterfacePtr<blink::mojom::PresentationService> service_ptr_; MockPresentationServiceClient mock_client_; std::unique_ptr<mojo::Binding<blink::mojom::PresentationServiceClient>> client_binding_; - base::Closure run_loop_quit_closure_; - GURL presentation_url1_; GURL presentation_url2_; GURL presentation_url3_; @@ -395,6 +342,14 @@ SimulateScreenAvailabilityChangeAndWait(presentation_url1_, true); } +TEST_F(PresentationServiceImplTest, ScreenAvailabilityNotSupported) { + mock_delegate_.set_screen_availability_listening_supported(false); + EXPECT_CALL(mock_client_, + OnScreenAvailabilityNotSupported(presentation_url1_)); + ListenForScreenAvailabilityAndWait(presentation_url1_, false); + base::RunLoop().RunUntilIdle(); +} + TEST_F(PresentationServiceImplTest, Reset) { ListenForScreenAvailabilityAndWait(presentation_url1_, true); @@ -429,14 +384,17 @@ // Since the frame matched the service, |service_impl_| will be deleted. PresentationServiceImpl* service = service_impl_.release(); EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1); - service->RenderFrameDeleted(contents()->GetMainFrame()); + service->RenderFrameDeleted(main_rfh()); } TEST_F(PresentationServiceImplTest, OtherRenderFrameDeleted) { ListenForScreenAvailabilityAndWait(presentation_url1_, true); - // TODO(imcheng): How to get a different RenderFrameHost? - service_impl_->RenderFrameDeleted(nullptr); + // Create a new frame and RFH. + RenderFrameHost* rfh = main_rfh(); + RenderFrameHostTester* rfh_tester = RenderFrameHostTester::For(rfh); + rfh = rfh_tester->AppendChild("subframe"); + service_impl_->RenderFrameDeleted(rfh); // Availability is reported and callback should be invoked since listener // has not been deleted. @@ -446,8 +404,8 @@ TEST_F(PresentationServiceImplTest, DelegateFails) { ListenForScreenAvailabilityAndWait(presentation_url1_, false); ASSERT_EQ( - service_impl_->screen_availability_listeners_.find(presentation_url1_), - service_impl_->screen_availability_listeners_.end()); + service_impl_->screen_availability_listeners_.end(), + service_impl_->screen_availability_listeners_.find(presentation_url1_)); } TEST_F(PresentationServiceImplTest, SetDefaultPresentationUrls) { @@ -468,13 +426,11 @@ PresentationInfo presentation_info(presentation_url2_, kPresentationId); - base::RunLoop run_loop; EXPECT_CALL(mock_client_, - OnDefaultPresentationStarted(InfoEquals(presentation_info))) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); + OnDefaultPresentationStarted(InfoEquals(presentation_info))); EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _)); callback.Run(PresentationInfo(presentation_url2_, kPresentationId)); - run_loop.Run(); + base::RunLoop().RunUntilIdle(); } TEST_F(PresentationServiceImplTest, ListenForConnectionStateChange) { @@ -487,16 +443,12 @@ .WillOnce(SaveArg<3>(&state_changed_cb)); service_impl_->ListenForConnectionStateChange(connection); - { - base::RunLoop run_loop; - EXPECT_CALL(mock_client_, OnConnectionStateChanged( - InfoEquals(presentation_connection), - PRESENTATION_CONNECTION_STATE_TERMINATED)) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); - state_changed_cb.Run(PresentationConnectionStateChangeInfo( - PRESENTATION_CONNECTION_STATE_TERMINATED)); - run_loop.Run(); - } + EXPECT_CALL(mock_client_, OnConnectionStateChanged( + InfoEquals(presentation_connection), + PRESENTATION_CONNECTION_STATE_TERMINATED)); + state_changed_cb.Run(PresentationConnectionStateChangeInfo( + PRESENTATION_CONNECTION_STATE_TERMINATED)); + base::RunLoop().RunUntilIdle(); } TEST_F(PresentationServiceImplTest, ListenForConnectionClose) { @@ -509,21 +461,17 @@ // Trigger connection close. It should be propagated back up to // |mock_client_|. PresentationInfo presentation_connection(presentation_url1_, kPresentationId); - { - base::RunLoop run_loop; - PresentationConnectionStateChangeInfo closed_info( - PRESENTATION_CONNECTION_STATE_CLOSED); - closed_info.close_reason = PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY; - closed_info.message = "Foo"; + PresentationConnectionStateChangeInfo closed_info( + PRESENTATION_CONNECTION_STATE_CLOSED); + closed_info.close_reason = PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY; + closed_info.message = "Foo"; - EXPECT_CALL(mock_client_, - OnConnectionClosed( - InfoEquals(presentation_connection), - PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY, "Foo")) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); - state_changed_cb.Run(closed_info); - run_loop.Run(); - } + EXPECT_CALL(mock_client_, + OnConnectionClosed(InfoEquals(presentation_connection), + PRESENTATION_CONNECTION_CLOSE_REASON_WENT_AWAY, + "Foo")); + state_changed_cb.Run(closed_info); + base::RunLoop().RunUntilIdle(); } TEST_F(PresentationServiceImplTest, SetSameDefaultPresentationUrls) { @@ -539,92 +487,107 @@ } TEST_F(PresentationServiceImplTest, StartPresentationSuccess) { - service_ptr_->StartPresentation( - presentation_urls_, - base::Bind( - &PresentationServiceImplTest::ExpectNewPresentationCallbackSuccess, - base::Unretained(this))); - base::RunLoop run_loop; + base::MockCallback<NewPresentationCallback> mock_presentation_cb; base::Callback<void(const PresentationInfo&)> success_cb; EXPECT_CALL(mock_delegate_, StartPresentation(_, _, presentation_urls_, _, _)) - .WillOnce(DoAll(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit), - SaveArg<3>(&success_cb))); - run_loop.Run(); - + .WillOnce(SaveArg<3>(&success_cb)); + service_impl_->StartPresentation(presentation_urls_, + mock_presentation_cb.Get()); + EXPECT_FALSE(success_cb.is_null()); EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _)) .Times(1); + EXPECT_CALL(mock_presentation_cb, Run(OptionalIsNotNull(), OptionalIsNull())); success_cb.Run(PresentationInfo(presentation_url1_, kPresentationId)); - SaveQuitClosureAndRunLoop(); } TEST_F(PresentationServiceImplTest, StartPresentationError) { - service_ptr_->StartPresentation( - presentation_urls_, - base::Bind( - &PresentationServiceImplTest::ExpectNewPresentationCallbackError, - base::Unretained(this))); - base::RunLoop run_loop; + base::MockCallback<NewPresentationCallback> mock_presentation_cb; base::Callback<void(const PresentationError&)> error_cb; EXPECT_CALL(mock_delegate_, StartPresentation(_, _, presentation_urls_, _, _)) - .WillOnce(DoAll(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit), - SaveArg<4>(&error_cb))); - run_loop.Run(); + .WillOnce(SaveArg<4>(&error_cb)); + service_impl_->StartPresentation(presentation_urls_, + mock_presentation_cb.Get()); + EXPECT_FALSE(error_cb.is_null()); + EXPECT_CALL(mock_presentation_cb, Run(OptionalIsNull(), OptionalIsNotNull())); error_cb.Run(PresentationError(PRESENTATION_ERROR_UNKNOWN, "Error message")); - SaveQuitClosureAndRunLoop(); +} + +TEST_F(PresentationServiceImplTest, StartPresentationInProgress) { + EXPECT_CALL(mock_delegate_, StartPresentation(_, _, presentation_urls_, _, _)) + .Times(1); + // Uninvoked callbacks must outlive |service_impl_| since they get invoked + // at |service_impl_|'s destruction. + service_impl_->StartPresentation(presentation_urls_, base::Bind(&DoNothing)); + + // This request should fail immediately, since there is already a + // StartPresentation in progress. + base::MockCallback<NewPresentationCallback> mock_presentation_cb; + EXPECT_CALL(mock_presentation_cb, Run(OptionalIsNull(), OptionalIsNotNull())); + service_impl_->StartPresentation(presentation_urls_, + mock_presentation_cb.Get()); } TEST_F(PresentationServiceImplTest, ReconnectPresentationSuccess) { - service_ptr_->ReconnectPresentation( - presentation_urls_, base::Optional<std::string>(kPresentationId), - base::Bind( - &PresentationServiceImplTest::ExpectNewPresentationCallbackSuccess, - base::Unretained(this))); - base::RunLoop run_loop; + base::MockCallback<NewPresentationCallback> mock_presentation_cb; base::Callback<void(const PresentationInfo&)> success_cb; EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, _, presentation_urls_, kPresentationId, _, _)) - .WillOnce(DoAll(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit), - SaveArg<4>(&success_cb))); - run_loop.Run(); - + .WillOnce(SaveArg<4>(&success_cb)); + service_impl_->ReconnectPresentation( + presentation_urls_, base::Optional<std::string>(kPresentationId), + mock_presentation_cb.Get()); + EXPECT_FALSE(success_cb.is_null()); EXPECT_CALL(mock_delegate_, ListenForConnectionStateChange(_, _, _, _)) .Times(1); + EXPECT_CALL(mock_presentation_cb, Run(OptionalIsNotNull(), OptionalIsNull())); success_cb.Run(PresentationInfo(presentation_url1_, kPresentationId)); - SaveQuitClosureAndRunLoop(); } TEST_F(PresentationServiceImplTest, ReconnectPresentationError) { - service_ptr_->ReconnectPresentation( - presentation_urls_, base::Optional<std::string>(kPresentationId), - base::Bind( - &PresentationServiceImplTest::ExpectNewPresentationCallbackError, - base::Unretained(this))); - base::RunLoop run_loop; + base::MockCallback<NewPresentationCallback> mock_presentation_cb; base::Callback<void(const PresentationError&)> error_cb; EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, _, presentation_urls_, kPresentationId, _, _)) - .WillOnce(DoAll(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit), - SaveArg<5>(&error_cb))); - run_loop.Run(); + .WillOnce(SaveArg<5>(&error_cb)); + service_impl_->ReconnectPresentation( + presentation_urls_, base::Optional<std::string>(kPresentationId), + mock_presentation_cb.Get()); + EXPECT_FALSE(error_cb.is_null()); + EXPECT_CALL(mock_presentation_cb, Run(OptionalIsNull(), OptionalIsNotNull())); error_cb.Run(PresentationError(PRESENTATION_ERROR_UNKNOWN, "Error message")); - SaveQuitClosureAndRunLoop(); +} + +TEST_F(PresentationServiceImplTest, MaxPendingReconnectPresentationRequests) { + const char* presentation_url = "http://fooUrl%d"; + const char* presentation_id = "presentationId%d"; + int num_requests = PresentationServiceImpl::kMaxQueuedRequests; + int i = 0; + EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, _, _, _, _, _)) + .Times(num_requests); + for (; i < num_requests; ++i) { + std::vector<GURL> urls = {GURL(base::StringPrintf(presentation_url, i))}; + // Uninvoked callbacks must outlive |service_impl_| since they get invoked + // at |service_impl_|'s destruction. + service_impl_->ReconnectPresentation( + urls, base::StringPrintf(presentation_id, i), base::Bind(&DoNothing)); + } + + std::vector<GURL> urls = {GURL(base::StringPrintf(presentation_url, i))}; + // Exceeded maximum queue size, should invoke mojo callback with error. + base::MockCallback<NewPresentationCallback> mock_presentation_cb; + EXPECT_CALL(mock_presentation_cb, Run(OptionalIsNull(), OptionalIsNotNull())); + service_impl_->ReconnectPresentation( + urls, base::StringPrintf(presentation_id, i), mock_presentation_cb.Get()); } TEST_F(PresentationServiceImplTest, CloseConnection) { - service_ptr_->CloseConnection(presentation_url1_, kPresentationId); - - base::RunLoop run_loop; - EXPECT_CALL(mock_delegate_, CloseConnection(_, _, Eq(kPresentationId))) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); - run_loop.Run(); + EXPECT_CALL(mock_delegate_, CloseConnection(_, _, Eq(kPresentationId))); + service_impl_->CloseConnection(presentation_url1_, kPresentationId); } TEST_F(PresentationServiceImplTest, Terminate) { - service_ptr_->Terminate(presentation_url1_, kPresentationId); - base::RunLoop run_loop; - EXPECT_CALL(mock_delegate_, Terminate(_, _, Eq(kPresentationId))) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); - run_loop.Run(); + EXPECT_CALL(mock_delegate_, Terminate(_, _, Eq(kPresentationId))); + service_impl_->Terminate(presentation_url1_, kPresentationId); } TEST_F(PresentationServiceImplTest, SetPresentationConnection) { @@ -647,9 +610,10 @@ TEST_F(PresentationServiceImplTest, ReceiverPresentationServiceDelegate) { MockReceiverPresentationServiceDelegate mock_receiver_delegate; + EXPECT_CALL(mock_receiver_delegate, AddObserver(_, _, _)).Times(1); - PresentationServiceImpl service_impl(contents()->GetMainFrame(), contents(), - nullptr, &mock_receiver_delegate); + PresentationServiceImpl service_impl(main_rfh(), contents(), nullptr, + &mock_receiver_delegate); ReceiverConnectionAvailableCallback callback; EXPECT_CALL(mock_receiver_delegate, @@ -665,58 +629,23 @@ EXPECT_FALSE(callback.is_null()); // NO-OP for ControllerPresentationServiceDelegate API functions - EXPECT_CALL(mock_delegate_, ListenForConnectionMessages(_, _, _, _)).Times(0); - PresentationInfo presentation_info(presentation_url1_, kPresentationId); + EXPECT_CALL(mock_delegate_, ListenForConnectionMessages(_, _, _, _)).Times(0); service_impl.ListenForConnectionMessages(presentation_info); -} -TEST_F(PresentationServiceImplTest, StartPresentationInProgress) { - EXPECT_CALL(mock_delegate_, StartPresentation(_, _, presentation_urls_, _, _)) - .Times(1); - service_ptr_->StartPresentation(presentation_urls_, base::Bind(&DoNothing)); - - // This request should fail immediately, since there is already a - // StartPresentation in progress. - service_ptr_->StartPresentation( - presentation_urls_, - base::Bind( - &PresentationServiceImplTest::ExpectNewPresentationCallbackError, - base::Unretained(this))); - SaveQuitClosureAndRunLoop(); -} - -TEST_F(PresentationServiceImplTest, MaxPendingReconnectPresentationRequests) { - const char* presentation_url = "http://fooUrl%d"; - const char* presentation_id = "presentationId%d"; - int num_requests = PresentationServiceImpl::kMaxQueuedRequests; - int i = 0; - EXPECT_CALL(mock_delegate_, ReconnectPresentation(_, _, _, _, _, _)) - .Times(num_requests); - for (; i < num_requests; ++i) { - std::vector<GURL> urls = {GURL(base::StringPrintf(presentation_url, i))}; - service_ptr_->ReconnectPresentation( - urls, base::StringPrintf(presentation_id, i), base::Bind(&DoNothing)); - } - - std::vector<GURL> urls = {GURL(base::StringPrintf(presentation_url, i))}; - // Exceeded maximum queue size, should invoke mojo callback with error. - service_ptr_->ReconnectPresentation( - urls, base::StringPrintf(presentation_id, i), - base::Bind( - &PresentationServiceImplTest::ExpectNewPresentationCallbackError, - base::Unretained(this))); - SaveQuitClosureAndRunLoop(); -} - -TEST_F(PresentationServiceImplTest, ScreenAvailabilityNotSupported) { - mock_delegate_.set_screen_availability_listening_supported(false); - base::RunLoop run_loop; + // Client gets notified of receiver connections. + blink::mojom::PresentationConnectionPtr controller_connection; + MockPresentationConnection mock_presentation_connection; + mojo::Binding<blink::mojom::PresentationConnection> connection_binding( + &mock_presentation_connection, mojo::MakeRequest(&controller_connection)); + blink::mojom::PresentationConnectionPtr receiver_connection; EXPECT_CALL(mock_client_, - OnScreenAvailabilityNotSupported(presentation_url1_)) - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit)); - ListenForScreenAvailabilityAndWait(presentation_url1_, false); - run_loop.Run(); + OnReceiverConnectionAvailable(InfoEquals(presentation_info))); + callback.Run(presentation_info, std::move(controller_connection), + mojo::MakeRequest(&receiver_connection)); + base::RunLoop().RunUntilIdle(); + + EXPECT_CALL(mock_receiver_delegate, RemoveObserver(_, _)).Times(1); } } // namespace content
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc index 2e4fe72..3c1bc45 100644 --- a/content/browser/tracing/background_tracing_manager_impl.cc +++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -17,6 +17,7 @@ #include "base/time/time.h" #include "content/browser/tracing/background_memory_tracing_observer.h" #include "content/browser/tracing/background_tracing_rule.h" +#include "content/browser/tracing/trace_message_filter.h" #include "content/browser/tracing/tracing_controller_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" @@ -189,7 +190,7 @@ } // Notify observers before starting tracing. - for (auto* observer : background_tracing_observer_list_) + for (auto* observer : background_tracing_observers_) observer->OnScenarioActivated(config_.get()); StartTracingIfConfigNeedsIt(); @@ -203,25 +204,57 @@ void BackgroundTracingManagerImpl::OnStartTracingDone( BackgroundTracingConfigImpl::CategoryPreset preset) { - DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - for (auto* observer : background_tracing_observer_list_) + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + for (auto* observer : background_tracing_observers_) observer->OnTracingEnabled(preset); } void BackgroundTracingManagerImpl::AddEnabledStateObserver( EnabledStateObserver* observer) { - DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - background_tracing_observer_list_.push_back(observer); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + background_tracing_observers_.insert(observer); } void BackgroundTracingManagerImpl::RemoveEnabledStateObserver( EnabledStateObserver* observer) { - DCHECK(BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - std::vector<EnabledStateObserver*>::iterator it = - std::find(background_tracing_observer_list_.begin(), - background_tracing_observer_list_.end(), observer); - if (it != background_tracing_observer_list_.end()) - background_tracing_observer_list_.erase(it); + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + background_tracing_observers_.erase(observer); +} + +void BackgroundTracingManagerImpl::AddTraceMessageFilter( + TraceMessageFilter* trace_message_filter) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + trace_message_filters_.insert(trace_message_filter); + + for (auto* observer : trace_message_filter_observers_) + observer->OnTraceMessageFilterAdded(trace_message_filter); +} + +void BackgroundTracingManagerImpl::RemoveTraceMessageFilter( + TraceMessageFilter* trace_message_filter) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + for (auto* observer : trace_message_filter_observers_) + observer->OnTraceMessageFilterRemoved(trace_message_filter); + + trace_message_filters_.erase(trace_message_filter); +} + +void BackgroundTracingManagerImpl::AddTraceMessageFilterObserver( + TraceMessageFilterObserver* observer) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + trace_message_filter_observers_.insert(observer); + + for (auto& filter : trace_message_filters_) + observer->OnTraceMessageFilterAdded(filter.get()); +} + +void BackgroundTracingManagerImpl::RemoveTraceMessageFilterObserver( + TraceMessageFilterObserver* observer) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + trace_message_filter_observers_.erase(observer); + + for (auto& filter : trace_message_filters_) + observer->OnTraceMessageFilterRemoved(filter.get()); } bool BackgroundTracingManagerImpl::IsTracingForTesting() {
diff --git a/content/browser/tracing/background_tracing_manager_impl.h b/content/browser/tracing/background_tracing_manager_impl.h index 4e329a3f..d1625be 100644 --- a/content/browser/tracing/background_tracing_manager_impl.h +++ b/content/browser/tracing/background_tracing_manager_impl.h
@@ -5,7 +5,10 @@ #ifndef CONTENT_BROWSER_TRACING_BACKGROUND_TRACING_MANAGER_IMPL_H_ #define CONTENT_BROWSER_TRACING_BACKGROUND_TRACING_MANAGER_IMPL_H_ +#include <map> #include <memory> +#include <set> +#include <string> #include "base/lazy_instance.h" #include "base/macros.h" @@ -19,6 +22,7 @@ namespace content { class BackgroundTracingRule; +class TraceMessageFilter; class TracingDelegate; class BackgroundTracingManagerImpl : public BackgroundTracingManager { @@ -40,6 +44,12 @@ virtual ~EnabledStateObserver() = default; }; + class TraceMessageFilterObserver { + public: + virtual void OnTraceMessageFilterAdded(TraceMessageFilter* filter) = 0; + virtual void OnTraceMessageFilterRemoved(TraceMessageFilter* filter) = 0; + }; + CONTENT_EXPORT static BackgroundTracingManagerImpl* GetInstance(); bool SetActiveScenario(std::unique_ptr<BackgroundTracingConfig>, @@ -64,6 +74,12 @@ CONTENT_EXPORT void RemoveEnabledStateObserver( EnabledStateObserver* observer); + // Add/remove TraceMessageFilter{Observer}. + void AddTraceMessageFilter(TraceMessageFilter* trace_message_filter); + void RemoveTraceMessageFilter(TraceMessageFilter* trace_message_filter); + void AddTraceMessageFilterObserver(TraceMessageFilterObserver* observer); + void RemoveTraceMessageFilterObserver(TraceMessageFilterObserver* observer); + // For tests void InvalidateTriggerHandlesForTesting() override; CONTENT_EXPORT void SetRuleTriggeredCallbackForTesting( @@ -125,7 +141,12 @@ TriggerHandle triggered_named_event_handle_; - std::vector<EnabledStateObserver*> background_tracing_observer_list_; + // There is no need to use base::ObserverList to store observers because we + // only access |background_tracing_observers_| and + // |trace_message_filter_observers_| from the UI thread. + std::set<EnabledStateObserver*> background_tracing_observers_; + std::set<scoped_refptr<TraceMessageFilter>> trace_message_filters_; + std::set<TraceMessageFilterObserver*> trace_message_filter_observers_; IdleCallback idle_callback_; base::Closure tracing_enabled_callback_for_testing_;
diff --git a/content/browser/tracing/background_tracing_rule.cc b/content/browser/tracing/background_tracing_rule.cc index 527d64a..3d339f0c 100644 --- a/content/browser/tracing/background_tracing_rule.cc +++ b/content/browser/tracing/background_tracing_rule.cc
@@ -141,8 +141,9 @@ std::string named_event_; }; -class HistogramRule : public BackgroundTracingRule, - public TracingControllerImpl::TraceMessageFilterObserver { +class HistogramRule + : public BackgroundTracingRule, + public BackgroundTracingManagerImpl::TraceMessageFilterObserver { private: HistogramRule(const std::string& histogram_name, int histogram_lower_value, @@ -186,8 +187,8 @@ ~HistogramRule() override { base::StatisticsRecorder::ClearCallback(histogram_name_); - TracingControllerImpl::GetInstance()->RemoveTraceMessageFilterObserver( - this); + BackgroundTracingManagerImpl::GetInstance() + ->RemoveTraceMessageFilterObserver(this); } // BackgroundTracingRule implementation @@ -198,7 +199,8 @@ base::Unretained(this), histogram_name_, histogram_lower_value_, histogram_upper_value_, repeat_)); - TracingControllerImpl::GetInstance()->AddTraceMessageFilterObserver(this); + BackgroundTracingManagerImpl::GetInstance()->AddTraceMessageFilterObserver( + this); } void IntoDict(base::DictionaryValue* dict) const override { @@ -231,7 +233,7 @@ base::Unretained(BackgroundTracingManagerImpl::GetInstance()))); } - // TracingControllerImpl::TraceMessageFilterObserver implementation + // BackgroundTracingManagerImpl::TraceMessageFilterObserver implementation void OnTraceMessageFilterAdded(TraceMessageFilter* filter) override { filter->Send( new TracingMsg_SetUMACallback(histogram_name_, histogram_lower_value_,
diff --git a/content/browser/tracing/trace_message_filter.cc b/content/browser/tracing/trace_message_filter.cc index a0e97d1b3..dcf2ac3 100644 --- a/content/browser/tracing/trace_message_filter.cc +++ b/content/browser/tracing/trace_message_filter.cc
@@ -4,10 +4,13 @@ #include "content/browser/tracing/trace_message_filter.h" +#include "base/bind.h" +#include "base/bind_helpers.h" #include "components/tracing/common/tracing_messages.h" #include "content/browser/tracing/background_tracing_manager_impl.h" #include "content/browser/tracing/tracing_controller_impl.h" #include "content/common/child_process_host_impl.h" +#include "content/public/browser/browser_thread.h" namespace content { @@ -31,7 +34,9 @@ if (is_awaiting_buffer_percent_full_ack_) OnTraceLogStatusReply(base::trace_event::TraceLogStatus()); - TracingControllerImpl::GetInstance()->RemoveTraceMessageFilter(this); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&TraceMessageFilter::Unregister, base::RetainedRef(this))); } } @@ -85,7 +90,9 @@ void TraceMessageFilter::OnChildSupportsTracing() { has_child_ = true; - TracingControllerImpl::GetInstance()->AddTraceMessageFilter(this); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&TraceMessageFilter::Register, base::RetainedRef(this))); } void TraceMessageFilter::OnEndTracingAck( @@ -101,6 +108,16 @@ } } +void TraceMessageFilter::Register() { + BackgroundTracingManagerImpl::GetInstance()->AddTraceMessageFilter(this); + TracingControllerImpl::GetInstance()->AddTraceMessageFilter(this); +} + +void TraceMessageFilter::Unregister() { + BackgroundTracingManagerImpl::GetInstance()->RemoveTraceMessageFilter(this); + TracingControllerImpl::GetInstance()->RemoveTraceMessageFilter(this); +} + void TraceMessageFilter::OnTraceDataCollected(const std::string& data) { scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString()); data_ptr->data() = data;
diff --git a/content/browser/tracing/trace_message_filter.h b/content/browser/tracing/trace_message_filter.h index 97ae0a2..10936c0 100644 --- a/content/browser/tracing/trace_message_filter.h +++ b/content/browser/tracing/trace_message_filter.h
@@ -49,6 +49,11 @@ void OnTriggerBackgroundTrace(const std::string& histogram_name); void OnAbortBackgroundTrace(); + // For registering/unregistering the filter to different tracing + // managers/controllers. + void Register(); + void Unregister(); + // ChildTraceMessageFilter exists: bool has_child_;
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 6bb7164..e3b447c 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -30,6 +30,7 @@ #include "content/browser/tracing/tracing_ui.h" #include "content/common/child_process_messages.h" #include "content/public/browser/browser_message_filter.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/tracing_delegate.h" @@ -407,14 +408,7 @@ void TracingControllerImpl::AddTraceMessageFilter( TraceMessageFilter* trace_message_filter) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&TracingControllerImpl::AddTraceMessageFilter, - base::Unretained(this), - base::RetainedRef(trace_message_filter))); - return; - } + DCHECK_CURRENTLY_ON(BrowserThread::UI); #if defined(OS_LINUX) // On Linux the browser process dumps process metrics for child process due to @@ -428,21 +422,11 @@ trace_message_filter->SendBeginTracing( TraceLog::GetInstance()->GetCurrentTraceConfig()); } - - for (auto& observer : trace_message_filter_observers_) - observer.OnTraceMessageFilterAdded(trace_message_filter); } void TracingControllerImpl::RemoveTraceMessageFilter( TraceMessageFilter* trace_message_filter) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&TracingControllerImpl::RemoveTraceMessageFilter, - base::Unretained(this), - base::RetainedRef(trace_message_filter))); - return; - } + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); #if defined(OS_LINUX) tracing::ProcessMetricsMemoryDumpProvider::UnregisterForProcess( @@ -924,22 +908,4 @@ return metadata_dict; } -void TracingControllerImpl::AddTraceMessageFilterObserver( - TraceMessageFilterObserver* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - trace_message_filter_observers_.AddObserver(observer); - - for (auto& filter : trace_message_filters_) - observer->OnTraceMessageFilterAdded(filter.get()); -} - -void TracingControllerImpl::RemoveTraceMessageFilterObserver( - TraceMessageFilterObserver* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - trace_message_filter_observers_.RemoveObserver(observer); - - for (auto& filter : trace_message_filters_) - observer->OnTraceMessageFilterRemoved(filter.get()); -} - } // namespace content
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h index 93d2c04c..be873583 100644 --- a/content/browser/tracing/tracing_controller_impl.h +++ b/content/browser/tracing/tracing_controller_impl.h
@@ -87,14 +87,6 @@ const std::string& sync_id, const RecordClockSyncMarkerCallback& callback) override; - class TraceMessageFilterObserver { - public: - virtual void OnTraceMessageFilterAdded(TraceMessageFilter* filter) = 0; - virtual void OnTraceMessageFilterRemoved(TraceMessageFilter* filter) = 0; - }; - void AddTraceMessageFilterObserver(TraceMessageFilterObserver* observer); - void RemoveTraceMessageFilterObserver(TraceMessageFilterObserver* observer); - private: friend struct base::LazyInstanceTraitsBase<TracingControllerImpl>; friend class TraceMessageFilter; @@ -120,7 +112,8 @@ return pending_trace_buffer_usage_callback_.is_null(); } - // Methods for use by TraceMessageFilter. + // Methods for use by TraceMessageFilter. These should be called on the UI + // thread. void AddTraceMessageFilter(TraceMessageFilter* trace_message_filter); void RemoveTraceMessageFilter(TraceMessageFilter* trace_message_filter); @@ -200,9 +193,6 @@ GetCategoriesDoneCallback pending_get_categories_done_callback_; GetTraceBufferUsageCallback pending_trace_buffer_usage_callback_; - base::ObserverList<TraceMessageFilterObserver> - trace_message_filter_observers_; - std::set<std::string> known_category_groups_; std::set<TracingUI*> tracing_uis_; scoped_refptr<TraceDataSink> trace_data_sink_;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 1dc6cdf6..2e686b4 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -1693,8 +1693,8 @@ void RenderThreadImpl::OnProcessBackgrounded(bool backgrounded) { ChildThreadImpl::OnProcessBackgrounded(backgrounded); + renderer_scheduler_->SetRendererBackgrounded(backgrounded); if (backgrounded) { - renderer_scheduler_->OnRendererBackgrounded(); needs_to_record_first_active_paint_ = false; GetRendererScheduler()->DefaultTaskRunner()->PostDelayedTask( FROM_HERE, @@ -1714,7 +1714,6 @@ process_foregrounded_count_), base::TimeDelta::FromMinutes(15)); } else { - renderer_scheduler_->OnRendererForegrounded(); process_foregrounded_count_++; } } @@ -2501,6 +2500,7 @@ // scheduled by the RendererScheduler - http://crbug.com/469210. if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) return; + renderer_scheduler_->SetRendererHidden(true); ScheduleIdleHandler(kInitialIdleHandlerDelayMs); } @@ -2508,6 +2508,7 @@ blink::MainThreadIsolate()->IsolateInForegroundNotification(); if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) return; + renderer_scheduler_->SetRendererHidden(false); ScheduleIdleHandler(kLongIdleHandlerDelayMs); }
diff --git a/content/test/data/accessibility/aria/aria-alertdialog-expected-android.txt b/content/test/data/accessibility/aria/aria-alertdialog-expected-android.txt index a9ff011..961b9c9 100644 --- a/content/test/data/accessibility/aria/aria-alertdialog-expected-android.txt +++ b/content/test/data/accessibility/aria/aria-alertdialog-expected-android.txt
@@ -1,2 +1,2 @@ android.webkit.WebView focusable focused scrollable -++android.view.View role_description='alert_dialog' live_region_type=2 \ No newline at end of file +++android.view.View role_description='alert_dialog'
diff --git a/content/test/data/accessibility/aria/aria-alertdialog-expected-blink.txt b/content/test/data/accessibility/aria/aria-alertdialog-expected-blink.txt new file mode 100644 index 0000000..ee6a33a --- /dev/null +++ b/content/test/data/accessibility/aria/aria-alertdialog-expected-blink.txt
@@ -0,0 +1,2 @@ +rootWebArea +++alertDialog
diff --git a/content/test/data/accessibility/aria/aria-alertdialog-expected-mac.txt b/content/test/data/accessibility/aria/aria-alertdialog-expected-mac.txt index 79b9e2d4..3dbdd687 100644 --- a/content/test/data/accessibility/aria/aria-alertdialog-expected-mac.txt +++ b/content/test/data/accessibility/aria/aria-alertdialog-expected-mac.txt
@@ -1,2 +1,2 @@ AXWebArea AXRoleDescription='HTML content' -++AXGroup AXSubrole=AXApplicationAlertDialog AXRoleDescription='alertdialog' AXARIABusy='0' AXARIALive='assertive' +++AXGroup AXSubrole=AXApplicationAlertDialog AXRoleDescription='alertdialog' \ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-alertdialog-expected-win.txt b/content/test/data/accessibility/aria/aria-alertdialog-expected-win.txt index 4981145..448b4d1e 100644 --- a/content/test/data/accessibility/aria/aria-alertdialog-expected-win.txt +++ b/content/test/data/accessibility/aria/aria-alertdialog-expected-win.txt
@@ -1,2 +1,2 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++ROLE_SYSTEM_DIALOG xml-roles:alertdialog live:assertive relevant:additions text atomic:false busy:false container-live:assertive container-relevant:additions text container-atomic:false container-busy:false +++ROLE_SYSTEM_DIALOG xml-roles:alertdialog \ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-current-expected-blink.txt b/content/test/data/accessibility/aria/aria-current-expected-blink.txt new file mode 100644 index 0000000..70ad9d4f --- /dev/null +++ b/content/test/data/accessibility/aria/aria-current-expected-blink.txt
@@ -0,0 +1,30 @@ +rootWebArea +++link name='Section one' +++++staticText name='Section one' +++++++inlineTextBox name='Section one' +++link name='Section two' +++++staticText name='Section two' +++++++inlineTextBox name='Section two' +++link name='Section three' ariaCurrentState=5 +++++staticText name='Section three' +++++++inlineTextBox name='Section three' +++lineBreak name='<newline>' +++heading name='Section one heading' +++++staticText name='Section one heading' +++++++inlineTextBox name='Section one heading' +++heading name='Section two heading' +++++staticText name='Section two heading' +++++++inlineTextBox name='Section two heading' +++heading name='Section three heading' +++++staticText name='Section three heading' +++++++inlineTextBox name='Section three heading' +++lineBreak name='<newline>' +++++inlineTextBox name='<newline>' +++genericContainer +++++staticText name='Span 1' +++++++inlineTextBox name='Span 1' +++++genericContainer ariaCurrentState=2 +++++++staticText name='Span 2' +++++++++inlineTextBox name='Span 2' +++++staticText name='Span 3' +++++++inlineTextBox name='Span 3'
diff --git a/content/test/data/accessibility/aria/aria-current-expected-win.txt b/content/test/data/accessibility/aria/aria-current-expected-win.txt index 7aaf6fb..a80fce7f 100644 --- a/content/test/data/accessibility/aria/aria-current-expected-win.txt +++ b/content/test/data/accessibility/aria/aria-current-expected-win.txt
@@ -12,3 +12,9 @@ ++++ROLE_SYSTEM_STATICTEXT name='Section two heading' ++IA2_ROLE_HEADING name='Section three heading' ++++ROLE_SYSTEM_STATICTEXT name='Section three heading' +++ROLE_SYSTEM_WHITESPACE name='<newline>' +++IA2_ROLE_SECTION +++++ROLE_SYSTEM_STATICTEXT name='Span 1' +++++IA2_ROLE_SECTION current:true +++++++ROLE_SYSTEM_STATICTEXT name='Span 2' +++++ROLE_SYSTEM_STATICTEXT name='Span 3' \ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-current.html b/content/test/data/accessibility/aria/aria-current.html index ea0eb34..e6106b63 100644 --- a/content/test/data/accessibility/aria/aria-current.html +++ b/content/test/data/accessibility/aria/aria-current.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <!-- @WIN-ALLOW:current:* +@BLINK-ALLOW:ariaCurrentState* --> <html> <body> @@ -11,5 +12,11 @@ <h1 id="section1">Section one heading</h1> <h1 id="section2">Section two heading</h1> <h1 id="section3">Section three heading</h1> + <br> + <div> + <span>Span 1</span> + <span aria-current="true">Span 2</span> + <span>Span 3</span> + </div> </body> </html>
diff --git a/extensions/browser/lazy_background_task_queue.h b/extensions/browser/lazy_background_task_queue.h index 842ee0f..2f24e27a 100644 --- a/extensions/browser/lazy_background_task_queue.h +++ b/extensions/browser/lazy_background_task_queue.h
@@ -48,9 +48,6 @@ // |context|. static LazyBackgroundTaskQueue* Get(content::BrowserContext* context); - // Returns the number of extensions having pending tasks. - size_t extensions_with_pending_tasks() { return pending_tasks_.size(); } - // Returns true if the task should be added to the queue (that is, if the // extension has a lazy background page that isn't ready yet). If the // extension has a lazy background page that is being suspended this method @@ -69,6 +66,7 @@ const PendingTask& task); private: + FRIEND_TEST_ALL_PREFIXES(LazyBackgroundTaskQueueTest, AddPendingTask); FRIEND_TEST_ALL_PREFIXES(LazyBackgroundTaskQueueTest, ProcessPendingTasks); // A map between a BrowserContext/extension_id pair and the queue of tasks
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc index be75177..17d6148c 100644 --- a/extensions/browser/lazy_background_task_queue_unittest.cc +++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -160,7 +160,7 @@ no_background->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); - EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); + EXPECT_EQ(1u, queue.pending_tasks_.size()); EXPECT_EQ(0, task_run_count()); // Another task on the same extension doesn't increase the number of @@ -169,7 +169,7 @@ no_background->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); - EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); + EXPECT_EQ(1u, queue.pending_tasks_.size()); EXPECT_EQ(0, task_run_count()); // Adding a task on an extension with a lazy background page tries to create @@ -179,7 +179,7 @@ lazy_background->id(), base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); - EXPECT_EQ(2u, queue.extensions_with_pending_tasks()); + EXPECT_EQ(2u, queue.pending_tasks_.size()); // The process manager tried to create a background host. EXPECT_EQ(1, process_manager->create_count()); // The task ran immediately because the creation failed. @@ -201,19 +201,19 @@ base::Bind(&LazyBackgroundTaskQueueTest::RunPendingTask, base::Unretained(this))); EXPECT_EQ(0, task_run_count()); - EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); + EXPECT_EQ(1u, queue.pending_tasks_.size()); // Trying to run tasks for an unrelated BrowserContext should do nothing. content::TestBrowserContext unrelated_context; queue.ProcessPendingTasks(NULL, &unrelated_context, extension.get()); EXPECT_EQ(0, task_run_count()); - EXPECT_EQ(1u, queue.extensions_with_pending_tasks()); + EXPECT_EQ(1u, queue.pending_tasks_.size()); // Processing tasks when there is one pending runs the task and removes the // extension from the list of extensions with pending tasks. queue.ProcessPendingTasks(NULL, browser_context(), extension.get()); EXPECT_EQ(1, task_run_count()); - EXPECT_EQ(0u, queue.extensions_with_pending_tasks()); + EXPECT_EQ(0u, queue.pending_tasks_.size()); } } // namespace extensions
diff --git a/ios/build/bots/chromium.fyi/ios-simulator.json b/ios/build/bots/chromium.fyi/ios-simulator.json index 872baca2..65dab5a 100644 --- a/ios/build/bots/chromium.fyi/ios-simulator.json +++ b/ios/build/bots/chromium.fyi/ios-simulator.json
@@ -6,7 +6,6 @@ "gn_args": [ "additional_target_cpus=[\"x86\"]", "goma_dir=\"$(goma_dir)\"", - "ios_enable_code_signing=false", "is_component_build=false", "is_debug=true", "target_cpu=\"x64\"", @@ -75,6 +74,12 @@ "device type": "iPad Retina", "os": "9.0", "xcode version": "8.0" + }, + { + "include": "eg_tests.json", + "device type": "iPhone 6s", + "os": "10.0", + "xcode version": "8.0" } ] }
diff --git a/ios/build/bots/chromium.mac/ios-simulator.json b/ios/build/bots/chromium.mac/ios-simulator.json index 79d61520..d4e05cf4 100644 --- a/ios/build/bots/chromium.mac/ios-simulator.json +++ b/ios/build/bots/chromium.mac/ios-simulator.json
@@ -6,7 +6,6 @@ "gn_args": [ "additional_target_cpus=[\"x86\"]", "goma_dir=\"$(goma_dir)\"", - "ios_enable_code_signing=false", "is_component_build=false", "is_debug=true", "target_cpu=\"x64\"", @@ -60,6 +59,12 @@ "device type": "iPad Air 2", "os": "9.0", "xcode version": "8.0" + }, + { + "include": "eg_tests.json", + "device type": "iPhone 6s", + "os": "10.0", + "xcode version": "8.0" } ] }
diff --git a/ios/build/bots/tests/eg_tests.json b/ios/build/bots/tests/eg_tests.json new file mode 100644 index 0000000..b55089c --- /dev/null +++ b/ios/build/bots/tests/eg_tests.json
@@ -0,0 +1,8 @@ +{ + "tests": [ + { + "app": "ios_chrome_integration_egtests", + "xctest": true + } + ] +}
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h index 201bb61..17054c7f 100644 --- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.h +++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.h
@@ -9,7 +9,6 @@ #include <string> #include <vector> -#include "base/mac/scoped_nsobject.h" #include "base/macros.h" #include "base/observer_list.h" @@ -118,25 +117,6 @@ ios::ChromeBrowserState* browser_state, id<ChromeIdentityInteractionManagerDelegate> delegate) const; - // Deprecated. Returns a new account details controller to present. A cancel - // button is present as leading navigation item. - virtual base::scoped_nsobject<UINavigationController> NewAccountDetails( - ChromeIdentity* identity, - id<ChromeIdentityBrowserOpener> browser_opener); - - // Deprecated. Returns a new Web and App Setting Details controller to - // present. - virtual base::scoped_nsobject<UINavigationController> - NewWebAndAppSettingDetails(ChromeIdentity* identity, - id<ChromeIdentityBrowserOpener> browser_opener); - - // Deprecated. Returns a new ChromeIdentityInteractionManager with |delegate| - // as its delegate. - virtual base::scoped_nsobject<ChromeIdentityInteractionManager> - NewChromeIdentityInteractionManager( - ios::ChromeBrowserState* browser_state, - id<ChromeIdentityInteractionManagerDelegate> delegate) const; - // Returns YES if |identity| is valid and if the service has it in its list of // identitites. virtual bool IsValidIdentity(ChromeIdentity* identity) const;
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm index 05cbbbd7..c2e347e 100644 --- a/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm +++ b/ios/public/provider/chrome/browser/signin/chrome_identity_service.mm
@@ -43,27 +43,6 @@ return nil; } -base::scoped_nsobject<UINavigationController> -ChromeIdentityService::NewAccountDetails( - ChromeIdentity* identity, - id<ChromeIdentityBrowserOpener> browser_opener) { - return base::scoped_nsobject<UINavigationController>(); -} - -base::scoped_nsobject<UINavigationController> -ChromeIdentityService::NewWebAndAppSettingDetails( - ChromeIdentity* identity, - id<ChromeIdentityBrowserOpener> browser_opener) { - return base::scoped_nsobject<UINavigationController>(); -} - -base::scoped_nsobject<ChromeIdentityInteractionManager> -ChromeIdentityService::NewChromeIdentityInteractionManager( - ios::ChromeBrowserState* browser_state, - id<ChromeIdentityInteractionManagerDelegate> delegate) const { - return base::scoped_nsobject<ChromeIdentityInteractionManager>(); -} - bool ChromeIdentityService::IsValidIdentity(ChromeIdentity* identity) const { return false; }
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 68aee907..c94914c4 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -907,7 +907,7 @@ if (!transaction->entry()) return; } - if (success && did_truncate) { + if (success && (did_truncate || is_partial)) { entry->writer = nullptr; // Restart already validated transactions so that they are able to read // the truncated status of the entry.
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 9bc8326..dd17ae5 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -149,6 +149,7 @@ HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache) : next_state_(STATE_NONE), + initial_request_(nullptr), request_(NULL), priority_(priority), cache_(cache->GetWeakPtr()), @@ -270,7 +271,8 @@ if (!cache_.get()) return ERR_UNEXPECTED; - SetRequest(net_log, request); + initial_request_ = request; + SetRequest(net_log); // We have to wait until the backend is initialized so we start the SM. next_state_ = STATE_GET_BACKEND; @@ -984,9 +986,6 @@ // This is only set if we have something to do with the response. range_requested_ = (partial_.get() != NULL); - // mode_ may change later, save the initial mode in case we need to restart - // this request. - restart_info_.mode = mode_; return OK; } @@ -1822,13 +1821,14 @@ // If its the Start state machine and it cannot proceed due to a cache // failure, restart this transaction. DCHECK(!reading_); - TransitionToState(STATE_INIT_ENTRY); - cache_entry_status_ = restart_info_.cache_entry_status; + + SetRequest(net_log_); + entry_ = nullptr; - mode_ = restart_info_.mode; if (network_trans_) network_trans_.reset(); + TransitionToState(STATE_GET_BACKEND); return OK; } @@ -2053,10 +2053,17 @@ //----------------------------------------------------------------------------- -void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log, - const HttpRequestInfo* request) { +void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log) { + // Reset the variables that might get set in this function. This is done + // because this function can be invoked multiple times for a transaction. + cache_entry_status_ = CacheEntryStatus::ENTRY_UNDEFINED; + external_validation_.Reset(); + range_requested_ = false; + partial_.reset(); + custom_request_.reset(); + net_log_ = net_log; - request_ = request; + request_ = initial_request_; effective_load_flags_ = request_->load_flags; method_ = request_->method; @@ -2152,7 +2159,6 @@ partial_.reset(NULL); } } - restart_info_.cache_entry_status = cache_entry_status_; } bool HttpCache::Transaction::ShouldPassThrough() {
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index 080d8b9..79274f0 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h
@@ -183,6 +183,11 @@ ValidationHeaders() : initialized(false) {} std::string values[kNumValidationHeaders]; + void Reset() { + initialized = false; + for (auto& value : values) + value.clear(); + } bool initialized; }; @@ -320,8 +325,7 @@ int DoCacheWriteTruncatedResponseComplete(int result); // Sets request_ and fields derived from it. - void SetRequest(const NetLogWithSource& net_log, - const HttpRequestInfo* request); + void SetRequest(const NetLogWithSource& net_log); // Returns true if the request should be handled exclusively by the network // layer (skipping the cache entirely). @@ -465,7 +469,12 @@ void TransitionToState(State state); State next_state_; + + // Initial request with which Start() was invoked. + const HttpRequestInfo* initial_request_; + const HttpRequestInfo* request_; + std::string method_; RequestPriority priority_; NetLogWithSource net_log_; @@ -542,12 +551,6 @@ // True if the Transaction is currently processing the DoLoop. bool in_do_loop_; - // Used to restore some members when the state machine is restarted after it - // has already been added to an entry e.g after |this| has completed - // validation and the writer transaction fails to completely write the - // response to the cache. - RestartInfo restart_info_; - base::WeakPtrFactory<Transaction> weak_factory_; DISALLOW_COPY_AND_ASSIGN(Transaction);
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 62269b79..d2f0971 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -1492,15 +1492,15 @@ // Let 1st transaction complete headers phase for ranges 40-49. std::string first_read; + MockHttpRequest request1(transaction); { - MockHttpRequest request(transaction); auto& c = context_list[0]; c->result = cache.CreateTransaction(&c->trans); ASSERT_THAT(c->result, IsOk()); EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); c->result = - c->trans->Start(&request, c->callback.callback(), NetLogWithSource()); + c->trans->Start(&request1, c->callback.callback(), NetLogWithSource()); base::RunLoop().RunUntilIdle(); // Start writing to the cache so that MockDiskEntry::CouldBeSparse() returns @@ -1518,16 +1518,16 @@ } // 2nd transaction requests ranges 30-39. + transaction.request_headers = "Range: bytes = 30-39\r\n" EXTRA_HEADER; + MockHttpRequest request2(transaction); { - transaction.request_headers = "Range: bytes = 30-39\r\n" EXTRA_HEADER; - MockHttpRequest request(transaction); auto& c = context_list[1]; c->result = cache.CreateTransaction(&c->trans); ASSERT_THAT(c->result, IsOk()); EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); c->result = - c->trans->Start(&request, c->callback.callback(), NetLogWithSource()); + c->trans->Start(&request2, c->callback.callback(), NetLogWithSource()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); @@ -1590,15 +1590,15 @@ // Let 1st transaction complete headers phase for ranges 40-49. std::string first_read; + MockHttpRequest request1(transaction); { - MockHttpRequest request(transaction); auto& c = context_list[0]; c->result = cache.CreateTransaction(&c->trans); ASSERT_THAT(c->result, IsOk()); EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); c->result = - c->trans->Start(&request, c->callback.callback(), NetLogWithSource()); + c->trans->Start(&request1, c->callback.callback(), NetLogWithSource()); base::RunLoop().RunUntilIdle(); // Start writing to the cache so that MockDiskEntry::CouldBeSparse() returns @@ -1616,16 +1616,16 @@ } // 2nd transaction requests ranges 30-49. + transaction.request_headers = "Range: bytes = 30-49\r\n" EXTRA_HEADER; + MockHttpRequest request2(transaction); { - transaction.request_headers = "Range: bytes = 30-49\r\n" EXTRA_HEADER; - MockHttpRequest request(transaction); auto& c = context_list[1]; c->result = cache.CreateTransaction(&c->trans); ASSERT_THAT(c->result, IsOk()); EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); c->result = - c->trans->Start(&request, c->callback.callback(), NetLogWithSource()); + c->trans->Start(&request2, c->callback.callback(), NetLogWithSource()); base::RunLoop().RunUntilIdle(); EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); @@ -1674,6 +1674,102 @@ EXPECT_EQ(1, cache.disk_cache()->create_count()); } +// Tests parallel validation on range requests with overlapping ranges and the +// impact of deleting the writer on transactions that have validated. +TEST(HttpCache, RangeGET_ParallelValidationRestartDoneHeaders) { + MockHttpCache cache; + + ScopedMockTransaction transaction(kRangeGET_TransactionOK); + + std::vector<std::unique_ptr<Context>> context_list; + const int kNumTransactions = 2; + + for (int i = 0; i < kNumTransactions; ++i) { + context_list.push_back(base::MakeUnique<Context>()); + } + + // Let 1st transaction complete headers phase for ranges 40-59. + std::string first_read; + transaction.request_headers = "Range: bytes = 40-59\r\n" EXTRA_HEADER; + MockHttpRequest request1(transaction); + { + auto& c = context_list[0]; + c->result = cache.CreateTransaction(&c->trans); + ASSERT_THAT(c->result, IsOk()); + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); + + c->result = + c->trans->Start(&request1, c->callback.callback(), NetLogWithSource()); + base::RunLoop().RunUntilIdle(); + + // Start writing to the cache so that MockDiskEntry::CouldBeSparse() returns + // true. + const int kBufferSize = 10; + scoped_refptr<IOBuffer> buffer(new IOBuffer(kBufferSize)); + ReleaseBufferCompletionCallback cb(buffer.get()); + c->result = c->trans->Read(buffer.get(), kBufferSize, cb.callback()); + EXPECT_EQ(kBufferSize, cb.GetResult(c->result)); + + std::string data_read(buffer->data(), kBufferSize); + first_read = data_read; + + EXPECT_EQ(LOAD_STATE_READING_RESPONSE, c->trans->GetLoadState()); + } + + // 2nd transaction requests ranges 30-59. + transaction.request_headers = "Range: bytes = 30-59\r\n" EXTRA_HEADER; + MockHttpRequest request2(transaction); + { + auto& c = context_list[1]; + c->result = cache.CreateTransaction(&c->trans); + ASSERT_THAT(c->result, IsOk()); + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); + + c->result = + c->trans->Start(&request2, c->callback.callback(), NetLogWithSource()); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState()); + } + + EXPECT_TRUE(cache.IsWriterPresent(kRangeGET_TransactionOK.url)); + EXPECT_EQ(1, cache.GetCountDoneHeadersQueue(kRangeGET_TransactionOK.url)); + + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Delete the writer transaction. + context_list[0].reset(); + + base::RunLoop().RunUntilIdle(); + + transaction.data = "rg: 30-39 rg: 40-49 rg: 50-59 "; + ReadAndVerifyTransaction(context_list[1]->trans.get(), transaction); + + // Create another network transaction since the 2nd transaction is restarted. + // 30-39 will be read from network, 40-49 from the cache and 50-59 from the + // network. + EXPECT_EQ(4, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Fetch from the cache to check that ranges 30-49 have been successfully + // cached. + { + MockTransaction transaction(kRangeGET_TransactionOK); + transaction.request_headers = "Range: bytes = 30-49\r\n" EXTRA_HEADER; + transaction.data = "rg: 30-39 rg: 40-49 "; + std::string headers; + RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); + Verify206Response(headers, 30, 49); + } + + EXPECT_EQ(4, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); +} + // Parallel validation results in 200. TEST(HttpCache, SimpleGET_ParallelValidationNoMatch) { MockHttpCache cache;
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc index 140dbc0a..8e27f43 100644 --- a/net/quic/chromium/quic_http_stream.cc +++ b/net/quic/chromium/quic_http_stream.cc
@@ -608,12 +608,13 @@ bool has_upload_data = request_body_stream_ != nullptr; next_state_ = STATE_SEND_HEADERS_COMPLETE; - size_t frame_len = stream_->WriteHeaders(std::move(request_headers_), - !has_upload_data, nullptr); - headers_bytes_sent_ += frame_len; + int rv = stream_->WriteHeaders(std::move(request_headers_), !has_upload_data, + nullptr); + if (rv > 0) + headers_bytes_sent_ += rv; request_headers_ = SpdyHeaderBlock(); - return static_cast<int>(frame_len); + return rv; } int QuicHttpStream::DoSendHeadersComplete(int rv) {
diff --git a/net/quic/chromium/quic_http_stream_test.cc b/net/quic/chromium/quic_http_stream_test.cc index d22ea64..9e48dc9b 100644 --- a/net/quic/chromium/quic_http_stream_test.cc +++ b/net/quic/chromium/quic_http_stream_test.cc
@@ -1530,6 +1530,9 @@ net_log_.bound(), callback_.callback())); ASSERT_EQ(ERR_QUIC_PROTOCOL_ERROR, stream_->SendRequest(headers_, &response_, callback_.callback())); + + EXPECT_LE(0, stream_->GetTotalSentBytes()); + EXPECT_EQ(0, stream_->GetTotalReceivedBytes()); } TEST_P(QuicHttpStreamTest, SessionClosedBeforeSendBodyComplete) {
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index ab2057d..443cbfbf 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -1606,7 +1606,7 @@ } ], "expiration": 10800, - "hard_timeout": 960, + "hard_timeout": 1200, "output_links": [ { "link": [ @@ -1616,7 +1616,8 @@ ], "name": "shard #${SHARD_INDEX} logcats" } - ] + ], + "shards": 2 }, "test": "unit_tests" },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index a9141a1..410a968 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -504,6 +504,21 @@ ] } ], + "CustomFeedbackUi": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "CustomFeedbackUi" + ] + } + ] + } + ], "DataCompressionProxyDevRollout": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index d7022c0..97f3895 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -9798,7 +9798,6 @@ crbug.com/591099 fast/css/rtl-ordering.html [ Failure ] crbug.com/591099 fast/css/rtl-to-viewport.html [ Failure ] crbug.com/591099 fast/css/run-in-crash.html [ Failure ] -crbug.com/591099 fast/css/scroll-snap-parsing.html [ Failure ] crbug.com/591099 fast/css/scrollbar-crash.html [ Failure ] crbug.com/591099 fast/css/selector-set-attribute.html [ Failure ] crbug.com/591099 fast/css/selector-text-escape.html [ Crash Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 04a4f551..1989869 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1233,8 +1233,6 @@ crbug.com/498845 [ Win ] fast/multicol/vertical-rl/float-content-break.html [ Failure ] crbug.com/443615 [ Linux Win ] external/wpt/css/css-shapes-1/shape-outside/supported-shapes/circle/shape-outside-circle-027.html [ Failure ] -crbug.com/443379 external/wpt/gamepad/idlharness.html [ Failure Timeout ] - crbug.com/381684 [ Mac Win ] fonts/family-fallback-gardiner.html [ Skip ] crbug.com/467635 fast/dom/HTMLImageElement/image-sizes-meta-viewport.html [ Skip ] @@ -1519,12 +1517,6 @@ crbug.com/582836 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-font-face-02.html [ Failure ] crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001a.html [ Failure ] -crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-001.html [ Failure ] -crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-002.html [ Failure ] -crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-003.html [ Failure ] -crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-004.html [ Failure ] -crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-005.html [ Failure ] -crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-005a.html [ Failure ] crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-006.html [ Failure ] crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-006a.html [ Failure ] crbug.com/553838 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-007.html [ Failure ] @@ -1815,10 +1807,10 @@ # These wpt/mixed-content tests have console errors that are different on different test runs. crbug.com/679742 external/wpt/mixed-content/allowed/http-csp/same-host-wss/websocket-request/top-level/keep-scheme-redirect/websocket-allowed.https.html [ Failure ] +crbug.com/679742 external/wpt/mixed-content/allowed/http-csp/same-host-wss/websocket-request/top-level/no-redirect/websocket-allowed.https.html [ Failure ] crbug.com/679742 external/wpt/mixed-content/allowed/meta-csp/same-host-wss/websocket-request/top-level/no-redirect/websocket-allowed.https.html [ Failure ] crbug.com/679742 external/wpt/mixed-content/allowed/no-opt-in/same-host-wss/websocket-request/top-level/keep-scheme-redirect/websocket-allowed.https.html [ Failure ] crbug.com/679742 external/wpt/mixed-content/allowed/no-opt-in/same-host-wss/websocket-request/top-level/no-redirect/websocket-allowed.https.html [ Failure ] -crbug.com/679742 external/wpt/mixed-content/allowed/http-csp/same-host-wss/websocket-request/top-level/no-redirect/websocket-allowed.https.html [ Failure ] # These wpt/mixed-content tests consistently time out. crbug.com/626703 external/wpt/mixed-content/blockable/http-csp/cross-origin-http/form-tag/top-level/keep-scheme-redirect/opt-in-blocks.https.html [ Timeout ] @@ -1850,14 +1842,6 @@ crbug.com/626703 external/wpt/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/no-redirect/no-opt-in-blocks.https.html [ Timeout ] crbug.com/626703 external/wpt/mixed-content/blockable/no-opt-in/same-host-http/iframe-tag/top-level/swap-scheme-redirect/no-opt-in-blocks.https.html [ Timeout ] -# These expectations are temporarily commented-out while the test directory is disabled (see top of file). -crbug.com/695270 [ Linux ] external/wpt/css/css-writing-modes-3/overconstrained-rel-pos-ltr-top-bottom-vlr-003.xht [ Failure ] -crbug.com/695270 [ Linux ] external/wpt/css/css-writing-modes-3/overconstrained-rel-pos-ltr-top-bottom-vrl-002.xht [ Failure ] -crbug.com/695270 [ Linux ] external/wpt/css/css-writing-modes-3/overconstrained-rel-pos-rtl-left-right-vlr-009.xht [ Failure ] -crbug.com/695270 [ Linux ] external/wpt/css/css-writing-modes-3/overconstrained-rel-pos-rtl-left-right-vrl-008.xht [ Failure ] -crbug.com/695270 [ Linux ] external/wpt/css/css-writing-modes-3/overconstrained-rel-pos-rtl-top-bottom-vlr-007.xht [ Failure ] -crbug.com/695270 [ Linux ] external/wpt/css/css-writing-modes-3/overconstrained-rel-pos-rtl-top-bottom-vrl-006.xht [ Failure ] - crbug.com/626703 external/wpt/domxpath/001.html [ Failure ] # These HTTP tests that started failing after a web-platform-tests import. @@ -1966,12 +1950,10 @@ crbug.com/626703 [ Android Linux Win ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Failure ] crbug.com/626703 [ Android Mac ] external/wpt/pointerevents/pointerevent_disabled_form_control-manual.html [ Timeout ] crbug.com/626703 [ Mac ] external/wpt/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html [ Timeout ] -crbug.com/626703 crbug.com/717157 external/wpt/fetch/api/basic/integrity-sharedworker.html [ Crash Timeout ] crbug.com/626703 external/wpt/compat/webkit-text-fill-color-property-005.html [ Failure ] crbug.com/626703 external/wpt/content-security-policy/connect-src/connect-src-eventsource-blocked.sub.html [ Timeout ] crbug.com/626703 external/wpt/css/css-display-3/display-contents-dynamic-before-after-001.html [ Failure ] crbug.com/626703 external/wpt/css/css-display-3/display-contents-dynamic-before-after-first-letter-001.html [ Failure ] -crbug.com/626703 external/wpt/css/css-ui-3/box-sizing-026.html [ Failure ] crbug.com/626703 external/wpt/css/CSS2/linebox/inline-formatting-context-012.xht [ Failure ] crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-001a.xhtml [ Failure ] crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-001b.xhtml [ Failure ] @@ -1985,7 +1967,6 @@ crbug.com/626703 external/wpt/cssom-view/matchMedia.xht [ Timeout ] crbug.com/626703 external/wpt/eventsource/eventsource-request-cancellation.htm [ Timeout ] crbug.com/626703 external/wpt/fullscreen/api/document-exit-fullscreen-nested-in-iframe-manual.html [ Timeout Pass ] -crbug.com/626703 external/wpt/html/browsers/offline/no-appcache-in-shared-workers-historical.html [ Timeout ] crbug.com/626703 external/wpt/html/browsers/the-window-object/window-open-noopener.html [ Timeout ] crbug.com/626703 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html [ Timeout ] crbug.com/626703 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16le.html [ Timeout ] @@ -2001,13 +1982,9 @@ crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/callback-exception.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/callback-iframe.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/callback-invoked.html [ Timeout ] -crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/callback-multiple-calls.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/callback-timeout.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/idle-callbacks/cancel-invoked.html [ Timeout ] crbug.com/626703 external/wpt/html/webappapis/scripting/events/event-handler-processing-algorithm-manual.html [ Timeout ] -crbug.com/626703 external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/allow-crossorigin.html [ Timeout ] -crbug.com/626703 external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html [ Timeout ] -crbug.com/626703 external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.sharedworker.html [ Timeout ] crbug.com/626703 external/wpt/http/basic-auth-cache-test.html [ Timeout ] crbug.com/626703 external/wpt/media-source/mediasource-appendbuffer-quota-exceeded.html [ Timeout ] crbug.com/626703 external/wpt/media-source/mediasource-avtracks.html [ Failure Crash ] @@ -2045,33 +2022,7 @@ crbug.com/626703 external/wpt/secure-contexts/basic-shared-worker.https.html [ Timeout ] crbug.com/626703 external/wpt/secure-contexts/shared-worker-insecure-first.https.html [ Timeout ] crbug.com/626703 external/wpt/secure-contexts/shared-worker-secure-first.https.html [ Timeout ] -crbug.com/626703 external/wpt/streams/byte-length-queuing-strategy.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/count-queuing-strategy.html [ Failure Timeout ] -crbug.com/626703 external/wpt/streams/count-queuing-strategy.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/close-propagation-backward.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/close-propagation-forward.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/error-propagation-backward.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/error-propagation-forward.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/flow-control.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/general.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/multiple-propagation.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/pipe-through.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/piping/transform-streams.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/bad-strategies.html [ Failure Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/bad-strategies.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/bad-underlying-sources.html [ Failure Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/bad-underlying-sources.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/brand-checks.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/cancel.html [ Failure Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/cancel.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/count-queuing-strategy-integration.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/default-reader.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/garbage-collection.sharedworker.html [ Timeout ] crbug.com/626703 external/wpt/streams/readable-streams/general.html [ Failure Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/general.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/pipe-through.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/tee.sharedworker.html [ Timeout ] -crbug.com/626703 external/wpt/streams/readable-streams/templated.sharedworker.html [ Timeout ] crbug.com/626703 external/wpt/svg/linking/reftests/href-filter-element.html [ Failure ] crbug.com/626703 external/wpt/uievents/interface/click-event-manual.htm [ Timeout ] crbug.com/626703 external/wpt/uievents/interface/dblclick-event-manual.htm [ Timeout ] @@ -2660,7 +2611,6 @@ crbug.com/657748 external/wpt/css/css-display-3/display-contents-dynamic-table-001-inline.html [ Failure ] crbug.com/657748 external/wpt/css/css-display-3/display-contents-flex-002.html [ Failure ] crbug.com/657748 external/wpt/css/css-display-3/display-contents-flex-003.html [ Failure ] -crbug.com/657748 external/wpt/css/css-display-3/display-contents-computed-style.html [ Failure ] # ====== End of display: contents tests ======
diff --git a/third_party/WebKit/LayoutTests/external/PRESUBMIT.py b/third_party/WebKit/LayoutTests/external/PRESUBMIT.py index bf6c0a8..e1c225a 100644 --- a/third_party/WebKit/LayoutTests/external/PRESUBMIT.py +++ b/third_party/WebKit/LayoutTests/external/PRESUBMIT.py
@@ -2,46 +2,53 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -"""Lint functionality duplicated from WPT upstream. +"""Lint functionality duplicated from web-platform-tests upstream. This is to catch lint errors that would otherwise be caught in WPT CI. +See http://web-platform-tests.org/writing-tests/lint-tool.html for more +information about the lint tool. """ + def _LintWPT(input_api, output_api): wpt_path = input_api.os_path.join(input_api.PresubmitLocalPath(), 'wpt') - linter_path = input_api.os_path.join(input_api.PresubmitLocalPath(), - '..', '..', 'Tools', 'Scripts', 'webkitpy', 'thirdparty', 'wpt', 'wpt', 'lint') + linter_path = input_api.os_path.join( + input_api.PresubmitLocalPath(), '..', '..', 'Tools', 'Scripts', + 'webkitpy', 'thirdparty', 'wpt', 'wpt', 'lint') paths_in_wpt = [] - for file in input_api.AffectedFiles(): - abs_path = file.AbsoluteLocalPath() + for f in input_api.AffectedFiles(): + abs_path = f.AbsoluteLocalPath() if abs_path.startswith(wpt_path): paths_in_wpt.append(abs_path[len(wpt_path) + 1:]) + # If there are changes in LayoutTests/external that aren't in wpt, e.g. + # changes to wpt_automation or this presubmit script, then we can return + # to avoid running the linter on all files in wpt (which is slow). + if not paths_in_wpt: + return [] + args = [ input_api.python_executable, linter_path, - '--repo-root', wpt_path, - '-ignore-glob' '"*-expected.txt"' + '--repo-root=%s' % wpt_path, + '--ignore-glob=*-expected.txt', ] + paths_in_wpt - stdout_data, _ = input_api.subprocess.Popen( + proc = input_api.subprocess.Popen( args, stdout=input_api.subprocess.PIPE, - stderr=input_api.subprocess.PIPE).communicate() + stderr=input_api.subprocess.PIPE) + stdout, _ = proc.communicate() - if stdout_data: - return [output_api.PresubmitError(stdout_data)] + if stdout: + return [output_api.PresubmitError(stdout)] return [] def CheckChangeOnUpload(input_api, output_api): - results = [] - results.extend(_LintWPT(input_api, output_api)) - return results + return _LintWPT(input_api, output_api) def CheckChangeOnCommit(input_api, output_api): - results = [] - results.extend(_LintWPT(input_api, output_api)) - return results + return _LintWPT(input_api, output_api)
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt index e1e19f09..182d8a9 100644 --- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-listing-expected.txt
@@ -241,11 +241,6 @@ ry: auto scale: none scroll-behavior: auto -scroll-snap-coordinate: none -scroll-snap-destination: 0px 0px -scroll-snap-points-x: none -scroll-snap-points-y: none -scroll-snap-type: none shape-image-threshold: 0 shape-margin: 0px shape-outside: none
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt index 95a01f87..9cd914c 100644 --- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/computed-style-without-renderer-listing-expected.txt
@@ -241,11 +241,6 @@ ry: auto scale: none scroll-behavior: auto -scroll-snap-coordinate: none -scroll-snap-destination: 0px 0px -scroll-snap-points-x: none -scroll-snap-points-y: none -scroll-snap-type: none shape-image-threshold: 0 shape-margin: 0px shape-outside: none
diff --git a/third_party/WebKit/LayoutTests/fast/css/scroll-snap-parsing-expected.txt b/third_party/WebKit/LayoutTests/fast/css/scroll-snap-parsing-expected.txt deleted file mode 100644 index 914ef142..0000000 --- a/third_party/WebKit/LayoutTests/fast/css/scroll-snap-parsing-expected.txt +++ /dev/null
@@ -1,126 +0,0 @@ -Test the parsing and application of the scroll-snap-* properties. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Test case: inherited type -PASS style.scrollSnapType is "mandatory" - -Test case: initial type -PASS style.scrollSnapType is "none" - -Test case: inherited points-x -PASS style.scrollSnapPointsX is "repeat(20%)" - -Test case: initial points-x -PASS style.scrollSnapPointsX is "none" - -Test case: inherited points-y -PASS style.scrollSnapPointsY is "repeat(20%)" - -Test case: initial points-y -PASS style.scrollSnapPointsY is "none" - -Test case: inherited destination -PASS style.scrollSnapDestination is "20px 20px" - -Test case: initial destination -PASS style.scrollSnapDestination is "0px 0px" - -Test case: inherited coordinate -PASS style.scrollSnapCoordinate is "10px 10px" - -Test case: initial coordinate -PASS style.scrollSnapCoordinate is "none" - -Test case: mandatory type -PASS style.scrollSnapType is "mandatory" - -Test case: proximity type -PASS style.scrollSnapType is "proximity" - -Test case: none type -PASS style.scrollSnapType is "none" - -Test case: percentage points repeat along x axis -PASS style.scrollSnapPointsX is "repeat(100%)" - -Test case: pixel points repeat along x axis -PASS style.scrollSnapPointsX is "repeat(25px)" - -Test case: percentage points repeat along y axis -PASS style.scrollSnapPointsY is "repeat(100%)" - -Test case: pixel points repeat along y axis -PASS style.scrollSnapPointsY is "repeat(25px)" - -Test case: calc repeat along y axis -PASS style.scrollSnapPointsY is "repeat(calc(25px + 1%))" - -Test case: reject zero -PASS style.scrollSnapPointsY is "none" - -Test case: reject negative -PASS style.scrollSnapPointsY is "none" - -Test case: pixel/pixel destination -PASS style.scrollSnapDestination is "10px 50px" - -Test case: pixel/percentage destination -PASS style.scrollSnapDestination is "20px 40%" - -Test case: unitless/pixel destination -PASS style.scrollSnapDestination is "0px 10px" - -Test case: percentage/pixel destination -PASS style.scrollSnapDestination is "0% 0px" - -Test case: percentage/percentage destination -PASS style.scrollSnapDestination is "5% 100%" - -Test case: calc/percentage destination -PASS style.scrollSnapDestination is "calc(20px + 10%) 40%" - -Test case: 3 piece percentage destination -PASS style.scrollSnapDestination is "0px 0px" - -Test case: 1 piece destination with implied center -PASS style.scrollSnapDestination is "50% 0%" - -Test case: single pixel coordinate -PASS style.scrollSnapCoordinate is "50px 100px" - -Test case: single percentage coordinate -PASS style.scrollSnapCoordinate is "50% 100%" - -Test case: 3 piece percentage coordinate -PASS style.scrollSnapCoordinate is "none" - -Test case: 4 piece pixel coordinate -PASS style.scrollSnapCoordinate is "10px 15px" - -Test case: 1 piece coordinate with implied center -PASS style.scrollSnapCoordinate is "0% 50%" - -Test case: multiple pixel coordinates -PASS style.scrollSnapCoordinate is "50px 100px, 150px 100px, 200px 100px" - -Test case: multiple percentage coordinates -PASS style.scrollSnapCoordinate is "50% 100%, 0% 100%, 200% 100%" - -Test case: multiple mixed pixel/percentage/calc coordinates -PASS style.scrollSnapCoordinate is "calc(100px + 10%) 100%, 150% 50%, 200px calc(10px + 5%)" - -Test case: reject invalid position list -PASS style.scrollSnapCoordinate is "none" - -Test case: reject invalid position separator -PASS style.scrollSnapCoordinate is "none" - -Test case: reject invalid position with terminating comma -PASS style.scrollSnapCoordinate is "none" - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/css/scroll-snap-parsing.html b/third_party/WebKit/LayoutTests/fast/css/scroll-snap-parsing.html deleted file mode 100644 index c88349b..0000000 --- a/third_party/WebKit/LayoutTests/fast/css/scroll-snap-parsing.html +++ /dev/null
@@ -1,83 +0,0 @@ -<!DOCTYPE html> -<script src="../../resources/js-test.js"></script> -<style> -div#container { - scroll-snap-type: mandatory; - scroll-snap-points-x: repeat(20%); - scroll-snap-points-y: repeat(20%); - scroll-snap-destination: 20px 20px; - scroll-snap-coordinate: 10px 10px; -} -</style> - -<!-- test initial and inherited values first --> -<div id="container"> - <div class="test" property="scroll-snap-type" style="scroll-snap-type: inherit;" expected="mandatory" desc="inherited type" ></div> - <div class="test" property="scroll-snap-type" style="scroll-snap-type: initial;" expected="none" desc="initial type" ></div> - <div class="test" property="scroll-snap-points-x" style="scroll-snap-points-x: inherit;" expected="repeat(20%)" desc="inherited points-x" ></div> - <div class="test" property="scroll-snap-points-x" style="scroll-snap-points-x: initial;" expected="none" desc="initial points-x" ></div> - <div class="test" property="scroll-snap-points-y" style="scroll-snap-points-y: inherit;" expected="repeat(20%)" desc="inherited points-y" ></div> - <div class="test" property="scroll-snap-points-y" style="scroll-snap-points-y: initial;" expected="none" desc="initial points-y" ></div> - <div class="test" property="scroll-snap-destination" style="scroll-snap-destination: inherit;" expected="20px 20px" desc="inherited destination" ></div> - <div class="test" property="scroll-snap-destination" style="scroll-snap-destination: initial;" expected="0px 0px" desc="initial destination" ></div> - <div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: inherit;" expected="10px 10px" desc="inherited coordinate" ></div> - <div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: initial;" expected="none" desc="initial coordinate" ></div> -</div> - -<div class="test" property="scroll-snap-type" style="scroll-snap-type: mandatory;" expected="mandatory" desc="mandatory type" ></div> -<div class="test" property="scroll-snap-type" style="scroll-snap-type: proximity;" expected="proximity" desc="proximity type" ></div> -<div class="test" property="scroll-snap-type" style="scroll-snap-type: none;" expected="none" desc="none type" ></div> - -<div class="test" property="scroll-snap-points-x" style="scroll-snap-points-x: repeat(100%);" expected="repeat(100%)" desc="percentage points repeat along x axis" ></div> -<div class="test" property="scroll-snap-points-x" style="scroll-snap-points-x: repeat(25px);" expected="repeat(25px)" desc="pixel points repeat along x axis" ></div> -<div class="test" property="scroll-snap-points-y" style="scroll-snap-points-y: repeat(100%);" expected="repeat(100%)" desc="percentage points repeat along y axis" ></div> -<div class="test" property="scroll-snap-points-y" style="scroll-snap-points-y: repeat(25px);" expected="repeat(25px)" desc="pixel points repeat along y axis" ></div> -<div class="test" property="scroll-snap-points-y" style="scroll-snap-points-y: repeat(calc(25px + 1%));" expected="repeat(calc(25px + 1%))" desc="calc repeat along y axis" ></div> -<div class="test" property="scroll-snap-points-y" style="scroll-snap-points-x: repeat(0px);" expected="none" desc="reject zero" ></div> -<div class="test" property="scroll-snap-points-y" style="scroll-snap-points-y: repeat(-1px);" expected="none" desc="reject negative" ></div> - - - -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: 10px 50px;" expected="10px 50px" desc="pixel/pixel destination" ></div> -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: 20px 40%;" expected="20px 40%" desc="pixel/percentage destination" ></div> -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: 0 10px;" expected="0px 10px" desc="unitless/pixel destination" ></div> -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: 0% 0px;" expected="0% 0px" desc="percentage/pixel destination" ></div> -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: 5% 100%;" expected="5% 100%" desc="percentage/percentage destination" ></div> -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: calc(10% + 20px) 40%;" expected="calc(20px + 10%) 40%" desc="calc/percentage destination" ></div> - -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: left top 50%;" expected="0px 0px" desc="3 piece percentage destination" ></div> -<div class="test" property="scroll-snap-destination" style="scroll-snap-destination: top;" expected="50% 0%" desc="1 piece destination with implied center" ></div> - -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: 50px 100px;" expected="50px 100px" desc="single pixel coordinate" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: 50% 100%;" expected="50% 100%" desc="single percentage coordinate" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: left top 50%;" expected="none" desc="3 piece percentage coordinate" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: left 10px top 15px;" expected="10px 15px" desc="4 piece pixel coordinate" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: left;" expected="0% 50%" desc="1 piece coordinate with implied center" ></div> - -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: 50px 100px, 150px 100px, left 200px top 100px;" expected="50px 100px, 150px 100px, 200px 100px" desc="multiple pixel coordinates" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: 50% 100%, left 0% top 100%, 200% 100%;" expected="50% 100%, 0% 100%, 200% 100%" desc="multiple percentage coordinates" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: calc(10% + 100px) 100%, 150%, 200px calc(5% + 10px);" expected="calc(100px + 10%) 100%, 150% 50%, 200px calc(10px + 5%)" desc="multiple mixed pixel/percentage/calc coordinates" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: 50px 100px, junk;" expected="none" desc="reject invalid position list" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: 50px 100px / 1px 1px;" expected="none" desc="reject invalid position separator" ></div> -<div class="test" property="scroll-snap-coordinate" style="scroll-snap-coordinate: 50px 100px,;" expected="none" desc="reject invalid position with terminating comma" ></div> - - -<script> -description("Test the parsing and application of the scroll-snap-* properties."); - -var tests = document.querySelectorAll('.test'); -var style; -for (var i = 0; i < tests.length; i++) { - debug('Test case: ' + tests[i].attributes.desc.value); - var property = camelCase(tests[i].attributes.property.value); - style = window.getComputedStyle(tests[i]); - shouldBeEqualToString('style.' + property, tests[i].attributes.expected.value); - debug(''); -} - -function camelCase(str) { - return str.replace(/-([a-z])/g, function (m, w) { - return w.toUpperCase(); - }); -} -</script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt index 4164b90..ae6128f5 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-modal-expected.txt
@@ -165,34 +165,6 @@ }, "properties": [ { - "name": "live", - "value": { - "type": "token", - "value": "assertive" - } - }, - { - "name": "atomic", - "value": { - "type": "boolean", - "value": false - } - }, - { - "name": "relevant", - "value": { - "type": "tokenList", - "value": "additions text" - } - }, - { - "name": "busy", - "value": { - "type": "boolean", - "value": false - } - }, - { "name": "modal", "value": { "type": "boolean",
diff --git a/third_party/WebKit/LayoutTests/paint/tables/stacking-context-row-background-clipped-with-offset-expected.html b/third_party/WebKit/LayoutTests/paint/tables/stacking-context-row-background-clipped-with-offset-expected.html new file mode 100644 index 0000000..ebe656b --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/tables/stacking-context-row-background-clipped-with-offset-expected.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<style> +table { border-spacing: 0; } +</style> +<table style="margin-left: 100px; margin-top: 100px; width: 200px; height: 200px"> + <tr style="background: green"><td></td><td></td><td></td><td></td></tr> + <tr style="background: blue"><td></td><td></td><td></td><td></td></tr> + <tr style="background: magenta"><td></td><td></td><td></td><td></td></tr> + <tr style="background: maroon"><td></td><td></td><td></td><td></td></tr> +</table> +<table style="margin-left: 100px; margin-top: 20px; width: 100px; height: 100px"> + <tr style="background: green"><td></td><td></td></tr> + <tr style="background: blue"><td></td><td></td></tr> +</table> +<table style="margin-left: 100px; margin-top: 20px; width: 100px; height: 100px"> + <tr style="background: magenta"><td></td><td></td></tr> + <tr style="background: maroon"><td></td><td></td></tr> +</table>
diff --git a/third_party/WebKit/LayoutTests/paint/tables/stacking-context-row-background-clipped-with-offset.html b/third_party/WebKit/LayoutTests/paint/tables/stacking-context-row-background-clipped-with-offset.html new file mode 100644 index 0000000..ef7a3d6f --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/tables/stacking-context-row-background-clipped-with-offset.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<style> +div { overflow: hidden; margin-left: 100px } +table { border-spacing: 0; width: 200px; height: 200px } +tr { will-change: transform } +tr:nth-child(1) { background: green } +tr:nth-child(2) { background: blue } +tr:nth-child(3) { background: magenta } +tr:nth-child(4) { background: maroon } +</style> +<div style="margin-top: 100px"> + <table> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + </table> +</div> +<div style="margin-top: 20px; width: 100px; height: 100px"> + <table> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + </table> +</div> +<div id="scrolled" style="margin-top: 20px; width: 100px; height: 100px"> + <table> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + <tr><td></td><td></td><td></td><td></td></tr> + </table> +</div> +<script> +scrolled.scrollTop = 100; +scrolled.scrollLeft = 100; +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray-deleteframe.html b/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray-deleteframe.html new file mode 100644 index 0000000..09e68fc --- /dev/null +++ b/third_party/WebKit/LayoutTests/plugins/navigator-pluginarray-deleteframe.html
@@ -0,0 +1,23 @@ +<!doctype html> +<html> +<body> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script type="text/javascript"> +test(function () { + var iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + var iframe_navigator = iframe.contentWindow.navigator; + assert_greater_than_equal(iframe_navigator.plugins.length, 1, "At least one plugin must be available."); + assert_greater_than_equal(iframe_navigator.mimeTypes.length, 1, "At least one mime type must be available."); + iframe.remove(); + for (var i = 0; i < iframe_navigator.plugins.length; i++) { + assert_equals(null, iframe_navigator.plugins[i]); + } + for (var i = 0; i < iframe_navigator.mimeTypes.length; i++) { + assert_equals(null, iframe_navigator.mimeTypes[i]); + } +}, "Tests that navigator.plugins returns null once the iframe is removed."); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt index 3f261c2..b4ae6eb 100644 --- a/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/svg/css/getComputedStyle-listing-expected.txt
@@ -241,11 +241,6 @@ ry: auto scale: none scroll-behavior: auto -scroll-snap-coordinate: none -scroll-snap-destination: 0px 0px -scroll-snap-points-x: none -scroll-snap-points-y: none -scroll-snap-type: none shape-image-threshold: 0 shape-margin: 0px shape-outside: none
diff --git a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt index fe295ea..8f7aadd 100644 --- a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
@@ -248,10 +248,30 @@ ry scale scrollBehavior -scrollSnapCoordinate -scrollSnapDestination -scrollSnapPointsX -scrollSnapPointsY +scrollPadding +scrollPaddingBlock +scrollPaddingBlockEnd +scrollPaddingBlockStart +scrollPaddingBottom +scrollPaddingInline +scrollPaddingInlineEnd +scrollPaddingInlineStart +scrollPaddingLeft +scrollPaddingRight +scrollPaddingTop +scrollSnapAlign +scrollSnapMargin +scrollSnapMarginBlock +scrollSnapMarginBlockEnd +scrollSnapMarginBlockStart +scrollSnapMarginBottom +scrollSnapMarginInline +scrollSnapMarginInlineEnd +scrollSnapMarginInlineStart +scrollSnapMarginLeft +scrollSnapMarginRight +scrollSnapMarginTop +scrollSnapStop scrollSnapType setProperty shapeImageThreshold
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn index b9f2ff0..0925f7e9 100644 --- a/third_party/WebKit/Source/core/BUILD.gn +++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -525,7 +525,10 @@ "$blink_core_output_dir/css/properties/CSSPropertyAPIRadius.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIRotate.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIScale.h", - "$blink_core_output_dir/css/properties/CSSPropertyAPIScrollSnapCoordinate.h", + "$blink_core_output_dir/css/properties/CSSPropertyAPIScrollSnapAlign.h", + "$blink_core_output_dir/css/properties/CSSPropertyAPIScrollPadding.h", + "$blink_core_output_dir/css/properties/CSSPropertyAPIScrollSnapMargin.h", + "$blink_core_output_dir/css/properties/CSSPropertyAPIScrollSnapType.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIShapeImageThreshold.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIShapeMargin.h", "$blink_core_output_dir/css/properties/CSSPropertyAPIShapeOutside.h",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn index aa1d635..d6b7ddf 100644 --- a/third_party/WebKit/Source/core/css/BUILD.gn +++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -443,7 +443,10 @@ "properties/CSSPropertyAPIRadius.cpp", "properties/CSSPropertyAPIRotate.cpp", "properties/CSSPropertyAPIScale.cpp", - "properties/CSSPropertyAPIScrollSnapCoordinate.cpp", + "properties/CSSPropertyAPIScrollPadding.cpp", + "properties/CSSPropertyAPIScrollSnapAlign.cpp", + "properties/CSSPropertyAPIScrollSnapMargin.cpp", + "properties/CSSPropertyAPIScrollSnapType.cpp", "properties/CSSPropertyAPIShapeImageThreshold.cpp", "properties/CSSPropertyAPIShapeMargin.cpp", "properties/CSSPropertyAPIShapeOutside.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp index 42cf16d..b3d9c8a5 100644 --- a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp +++ b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
@@ -173,10 +173,8 @@ CSSPropertyDominantBaseline, CSSPropertyTextAnchor, CSSPropertyWritingMode, CSSPropertyVectorEffect, CSSPropertyPaintOrder, CSSPropertyD, CSSPropertyCx, CSSPropertyCy, CSSPropertyX, CSSPropertyY, CSSPropertyR, CSSPropertyRx, - CSSPropertyRy, CSSPropertyScrollSnapType, CSSPropertyScrollSnapPointsX, - CSSPropertyScrollSnapPointsY, CSSPropertyScrollSnapCoordinate, - CSSPropertyScrollSnapDestination, CSSPropertyTranslate, CSSPropertyRotate, - CSSPropertyScale, CSSPropertyCaretColor}; + CSSPropertyRy, CSSPropertyTranslate, CSSPropertyRotate, CSSPropertyScale, + CSSPropertyCaretColor}; CSSValueID CssIdentifierForFontSizeKeyword(int keyword_size) { DCHECK_NE(keyword_size, 0);
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h index 383e1e8..41e6f5a 100644 --- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h +++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -2583,35 +2583,109 @@ } template <> -inline CSSIdentifierValue::CSSIdentifierValue(ScrollSnapType snap_type) +inline CSSIdentifierValue::CSSIdentifierValue(SnapAxis axis) : CSSValue(kIdentifierClass) { - switch (snap_type) { - case kScrollSnapTypeNone: - value_id_ = CSSValueNone; + switch (axis) { + case kSnapAxisX: + value_id_ = CSSValueX; break; - case kScrollSnapTypeMandatory: - value_id_ = CSSValueMandatory; + case kSnapAxisY: + value_id_ = CSSValueY; break; - case kScrollSnapTypeProximity: - value_id_ = CSSValueProximity; + case kSnapAxisBlock: + value_id_ = CSSValueBlock; + break; + case kSnapAxisInline: + value_id_ = CSSValueInline; + break; + case kSnapAxisBoth: + value_id_ = CSSValueBoth; break; } } template <> -inline ScrollSnapType CSSIdentifierValue::ConvertTo() const { +inline SnapAxis CSSIdentifierValue::ConvertTo() const { switch (GetValueID()) { - case CSSValueNone: - return kScrollSnapTypeNone; - case CSSValueMandatory: - return kScrollSnapTypeMandatory; - case CSSValueProximity: - return kScrollSnapTypeProximity; + case CSSValueX: + return kSnapAxisX; + case CSSValueY: + return kSnapAxisY; + case CSSValueBlock: + return kSnapAxisBlock; + case CSSValueInline: + return kSnapAxisInline; + case CSSValueBoth: + return kSnapAxisBoth; default: break; } NOTREACHED(); - return kScrollSnapTypeNone; + return kSnapAxisBoth; +} + +template <> +inline CSSIdentifierValue::CSSIdentifierValue(SnapStrictness strictness) + : CSSValue(kIdentifierClass) { + switch (strictness) { + case kSnapStrictnessProximity: + value_id_ = CSSValueProximity; + break; + case kSnapStrictnessMandatory: + value_id_ = CSSValueMandatory; + break; + } +} + +template <> +inline SnapStrictness CSSIdentifierValue::ConvertTo() const { + switch (GetValueID()) { + case CSSValueProximity: + return kSnapStrictnessProximity; + case CSSValueMandatory: + return kSnapStrictnessMandatory; + default: + break; + } + NOTREACHED(); + return kSnapStrictnessProximity; +} + +template <> +inline CSSIdentifierValue::CSSIdentifierValue(SnapAlignment alignment) + : CSSValue(kIdentifierClass) { + switch (alignment) { + case kSnapAlignmentNone: + value_id_ = CSSValueNone; + break; + case kSnapAlignmentStart: + value_id_ = CSSValueStart; + break; + case kSnapAlignmentEnd: + value_id_ = CSSValueEnd; + break; + case kSnapAlignmentCenter: + value_id_ = CSSValueCenter; + break; + } +} + +template <> +inline SnapAlignment CSSIdentifierValue::ConvertTo() const { + switch (GetValueID()) { + case CSSValueNone: + return kSnapAlignmentNone; + case CSSValueStart: + return kSnapAlignmentStart; + case CSSValueEnd: + return kSnapAlignmentEnd; + case CSSValueCenter: + return kSnapAlignmentCenter; + default: + break; + } + NOTREACHED(); + return kSnapAlignmentNone; } template <>
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5 index 85e28b5..02e281e0 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.json5 +++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -1973,33 +1973,201 @@ }, { name: "scroll-snap-type", - runtime_flag: "CSSScrollSnapPoints", - type_name: "ScrollSnapType", - field_template: "storage_only", - field_group: "rare-non-inherited", - field_size: 2, - default_value: "kScrollSnapTypeNone", - }, - { - name: "scroll-snap-points-x", - converter: "ConvertSnapPoints", - runtime_flag: "CSSScrollSnapPoints", - }, - { - name: "scroll-snap-points-y", - converter: "ConvertSnapPoints", - runtime_flag: "CSSScrollSnapPoints", - }, - { - name: "scroll-snap-destination", - converter: "ConvertPosition", - runtime_flag: "CSSScrollSnapPoints", - }, - { - name: "scroll-snap-coordinate", api_class: true, api_methods: ["parseSingleValue"], - converter: "ConvertSnapCoordinates", + converter: "ConvertSnapType", + getter: "GetScrollSnapType", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-align", + api_class: true, + api_methods: ["parseSingleValue"], + converter: "ConvertSnapAlign", + getter: "GetScrollSnapAlign", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-stop", + default_value: "normal", + field_template: "keyword", + keywords: ["normal", "always"], + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-top", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-bottom", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-left", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-right", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-block-start", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + direction_aware: true, + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-block-end", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + direction_aware: true, + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-inline-start", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + direction_aware: true, + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-inline-end", + api_class: "CSSPropertyAPIScrollPadding", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollPadding", + include_paths: ["platform/Length.h"], + typedom_types: ["Length", "Percent"], + type_name: "Length", + direction_aware: true, + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-top", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + include_paths: ["platform/Length.h"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-bottom", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + include_paths: ["platform/Length.h"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-left", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + include_paths: ["platform/Length.h"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-right", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + include_paths: ["platform/Length.h"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-block-start", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + direction_aware: true, + include_paths: ["platform/Length.h"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-block-end", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + direction_aware: true, + include_paths: ["platform/Length.h"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-inline-start", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + direction_aware: true, + include_paths: ["platform/Length.h"], + type_name: "Length", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-inline-end", + api_class: "CSSPropertyAPIScrollSnapMargin", + api_methods: ["parseSingleValue"], + converter: "ConvertLength", + initial: "InitialScrollSnapMargin", + direction_aware: true, + include_paths: ["platform/Length.h"], + type_name: "Length", runtime_flag: "CSSScrollSnapPoints", }, { @@ -3476,6 +3644,36 @@ longhands: "break-inside", }, { + name: "scroll-padding", + longhands: "scroll-padding-top;scroll-padding-right;scroll-padding-bottom;scroll-padding-left", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-block", + longhands: "scroll-padding-block-start;scroll-padding-block-end", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-padding-inline", + longhands: "scroll-padding-inline-start;scroll-padding-inline-end", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin", + longhands: "scroll-snap-margin-top;scroll-snap-margin-right;scroll-snap-margin-bottom;scroll-snap-margin-left", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-block", + longhands: "scroll-snap-margin-block-start;scroll-snap-margin-block-end", + runtime_flag: "CSSScrollSnapPoints", + }, + { + name: "scroll-snap-margin-inline", + longhands: "scroll-snap-margin-inline-start;scroll-snap-margin-inline-end", + runtime_flag: "CSSScrollSnapPoints", + }, + { name: "transition", longhands: "transition-property;transition-duration;transition-timing-function;transition-delay", },
diff --git a/third_party/WebKit/Source/core/css/CSSProperty.cpp b/third_party/WebKit/Source/core/css/CSSProperty.cpp index 1d21939f..3b7a354 100644 --- a/third_party/WebKit/Source/core/css/CSSProperty.cpp +++ b/third_party/WebKit/Source/core/css/CSSProperty.cpp
@@ -227,6 +227,30 @@ case CSSPropertyWebkitBorderAfterWidth: return ResolveToPhysicalProperty(direction, writing_mode, kAfterSide, borderWidthShorthand()); + case CSSPropertyScrollPaddingInlineStart: + return ResolveToPhysicalProperty(direction, writing_mode, kStartSide, + scrollPaddingShorthand()); + case CSSPropertyScrollPaddingInlineEnd: + return ResolveToPhysicalProperty(direction, writing_mode, kEndSide, + scrollPaddingShorthand()); + case CSSPropertyScrollPaddingBlockStart: + return ResolveToPhysicalProperty(direction, writing_mode, kBeforeSide, + scrollPaddingShorthand()); + case CSSPropertyScrollPaddingBlockEnd: + return ResolveToPhysicalProperty(direction, writing_mode, kAfterSide, + scrollPaddingShorthand()); + case CSSPropertyScrollSnapMarginInlineStart: + return ResolveToPhysicalProperty(direction, writing_mode, kStartSide, + scrollSnapMarginShorthand()); + case CSSPropertyScrollSnapMarginInlineEnd: + return ResolveToPhysicalProperty(direction, writing_mode, kEndSide, + scrollSnapMarginShorthand()); + case CSSPropertyScrollSnapMarginBlockStart: + return ResolveToPhysicalProperty(direction, writing_mode, kBeforeSide, + scrollSnapMarginShorthand()); + case CSSPropertyScrollSnapMarginBlockEnd: + return ResolveToPhysicalProperty(direction, writing_mode, kAfterSide, + scrollSnapMarginShorthand()); case CSSPropertyInlineSize: case CSSPropertyWebkitLogicalWidth: { const CSSPropertyID kProperties[2] = {CSSPropertyWidth,
diff --git a/third_party/WebKit/Source/core/css/CSSValueKeywords.json5 b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5 index 39ff4fa..966692a 100644 --- a/third_party/WebKit/Source/core/css/CSSValueKeywords.json5 +++ b/third_party/WebKit/Source/core/css/CSSValueKeywords.json5
@@ -885,6 +885,9 @@ "pixelated", "-webkit-optimize-contrast", + // image-orientation + "from-image", + // shape-outside "nonzero", "evenodd", @@ -1110,9 +1113,24 @@ // scroll-snap-type // none + "x", + "y", + // block + // inline + // both "mandatory", "proximity", - "from-image", + + // scroll-snap-align + // none + // start + // end + // center + + // scroll-snap-stop + // normal + // always + // containment // paint
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index 3713d852..6758297 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -1653,6 +1653,27 @@ return list; } +static CSSValuePair* ValuesForInlineBlockShorthand( + const StylePropertyShorthand& shorthand, + const ComputedStyle& style, + const LayoutObject* layout_object, + Node* styled_node, + bool allow_visited_style) { + const CSSValue* start_value = ComputedStyleCSSValueMapping::Get( + shorthand.properties()[0], style, layout_object, styled_node, + allow_visited_style); + const CSSValue* end_value = ComputedStyleCSSValueMapping::Get( + shorthand.properties()[1], style, layout_object, styled_node, + allow_visited_style); + // Both properties must be specified. + if (!start_value || !end_value) + return nullptr; + + CSSValuePair* pair = CSSValuePair::Create(start_value, end_value, + CSSValuePair::kDropIdenticalValues); + return pair; +} + static CSSValueList* ValueForBorderRadiusShorthand(const ComputedStyle& style) { CSSValueList* list = CSSValueList::CreateSlashSeparated(); @@ -1968,42 +1989,21 @@ return list; } -static CSSValue* ValueForScrollSnapDestination(const LengthPoint& destination, - const ComputedStyle& style) { - CSSValueList* list = CSSValueList::CreateSpaceSeparated(); - list->Append(*ZoomAdjustedPixelValueForLength(destination.X(), style)); - list->Append(*ZoomAdjustedPixelValueForLength(destination.Y(), style)); - return list; -} - -static CSSValue* ValueForScrollSnapPoints(const ScrollSnapPoints& points, - const ComputedStyle& style) { - if (points.has_repeat) { - CSSFunctionValue* repeat = CSSFunctionValue::Create(CSSValueRepeat); - repeat->Append( - *ZoomAdjustedPixelValueForLength(points.repeat_offset, style)); - return repeat; +static CSSValue* ValueForScrollSnapType(const ScrollSnapType& type, + const ComputedStyle& style) { + if (!type.is_none) { + return CSSValuePair::Create(CSSIdentifierValue::Create(type.axis), + CSSIdentifierValue::Create(type.strictness), + CSSValuePair::kDropIdenticalValues); } - return CSSIdentifierValue::Create(CSSValueNone); } -static CSSValue* ValueForScrollSnapCoordinate( - const Vector<LengthPoint>& coordinates, - const ComputedStyle& style) { - if (coordinates.IsEmpty()) - return CSSIdentifierValue::Create(CSSValueNone); - - CSSValueList* list = CSSValueList::CreateCommaSeparated(); - - for (auto& coordinate : coordinates) { - auto pair = CSSValueList::CreateSpaceSeparated(); - pair->Append(*ZoomAdjustedPixelValueForLength(coordinate.X(), style)); - pair->Append(*ZoomAdjustedPixelValueForLength(coordinate.Y(), style)); - list->Append(*pair); - } - - return list; +static CSSValue* ValueForScrollSnapAlign(const ScrollSnapAlign& align, + const ComputedStyle& style) { + return CSSValuePair::Create(CSSIdentifierValue::Create(align.alignmentX), + CSSIdentifierValue::Create(align.alignmentY), + CSSValuePair::kDropIdenticalValues); } // Returns a suitable value for the page-break-(before|after) property, given @@ -3460,6 +3460,30 @@ case CSSPropertyPadding: return ValuesForSidesShorthand(paddingShorthand(), style, layout_object, styled_node, allow_visited_style); + case CSSPropertyScrollPadding: + return ValuesForSidesShorthand(scrollPaddingShorthand(), style, + layout_object, styled_node, + allow_visited_style); + case CSSPropertyScrollPaddingBlock: + return ValuesForInlineBlockShorthand(scrollPaddingBlockShorthand(), style, + layout_object, styled_node, + allow_visited_style); + case CSSPropertyScrollPaddingInline: + return ValuesForInlineBlockShorthand(scrollPaddingInlineShorthand(), + style, layout_object, styled_node, + allow_visited_style); + case CSSPropertyScrollSnapMargin: + return ValuesForSidesShorthand(scrollSnapMarginShorthand(), style, + layout_object, styled_node, + allow_visited_style); + case CSSPropertyScrollSnapMarginBlock: + return ValuesForInlineBlockShorthand(scrollSnapMarginBlockShorthand(), + style, layout_object, styled_node, + allow_visited_style); + case CSSPropertyScrollSnapMarginInline: + return ValuesForInlineBlockShorthand(scrollSnapMarginInlineShorthand(), + style, layout_object, styled_node, + allow_visited_style); // Individual properties not part of the spec. case CSSPropertyBackgroundRepeatX: case CSSPropertyBackgroundRepeatY: @@ -3690,16 +3714,56 @@ case CSSPropertyRy: return ZoomAdjustedPixelValueForLength(svg_style.Ry(), style); case CSSPropertyScrollSnapType: - return CSSIdentifierValue::Create(style.GetScrollSnapType()); - case CSSPropertyScrollSnapPointsX: - return ValueForScrollSnapPoints(style.ScrollSnapPointsX(), style); - case CSSPropertyScrollSnapPointsY: - return ValueForScrollSnapPoints(style.ScrollSnapPointsY(), style); - case CSSPropertyScrollSnapCoordinate: - return ValueForScrollSnapCoordinate(style.ScrollSnapCoordinate(), style); - case CSSPropertyScrollSnapDestination: - return ValueForScrollSnapDestination(style.ScrollSnapDestination(), - style); + return ValueForScrollSnapType(style.GetScrollSnapType(), style); + case CSSPropertyScrollSnapAlign: + return ValueForScrollSnapAlign(style.GetScrollSnapAlign(), style); + case CSSPropertyScrollSnapStop: + return CSSIdentifierValue::Create(style.ScrollSnapStop()); + case CSSPropertyScrollPaddingTop: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingTop(), style); + case CSSPropertyScrollPaddingRight: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingRight(), style); + case CSSPropertyScrollPaddingBottom: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingBottom(), + style); + case CSSPropertyScrollPaddingLeft: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingLeft(), style); + case CSSPropertyScrollPaddingBlockStart: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingBlockStart(), + style); + case CSSPropertyScrollPaddingBlockEnd: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingBlockEnd(), + style); + case CSSPropertyScrollPaddingInlineStart: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingInlineStart(), + style); + case CSSPropertyScrollPaddingInlineEnd: + return ZoomAdjustedPixelValueForLength(style.ScrollPaddingInlineEnd(), + style); + case CSSPropertyScrollSnapMarginTop: + return ZoomAdjustedPixelValueForLength(style.ScrollSnapMarginTop(), + style); + case CSSPropertyScrollSnapMarginRight: + return ZoomAdjustedPixelValueForLength(style.ScrollSnapMarginRight(), + style); + case CSSPropertyScrollSnapMarginBottom: + return ZoomAdjustedPixelValueForLength(style.ScrollSnapMarginBottom(), + style); + case CSSPropertyScrollSnapMarginLeft: + return ZoomAdjustedPixelValueForLength(style.ScrollSnapMarginLeft(), + style); + case CSSPropertyScrollSnapMarginBlockStart: + return ZoomAdjustedPixelValueForLength(style.ScrollSnapMarginBlockStart(), + style); + case CSSPropertyScrollSnapMarginBlockEnd: + return ZoomAdjustedPixelValueForLength(style.ScrollSnapMarginBlockEnd(), + style); + case CSSPropertyScrollSnapMarginInlineStart: + return ZoomAdjustedPixelValueForLength( + style.ScrollSnapMarginInlineStart(), style); + case CSSPropertyScrollSnapMarginInlineEnd: + return ZoomAdjustedPixelValueForLength(style.ScrollSnapMarginInlineEnd(), + style); case CSSPropertyTranslate: { if (!style.Translate()) return CSSIdentifierValue::Create(CSSValueNone);
diff --git a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp index 21c3734..3e42083 100644 --- a/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp +++ b/third_party/WebKit/Source/core/css/StylePropertySerializer.cpp
@@ -506,6 +506,18 @@ } case CSSPropertyBorderRadius: return Get4Values(borderRadiusShorthand()); + case CSSPropertyScrollPadding: + return Get4Values(scrollPaddingShorthand()); + case CSSPropertyScrollPaddingBlock: + return Get2Values(scrollPaddingBlockShorthand()); + case CSSPropertyScrollPaddingInline: + return Get2Values(scrollPaddingInlineShorthand()); + case CSSPropertyScrollSnapMargin: + return Get4Values(scrollSnapMarginShorthand()); + case CSSPropertyScrollSnapMarginBlock: + return Get2Values(scrollSnapMarginBlockShorthand()); + case CSSPropertyScrollSnapMarginInline: + return Get2Values(scrollSnapMarginInlineShorthand()); default: return String(); } @@ -695,6 +707,32 @@ return result.ToString(); } +String StylePropertySerializer::Get2Values( + const StylePropertyShorthand& shorthand) const { + // Assume the properties are in the usual order start, end. + int start_value_index = + property_set_.FindPropertyIndex(shorthand.properties()[0]); + int end_value_index = + property_set_.FindPropertyIndex(shorthand.properties()[1]); + + if (start_value_index == -1 || end_value_index == -1) + return String(); + + PropertyValueForSerializer start = + property_set_.PropertyAt(start_value_index); + PropertyValueForSerializer end = property_set_.PropertyAt(end_value_index); + + bool show_end = !DataEquivalent(start.Value(), end.Value()); + + StringBuilder result; + result.Append(start.Value()->CssText()); + if (show_end) { + result.Append(' '); + result.Append(end.Value()->CssText()); + } + return result.ToString(); +} + String StylePropertySerializer::Get4Values( const StylePropertyShorthand& shorthand) const { // Assume the properties are in the usual order top, right, bottom, left.
diff --git a/third_party/WebKit/Source/core/css/StylePropertySerializer.h b/third_party/WebKit/Source/core/css/StylePropertySerializer.h index cddd0193..4045910 100644 --- a/third_party/WebKit/Source/core/css/StylePropertySerializer.h +++ b/third_party/WebKit/Source/core/css/StylePropertySerializer.h
@@ -47,6 +47,7 @@ String GetAlignmentShorthandValue(const StylePropertyShorthand&) const; String BorderPropertyValue() const; String GetLayeredShorthandValue(const StylePropertyShorthand&) const; + String Get2Values(const StylePropertyShorthand&) const; String Get4Values(const StylePropertyShorthand&) const; String BorderSpacingValue(const StylePropertyShorthand&) const; String GetShorthandValue(const StylePropertyShorthand&,
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp index d756114..4588ef58 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
@@ -40,6 +40,22 @@ case CSSPropertyPaddingLeft: case CSSPropertyPaddingRight: case CSSPropertyPaddingTop: + case CSSPropertyScrollPaddingTop: + case CSSPropertyScrollPaddingRight: + case CSSPropertyScrollPaddingBottom: + case CSSPropertyScrollPaddingLeft: + case CSSPropertyScrollPaddingBlockStart: + case CSSPropertyScrollPaddingBlockEnd: + case CSSPropertyScrollPaddingInlineStart: + case CSSPropertyScrollPaddingInlineEnd: + case CSSPropertyScrollSnapMarginTop: + case CSSPropertyScrollSnapMarginRight: + case CSSPropertyScrollSnapMarginBottom: + case CSSPropertyScrollSnapMarginLeft: + case CSSPropertyScrollSnapMarginBlockStart: + case CSSPropertyScrollSnapMarginBlockEnd: + case CSSPropertyScrollSnapMarginInlineStart: + case CSSPropertyScrollSnapMarginInlineEnd: case CSSPropertyWebkitLogicalWidth: case CSSPropertyWebkitLogicalHeight: case CSSPropertyWebkitMinLogicalWidth: @@ -841,10 +857,9 @@ case CSSPropertyWordBreak: return value_id == CSSValueNormal || value_id == CSSValueBreakAll || value_id == CSSValueKeepAll || value_id == CSSValueBreakWord; - case CSSPropertyScrollSnapType: + case CSSPropertyScrollSnapStop: DCHECK(RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()); - return value_id == CSSValueNone || value_id == CSSValueMandatory || - value_id == CSSValueProximity; + return value_id == CSSValueNormal || value_id == CSSValueAlways; default: NOTREACHED(); return false; @@ -957,7 +972,7 @@ case CSSPropertyWordBreak: case CSSPropertyWordWrap: case CSSPropertyWritingMode: - case CSSPropertyScrollSnapType: + case CSSPropertyScrollSnapStop: return true; case CSSPropertyJustifyContent: case CSSPropertyAlignContent:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index cfefdb0..4ef06b9 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -807,24 +807,6 @@ return nullptr; } -static CSSValue* ConsumeScrollSnapPoints(CSSParserTokenRange& range, - CSSParserMode css_parser_mode) { - if (range.Peek().Id() == CSSValueNone) - return ConsumeIdent(range); - if (range.Peek().FunctionId() == CSSValueRepeat) { - CSSParserTokenRange args = ConsumeFunction(range); - CSSPrimitiveValue* parsed_value = - ConsumeLengthOrPercent(args, css_parser_mode, kValueRangeNonNegative); - if (args.AtEnd() && parsed_value && - (parsed_value->IsCalculated() || parsed_value->GetDoubleValue() > 0)) { - CSSFunctionValue* result = CSSFunctionValue::Create(CSSValueRepeat); - result->Append(*parsed_value); - return result; - } - } - return nullptr; -} - static CSSValue* ConsumeReflect(CSSParserTokenRange& range, const CSSParserContext* context) { CSSIdentifierValue* direction = @@ -1534,10 +1516,6 @@ case CSSPropertyWebkitLogicalWidth: case CSSPropertyWebkitLogicalHeight: return CSSPropertyLengthUtils::ConsumeWidthOrHeight(range_, *context_); - case CSSPropertyScrollSnapDestination: - // TODO(crbug.com/724912): Retire scroll-snap-destination - return ConsumePosition(range_, *context_, UnitlessQuirk::kForbid, - Optional<WebFeature>()); case CSSPropertyObjectPosition: return ConsumePosition(range_, *context_, UnitlessQuirk::kForbid, WebFeature::kThreeValuedPositionObjectPosition); @@ -1654,9 +1632,6 @@ return ConsumePerspective( range_, context_, unresolved_property == CSSPropertyAliasWebkitPerspective); - case CSSPropertyScrollSnapPointsX: - case CSSPropertyScrollSnapPointsY: - return ConsumeScrollSnapPoints(range_, context_->Mode()); case CSSPropertyBorderImageRepeat: case CSSPropertyWebkitMaskBoxImageRepeat: return CSSPropertyBorderImageUtils::ConsumeBorderImageRepeat(range_); @@ -2343,6 +2318,23 @@ return range_.AtEnd(); } +bool CSSPropertyParser::Consume2Values(const StylePropertyShorthand& shorthand, + bool important) { + DCHECK_EQ(shorthand.length(), 2u); + const CSSPropertyID* longhands = shorthand.properties(); + const CSSValue* start = ParseSingleValue(longhands[0], shorthand.id()); + if (!start) + return false; + + const CSSValue* end = ParseSingleValue(longhands[1], shorthand.id()); + if (!end) + end = start; + AddParsedProperty(longhands[0], shorthand.id(), *start, important); + AddParsedProperty(longhands[1], shorthand.id(), *end, important); + + return range_.AtEnd(); +} + bool CSSPropertyParser::Consume4Values(const StylePropertyShorthand& shorthand, bool important) { DCHECK_EQ(shorthand.length(), 4u); @@ -3286,6 +3278,18 @@ return ConsumePlaceItemsShorthand(important); case CSSPropertyPlaceSelf: return ConsumePlaceSelfShorthand(important); + case CSSPropertyScrollPadding: + return Consume4Values(scrollPaddingShorthand(), important); + case CSSPropertyScrollPaddingBlock: + return Consume2Values(scrollPaddingBlockShorthand(), important); + case CSSPropertyScrollPaddingInline: + return Consume2Values(scrollPaddingInlineShorthand(), important); + case CSSPropertyScrollSnapMargin: + return Consume4Values(scrollSnapMarginShorthand(), important); + case CSSPropertyScrollSnapMarginBlock: + return Consume2Values(scrollSnapMarginBlockShorthand(), important); + case CSSPropertyScrollSnapMarginInline: + return Consume2Values(scrollSnapMarginInlineShorthand(), important); default: return false; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h index e6d338d..7e9a362 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -85,6 +85,7 @@ bool ParseShorthand(CSSPropertyID, bool important); bool ConsumeShorthandGreedily(const StylePropertyShorthand&, bool important); + bool Consume2Values(const StylePropertyShorthand&, bool important); bool Consume4Values(const StylePropertyShorthand&, bool important); // Legacy parsing allows <string>s for animation-name
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollPadding.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollPadding.cpp new file mode 100644 index 0000000..1e911fd --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollPadding.cpp
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIScrollPadding.h" + +#include "core/css/parser/CSSParserContext.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIScrollPadding::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext&) { + return ConsumeLengthOrPercent( + range, context.Mode(), kValueRangeNonNegative, + CSSPropertyParserHelpers::UnitlessQuirk::kAllow); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapAlign.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapAlign.cpp new file mode 100644 index 0000000..8aa1dae --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapAlign.cpp
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIScrollSnapAlign.h" + +#include "core/css/CSSValuePair.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIScrollSnapAlign::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext&) { + CSSValueID x_id = range.Peek().Id(); + if (x_id != CSSValueNone && x_id != CSSValueStart && x_id != CSSValueEnd && + x_id != CSSValueCenter) + return nullptr; + CSSValue* x_value = CSSPropertyParserHelpers::ConsumeIdent(range); + if (range.AtEnd()) + return x_value; + + CSSValueID y_id = range.Peek().Id(); + if (y_id != CSSValueNone && y_id != CSSValueStart && y_id != CSSValueEnd && + y_id != CSSValueCenter) + return x_value; + CSSValue* y_value = CSSPropertyParserHelpers::ConsumeIdent(range); + CSSValuePair* pair = CSSValuePair::Create(x_value, y_value, + CSSValuePair::kDropIdenticalValues); + return pair; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapCoordinate.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapCoordinate.cpp deleted file mode 100644 index 95a03eb3..0000000 --- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapCoordinate.cpp +++ /dev/null
@@ -1,41 +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. - -#include "core/css/properties/CSSPropertyAPIScrollSnapCoordinate.h" - -#include "core/css/CSSValueList.h" -#include "core/css/CSSValuePair.h" -#include "core/css/parser/CSSParserContext.h" -#include "core/css/parser/CSSPropertyParserHelpers.h" - -// TODO(crbug.com/724912): Retire scroll-snap-coordinate - -class CSSParserLocalContext; -namespace blink { - -using namespace CSSPropertyParserHelpers; - -static CSSValueList* ConsumePositionList(CSSParserTokenRange& range, - const CSSParserContext& context) { - CSSValueList* positions = CSSValueList::CreateCommaSeparated(); - do { - CSSValue* position = ConsumePosition(range, context, UnitlessQuirk::kForbid, - Optional<WebFeature>()); - if (!position) - return nullptr; - positions->Append(*position); - } while (ConsumeCommaIncludingWhitespace(range)); - return positions; -} - -const CSSValue* CSSPropertyAPIScrollSnapCoordinate::parseSingleValue( - CSSParserTokenRange& range, - const CSSParserContext& context, - const CSSParserLocalContext&) { - if (range.Peek().Id() == CSSValueNone) - return ConsumeIdent(range); - return ConsumePositionList(range, context); -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapMargin.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapMargin.cpp new file mode 100644 index 0000000..ee0e8e45 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapMargin.cpp
@@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIScrollSnapMargin.h" + +#include "core/css/parser/CSSParserContext.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIScrollSnapMargin::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext&) { + return ConsumeLengthOrPercent( + range, context.Mode(), kValueRangeNonNegative, + CSSPropertyParserHelpers::UnitlessQuirk::kAllow); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapType.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapType.cpp new file mode 100644 index 0000000..fa30bb9 --- /dev/null +++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapType.cpp
@@ -0,0 +1,34 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/css/properties/CSSPropertyAPIScrollSnapType.h" + +#include "core/css/CSSValuePair.h" +#include "core/css/parser/CSSPropertyParserHelpers.h" + +namespace blink { + +const CSSValue* CSSPropertyAPIScrollSnapType::parseSingleValue( + CSSParserTokenRange& range, + const CSSParserContext& context, + const CSSParserLocalContext&) { + CSSValueID axis_id = range.Peek().Id(); + if (axis_id != CSSValueNone && axis_id != CSSValueX && axis_id != CSSValueY && + axis_id != CSSValueBlock && axis_id != CSSValueInline && + axis_id != CSSValueBoth) + return nullptr; + CSSValue* axis_value = CSSPropertyParserHelpers::ConsumeIdent(range); + if (range.AtEnd() || axis_id == CSSValueNone) + return axis_value; + + CSSValueID strictness_id = range.Peek().Id(); + if (strictness_id != CSSValueProximity && strictness_id != CSSValueMandatory) + return axis_value; + CSSValue* strictness_value = CSSPropertyParserHelpers::ConsumeIdent(range); + CSSValuePair* pair = CSSValuePair::Create(axis_value, strictness_value, + CSSValuePair::kDropIdenticalValues); + return pair; +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp index 2c6c1ef..be66909 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -1247,41 +1247,43 @@ StyleBuilderConverter::ConvertComputedLength<float>(state, list.Item(2))); } -ScrollSnapPoints StyleBuilderConverter::ConvertSnapPoints( - StyleResolverState& state, - const CSSValue& value) { - // Handles: none | repeat(<length>) - ScrollSnapPoints points; - points.has_repeat = false; - - if (!value.IsFunctionValue()) - return points; - - const CSSFunctionValue& repeat_function = ToCSSFunctionValue(value); - SECURITY_DCHECK(repeat_function.length() == 1); - points.repeat_offset = - ConvertLength(state, ToCSSPrimitiveValue(repeat_function.Item(0))); - points.has_repeat = true; - - return points; -} - -Vector<LengthPoint> StyleBuilderConverter::ConvertSnapCoordinates( - StyleResolverState& state, - const CSSValue& value) { - // Handles: none | <position># - Vector<LengthPoint> coordinates; - - if (!value.IsValueList()) - return coordinates; - - const CSSValueList& value_list = ToCSSValueList(value); - coordinates.ReserveInitialCapacity(value_list.length()); - for (auto& snap_coordinate : value_list) { - coordinates.UncheckedAppend(ConvertPosition(state, *snap_coordinate)); +ScrollSnapType StyleBuilderConverter::ConvertSnapType(StyleResolverState&, + const CSSValue& value) { + ScrollSnapType snapType = ComputedStyle::InitialScrollSnapType(); + if (value.IsValuePair()) { + const CSSValuePair& pair = ToCSSValuePair(value); + snapType.is_none = false; + snapType.axis = ToCSSIdentifierValue(pair.First()).ConvertTo<SnapAxis>(); + snapType.strictness = + ToCSSIdentifierValue(pair.Second()).ConvertTo<SnapStrictness>(); + return snapType; } - return coordinates; + if (ToCSSIdentifierValue(value).GetValueID() == CSSValueNone) { + snapType.is_none = true; + return snapType; + } + + snapType.is_none = false; + snapType.axis = ToCSSIdentifierValue(value).ConvertTo<SnapAxis>(); + return snapType; +} + +ScrollSnapAlign StyleBuilderConverter::ConvertSnapAlign(StyleResolverState&, + const CSSValue& value) { + ScrollSnapAlign snapAlign = ComputedStyle::InitialScrollSnapAlign(); + if (value.IsValuePair()) { + const CSSValuePair& pair = ToCSSValuePair(value); + snapAlign.alignmentX = + ToCSSIdentifierValue(pair.First()).ConvertTo<SnapAlignment>(); + snapAlign.alignmentY = + ToCSSIdentifierValue(pair.Second()).ConvertTo<SnapAlignment>(); + } else { + snapAlign.alignmentX = + ToCSSIdentifierValue(value).ConvertTo<SnapAlignment>(); + snapAlign.alignmentY = snapAlign.alignmentX; + } + return snapAlign; } PassRefPtr<TranslateTransformOperation> StyleBuilderConverter::ConvertTranslate(
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h index 7311c164..eb69d8a9 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h +++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.h
@@ -178,12 +178,8 @@ const OrderedNamedGridLines&, NamedGridLinesMap&); - static ScrollSnapPoints ConvertSnapPoints(StyleResolverState&, - const CSSValue&); - static Vector<LengthPoint> ConvertSnapCoordinates(StyleResolverState&, - const CSSValue&); - static LengthPoint ConvertSnapDestination(StyleResolverState&, - const CSSValue&); + static ScrollSnapType ConvertSnapType(StyleResolverState&, const CSSValue&); + static ScrollSnapAlign ConvertSnapAlign(StyleResolverState&, const CSSValue&); static PassRefPtr<TranslateTransformOperation> ConvertTranslate( StyleResolverState&, const CSSValue&);
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 61e9ade..fd0f51c 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -1949,7 +1949,6 @@ } ScrollSnapType snap_type = overflow_style->GetScrollSnapType(); - const LengthPoint& snap_destination = overflow_style->ScrollSnapDestination(); RefPtr<ComputedStyle> document_style = GetLayoutViewItem().MutableStyle(); if (document_style->GetWritingMode() != root_writing_mode || @@ -1962,8 +1961,7 @@ document_style->OverflowX() != overflow_x || document_style->OverflowY() != overflow_y || document_style->ColumnGap() != column_gap || - document_style->GetScrollSnapType() != snap_type || - document_style->ScrollSnapDestination() != snap_destination) { + document_style->GetScrollSnapType() != snap_type) { RefPtr<ComputedStyle> new_style = ComputedStyle::Clone(*document_style); new_style->SetWritingMode(root_writing_mode); new_style->SetDirection(root_direction); @@ -1975,7 +1973,6 @@ new_style->SetOverflowY(overflow_y); new_style->SetColumnGap(column_gap); new_style->SetScrollSnapType(snap_type); - new_style->SetScrollSnapDestination(snap_destination); GetLayoutViewItem().SetStyle(new_style); SetupFontBuilder(*new_style); }
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp index e803c85..f801238 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.cpp +++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -46,7 +46,7 @@ } // Make sure update_use_counter_css.py was run which updates histograms.xml. -constexpr int kMaximumCSSSampleId = 560; +constexpr int kMaximumCSSSampleId = 584; } // namespace @@ -963,14 +963,10 @@ return 498; case CSSPropertyScrollSnapType: return 499; - case CSSPropertyScrollSnapPointsX: - return 500; - case CSSPropertyScrollSnapPointsY: - return 501; - case CSSPropertyScrollSnapCoordinate: - return 502; - case CSSPropertyScrollSnapDestination: - return 503; + // CSSPropertyScrollSnapPointsX was 500. + // CSSPropertyScrollSnapPointsY was 501. + // CSSPropertyScrollSnapCoordinate was 502. + // CSSPropertyScrollSnapDestination was 503. case CSSPropertyTranslate: return 504; case CSSPropertyRotate: @@ -1084,6 +1080,54 @@ return 559; case CSSPropertyPlaceSelf: return 560; + case CSSPropertyScrollSnapAlign: + return 561; + case CSSPropertyScrollPadding: + return 562; + case CSSPropertyScrollPaddingTop: + return 563; + case CSSPropertyScrollPaddingRight: + return 564; + case CSSPropertyScrollPaddingBottom: + return 565; + case CSSPropertyScrollPaddingLeft: + return 566; + case CSSPropertyScrollPaddingBlock: + return 567; + case CSSPropertyScrollPaddingBlockStart: + return 568; + case CSSPropertyScrollPaddingBlockEnd: + return 569; + case CSSPropertyScrollPaddingInline: + return 570; + case CSSPropertyScrollPaddingInlineStart: + return 571; + case CSSPropertyScrollPaddingInlineEnd: + return 572; + case CSSPropertyScrollSnapMargin: + return 573; + case CSSPropertyScrollSnapMarginTop: + return 574; + case CSSPropertyScrollSnapMarginRight: + return 575; + case CSSPropertyScrollSnapMarginBottom: + return 576; + case CSSPropertyScrollSnapMarginLeft: + return 577; + case CSSPropertyScrollSnapMarginBlock: + return 578; + case CSSPropertyScrollSnapMarginBlockStart: + return 579; + case CSSPropertyScrollSnapMarginBlockEnd: + return 580; + case CSSPropertyScrollSnapMarginInline: + return 581; + case CSSPropertyScrollSnapMarginInlineStart: + return 582; + case CSSPropertyScrollSnapMarginInlineEnd: + return 583; + case CSSPropertyScrollSnapStop: + return 584; // 1. Add new features above this line (don't change the assigned numbers of // the existing items). // 2. Update kMaximumCSSSampleId with the new maximum value.
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 8c1b379..21f1a31 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -451,20 +451,20 @@ GetNode() != GetDocument().ViewportDefiningElement(); ScrollSnapType old_snap_type = - old_style ? old_style->GetScrollSnapType() : kScrollSnapTypeNone; + old_style ? old_style->GetScrollSnapType() : ScrollSnapType(); ScrollSnapType new_snap_type = new_style && allows_snap_container ? new_style->GetScrollSnapType() - : kScrollSnapTypeNone; + : ScrollSnapType(); if (old_snap_type != new_snap_type) snap_coordinator->SnapContainerDidChange(*this, new_snap_type); - Vector<LengthPoint> empty_vector; - const Vector<LengthPoint>& old_snap_coordinate = - old_style ? old_style->ScrollSnapCoordinate() : empty_vector; - const Vector<LengthPoint>& new_snap_coordinate = - new_style ? new_style->ScrollSnapCoordinate() : empty_vector; - if (old_snap_coordinate != new_snap_coordinate) - snap_coordinator->SnapAreaDidChange(*this, new_snap_coordinate); + ScrollSnapAlign old_snap_align = + old_style ? old_style->GetScrollSnapAlign() : ScrollSnapAlign(); + ScrollSnapAlign new_snap_align = new_style && allows_snap_container + ? new_style->GetScrollSnapAlign() + : ScrollSnapAlign(); + if (old_snap_align != new_snap_align) + snap_coordinator->SnapAreaDidChange(*this, new_snap_align); } void LayoutBox::AddScrollSnapMapping() {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h index cd43aa2..d2c10a3 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -297,6 +297,12 @@ -BorderLeft()); } + LayoutRectOutsets BorderPaddingInsets() const { + return LayoutRectOutsets( + -(PaddingTop() + BorderTop()), -(PaddingRight() + BorderRight()), + -(PaddingBottom() + BorderBottom()), -(PaddingLeft() + BorderLeft())); + } + bool HasBorderOrPadding() const { return Style()->HasBorder() || Style()->HasPadding(); }
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h index 6a312e3..ea695dd8 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
@@ -93,6 +93,7 @@ // NGInlineItemResults for this line. NGInlineItemResults& Results() { return results_; } + const NGInlineItemResults& Results() const { return results_; } private: const ComputedStyle* line_style_ = nullptr;
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc index 38a28a8..d387bb9 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -255,7 +255,8 @@ container_builder_.AddChild(line_box.ToLineBoxFragment(), offset); max_inline_size_ = std::max(max_inline_size_, inline_size); - content_size_ = line_bottom; + content_size_ = ComputeContentSize(*line_info, line_bottom); + return true; } @@ -332,6 +333,35 @@ } } +LayoutUnit NGInlineLayoutAlgorithm::ComputeContentSize( + const NGLineInfo& line_info, + LayoutUnit line_bottom) { + LayoutUnit content_size = line_bottom; + + const Vector<NGInlineItem>& items = Node().Items(); + const NGInlineItemResults& line_items = line_info.Results(); + DCHECK(!line_items.IsEmpty()); + + // If the last item was a <br> we need to adjust the content_size to clear + // floats if specified. The <br> element must be at the back of the item + // result list as it forces a line to break. + const NGInlineItemResult& item_result = line_items.back(); + const NGInlineItem& item = items[item_result.item_index]; + const LayoutObject* layout_object = item.GetLayoutObject(); + + // layout_object may be null in certain cases, e.g. if it's a kBidiControl. + if (layout_object && layout_object->IsBR()) { + NGLogicalOffset bfc_offset = + ContainerBfcOffset() + NGLogicalOffset(LayoutUnit(), content_size); + AdjustToClearance(GetClearanceOffset(ConstraintSpace().Exclusions(), + item.Style()->Clear()), + &bfc_offset); + content_size = bfc_offset.block_offset - ContainerBfcOffset().block_offset; + } + + return content_size; +} + NGLayoutOpportunity NGInlineLayoutAlgorithm::FindLayoutOpportunityForLine() { // TODO(ikilpatrick): Using the constraint space BFC offset here seems wrong. // Logically we shouldn't hit this codepath when placing the items as we
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h index 42dd4c4..fe8b26d 100644 --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -68,6 +68,8 @@ LayoutUnit inline_size, LayoutUnit available_width); + LayoutUnit ComputeContentSize(const NGLineInfo&, LayoutUnit line_bottom); + NGLayoutOpportunity FindLayoutOpportunityForLine(); NGInlineLayoutStateStack box_states_;
diff --git a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp index 5762342d..b39e900 100644 --- a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.cpp
@@ -43,10 +43,10 @@ return box; } -void SnapCoordinator::SnapAreaDidChange( - LayoutBox& snap_area, - const Vector<LengthPoint>& snap_coordinates) { - if (snap_coordinates.IsEmpty()) { +void SnapCoordinator::SnapAreaDidChange(LayoutBox& snap_area, + ScrollSnapAlign scroll_snap_align) { + if (scroll_snap_align.alignmentX == kSnapAlignmentNone && + scroll_snap_align.alignmentY == kSnapAlignmentNone) { snap_area.SetSnapContainer(nullptr); return; } @@ -62,7 +62,7 @@ void SnapCoordinator::SnapContainerDidChange(LayoutBox& snap_container, ScrollSnapType scroll_snap_type) { - if (scroll_snap_type == kScrollSnapTypeNone) { + if (scroll_snap_type.is_none) { // TODO(majidvp): Track and report these removals to CompositorWorker // instance responsible for snapping snap_containers_.erase(&snap_container); @@ -79,88 +79,6 @@ // container or from existing areas in orphan pool. } -// Translate local snap coordinates into snap container's scrolling content -// coordinate space. -static Vector<FloatPoint> LocalToContainerSnapCoordinates( - const LayoutBox& container_box, - const LayoutBox& snap_area) { - Vector<FloatPoint> result; - LayoutPoint scroll_offset(container_box.ScrollLeft(), - container_box.ScrollTop()); - - const Vector<LengthPoint>& snap_coordinates = - snap_area.Style()->ScrollSnapCoordinate(); - for (auto& coordinate : snap_coordinates) { - FloatPoint local_point = - FloatPointForLengthPoint(coordinate, FloatSize(snap_area.Size())); - FloatPoint container_point = - snap_area.LocalToAncestorPoint(local_point, &container_box); - container_point.MoveBy(scroll_offset); - result.push_back(container_point); - } - return result; -} - -Vector<double> SnapCoordinator::SnapOffsets(const ContainerNode& element, - ScrollbarOrientation orientation) { - const ComputedStyle* style = element.GetComputedStyle(); - const LayoutBox* snap_container = element.GetLayoutBox(); - DCHECK(style); - DCHECK(snap_container); - - Vector<double> result; - - if (style->GetScrollSnapType() == kScrollSnapTypeNone) - return result; - - const ScrollSnapPoints& snap_points = (orientation == kHorizontalScrollbar) - ? style->ScrollSnapPointsX() - : style->ScrollSnapPointsY(); - - LayoutUnit client_size = (orientation == kHorizontalScrollbar) - ? snap_container->ClientWidth() - : snap_container->ClientHeight(); - LayoutUnit scroll_size = (orientation == kHorizontalScrollbar) - ? snap_container->ScrollWidth() - : snap_container->ScrollHeight(); - - if (snap_points.has_repeat) { - LayoutUnit repeat = ValueForLength(snap_points.repeat_offset, client_size); - - // calc() values may be negative or zero in which case we clamp them to 1px. - // See: https://lists.w3.org/Archives/Public/www-style/2015Jul/0075.html - repeat = std::max<LayoutUnit>(repeat, LayoutUnit(1)); - for (LayoutUnit offset = repeat; offset <= (scroll_size - client_size); - offset += repeat) { - result.push_back(offset.ToFloat()); - } - } - - // Compute element-based snap points by mapping the snap coordinates from - // snap areas to snap container. - bool did_add_snap_area_offset = false; - if (SnapAreaSet* snap_areas = snap_container->SnapAreas()) { - for (auto& snap_area : *snap_areas) { - Vector<FloatPoint> snap_coordinates = - LocalToContainerSnapCoordinates(*snap_container, *snap_area); - for (const FloatPoint& snap_coordinate : snap_coordinates) { - float snap_offset = (orientation == kHorizontalScrollbar) - ? snap_coordinate.X() - : snap_coordinate.Y(); - if (snap_offset > scroll_size - client_size) - continue; - result.push_back(snap_offset); - did_add_snap_area_offset = true; - } - } - } - - if (did_add_snap_area_offset) - std::sort(result.begin(), result.end()); - - return result; -} - #ifndef NDEBUG void SnapCoordinator::ShowSnapAreaMap() {
diff --git a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h index c9f5558..7f1b645 100644 --- a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h +++ b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinator.h
@@ -12,9 +12,9 @@ namespace blink { -class ContainerNode; class LayoutBox; -struct LengthPoint; +struct ScrollSnapType; +struct ScrollSnapAlign; // Snap Coordinator keeps track of snap containers and all of their associated // snap areas. It also contains the logic to generate the list of valid snap @@ -39,8 +39,7 @@ DEFINE_INLINE_TRACE() {} void SnapContainerDidChange(LayoutBox&, ScrollSnapType); - void SnapAreaDidChange(LayoutBox&, - const Vector<LengthPoint>& snap_coordinates); + void SnapAreaDidChange(LayoutBox&, ScrollSnapAlign); #ifndef NDEBUG void ShowSnapAreaMap(); @@ -51,8 +50,6 @@ friend class SnapCoordinatorTest; explicit SnapCoordinator(); - Vector<double> SnapOffsets(const ContainerNode&, ScrollbarOrientation); - HashSet<const LayoutBox*> snap_containers_; };
diff --git a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp index fd5486f6..4f7c9ef 100644 --- a/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/SnapCoordinatorTest.cpp
@@ -10,6 +10,7 @@ #include "core/dom/Element.h" #include "core/frame/LocalFrameView.h" #include "core/html/HTMLElement.h" +#include "core/layout/LayoutBox.h" #include "core/style/ComputedStyle.h" #include "core/testing/DummyPageHolder.h" #include "platform/scroll/ScrollTypes.h" @@ -35,7 +36,7 @@ " height: 1000px;" " width: 1000px;" " overflow: scroll;" - " scroll-snap-type: mandatory;" + " scroll-snap-type: both mandatory;" " }" " #snap-element-fixed-position {" " position: fixed;" @@ -66,11 +67,10 @@ return *GetDocument().getElementById("snap-container"); } - SnapCoordinator& Coordinator() { return *GetDocument().GetSnapCoordinator(); } - - Vector<double> SnapOffsets(const ContainerNode& node, - ScrollbarOrientation orientation) { - return Coordinator().SnapOffsets(node, orientation); + unsigned SizeOfSnapAreas(const ContainerNode& node) { + if (node.GetLayoutBox()->SnapAreas()) + return node.GetLayoutBox()->SnapAreas()->size(); + return 0U; } std::unique_ptr<DummyPageHolder> page_holder_; @@ -78,100 +78,25 @@ INSTANTIATE_TEST_CASE_P(All, SnapCoordinatorTest, ::testing::Bool()); -TEST_P(SnapCoordinatorTest, ValidRepeat) { - SnapContainer().setAttribute(styleAttr, - "scroll-snap-points-x: repeat(20%); " - "scroll-snap-points-y: repeat(400px);"); - GetDocument().UpdateStyleAndLayout(); - { - const int expected_step_size = SnapContainer().clientWidth() * 0.2; - Vector<double> actual = SnapOffsets(SnapContainer(), kHorizontalScrollbar); - EXPECT_EQ(5U, actual.size()); - for (size_t i = 0; i < actual.size(); ++i) - EXPECT_EQ((i + 1) * expected_step_size, actual[i]); - } - { - Vector<double> actual = SnapOffsets(SnapContainer(), kVerticalScrollbar); - EXPECT_EQ(2U, actual.size()); - EXPECT_EQ(400, actual[0]); - EXPECT_EQ(800, actual[1]); - } -} - -TEST_P(SnapCoordinatorTest, EmptyRepeat) { - SnapContainer().setAttribute( - styleAttr, "scroll-snap-points-x: none; scroll-snap-points-y: none;"); - GetDocument().UpdateStyleAndLayout(); - - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kHorizontalScrollbar).size()); - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kVerticalScrollbar).size()); -} - -TEST_P(SnapCoordinatorTest, ZeroAndNegativeRepeat) { - // These be rejected as an invalid repeat values thus no snap offset is - // created. - SnapContainer().setAttribute( - styleAttr, - "scroll-snap-points-x: repeat(-1px); scroll-snap-points-y: repeat(0px);"); - GetDocument().UpdateStyleAndLayout(); - - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kHorizontalScrollbar).size()); - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kVerticalScrollbar).size()); - - // Calc values are not be rejected outright but instead clamped to 1px min - // repeat value. - SnapContainer().setAttribute(styleAttr, - "scroll-snap-points-x: repeat(calc(10px - " - "100%)); scroll-snap-points-y: " - "repeat(calc(0px));"); - GetDocument().UpdateStyleAndLayout(); - - // A repeat value of 1px should give us |(scroll size - client size) / 1| snap - // offsets. - unsigned expected_horizontal_snap_offsets = - SnapContainer().scrollWidth() - SnapContainer().clientWidth(); - EXPECT_EQ(expected_horizontal_snap_offsets, - SnapOffsets(SnapContainer(), kHorizontalScrollbar).size()); - unsigned expected_vertical_snap_offsets = - SnapContainer().scrollHeight() - SnapContainer().clientHeight(); - EXPECT_EQ(expected_vertical_snap_offsets, - SnapOffsets(SnapContainer(), kVerticalScrollbar).size()); -} - TEST_P(SnapCoordinatorTest, SimpleSnapElement) { Element& snap_element = *GetDocument().getElementById("snap-element"); - snap_element.setAttribute(styleAttr, "scroll-snap-coordinate: 10px 11px;"); + snap_element.setAttribute(styleAttr, "scroll-snap-align: start;"); GetDocument().UpdateStyleAndLayout(); - EXPECT_EQ(10, SnapOffsets(SnapContainer(), kHorizontalScrollbar)[0]); - EXPECT_EQ(11, SnapOffsets(SnapContainer(), kVerticalScrollbar)[0]); - - // Multiple coordinate and translates - snap_element.setAttribute(styleAttr, - "scroll-snap-coordinate: 20px 21px, 40px 41px; " - "transform: translate(10px, 10px);"); - GetDocument().UpdateStyleAndLayout(); - - Vector<double> result = SnapOffsets(SnapContainer(), kHorizontalScrollbar); - EXPECT_EQ(30, result[0]); - EXPECT_EQ(50, result[1]); - result = SnapOffsets(SnapContainer(), kVerticalScrollbar); - EXPECT_EQ(31, result[0]); - EXPECT_EQ(51, result[1]); + EXPECT_EQ(1U, SizeOfSnapAreas(SnapContainer())); } TEST_P(SnapCoordinatorTest, NestedSnapElement) { Element& snap_element = *GetDocument().getElementById("nested-snap-element"); - snap_element.setAttribute(styleAttr, "scroll-snap-coordinate: 20px 25px;"); + snap_element.setAttribute(styleAttr, "scroll-snap-align: start;"); GetDocument().UpdateStyleAndLayout(); - EXPECT_EQ(20, SnapOffsets(SnapContainer(), kHorizontalScrollbar)[0]); - EXPECT_EQ(25, SnapOffsets(SnapContainer(), kVerticalScrollbar)[0]); + EXPECT_EQ(1U, SizeOfSnapAreas(SnapContainer())); } TEST_P(SnapCoordinatorTest, NestedSnapElementCaptured) { Element& snap_element = *GetDocument().getElementById("nested-snap-element"); - snap_element.setAttribute(styleAttr, "scroll-snap-coordinate: 20px 25px;"); + snap_element.setAttribute(styleAttr, "scroll-snap-align: start;"); Element* intermediate = GetDocument().getElementById("intermediate"); intermediate->setAttribute(styleAttr, "overflow: scroll;"); @@ -180,92 +105,47 @@ // Intermediate scroller captures nested snap elements first so ancestor // does not get them. - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kHorizontalScrollbar).size()); - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kVerticalScrollbar).size()); + EXPECT_EQ(0U, SizeOfSnapAreas(SnapContainer())); + EXPECT_EQ(1U, SizeOfSnapAreas(*intermediate)); } TEST_P(SnapCoordinatorTest, PositionFixedSnapElement) { Element& snap_element = *GetDocument().getElementById("snap-element-fixed-position"); - snap_element.setAttribute(styleAttr, "scroll-snap-coordinate: 1px 1px;"); + snap_element.setAttribute(styleAttr, "scroll-snap-align: start;"); GetDocument().UpdateStyleAndLayout(); // Position fixed elements are contained in document and not its immediate // ancestor scroller. They cannot be a valid snap destination so they should // not contribute snap points to their immediate snap container or document // See: https://lists.w3.org/Archives/Public/www-style/2015Jun/0376.html - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kHorizontalScrollbar).size()); - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kVerticalScrollbar).size()); + EXPECT_EQ(0U, SizeOfSnapAreas(SnapContainer())); Element* body = GetDocument().ViewportDefiningElement(); - EXPECT_EQ(0U, SnapOffsets(*body, kHorizontalScrollbar).size()); - EXPECT_EQ(0U, SnapOffsets(*body, kVerticalScrollbar).size()); -} - -TEST_P(SnapCoordinatorTest, RepeatAndSnapElementTogether) { - GetDocument() - .getElementById("snap-element") - ->setAttribute(styleAttr, "scroll-snap-coordinate: 5px 10px;"); - GetDocument() - .getElementById("nested-snap-element") - ->setAttribute(styleAttr, "scroll-snap-coordinate: 250px 450px;"); - - SnapContainer().setAttribute(styleAttr, - "scroll-snap-points-x: repeat(200px); " - "scroll-snap-points-y: repeat(400px);"); - GetDocument().UpdateStyleAndLayout(); - - { - Vector<double> result = SnapOffsets(SnapContainer(), kHorizontalScrollbar); - EXPECT_EQ(7U, result.size()); - EXPECT_EQ(5, result[0]); - EXPECT_EQ(200, result[1]); - EXPECT_EQ(250, result[2]); - } - { - Vector<double> result = SnapOffsets(SnapContainer(), kVerticalScrollbar); - EXPECT_EQ(4U, result.size()); - EXPECT_EQ(10, result[0]); - EXPECT_EQ(400, result[1]); - EXPECT_EQ(450, result[2]); - } -} - -TEST_P(SnapCoordinatorTest, SnapPointsAreScrollOffsetIndependent) { - Element& snap_element = *GetDocument().getElementById("snap-element"); - snap_element.setAttribute(styleAttr, "scroll-snap-coordinate: 10px 11px;"); - SnapContainer().scrollBy(100, 100); - GetDocument().UpdateStyleAndLayout(); - - EXPECT_EQ(SnapContainer().scrollLeft(), 100); - EXPECT_EQ(SnapContainer().scrollTop(), 100); - EXPECT_EQ(10, SnapOffsets(SnapContainer(), kHorizontalScrollbar)[0]); - EXPECT_EQ(11, SnapOffsets(SnapContainer(), kVerticalScrollbar)[0]); + EXPECT_EQ(0U, SizeOfSnapAreas(*body)); } TEST_P(SnapCoordinatorTest, UpdateStyleForSnapElement) { Element& snap_element = *GetDocument().getElementById("snap-element"); - snap_element.setAttribute(styleAttr, "scroll-snap-coordinate: 10px 11px;"); + snap_element.setAttribute(styleAttr, "scroll-snap-align: start;"); GetDocument().UpdateStyleAndLayout(); - EXPECT_EQ(10, SnapOffsets(SnapContainer(), kHorizontalScrollbar)[0]); - EXPECT_EQ(11, SnapOffsets(SnapContainer(), kVerticalScrollbar)[0]); + EXPECT_EQ(1U, SizeOfSnapAreas(SnapContainer())); snap_element.remove(); GetDocument().UpdateStyleAndLayout(); - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kHorizontalScrollbar).size()); - EXPECT_EQ(0U, SnapOffsets(SnapContainer(), kVerticalScrollbar).size()); + EXPECT_EQ(0U, SizeOfSnapAreas(SnapContainer())); // Add a new snap element Element& container = *GetDocument().getElementById("snap-container"); container.setInnerHTML( - "<div style='scroll-snap-coordinate: 20px 22px;'><div " - "style='width:2000px; height:2000px;'></div></div>"); + "<div style='scroll-snap-align: start;'>" + " <div style='width:2000px; height:2000px;'></div>" + "</div>"); GetDocument().UpdateStyleAndLayout(); - EXPECT_EQ(20, SnapOffsets(SnapContainer(), kHorizontalScrollbar)[0]); - EXPECT_EQ(22, SnapOffsets(SnapContainer(), kVerticalScrollbar)[0]); + EXPECT_EQ(1U, SizeOfSnapAreas(SnapContainer())); } TEST_P(SnapCoordinatorTest, LayoutViewCapturesWhenBodyElementViewportDefining) { @@ -273,18 +153,17 @@ "<style>" "body {" " overflow: scroll;" - " scroll-snap-type: mandatory;" + " scroll-snap-type: both mandatory;" " height: 1000px;" " width: 1000px;" " margin: 5px;" "}" "</style>" "<body>" - " <div id='snap-element' style='scroll-snap-coordinate: 5px " - "6px;'></div>" - " <div>" - " <div id='nested-snap-element' style='scroll-snap-coordinate: " - "10px 11px;'></div>" + " <div id='snap-element' style='scroll-snap-align: start;></div>" + " <div id='intermediate'>" + " <div id='nested-snap-element'" + " style='scroll-snap-align: start;'></div>" " </div>" " <div style='width:2000px; height:2000px;'></div>" "</body>"); @@ -296,12 +175,9 @@ // When body is viewport defining and overflows then any snap points on the // body element will be captured by layout view as the snap container. - Vector<double> result = SnapOffsets(GetDocument(), kHorizontalScrollbar); - EXPECT_EQ(10, result[0]); - EXPECT_EQ(15, result[1]); - result = SnapOffsets(GetDocument(), kVerticalScrollbar); - EXPECT_EQ(11, result[0]); - EXPECT_EQ(16, result[1]); + EXPECT_EQ(2U, SizeOfSnapAreas(GetDocument())); + EXPECT_EQ(0U, SizeOfSnapAreas(*(GetDocument().body()))); + EXPECT_EQ(0U, SizeOfSnapAreas(*(GetDocument().documentElement()))); } TEST_P(SnapCoordinatorTest, @@ -310,7 +186,7 @@ "<style>" ":root {" " overflow: scroll;" - " scroll-snap-type: mandatory;" + " scroll-snap-type: both mandatory;" " height: 500px;" " width: 500px;" "}" @@ -320,11 +196,10 @@ "</style>" "<html>" " <body>" - " <div id='snap-element' style='scroll-snap-coordinate: 5px " - "6px;'></div>" - " <div>" - " <div id='nested-snap-element' style='scroll-snap-coordinate: " - "10px 11px;'></div>" + " <div id='snap-element' style='scroll-snap-align: start;></div>" + " <div id='intermediate'>" + " <div id='nested-snap-element'" + " style='scroll-snap-align: start;'></div>" " </div>" " <div style='width:2000px; height:2000px;'></div>" " </body>" @@ -339,12 +214,9 @@ // When body is viewport defining and overflows then any snap points on the // the document element will be captured by layout view as the snap // container. - Vector<double> result = SnapOffsets(GetDocument(), kHorizontalScrollbar); - EXPECT_EQ(10, result[0]); - EXPECT_EQ(15, result[1]); - result = SnapOffsets(GetDocument(), kVerticalScrollbar); - EXPECT_EQ(11, result[0]); - EXPECT_EQ(16, result[1]); + EXPECT_EQ(2U, SizeOfSnapAreas(GetDocument())); + EXPECT_EQ(0U, SizeOfSnapAreas(*(GetDocument().body()))); + EXPECT_EQ(0U, SizeOfSnapAreas(*(GetDocument().documentElement()))); } TEST_P(SnapCoordinatorTest, @@ -353,26 +225,25 @@ "<style>" ":root {" " overflow: scroll;" - " scroll-snap-type: mandatory;" + " scroll-snap-type: both mandatory;" " height: 500px;" " width: 500px;" "}" "body {" " overflow: scroll;" - " scroll-snap-type: mandatory;" + " scroll-snap-type: both mandatory;" " height: 1000px;" " width: 1000px;" " margin: 5px;" "}" "</style>" "<html>" - " <body style='overflow: scroll; scroll-snap-type: mandatory; " + " <body style='overflow: scroll; scroll-snap-type: both mandatory; " "height:1000px; width:1000px;'>" - " <div id='snap-element' style='scroll-snap-coordinate: 5px " - "6px;'></div>" - " <div>" - " <div id='nested-snap-element' style='scroll-snap-coordinate: " - "10px 11px;'></div>" + " <div id='snap-element' style='scroll-snap-align: start;></div>" + " <div id='intermediate'>" + " <div id='nested-snap-element'" + " style='scroll-snap-align: start;'></div>" " </div>" " <div style='width:2000px; height:2000px;'></div>" " </body>" @@ -387,12 +258,7 @@ // When body and document elements are both scrollable then body element // should capture snap points defined on it as opposed to layout view. Element& body = *GetDocument().body(); - Vector<double> result = SnapOffsets(body, kHorizontalScrollbar); - EXPECT_EQ(5, result[0]); - EXPECT_EQ(10, result[1]); - result = SnapOffsets(body, kVerticalScrollbar); - EXPECT_EQ(6, result[0]); - EXPECT_EQ(11, result[1]); + EXPECT_EQ(2U, SizeOfSnapAreas(body)); } } // namespace
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp index 2e1d851..55b61d7 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -24,16 +24,13 @@ #include "core/paint/ObjectPainter.h" #include "core/paint/PaintInfo.h" #include "core/paint/PaintLayer.h" -#include "core/paint/RoundedInnerRectClipper.h" #include "core/paint/ScrollRecorder.h" #include "core/paint/ThemePainter.h" #include "core/style/ShadowList.h" #include "platform/LengthFunctions.h" #include "platform/geometry/LayoutPoint.h" -#include "platform/geometry/LayoutRectOutsets.h" #include "platform/graphics/GraphicsContextStateSaver.h" #include "platform/graphics/paint/CompositingDisplayItem.h" -#include "platform/wtf/Optional.h" namespace blink { @@ -433,30 +430,9 @@ Optional<RoundedInnerRectClipper> clip_to_border; if (info.is_rounded_fill) { - FloatRoundedRect border = - info.is_border_fill - ? BackgroundRoundedRectAdjustedForBleedAvoidance( - obj.StyleRef(), rect, bleed_avoidance, has_line_box_sibling, - box_size, info.include_left_edge, info.include_right_edge) - : GetBackgroundRoundedRect( - obj.StyleRef(), rect, has_line_box_sibling, box_size, - info.include_left_edge, info.include_right_edge); - - // Clip to the padding or content boxes as necessary. - if (bg_layer.Clip() == kContentFillBox) { - border = obj.Style()->GetRoundedInnerBorderFor( - LayoutRect(border.Rect()), - LayoutRectOutsets(-(obj.PaddingTop() + obj.BorderTop()), - -(obj.PaddingRight() + obj.BorderRight()), - -(obj.PaddingBottom() + obj.BorderBottom()), - -(obj.PaddingLeft() + obj.BorderLeft())), - info.include_left_edge, info.include_right_edge); - } else if (bg_layer.Clip() == kPaddingFillBox) { - border = obj.Style()->GetRoundedInnerBorderFor(LayoutRect(border.Rect()), - info.include_left_edge, - info.include_right_edge); - } - + FloatRoundedRect border = RoundedBorderRectForClip( + obj.StyleRef(), info, bg_layer, rect, bleed_avoidance, + has_line_box_sibling, box_size, obj.BorderPaddingInsets()); clip_to_border.emplace(obj, paint_info, rect, border, kApplyToContext); }
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.h b/third_party/WebKit/Source/core/paint/BoxPainter.h index 66e10e3b6d..bb6dbf9 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainter.h +++ b/third_party/WebKit/Source/core/paint/BoxPainter.h
@@ -7,9 +7,11 @@ #include "core/layout/BackgroundBleedAvoidance.h" #include "core/paint/BoxPainterBase.h" +#include "core/paint/RoundedInnerRectClipper.h" #include "platform/geometry/LayoutSize.h" #include "platform/graphics/GraphicsTypes.h" #include "platform/wtf/Allocator.h" +#include "platform/wtf/Optional.h" #include "third_party/skia/include/core/SkBlendMode.h" namespace blink {
diff --git a/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp b/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp index 816dc5c..9b69143 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp +++ b/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp
@@ -12,6 +12,7 @@ #include "core/style/ShadowList.h" #include "platform/LengthFunctions.h" #include "platform/geometry/LayoutRect.h" +#include "platform/geometry/LayoutRectOutsets.h" #include "platform/graphics/GraphicsContextStateSaver.h" namespace blink { @@ -354,4 +355,35 @@ (!should_paint_image || !layer.ImageOccludesNextLayers(doc, style)); } +FloatRoundedRect BoxPainterBase::RoundedBorderRectForClip( + const ComputedStyle& style, + const BoxPainterBase::FillLayerInfo info, + const FillLayer& bg_layer, + const LayoutRect& rect, + BackgroundBleedAvoidance bleed_avoidance, + bool has_line_box_sibling, + const LayoutSize& box_size, + LayoutRectOutsets border_padding_insets) { + FloatRoundedRect border = + info.is_border_fill + ? BackgroundRoundedRectAdjustedForBleedAvoidance( + style, rect, bleed_avoidance, has_line_box_sibling, box_size, + info.include_left_edge, info.include_right_edge) + : GetBackgroundRoundedRect(style, rect, has_line_box_sibling, + box_size, info.include_left_edge, + info.include_right_edge); + + // Clip to the padding or content boxes as necessary. + if (bg_layer.Clip() == kContentFillBox) { + border = style.GetRoundedInnerBorderFor( + LayoutRect(border.Rect()), border_padding_insets, + info.include_left_edge, info.include_right_edge); + } else if (bg_layer.Clip() == kPaddingFillBox) { + border = style.GetRoundedInnerBorderFor(LayoutRect(border.Rect()), + info.include_left_edge, + info.include_right_edge); + } + return border; +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/BoxPainterBase.h b/third_party/WebKit/Source/core/paint/BoxPainterBase.h index db613b3..f4131d0 100644 --- a/third_party/WebKit/Source/core/paint/BoxPainterBase.h +++ b/third_party/WebKit/Source/core/paint/BoxPainterBase.h
@@ -19,6 +19,7 @@ class LayoutPoint; class LayoutRect; class FillLayer; +class LayoutRectOutsets; struct PaintInfo; // Base class for box painting. Has no dependencies on the layout tree and thus @@ -114,6 +115,15 @@ const LayoutSize& box_size, bool include_logical_left_edge, bool include_logical_right_edge); + static FloatRoundedRect RoundedBorderRectForClip( + const ComputedStyle&, + const FillLayerInfo, + const FillLayer&, + const LayoutRect&, + BackgroundBleedAvoidance, + bool has_line_box_sibling, + const LayoutSize&, + LayoutRectOutsets border_padding_insets); }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp index 9203531..028cbbd 100644 --- a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp +++ b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp
@@ -4,15 +4,15 @@ #include "core/paint/RoundedInnerRectClipper.h" -#include "core/layout/LayoutObject.h" #include "core/paint/PaintInfo.h" #include "platform/graphics/paint/ClipDisplayItem.h" +#include "platform/graphics/paint/DisplayItemClient.h" #include "platform/graphics/paint/PaintController.h" namespace blink { RoundedInnerRectClipper::RoundedInnerRectClipper( - const LayoutObject& layout_object, + const DisplayItemClient& layout_object, const PaintInfo& paint_info, const LayoutRect& rect, const FloatRoundedRect& clip_rect,
diff --git a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h index fb82d54..2b1f5fe 100644 --- a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h +++ b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.h
@@ -12,7 +12,7 @@ class FloatRoundedRect; class LayoutRect; -class LayoutObject; +class DisplayItemClient; struct PaintInfo; enum RoundedInnerRectClipperBehavior { kApplyToDisplayList, kApplyToContext }; @@ -21,7 +21,7 @@ DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: - RoundedInnerRectClipper(const LayoutObject&, + RoundedInnerRectClipper(const DisplayItemClient&, const PaintInfo&, const LayoutRect&, const FloatRoundedRect& clip_rect, @@ -29,7 +29,7 @@ ~RoundedInnerRectClipper(); private: - const LayoutObject& layout_object_; + const DisplayItemClient& layout_object_; const PaintInfo& paint_info_; bool use_paint_controller_; DisplayItem::Type clip_type_;
diff --git a/third_party/WebKit/Source/core/paint/TableRowPainter.cpp b/third_party/WebKit/Source/core/paint/TableRowPainter.cpp index 3edfcc56..a34d901 100644 --- a/third_party/WebKit/Source/core/paint/TableRowPainter.cpp +++ b/third_party/WebKit/Source/core/paint/TableRowPainter.cpp
@@ -27,16 +27,9 @@ return; if (ShouldPaintSelfBlockBackground(paint_info.phase)) { - const auto* section = layout_table_row_.Section(); - LayoutRect cull_rect = LayoutRect(paint_info.GetCullRect().rect_); - cull_rect.MoveBy(layout_table_row_.PhysicalLocation(section)); - LayoutRect logical_rect_in_section = - section->LogicalRectForWritingModeAndDirection(cull_rect); - CellSpan dirtied_rows; - CellSpan dirtied_columns; - section->DirtiedRowsAndEffectiveColumns(logical_rect_in_section, - dirtied_rows, dirtied_columns); - PaintBoxDecorationBackground(paint_info, paint_offset, dirtied_columns); + PaintBoxDecorationBackground( + paint_info, paint_offset, + layout_table_row_.Section()->FullTableEffectiveColumnSpan()); } if (paint_info.phase == kPaintPhaseSelfBlockBackgroundOnly)
diff --git a/third_party/WebKit/Source/core/style/BUILD.gn b/third_party/WebKit/Source/core/style/BUILD.gn index 1c6f6e95..9964caf 100644 --- a/third_party/WebKit/Source/core/style/BUILD.gn +++ b/third_party/WebKit/Source/core/style/BUILD.gn
@@ -55,9 +55,9 @@ "OrderedNamedGridLines.h", "OutlineValue.h", "PaintImages.h", + "QuadLengthValue.h", "QuotesData.cpp", "QuotesData.h", - "ScrollSnapPoints.h", "ShadowData.cpp", "ShadowData.h", "ShadowList.cpp",
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index a131cf65..f27fa12 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -1311,60 +1311,193 @@ SET_VAR(rare_non_inherited_data_, scroll_behavior_, b); } - // scroll-snap-coordinate - static Vector<LengthPoint> InitialScrollSnapCoordinate() { - return Vector<LengthPoint>(); - } - const Vector<LengthPoint>& ScrollSnapCoordinate() const { - return rare_non_inherited_data_->scroll_snap_data_->coordinates_; - } - void SetScrollSnapCoordinate(const Vector<LengthPoint>& b) { - SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, coordinates_, - b); - } - - // scroll-snap-destination - static LengthPoint InitialScrollSnapDestination() { - return LengthPoint(Length(0, kFixed), Length(0, kFixed)); - } - const LengthPoint& ScrollSnapDestination() const { - return rare_non_inherited_data_->scroll_snap_data_->destination_; - } - void SetScrollSnapDestination(const LengthPoint& b) { - SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, destination_, - b); - } - - // scroll-snap-points-x - static ScrollSnapPoints InitialScrollSnapPointsX() { - return ScrollSnapPoints(); - } - const ScrollSnapPoints& ScrollSnapPointsX() const { - return rare_non_inherited_data_->scroll_snap_data_->x_points_; - } - void SetScrollSnapPointsX(const ScrollSnapPoints& b) { - SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, x_points_, b); - } - - // scroll-snap-points-y - static ScrollSnapPoints InitialScrollSnapPointsY() { - return ScrollSnapPoints(); - } - const ScrollSnapPoints& ScrollSnapPointsY() const { - return rare_non_inherited_data_->scroll_snap_data_->y_points_; - } - void SetScrollSnapPointsY(const ScrollSnapPoints& b) { - SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, y_points_, b); - } - // scroll-snap-type - static ScrollSnapType InitialScrollSnapType() { return kScrollSnapTypeNone; } + static ScrollSnapType InitialScrollSnapType() { return ScrollSnapType(); } ScrollSnapType GetScrollSnapType() const { - return static_cast<ScrollSnapType>( - rare_non_inherited_data_->scroll_snap_type_); + return rare_non_inherited_data_->scroll_snap_data_->type_; } - void SetScrollSnapType(ScrollSnapType b) { - SET_VAR(rare_non_inherited_data_, scroll_snap_type_, b); + void SetScrollSnapType(const ScrollSnapType& b) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, type_, b); + } + + // Scroll Padding properties + static Length InitialScrollPadding() { return Length(); } + + // scroll-padding-top + const Length& ScrollPaddingTop() const { + return rare_non_inherited_data_->scroll_snap_data_->padding_.top; + } + void SetScrollPaddingTop(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, padding_.top, + v); + } + + // scroll-padding-bottom + const Length& ScrollPaddingBottom() const { + return rare_non_inherited_data_->scroll_snap_data_->padding_.bottom; + } + void SetScrollPaddingBottom(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, padding_.bottom, + v); + } + + // scroll-padding-left + const Length& ScrollPaddingLeft() const { + return rare_non_inherited_data_->scroll_snap_data_->padding_.left; + } + void SetScrollPaddingLeft(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, padding_.left, + v); + } + + // scroll-padding-right + const Length& ScrollPaddingRight() const { + return rare_non_inherited_data_->scroll_snap_data_->padding_.right; + } + void SetScrollPaddingRight(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, padding_.right, + v); + } + + // scroll-padding-block-start + const Length& ScrollPaddingBlockStart() const { + return IsHorizontalWritingMode() ? ScrollPaddingTop() : ScrollPaddingLeft(); + } + void SetScrollPaddingBlockStart(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollPaddingTop(v); + else + SetScrollPaddingLeft(v); + } + + // scroll-padding-block-end + const Length& ScrollPaddingBlockEnd() const { + return IsHorizontalWritingMode() ? ScrollPaddingBottom() + : ScrollPaddingRight(); + } + void SetScrollPaddingBlockEnd(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollPaddingBottom(v); + else + SetScrollPaddingRight(v); + } + + // scroll-padding-inline-start + const Length& ScrollPaddingInlineStart() const { + return IsHorizontalWritingMode() ? ScrollPaddingLeft() : ScrollPaddingTop(); + } + void SetScrollPaddingInlineStart(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollPaddingLeft(v); + else + SetScrollPaddingTop(v); + } + + // scroll-padding-inline-end + const Length& ScrollPaddingInlineEnd() const { + return IsHorizontalWritingMode() ? ScrollPaddingRight() + : ScrollPaddingBottom(); + } + void SetScrollPaddingInlineEnd(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollPaddingRight(v); + else + SetScrollPaddingBottom(v); + } + + // scroll-snap-margin + static Length InitialScrollSnapMargin() { return Length(); } + + // scroll-snap-margin-top + const Length& ScrollSnapMarginTop() const { + return rare_non_inherited_data_->scroll_snap_data_->margin_.top; + } + void SetScrollSnapMarginTop(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, margin_.top, v); + } + + // scroll-snap-margin-bottom + const Length& ScrollSnapMarginBottom() const { + return rare_non_inherited_data_->scroll_snap_data_->margin_.bottom; + } + void SetScrollSnapMarginBottom(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, margin_.bottom, + v); + } + + // scroll-snap-margin-left + const Length& ScrollSnapMarginLeft() const { + return rare_non_inherited_data_->scroll_snap_data_->margin_.left; + } + void SetScrollSnapMarginLeft(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, margin_.left, + v); + } + + // scroll-snap-margin-right + const Length& ScrollSnapMarginRight() const { + return rare_non_inherited_data_->scroll_snap_data_->margin_.right; + } + void SetScrollSnapMarginRight(const Length& v) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, margin_.right, + v); + } + + // scroll-snap-margin-block-start + const Length& ScrollSnapMarginBlockStart() const { + return IsHorizontalWritingMode() ? ScrollSnapMarginTop() + : ScrollSnapMarginLeft(); + } + void SetScrollSnapMarginBlockStart(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollSnapMarginTop(v); + else + SetScrollSnapMarginLeft(v); + } + + // scroll-snap-margin-block-end + const Length& ScrollSnapMarginBlockEnd() const { + return IsHorizontalWritingMode() ? ScrollSnapMarginBottom() + : ScrollSnapMarginRight(); + } + void SetScrollSnapMarginBlockEnd(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollSnapMarginBottom(v); + else + SetScrollSnapMarginRight(v); + } + + // scroll-snap-margin-inline-start + const Length& ScrollSnapMarginInlineStart() const { + return IsHorizontalWritingMode() ? ScrollSnapMarginLeft() + : ScrollSnapMarginTop(); + } + void SetScrollSnapMarginInlineStart(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollSnapMarginLeft(v); + else + SetScrollSnapMarginTop(v); + } + + // scroll-snap-margin-inline-end + const Length& ScrollSnapMarginInlineEnd() const { + return IsHorizontalWritingMode() ? ScrollSnapMarginRight() + : ScrollSnapMarginBottom(); + } + void SetScrollSnapMarginInlineEnd(const Length& v) { + if (IsHorizontalWritingMode()) + SetScrollSnapMarginRight(v); + else + SetScrollSnapMarginBottom(v); + } + + // scroll-snap-align + static ScrollSnapAlign InitialScrollSnapAlign() { return ScrollSnapAlign(); } + ScrollSnapAlign GetScrollSnapAlign() const { + return rare_non_inherited_data_->scroll_snap_data_->align_; + } + void SetScrollSnapAlign(const ScrollSnapAlign& b) { + SET_NESTED_VAR(rare_non_inherited_data_, scroll_snap_data_, align_, b); } // shape-image-threshold (aka -webkit-shape-image-threshold)
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h index 243afcd4..c381ef9 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h +++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -350,10 +350,21 @@ kContentBox }; -enum ScrollSnapType { - kScrollSnapTypeNone, - kScrollSnapTypeMandatory, - kScrollSnapTypeProximity +enum SnapAxis { + kSnapAxisBoth, + kSnapAxisX, + kSnapAxisY, + kSnapAxisBlock, + kSnapAxisInline, +}; + +enum SnapStrictness { kSnapStrictnessProximity, kSnapStrictnessMandatory }; + +enum SnapAlignment { + kSnapAlignmentNone, + kSnapAlignmentStart, + kSnapAlignmentEnd, + kSnapAlignmentCenter }; enum AutoRepeatType { kNoAutoRepeat, kAutoFill, kAutoFit };
diff --git a/third_party/WebKit/Source/core/style/QuadLengthValue.h b/third_party/WebKit/Source/core/style/QuadLengthValue.h new file mode 100644 index 0000000..b3cb447 --- /dev/null +++ b/third_party/WebKit/Source/core/style/QuadLengthValue.h
@@ -0,0 +1,44 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef QuadLengthValue_h +#define QuadLengthValue_h + +#include <memory> +#include "platform/Length.h" + +namespace blink { + +struct QuadLengthValue { + DISALLOW_NEW(); + + QuadLengthValue() {} + + explicit QuadLengthValue(Length length) + : top(length), right(length), bottom(length), left(length) {} + + QuadLengthValue(const QuadLengthValue& other) + : top(other.top), + right(other.right), + bottom(other.bottom), + left(other.left) {} + + bool operator==(const QuadLengthValue& other) const { + return top == other.top && right == other.right && bottom == other.bottom && + left == other.left; + } + + bool operator!=(const QuadLengthValue& other) const { + return !(*this == other); + } + + Length top; + Length right; + Length bottom; + Length left; +}; + +} // namespace blink + +#endif // QuadLengthValue_h
diff --git a/third_party/WebKit/Source/core/style/ScrollSnapPoints.h b/third_party/WebKit/Source/core/style/ScrollSnapPoints.h deleted file mode 100644 index 473265b6..0000000 --- a/third_party/WebKit/Source/core/style/ScrollSnapPoints.h +++ /dev/null
@@ -1,35 +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. - -#ifndef ScrollSnapPoints_h -#define ScrollSnapPoints_h - -#include <memory> -#include "platform/Length.h" - -namespace blink { - -struct ScrollSnapPoints { - DISALLOW_NEW(); - - ScrollSnapPoints() - : repeat_offset(100, kPercent), has_repeat(false), uses_elements(false) {} - - bool operator==(const ScrollSnapPoints& other) const { - return repeat_offset == other.repeat_offset && - has_repeat == other.has_repeat && - uses_elements == other.uses_elements; - } - bool operator!=(const ScrollSnapPoints& other) const { - return !(*this == other); - } - - Length repeat_offset; - bool has_repeat; - bool uses_elements; -}; - -} // namespace blink - -#endif // ScrollSnapPoints_h
diff --git a/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp b/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp index b33d1b2..e6841a2 100644 --- a/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp +++ b/third_party/WebKit/Source/core/style/StyleScrollSnapData.cpp
@@ -30,20 +30,20 @@ namespace blink { StyleScrollSnapData::StyleScrollSnapData() - : x_points_(ComputedStyle::InitialScrollSnapPointsX()), - y_points_(ComputedStyle::InitialScrollSnapPointsY()), - destination_(ComputedStyle::InitialScrollSnapDestination()), - coordinates_(ComputedStyle::InitialScrollSnapCoordinate()) {} + : type_(ComputedStyle::InitialScrollSnapType()), + align_(ComputedStyle::InitialScrollSnapAlign()), + padding_(ComputedStyle::InitialScrollPadding()), + margin_(ComputedStyle::InitialScrollSnapMargin()) {} StyleScrollSnapData::StyleScrollSnapData(const StyleScrollSnapData& other) - : x_points_(other.x_points_), - y_points_(other.y_points_), - destination_(other.destination_), - coordinates_(other.coordinates_) {} + : type_(other.type_), + align_(other.align_), + padding_(other.padding_), + margin_(other.margin_) {} bool operator==(const StyleScrollSnapData& a, const StyleScrollSnapData& b) { - return a.x_points_ == b.x_points_ && a.y_points_ == b.y_points_ && - a.destination_ == b.destination_ && a.coordinates_ == b.coordinates_; + return a.type_ == b.type_ && a.align_ == b.align_ && + a.padding_ == b.padding_ && a.margin_ == b.margin_; } } // namespace blink
diff --git a/third_party/WebKit/Source/core/style/StyleScrollSnapData.h b/third_party/WebKit/Source/core/style/StyleScrollSnapData.h index 517f57b..ea02b97 100644 --- a/third_party/WebKit/Source/core/style/StyleScrollSnapData.h +++ b/third_party/WebKit/Source/core/style/StyleScrollSnapData.h
@@ -26,7 +26,8 @@ #ifndef StyleScrollSnapData_h #define StyleScrollSnapData_h -#include "core/style/ScrollSnapPoints.h" +#include "core/style/ComputedStyleConstants.h" +#include "core/style/QuadLengthValue.h" #include "platform/LengthPoint.h" #include "platform/wtf/Allocator.h" #include "platform/wtf/RefCounted.h" @@ -34,6 +35,57 @@ namespace blink { +using ScrollPadding = QuadLengthValue; +using ScrollSnapMargin = QuadLengthValue; + +struct ScrollSnapType { + DISALLOW_NEW(); + + ScrollSnapType() + : is_none(true), + axis(kSnapAxisBoth), + strictness(kSnapStrictnessProximity) {} + + ScrollSnapType(const ScrollSnapType& other) + : is_none(other.is_none), + axis(other.axis), + strictness(other.strictness) {} + + bool operator==(const ScrollSnapType& other) const { + return is_none == other.is_none && axis == other.axis && + strictness == other.strictness; + } + + bool operator!=(const ScrollSnapType& other) const { + return !(*this == other); + } + + bool is_none; + SnapAxis axis; + SnapStrictness strictness; +}; + +struct ScrollSnapAlign { + DISALLOW_NEW(); + + ScrollSnapAlign() + : alignmentX(kSnapAlignmentNone), alignmentY(kSnapAlignmentNone) {} + + ScrollSnapAlign(const ScrollSnapAlign& other) + : alignmentX(other.alignmentX), alignmentY(other.alignmentY) {} + + bool operator==(const ScrollSnapAlign& other) const { + return alignmentX == other.alignmentX && alignmentY == other.alignmentY; + } + + bool operator!=(const ScrollSnapAlign& other) const { + return !(*this == other); + } + + SnapAlignment alignmentX; + SnapAlignment alignmentY; +}; + class StyleScrollSnapData : public RefCounted<StyleScrollSnapData> { public: static PassRefPtr<StyleScrollSnapData> Create() { @@ -43,14 +95,14 @@ return AdoptRef(new StyleScrollSnapData(*this)); } - ScrollSnapPoints x_points_; - ScrollSnapPoints y_points_; - LengthPoint destination_; - Vector<LengthPoint> coordinates_; + ScrollSnapType type_; + ScrollSnapAlign align_; + ScrollPadding padding_; + ScrollSnapMargin margin_; private: StyleScrollSnapData(); - StyleScrollSnapData(const StyleScrollSnapData&); + StyleScrollSnapData(const StyleScrollSnapData& other); }; bool operator==(const StyleScrollSnapData&, const StyleScrollSnapData&);
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp index db6ef3fa..b5aec8e 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -1347,7 +1347,6 @@ // These roles have implicit live region status. if (live_region_status.IsEmpty()) { switch (RoleValue()) { - case kAlertDialogRole: case kAlertRole: return live_region_status_assertive; case kLogRole:
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp index 3f6f763f..0141a1d8 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp
@@ -1206,7 +1206,7 @@ bool AXObjectImpl::SupportsARIAAttributes() const { return IsLiveRegion() || SupportsARIADragging() || SupportsARIADropping() || SupportsARIAFlowTo() || SupportsARIAOwns() || - HasAttribute(aria_labelAttr); + HasAttribute(aria_labelAttr) || HasAttribute(aria_currentAttr); } bool AXObjectImpl::SupportsRangeValue() const {
diff --git a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp index 66d6a66cf..a46663d 100644 --- a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp +++ b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.cpp
@@ -20,6 +20,7 @@ #include "modules/plugins/DOMMimeTypeArray.h" +#include "core/dom/Document.h" #include "core/frame/LocalFrame.h" #include "core/page/Page.h" #include "platform/plugins/PluginData.h" @@ -28,12 +29,13 @@ namespace blink { -DOMMimeTypeArray::DOMMimeTypeArray(LocalFrame* frame) : ContextClient(frame) { +DOMMimeTypeArray::DOMMimeTypeArray(LocalFrame* frame) + : ContextLifecycleObserver(frame ? frame->GetDocument() : nullptr) { UpdatePluginData(); } DEFINE_TRACE(DOMMimeTypeArray) { - ContextClient::Trace(visitor); + ContextLifecycleObserver::Trace(visitor); visitor->Trace(dom_mime_types_); } @@ -96,4 +98,8 @@ } } +void DOMMimeTypeArray::ContextDestroyed(ExecutionContext*) { + dom_mime_types_.clear(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h index 62a63a1..a935f90 100644 --- a/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h +++ b/third_party/WebKit/Source/modules/plugins/DOMMimeTypeArray.h
@@ -34,7 +34,7 @@ class DOMMimeTypeArray final : public GarbageCollected<DOMMimeTypeArray>, public ScriptWrappable, - public ContextClient { + public ContextLifecycleObserver { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(DOMMimeTypeArray); @@ -53,6 +53,7 @@ private: explicit DOMMimeTypeArray(LocalFrame*); PluginData* GetPluginData() const; + void ContextDestroyed(ExecutionContext*) override; HeapVector<Member<DOMMimeType>> dom_mime_types_; };
diff --git a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp index 9527ae103f..829bf44 100644 --- a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp +++ b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.cpp
@@ -20,6 +20,7 @@ #include "modules/plugins/DOMPluginArray.h" +#include "core/dom/Document.h" #include "core/frame/LocalDOMWindow.h" #include "core/frame/LocalFrame.h" #include "core/frame/Navigator.h" @@ -33,12 +34,13 @@ namespace blink { -DOMPluginArray::DOMPluginArray(LocalFrame* frame) : ContextClient(frame) { +DOMPluginArray::DOMPluginArray(LocalFrame* frame) + : ContextLifecycleObserver(frame ? frame->GetDocument() : nullptr) { UpdatePluginData(); } DEFINE_TRACE(DOMPluginArray) { - ContextClient::Trace(visitor); + ContextLifecycleObserver::Trace(visitor); visitor->Trace(dom_plugins_); } @@ -47,11 +49,12 @@ } DOMPlugin* DOMPluginArray::item(unsigned index) { + if (index >= dom_plugins_.size()) + return nullptr; + // TODO(lfg): Temporary to track down https://crbug.com/731239. CHECK(main_frame_origin_->IsSameSchemeHostPort(GetPluginData()->Origin())); - if (index >= dom_plugins_.size()) - return nullptr; if (!dom_plugins_[index]) { dom_plugins_[index] = DOMPlugin::Create(GetFrame(), *GetPluginData()->Plugins()[index]); @@ -128,4 +131,8 @@ } } +void DOMPluginArray::ContextDestroyed(ExecutionContext*) { + dom_plugins_.clear(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h index c5ea54b8..197092c 100644 --- a/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h +++ b/third_party/WebKit/Source/modules/plugins/DOMPluginArray.h
@@ -35,7 +35,7 @@ class DOMPluginArray final : public GarbageCollectedFinalized<DOMPluginArray>, public ScriptWrappable, - public ContextClient { + public ContextLifecycleObserver { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(DOMPluginArray); @@ -56,6 +56,7 @@ private: explicit DOMPluginArray(LocalFrame*); PluginData* GetPluginData() const; + void ContextDestroyed(ExecutionContext*) override; HeapVector<Member<DOMPlugin>> dom_plugins_;
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp index c1fb7fc..75d7fbf3a 100644 --- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp +++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.cpp
@@ -30,6 +30,7 @@ #include "modules/websockets/DocumentWebSocketChannel.h" +#include <memory> #include "core/dom/DOMArrayBuffer.h" #include "core/dom/ExecutionContext.h" #include "core/dom/TaskRunnerHelper.h" @@ -37,15 +38,12 @@ #include "core/fileapi/FileReaderLoaderClient.h" #include "core/frame/LocalFrame.h" #include "core/frame/LocalFrameClient.h" -#include "core/frame/WebLocalFrameBase.h" #include "core/inspector/ConsoleMessage.h" #include "core/loader/DocumentLoader.h" #include "core/loader/FrameLoader.h" #include "core/loader/MixedContentChecker.h" #include "core/loader/SubresourceFilter.h" #include "core/loader/ThreadableLoadingContext.h" -#include "core/page/ChromeClient.h" -#include "core/page/Page.h" #include "core/probe/CoreProbes.h" #include "modules/websockets/InspectorWebSocketEvents.h" #include "modules/websockets/WebSocketChannelClient.h" @@ -61,9 +59,7 @@ #include "platform/wtf/PtrUtil.h" #include "public/platform/InterfaceProvider.h" #include "public/platform/Platform.h" -#include "public/platform/WebSocketHandshakeThrottle.h" #include "public/platform/WebTraceLocation.h" -#include "public/platform/WebURL.h" namespace blink { @@ -139,44 +135,12 @@ // |this| is deleted here. } -struct DocumentWebSocketChannel::ConnectInfo { - ConnectInfo(const String& selected_protocol, const String& extensions) - : selected_protocol(selected_protocol), extensions(extensions) {} - - const String selected_protocol; - const String extensions; -}; - -// static -DocumentWebSocketChannel* DocumentWebSocketChannel::CreateForTesting( - Document* document, - WebSocketChannelClient* client, - std::unique_ptr<SourceLocation> location, - WebSocketHandle* handle, - std::unique_ptr<WebSocketHandshakeThrottle> handshake_throttle) { - return new DocumentWebSocketChannel( - ThreadableLoadingContext::Create(*document), client, std::move(location), - WTF::WrapUnique(handle), std::move(handshake_throttle)); -} - -// static -DocumentWebSocketChannel* DocumentWebSocketChannel::Create( - ThreadableLoadingContext* loading_context, - WebSocketChannelClient* client, - std::unique_ptr<SourceLocation> location) { - return new DocumentWebSocketChannel( - loading_context, client, std::move(location), - WTF::MakeUnique<WebSocketHandleImpl>(), - Platform::Current()->CreateWebSocketHandshakeThrottle()); -} - DocumentWebSocketChannel::DocumentWebSocketChannel( ThreadableLoadingContext* loading_context, WebSocketChannelClient* client, std::unique_ptr<SourceLocation> location, - std::unique_ptr<WebSocketHandle> handle, - std::unique_ptr<WebSocketHandshakeThrottle> handshake_throttle) - : handle_(std::move(handle)), + WebSocketHandle* handle) + : handle_(WTF::WrapUnique(handle ? handle : new WebSocketHandleImpl())), client_(client), identifier_(CreateUniqueIdentifier()), loading_context_(loading_context), @@ -184,9 +148,7 @@ received_data_size_for_flow_control_( kReceivedDataSizeForFlowControlHighWaterMark * 2), // initial quota sent_size_of_top_message_(0), - location_at_construction_(std::move(location)), - handshake_throttle_(std::move(handshake_throttle)), - throttle_passed_(false) {} + location_at_construction_(std::move(location)) {} DocumentWebSocketChannel::~DocumentWebSocketChannel() { DCHECK(!blob_loader_); @@ -260,22 +222,6 @@ loading_context_->FirstPartyForCookies(), loading_context_->UserAgent(), this); - // TODO(ricea): Maybe lookup GetDocument()->GetFrame() less often? - if (handshake_throttle_ && GetDocument() && GetDocument()->GetFrame() && - GetDocument()->GetFrame()->GetPage()) { - // TODO(ricea): We may need to do something special here for SharedWorkers - // and ServiceWorkers - // TODO(ricea): Figure out who owns this WebFrame object and how long it can - // be expected to live. - LocalFrame* frame = GetDocument()->GetFrame(); - WebLocalFrame* web_frame = - frame->GetPage()->GetChromeClient().GetWebLocalFrameBase(frame); - handshake_throttle_->ThrottleHandshake(url, web_frame, this); - } else { - // Treat no throttle as success. - throttle_passed_ = true; - } - FlowControlIfNecessary(); TRACE_EVENT_INSTANT1("devtools.timeline", "WebSocketCreate", TRACE_EVENT_SCOPE_THREAD, "data", @@ -397,7 +343,6 @@ } connection_handle_for_scheduler_.reset(); AbortAsyncOperations(); - handshake_throttle_.reset(); handle_.reset(); client_ = nullptr; identifier_ = 0; @@ -490,7 +435,6 @@ // No message should be sent from now on. DCHECK_EQ(messages_.size(), 1u); DCHECK_EQ(sent_size_of_top_message_, 0u); - handshake_throttle_.reset(); handle_->Close(message->code, message->reason); messages_.pop_front(); break; @@ -520,7 +464,6 @@ void DocumentWebSocketChannel::HandleDidClose(bool was_clean, unsigned short code, const String& reason) { - handshake_throttle_.reset(); handle_.reset(); AbortAsyncOperations(); if (!client_) { @@ -554,13 +497,6 @@ DCHECK_EQ(handle, handle_.get()); DCHECK(client_); - if (!throttle_passed_) { - connect_info_ = WTF::MakeUnique<ConnectInfo>(selected_protocol, extensions); - return; - } - - handshake_throttle_.reset(); - client_->DidConnect(selected_protocol, extensions); } @@ -736,25 +672,6 @@ client_->DidStartClosingHandshake(); } -void DocumentWebSocketChannel::OnSuccess() { - DCHECK(!throttle_passed_); - DCHECK(handshake_throttle_); - throttle_passed_ = true; - handshake_throttle_ = nullptr; - if (connect_info_) { - client_->DidConnect(std::move(connect_info_->selected_protocol), - std::move(connect_info_->extensions)); - connect_info_.reset(); - } -} - -void DocumentWebSocketChannel::OnError(const WebString& console_message) { - DCHECK(!throttle_passed_); - DCHECK(handshake_throttle_); - handshake_throttle_ = nullptr; - FailAsError(console_message); -} - void DocumentWebSocketChannel::DidFinishLoadingBlob(DOMArrayBuffer* buffer) { blob_loader_.Clear(); DCHECK(handle_); @@ -782,7 +699,6 @@ void DocumentWebSocketChannel::TearDownFailedConnection() { // m_handle and m_client can be null here. connection_handle_for_scheduler_.reset(); - handshake_throttle_.reset(); if (client_) client_->DidError();
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h index 8e05203c..d779151e 100644 --- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h +++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannel.h
@@ -33,7 +33,6 @@ #include <stdint.h> #include <memory> -#include <utility> #include "bindings/core/v8/SourceLocation.h" #include "core/fileapi/Blob.h" #include "core/fileapi/FileError.h" @@ -51,43 +50,40 @@ #include "platform/wtf/Vector.h" #include "platform/wtf/text/CString.h" #include "platform/wtf/text/WTFString.h" -#include "public/platform/WebCallbacks.h" namespace blink { class ThreadableLoadingContext; class WebSocketHandshakeRequest; -class WebSocketHandshakeThrottle; // This class is a WebSocketChannel subclass that works with a Document in a // DOMWindow (i.e. works in the main thread). class MODULES_EXPORT DocumentWebSocketChannel final : public WebSocketChannel, - public WebSocketHandleClient, - public WebCallbacks<void, const WebString&> { + public WebSocketHandleClient { public: // You can specify the source file and the line number information // explicitly by passing the last parameter. // In the usual case, they are set automatically and you don't have to // pass it. + // Specify handle explicitly only in tests. static DocumentWebSocketChannel* Create( Document* document, WebSocketChannelClient* client, - std::unique_ptr<SourceLocation> location) { + std::unique_ptr<SourceLocation> location, + WebSocketHandle* handle = 0) { DCHECK(document); return Create(ThreadableLoadingContext::Create(*document), client, - std::move(location)); + std::move(location), handle); } - static DocumentWebSocketChannel* Create(ThreadableLoadingContext*, - WebSocketChannelClient*, - std::unique_ptr<SourceLocation>); - static DocumentWebSocketChannel* CreateForTesting( - Document*, - WebSocketChannelClient*, - std::unique_ptr<SourceLocation>, - WebSocketHandle*, - std::unique_ptr<WebSocketHandshakeThrottle>); - + static DocumentWebSocketChannel* Create( + ThreadableLoadingContext* loading_context, + WebSocketChannelClient* client, + std::unique_ptr<SourceLocation> location, + WebSocketHandle* handle = 0) { + return new DocumentWebSocketChannel(loading_context, client, + std::move(location), handle); + } ~DocumentWebSocketChannel() override; // WebSocketChannel functions. @@ -112,7 +108,6 @@ private: class BlobLoader; class Message; - struct ConnectInfo; enum MessageType { kMessageTypeText, @@ -131,9 +126,7 @@ DocumentWebSocketChannel(ThreadableLoadingContext*, WebSocketChannelClient*, std::unique_ptr<SourceLocation>, - std::unique_ptr<WebSocketHandle>, - std::unique_ptr<WebSocketHandshakeThrottle>); - + WebSocketHandle*); void SendInternal(WebSocketHandle::MessageType, const char* data, size_t total_size, @@ -174,11 +167,6 @@ void DidReceiveFlowControl(WebSocketHandle*, int64_t quota) override; void DidStartClosingHandshake(WebSocketHandle*) override; - // WebCallbacks<void, const WebString&> functions. These are called with the - // results of throttling. - void OnSuccess() override; - void OnError(const WebString& console_message) override; - // Methods for BlobLoader. void DidFinishLoadingBlob(DOMArrayBuffer*); void DidFailLoadingBlob(FileError::ErrorCode); @@ -210,11 +198,6 @@ std::unique_ptr<SourceLocation> location_at_construction_; RefPtr<WebSocketHandshakeRequest> handshake_request_; - std::unique_ptr<WebSocketHandshakeThrottle> handshake_throttle_; - // This field is only initialised if the object is still waiting for a - // throttle response when DidConnect is called. - std::unique_ptr<ConnectInfo> connect_info_; - bool throttle_passed_; static const uint64_t kReceivedDataSizeForFlowControlHighWaterMark = 1 << 15; };
diff --git a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp index 079360f..a17e615 100644 --- a/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp +++ b/third_party/WebKit/Source/modules/websockets/DocumentWebSocketChannelTest.cpp
@@ -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 "modules/websockets/DocumentWebSocketChannel.h" +#include "modules/websockets/WebSocketChannel.h" #include <stdint.h> #include <memory> @@ -10,7 +10,7 @@ #include "core/dom/Document.h" #include "core/fileapi/Blob.h" #include "core/testing/DummyPageHolder.h" -#include "modules/websockets/WebSocketChannel.h" +#include "modules/websockets/DocumentWebSocketChannel.h" #include "modules/websockets/WebSocketChannelClient.h" #include "modules/websockets/WebSocketHandle.h" #include "modules/websockets/WebSocketHandleClient.h" @@ -19,10 +19,6 @@ #include "platform/wtf/PtrUtil.h" #include "platform/wtf/Vector.h" #include "platform/wtf/text/WTFString.h" -#include "public/platform/WebCallbacks.h" -#include "public/platform/WebSocketHandshakeThrottle.h" -#include "public/platform/WebURL.h" -#include "public/web/WebLocalFrame.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -93,31 +89,16 @@ MOCK_METHOD2(Close, void(unsigned short, const String&)); }; -class MockWebSocketHandshakeThrottle : public WebSocketHandshakeThrottle { - public: - static MockWebSocketHandshakeThrottle* Create() { - return new testing::StrictMock<MockWebSocketHandshakeThrottle>(); - } - MockWebSocketHandshakeThrottle() {} - ~MockWebSocketHandshakeThrottle() override { Destructor(); } - - MOCK_METHOD3(ThrottleHandshake, - void(const WebURL&, - WebLocalFrame*, - WebCallbacks<void, const WebString&>*)); - - // This method is used to allow us to require that the destructor is called at - // a particular time. - MOCK_METHOD0(Destructor, void()); -}; - class DocumentWebSocketChannelTest : public ::testing::Test { public: DocumentWebSocketChannelTest() : page_holder_(DummyPageHolder::Create()), channel_client_(MockWebSocketChannelClient::Create()), handle_(MockWebSocketHandle::Create()), - handshake_throttle_(nullptr), + channel_(DocumentWebSocketChannel::Create(&page_holder_->GetDocument(), + channel_client_.Get(), + SourceLocation::Capture(), + Handle())), sum_of_consumed_buffered_amount_(0) { ON_CALL(*ChannelClient(), DidConsumeBufferedAmount(_)) .WillByDefault(Invoke( @@ -126,13 +107,6 @@ ~DocumentWebSocketChannelTest() { Channel()->Disconnect(); } - void SetUp() override { - channel_ = DocumentWebSocketChannel::CreateForTesting( - &page_holder_->GetDocument(), channel_client_.Get(), - SourceLocation::Capture(), Handle(), - WTF::WrapUnique(handshake_throttle_)); - } - MockWebSocketChannelClient* ChannelClient() { return channel_client_.Get(); } WebSocketChannel* Channel() { @@ -143,10 +117,6 @@ return static_cast<WebSocketHandleClient*>(channel_.Get()); } - WebCallbacks<void, const WebString&>* WebCallbacks() { - return channel_.Get(); - } - MockWebSocketHandle* Handle() { return handle_; } void DidConsumeBufferedAmount(unsigned long a) { @@ -170,8 +140,6 @@ std::unique_ptr<DummyPageHolder> page_holder_; Persistent<MockWebSocketChannelClient> channel_client_; MockWebSocketHandle* handle_; - // |handshake_throttle_| is owned by |channel_| once SetUp() has been called. - MockWebSocketHandshakeThrottle* handshake_throttle_; Persistent<DocumentWebSocketChannel> channel_; unsigned long sum_of_consumed_buffered_amount_; }; @@ -807,221 +775,6 @@ SourceLocation::Create(String(), 0, 0, nullptr)); } -class DocumentWebSocketChannelHandshakeThrottleTest - : public DocumentWebSocketChannelTest { - public: - DocumentWebSocketChannelHandshakeThrottleTest() { - handshake_throttle_ = MockWebSocketHandshakeThrottle::Create(); - } - - // Expectations for the normal result of calling Channel()->Connect() with a - // non-null throttle. - void NormalHandshakeExpectations() { - EXPECT_CALL(*Handle(), Initialize(_)); - EXPECT_CALL(*Handle(), Connect(_, _, _, _, _, _)); - EXPECT_CALL(*Handle(), FlowControl(_)); - EXPECT_CALL(*handshake_throttle_, ThrottleHandshake(_, _, _)); - } - - static KURL url() { return KURL(KURL(), "ws://localhost/"); } -}; - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, ThrottleArguments) { - EXPECT_CALL(*Handle(), Initialize(_)); - EXPECT_CALL(*Handle(), Connect(_, _, _, _, _, _)); - EXPECT_CALL(*Handle(), FlowControl(_)); - EXPECT_CALL(*handshake_throttle_, - ThrottleHandshake(WebURL(url()), _, WebCallbacks())); - EXPECT_CALL(*handshake_throttle_, Destructor()); - Channel()->Connect(url(), ""); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, ThrottleSucceedsFirst) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); - } - Channel()->Connect(url(), ""); - checkpoint.Call(1); - WebCallbacks()->OnSuccess(); - checkpoint.Call(2); - HandleClient()->DidConnect(Handle(), String("a"), String("b")); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, HandshakeSucceedsFirst) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*ChannelClient(), DidConnect(String("a"), String("b"))); - } - Channel()->Connect(url(), ""); - checkpoint.Call(1); - HandleClient()->DidConnect(Handle(), String("a"), String("b")); - checkpoint.Call(2); - WebCallbacks()->OnSuccess(); -} - -// This happens if JS code calls close() during the handshake. -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, FailDuringThrottle) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*ChannelClient(), DidError()); - EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); - EXPECT_CALL(checkpoint, Call(1)); - } - Channel()->Connect(url(), ""); - Channel()->Fail("close during handshake", kWarningMessageLevel, - SourceLocation::Create(String(), 0, 0, nullptr)); - checkpoint.Call(1); -} - -// It makes no difference to the behaviour if the WebSocketHandle has actually -// connected. -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - FailDuringThrottleAfterConnect) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*ChannelClient(), DidError()); - EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); - EXPECT_CALL(checkpoint, Call(1)); - } - Channel()->Connect(url(), ""); - HandleClient()->DidConnect(Handle(), String("a"), String("b")); - Channel()->Fail("close during handshake", kWarningMessageLevel, - SourceLocation::Create(String(), 0, 0, nullptr)); - checkpoint.Call(1); -} - -// This happens if the JS context is destroyed during the handshake. -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, CloseDuringThrottle) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*Handle(), Close(_, _)); - EXPECT_CALL(checkpoint, Call(1)); - } - Channel()->Connect(url(), ""); - Channel()->Close(DocumentWebSocketChannel::kCloseEventCodeGoingAway, ""); - checkpoint.Call(1); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - CloseDuringThrottleAfterConnect) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*Handle(), Close(_, _)); - EXPECT_CALL(checkpoint, Call(1)); - } - Channel()->Connect(url(), ""); - HandleClient()->DidConnect(Handle(), String("a"), String("b")); - Channel()->Close(DocumentWebSocketChannel::kCloseEventCodeGoingAway, ""); - checkpoint.Call(1); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - DisconnectDuringThrottle) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(checkpoint, Call(1)); - } - Channel()->Connect(url(), ""); - Channel()->Disconnect(); - checkpoint.Call(1); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - DisconnectDuringThrottleAfterConnect) { - Checkpoint checkpoint; - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(checkpoint, Call(1)); - } - Channel()->Connect(url(), ""); - HandleClient()->DidConnect(Handle(), String("a"), String("b")); - Channel()->Disconnect(); - checkpoint.Call(1); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - ThrottleReportsErrorBeforeConnect) { - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*ChannelClient(), DidError()); - EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); - } - Channel()->Connect(url(), ""); - WebCallbacks()->OnError("Connection blocked by throttle"); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - ThrottleReportsErrorAfterConnect) { - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*ChannelClient(), DidError()); - EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); - } - Channel()->Connect(url(), ""); - HandleClient()->DidConnect(Handle(), String("a"), String("b")); - WebCallbacks()->OnError("Connection blocked by throttle"); -} - -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - ConnectFailBeforeThrottle) { - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*ChannelClient(), DidError()); - EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); - } - Channel()->Connect(url(), ""); - HandleClient()->DidFail(Handle(), "connect failed"); -} - -// TODO(ricea): Can this actually happen? -TEST_F(DocumentWebSocketChannelHandshakeThrottleTest, - ConnectCloseBeforeThrottle) { - NormalHandshakeExpectations(); - { - InSequence s; - EXPECT_CALL(*handshake_throttle_, Destructor()); - EXPECT_CALL(*ChannelClient(), DidClose(_, _, _)); - } - Channel()->Connect(url(), ""); - HandleClient()->DidClose(Handle(), false, - WebSocketChannel::kCloseEventCodeProtocolError, - "connect error"); -} - } // namespace } // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp index c28506a..d8a57f7 100644 --- a/third_party/WebKit/Source/platform/exported/Platform.cpp +++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -53,7 +53,6 @@ #include "public/platform/WebPrerenderingSupport.h" #include "public/platform/WebRTCCertificateGenerator.h" #include "public/platform/WebRTCPeerConnectionHandler.h" -#include "public/platform/WebSocketHandshakeThrottle.h" #include "public/platform/WebStorageNamespace.h" #include "public/platform/WebThread.h" #include "public/platform/modules/serviceworker/WebServiceWorkerCacheStorage.h" @@ -228,11 +227,6 @@ return nullptr; } -std::unique_ptr<WebSocketHandshakeThrottle> -Platform::CreateWebSocketHandshakeThrottle() { - return nullptr; -} - std::unique_ptr<WebImageCaptureFrameGrabber> Platform::CreateImageCaptureFrameGrabber() { return nullptr;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp index 0a37e356..0fab5bcd 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
@@ -454,4 +454,20 @@ composite_result->SnappedStartPositionForOffset(8)); } +TEST_F(HarfBuzzShaperTest, ShapeResultCopyRangeAcrossRuns) { + // Create 3 runs: + // [0]: 1 character. + // [1]: 5 characters. + // [2]: 2 character. + String mixed_string(u"\u65E5Hello\u65E5\u65E5"); + TextDirection direction = TextDirection::kLtr; + HarfBuzzShaper shaper(mixed_string.Characters16(), mixed_string.length()); + RefPtr<ShapeResult> result = shaper.Shape(&font, direction); + + // CopyRange(5, 7) should copy 1 character from [1] and 1 from [2]. + RefPtr<ShapeResult> target = ShapeResult::Create(&font, 0, direction); + result->CopyRange(5, 7, target.Get()); + EXPECT_EQ(2u, target->NumCharacters()); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp index ce2a8c34..c5734e0 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -466,7 +466,7 @@ if (start_offset < run_end && end_offset > run_start) { unsigned start = start_offset > run_start ? start_offset - run_start : 0; - unsigned end = std::min(end_offset - run_start, run_end); + unsigned end = std::min(end_offset, run_end) - run_start; DCHECK(end > start); auto sub_run = (*run).CreateSubRun(start, end); @@ -477,6 +477,9 @@ } } + DCHECK_EQ(index - target->num_characters_, + std::min(end_offset, EndIndexForResult()) - + std::max(start_offset, StartIndexForResult())); target->num_characters_ = index; }
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp index 33da1532..d2674f18 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
@@ -280,7 +280,7 @@ // use cc_list because it is not finalized yet. auto list_clone = Convert(paint_chunks, layer_state, layer_offset, display_items); - recorder.getRecordingCanvas()->drawDisplayItemList(list_clone); + recorder.getRecordingCanvas()->drawPicture(list_clone->ReleaseAsRecord()); params.tracking.CheckUnderInvalidations(params.debug_name, recorder.finishRecordingAsPicture(), params.interest_rect);
diff --git a/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp b/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp index 2325bb9..e554812 100644 --- a/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp +++ b/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp
@@ -132,8 +132,8 @@ // can be serialized. SkBitmap bitmap; const SkRect mask_record_bounds = reflection.MaskBounds(); - if (mask_record_bounds.width() * mask_record_bounds.height() < - kMaxMaskBufferSize) { + SkScalar mask_buffer_size = mask_record_bounds.width() * mask_record_bounds.height(); + if (mask_buffer_size < kMaxMaskBufferSize && mask_buffer_size > 0.0f) { bitmap.allocPixels(SkImageInfo::MakeN32Premul( mask_record_bounds.width(), mask_record_bounds.height())); SkiaPaintCanvas canvas(bitmap);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp index 2754e91..8b90a505 100644 --- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp +++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
@@ -103,7 +103,7 @@ scoped_refptr<cc::DisplayItemList> display_item_list = PaintChunksToCcLayer::Convert(pointer_paint_chunks, replay_state, gfx::Vector2dF(), GetDisplayItemList()); - canvas.drawDisplayItemList(display_item_list); + canvas.drawPicture(display_item_list->ReleaseAsRecord()); } DISABLE_CFI_PERF
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc index 4cd61c3..542a75f 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -121,10 +121,6 @@ end_renderer_hidden_idle_period_closure_.Reset(base::Bind( &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr())); - suspend_timers_when_backgrounded_closure_.Reset( - base::Bind(&RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded, - weak_factory_.GetWeakPtr())); - default_loading_task_queue_ = NewLoadingTaskQueue(TaskQueue::QueueType::DEFAULT_LOADING); default_timer_task_queue_ = @@ -234,7 +230,13 @@ "RendererScheduler.TaskDurationPerQueueType2.Background.FirstMinute"), background_after_first_minute_task_duration_reporter( "RendererScheduler.TaskDurationPerQueueType2.Background." - "AfterFirstMinute") { + "AfterFirstMinute"), + hidden_task_duration_reporter( + "RendererScheduler.TaskDurationPerQueueType2.Hidden"), + visible_task_duration_reporter( + "RendererScheduler.TaskDurationPerQueueType.Visible"), + hidden_music_task_duration_reporter( + "RendererScheduler.TaskDurationPerQueueType.HiddenMusic") { foreground_main_thread_load_tracker.Resume(now); } @@ -559,51 +561,47 @@ UpdatePolicyLocked(UpdateType::FORCE_UPDATE); } -void RendererSchedulerImpl::OnRendererBackgrounded() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::OnRendererBackgrounded"); +void RendererSchedulerImpl::SetRendererHidden(bool hidden) { + if (hidden) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::OnRendererHidden"); + } else { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::OnRendererVisible"); + } helper_.CheckOnValidThread(); - if (helper_.IsShutdown() || GetMainThreadOnly().renderer_backgrounded) - return; - - GetMainThreadOnly().renderer_backgrounded = true; - - UpdatePolicy(); - - base::TimeTicks now = tick_clock()->NowTicks(); - GetMainThreadOnly().foreground_main_thread_load_tracker.Pause(now); - GetMainThreadOnly().background_main_thread_load_tracker.Resume(now); - - if (!GetMainThreadOnly().timer_queue_suspension_when_backgrounded_enabled) - return; - - suspend_timers_when_backgrounded_closure_.Cancel(); - base::TimeDelta suspend_timers_when_backgrounded_delay = - base::TimeDelta::FromMilliseconds( - kSuspendTimersWhenBackgroundedDelayMillis); - control_task_queue_->PostDelayedTask( - FROM_HERE, suspend_timers_when_backgrounded_closure_.GetCallback(), - suspend_timers_when_backgrounded_delay); + GetMainThreadOnly().renderer_hidden = hidden; } -void RendererSchedulerImpl::OnRendererForegrounded() { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), - "RendererSchedulerImpl::OnRendererForegrounded"); +void RendererSchedulerImpl::SetRendererBackgrounded(bool backgrounded) { + if (backgrounded) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::OnRendererBackgrounded"); + } else { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), + "RendererSchedulerImpl::OnRendererForegrounded"); + } helper_.CheckOnValidThread(); - if (helper_.IsShutdown() || !GetMainThreadOnly().renderer_backgrounded) + if (helper_.IsShutdown() || + GetMainThreadOnly().renderer_backgrounded == backgrounded) return; - GetMainThreadOnly().renderer_backgrounded = false; - GetMainThreadOnly().renderer_suspended = false; + GetMainThreadOnly().renderer_backgrounded = backgrounded; + if (!backgrounded) + GetMainThreadOnly().renderer_suspended = false; + + GetMainThreadOnly().background_status_changed_at = tick_clock()->NowTicks(); UpdatePolicy(); base::TimeTicks now = tick_clock()->NowTicks(); - GetMainThreadOnly().foreground_main_thread_load_tracker.Resume(now); - GetMainThreadOnly().background_main_thread_load_tracker.Pause(now); - - suspend_timers_when_backgrounded_closure_.Cancel(); - ResumeTimerQueueWhenForegroundedOrResumed(); + if (backgrounded) { + GetMainThreadOnly().foreground_main_thread_load_tracker.Pause(now); + GetMainThreadOnly().background_main_thread_load_tracker.Resume(now); + } else { + GetMainThreadOnly().foreground_main_thread_load_tracker.Resume(now); + GetMainThreadOnly().background_main_thread_load_tracker.Pause(now); + } } void RendererSchedulerImpl::OnAudioStateChanged() { @@ -629,7 +627,6 @@ return; if (!GetMainThreadOnly().renderer_backgrounded) return; - suspend_timers_when_backgrounded_closure_.Cancel(); UMA_HISTOGRAM_COUNTS("PurgeAndSuspend.PendingTaskCount", helper_.GetNumberOfPendingTasks()); @@ -637,7 +634,7 @@ // TODO(hajimehoshi): We might need to suspend not only timer queue but also // e.g. loading tasks or postMessage. GetMainThreadOnly().renderer_suspended = true; - SuspendTimerQueueWhenBackgrounded(); + UpdatePolicy(); } void RendererSchedulerImpl::ResumeRenderer() { @@ -646,9 +643,8 @@ return; if (!GetMainThreadOnly().renderer_backgrounded) return; - suspend_timers_when_backgrounded_closure_.Cancel(); GetMainThreadOnly().renderer_suspended = false; - ResumeTimerQueueWhenForegroundedOrResumed(); + UpdatePolicy(); } void RendererSchedulerImpl::EndIdlePeriod() { @@ -947,6 +943,24 @@ UpdatePolicyLocked(UpdateType::FORCE_UPDATE); } +namespace { + +void UpdatePolicyDuration(base::TimeTicks now, + base::TimeTicks policy_expiration, + base::TimeDelta* policy_duration) { + if (policy_expiration <= now) + return; + + if (policy_duration->is_zero()) { + *policy_duration = policy_expiration - now; + return; + } + + *policy_duration = std::min(*policy_duration, policy_expiration - now); +} + +} // namespace + void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { helper_.CheckOnValidThread(); any_thread_lock_.AssertAcquired(); @@ -1002,20 +1016,31 @@ // work. if (GetMainThreadOnly().last_audio_state_change && !GetMainThreadOnly().is_audio_playing) { - base::TimeTicks audio_will_expire = - GetMainThreadOnly().last_audio_state_change.value() + - kThrottlingDelayAfterAudioIsPlayed; + UpdatePolicyDuration(now, + GetMainThreadOnly().last_audio_state_change.value() + + kThrottlingDelayAfterAudioIsPlayed, + &new_policy_duration); + } - base::TimeDelta audio_will_expire_after = audio_will_expire - now; + bool timer_queue_newly_suspended = false; + if (GetMainThreadOnly().renderer_backgrounded && + GetMainThreadOnly().timer_queue_suspension_when_backgrounded_enabled) { + base::TimeTicks suspend_timers_at = + GetMainThreadOnly().background_status_changed_at + + base::TimeDelta::FromMilliseconds( + kSuspendTimersWhenBackgroundedDelayMillis); - if (audio_will_expire_after > base::TimeDelta()) { - if (new_policy_duration.is_zero()) { - new_policy_duration = audio_will_expire_after; - } else { - new_policy_duration = - std::min(new_policy_duration, audio_will_expire_after); - } - } + timer_queue_newly_suspended = + !GetMainThreadOnly().timer_queue_suspended_when_backgrounded; + GetMainThreadOnly().timer_queue_suspended_when_backgrounded = + now >= suspend_timers_at || GetMainThreadOnly().renderer_suspended; + timer_queue_newly_suspended &= + GetMainThreadOnly().timer_queue_suspended_when_backgrounded; + + if (!GetMainThreadOnly().timer_queue_suspended_when_backgrounded) + UpdatePolicyDuration(now, suspend_timers_at, &new_policy_duration); + } else { + GetMainThreadOnly().timer_queue_suspended_when_backgrounded = false; } if (new_policy_duration > base::TimeDelta()) { @@ -1162,7 +1187,7 @@ if (GetMainThreadOnly().renderer_suspended) { new_policy.loading_queue_policy.is_enabled = false; - DCHECK(!new_policy.timer_queue_policy.is_enabled); + new_policy.timer_queue_policy.is_enabled = false; } if (GetMainThreadOnly().use_virtual_time) { @@ -1245,6 +1270,9 @@ DCHECK(compositor_task_queue_->IsQueueEnabled()); GetMainThreadOnly().current_policy = new_policy; + + if (timer_queue_newly_suspended) + Platform::Current()->RequestPurgeMemory(); } void RendererSchedulerImpl::ApplyTaskQueuePolicy( @@ -1719,27 +1747,6 @@ UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED); } -void RendererSchedulerImpl::SuspendTimerQueueWhenBackgrounded() { - DCHECK(GetMainThreadOnly().renderer_backgrounded); - if (GetMainThreadOnly().timer_queue_suspended_when_backgrounded) - return; - - GetMainThreadOnly().timer_queue_suspended_when_backgrounded = true; - ForceUpdatePolicy(); - Platform::Current()->RequestPurgeMemory(); -} - -void RendererSchedulerImpl::ResumeTimerQueueWhenForegroundedOrResumed() { - DCHECK(!GetMainThreadOnly().renderer_backgrounded || - (GetMainThreadOnly().renderer_backgrounded && - !GetMainThreadOnly().renderer_suspended)); - if (!GetMainThreadOnly().timer_queue_suspended_when_backgrounded) - return; - - GetMainThreadOnly().timer_queue_suspended_when_backgrounded = false; - ForceUpdatePolicy(); -} - void RendererSchedulerImpl::ResetForNavigationLocked() { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererSchedulerImpl::ResetForNavigationLocked"); @@ -1989,6 +1996,19 @@ GetMainThreadOnly().foreground_task_duration_reporter.RecordTask(queue_type, duration); } + + if (GetMainThreadOnly().renderer_hidden) { + GetMainThreadOnly().hidden_task_duration_reporter.RecordTask(queue_type, + duration); + + if (ShouldDisableThrottlingBecauseOfAudio(start_time)) { + GetMainThreadOnly().hidden_music_task_duration_reporter.RecordTask( + queue_type, duration); + } + } else { + GetMainThreadOnly().visible_task_duration_reporter.RecordTask(queue_type, + duration); + } } void RendererSchedulerImpl::OnBeginNestedRunLoop() {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h index 41ee62b..8336f29a 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.h
@@ -102,8 +102,8 @@ void DidHandleInputEventOnMainThread(const WebInputEvent& web_input_event, WebInputEventResult result) override; void DidAnimateForInputOnCompositorThread() override; - void OnRendererBackgrounded() override; - void OnRendererForegrounded() override; + void SetRendererHidden(bool hidden) override; + void SetRendererBackgrounded(bool backgrounded) override; void SuspendRenderer() override; void ResumeRenderer() override; void AddPendingNavigation(NavigatingFrameType type) override; @@ -521,6 +521,9 @@ TaskDurationMetricReporter background_first_minute_task_duration_reporter; TaskDurationMetricReporter background_after_first_minute_task_duration_reporter; + TaskDurationMetricReporter hidden_task_duration_reporter; + TaskDurationMetricReporter visible_task_duration_reporter; + TaskDurationMetricReporter hidden_music_task_duration_reporter; }; struct AnyThread {
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc index ab19544..3ef917d 100644 --- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -1192,7 +1192,7 @@ FakeInputEvent(blink::WebInputEvent::kGestureTapDown), RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); // Action events like ScrollBegin will kick us back into compositor priority, // allowing service of the timer, loading and idle queues. @@ -1240,7 +1240,7 @@ FakeInputEvent(blink::WebInputEvent::kGestureTapDown), WebInputEventResult::kHandledSystem); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); // Action events like ScrollBegin will kick us back into compositor priority, // allowing service of the timer, loading and idle queues. @@ -1670,7 +1670,7 @@ FakeInputEvent(blink::WebInputEvent::kTouchMove), RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); // Receiving the second touchmove will kick us back into compositor priority. run_order.clear(); @@ -2360,7 +2360,7 @@ scheduler_->SuspendTimerQueue(); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); scheduler_->ResumeTimerQueue(); RunUntilIdle(); @@ -2377,7 +2377,7 @@ scheduler_->task_queue_throttler()->IncreaseThrottleRefCount( static_cast<TaskQueue*>(timer_task_runner_.get())); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); } TEST_F(RendererSchedulerImplTest, ThrottleAndSuspendTimerQueue) { @@ -2389,7 +2389,7 @@ RunUntilIdle(); scheduler_->SuspendTimerQueue(); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); } TEST_F(RendererSchedulerImplTest, MultipleSuspendsNeedMultipleResumes) { @@ -2400,15 +2400,15 @@ scheduler_->SuspendTimerQueue(); scheduler_->SuspendTimerQueue(); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); scheduler_->ResumeTimerQueue(); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); scheduler_->ResumeTimerQueue(); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); scheduler_->ResumeTimerQueue(); RunUntilIdle(); @@ -2418,7 +2418,7 @@ TEST_F(RendererSchedulerImplTest, SuspendRenderer) { // Assume that the renderer is backgrounded. - scheduler_->OnRendererBackgrounded(); + scheduler_->SetRendererBackgrounded(true); // Tasks in some queues don't fire when the renderer is suspended. std::vector<std::string> run_order; @@ -2432,7 +2432,7 @@ // The rest queued tasks fire when the tab goes foregrounded. run_order.clear(); - scheduler_->OnRendererForegrounded(); + scheduler_->SetRendererBackgrounded(false); RunUntilIdle(); EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1"), std::string("T1"))); @@ -2450,7 +2450,7 @@ ScopedAutoAdvanceNowEnabler enable_auto_advance_now(mock_task_runner_); // Assume that the renderer is backgrounded. - scheduler_->OnRendererBackgrounded(); + scheduler_->SetRendererBackgrounded(true); // Tasks in some queues don't fire when the renderer is suspended. std::vector<std::string> run_order; @@ -2491,7 +2491,7 @@ PostTestTasks(&run_order, "D3 T3"); // No crash occurs when the resumed renderer goes foregrounded. // Posted tasks while the renderer is resumed fire. - scheduler_->OnRendererForegrounded(); + scheduler_->SetRendererBackgrounded(false); RunUntilIdle(); EXPECT_THAT(run_order, testing::ElementsAre(std::string("D3"), std::string("T3"))); @@ -2539,7 +2539,7 @@ std::vector<std::string> run_order; PostTestTasks(&run_order, "D1 C1"); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); } TEST_F(RendererSchedulerImplTest, TestRendererBackgroundedTimerSuspension) { @@ -2551,7 +2551,7 @@ base::TimeTicks now; // The background signal will not immediately suspend the timer queue. - scheduler_->OnRendererBackgrounded(); + scheduler_->SetRendererBackgrounded(true); now += base::TimeDelta::FromMilliseconds(1100); clock_->SetNowTicks(now); RunUntilIdle(); @@ -2577,10 +2577,11 @@ // Timer tasks should be suspended until the foregrounded signal. PostTestTasks(&run_order, "T4 T5"); now += base::TimeDelta::FromSeconds(10); + clock_->SetNowTicks(now); RunUntilIdle(); - EXPECT_TRUE(run_order.empty()); + EXPECT_THAT(run_order, testing::ElementsAre()); - scheduler_->OnRendererForegrounded(); + scheduler_->SetRendererBackgrounded(false); RunUntilIdle(); EXPECT_THAT(run_order, testing::ElementsAre(std::string("T4"), std::string("T5"))); @@ -3853,7 +3854,7 @@ DISABLED_DefaultTimerTasksAreThrottledWhenBackgrounded) { ScopedAutoAdvanceNowEnabler enable_auto_advance_now(mock_task_runner_); - scheduler_->OnRendererBackgrounded(); + scheduler_->SetRendererBackgrounded(true); std::vector<base::TimeTicks> run_times; @@ -3871,7 +3872,7 @@ FROM_HERE, base::Bind(&RecordingTimeTestTask, &run_times, clock_.get()), base::TimeDelta::FromMilliseconds(200)); - scheduler_->OnRendererForegrounded(); + scheduler_->SetRendererBackgrounded(false); mock_task_runner_->RunUntilTime(base::TimeTicks() + base::TimeDelta::FromMilliseconds(1500));
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc index e2027fc..6b0e10c 100644 --- a/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc +++ b/third_party/WebKit/Source/platform/scheduler/test/fake_renderer_scheduler.cc
@@ -72,9 +72,9 @@ return false; } -void FakeRendererScheduler::OnRendererBackgrounded() {} +void FakeRendererScheduler::SetRendererHidden(bool hidden) {} -void FakeRendererScheduler::OnRendererForegrounded() {} +void FakeRendererScheduler::SetRendererBackgrounded(bool backgrounded) {} void FakeRendererScheduler::SuspendRenderer() {}
diff --git a/third_party/WebKit/Source/web/tests/scheduler/ThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/scheduler/ThrottlingTest.cpp index a36b99b..e31600f 100644 --- a/third_party/WebKit/Source/web/tests/scheduler/ThrottlingTest.cpp +++ b/third_party/WebKit/Source/web/tests/scheduler/ThrottlingTest.cpp
@@ -56,7 +56,7 @@ ->CurrentThread() ->Scheduler() ->GetRendererSchedulerForTest() - ->OnRendererBackgrounded(); + ->SetRendererBackgrounded(true); // Run delayed tasks for 1 second. All tasks should be completed // with throttling disabled. @@ -88,7 +88,7 @@ ->CurrentThread() ->Scheduler() ->GetRendererSchedulerForTest() - ->OnRendererBackgrounded(); + ->SetRendererBackgrounded(true); // Make sure that we run a task once a second. for (int i = 0; i < 3; ++i) {
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h index 2fdcc52a..f65d73f 100644 --- a/third_party/WebKit/public/platform/Platform.h +++ b/third_party/WebKit/public/platform/Platform.h
@@ -35,8 +35,6 @@ #include <windows.h> #endif -#include <memory> - #include "BlameContext.h" #include "UserMetricsAction.h" #include "WebAudioDevice.h" @@ -120,7 +118,6 @@ class WebScrollbarBehavior; class WebSecurityOrigin; class WebServiceWorkerCacheStorage; -class WebSocketHandshakeThrottle; class WebSpeechSynthesizer; class WebSpeechSynthesizerClient; class WebStorageNamespace; @@ -573,13 +570,6 @@ virtual std::unique_ptr<WebImageCaptureFrameGrabber> CreateImageCaptureFrameGrabber(); - // WebSocket ---------------------------------------------------------- - - // If this method returns non-null the returned object will be used to - // determine if/when a new WebSocket connection can be exposed to Javascript. - virtual std::unique_ptr<WebSocketHandshakeThrottle> - CreateWebSocketHandshakeThrottle(); - // WebWorker ---------------------------------------------------------- virtual void DidStartWorkerThread() {}
diff --git a/third_party/WebKit/public/platform/WebSocketHandshakeThrottle.h b/third_party/WebKit/public/platform/WebSocketHandshakeThrottle.h deleted file mode 100644 index dfe09e1..0000000 --- a/third_party/WebKit/public/platform/WebSocketHandshakeThrottle.h +++ /dev/null
@@ -1,46 +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. -// -// WebSocketHandshakeThrottle provides a facility for embedders to delay -// WebSocket connection establishment. Specifically, at the same time as the -// handshake is started blink::Platform::CreateWebSocketHandshakeThrottle() will -// be called. If a non-null WebSocketHandshakeThrottle is returned then -// ThrottleHandshake() will be called on it. If the result is error then the -// handshake will be aborted, and a connection error will be reported to -// Javascript. If the throttle hasn't reported a result when the WebSocket -// handshake succeeds then Blink will wait for the throttle result before -// reporting the connection is open to Javascript. - -#ifndef WebSocketHandshakeThrottle_h -#define WebSocketHandshakeThrottle_h - -#include "public/platform/WebCallbacks.h" - -namespace blink { - -class WebURL; -class WebLocalFrame; -class WebString; - -// Embedders can implement this class to delay WebSocket connections. -class WebSocketHandshakeThrottle { - public: - // Destruction implies that the handshake has been aborted. Any ongoing work - // should be cleaned up if possible. - virtual ~WebSocketHandshakeThrottle() {} - - // The WebCallbacks OnSuccess or OnError should be called asychronously to - // permit Javascript to use the connection or not. OnError should be passed - // a message to be displayed on the console indicating why the handshake was - // blocked. This object will be destroyed synchronously inside the - // callbacks. Callbacks must not be called after this object has been - // destroyed. - virtual void ThrottleHandshake(const WebURL&, - WebLocalFrame*, - WebCallbacks<void, const WebString&>*) = 0; -}; - -} // namespace blink - -#endif // WebSocketHandshakeThrottle_h
diff --git a/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h index 656c3fa..17fadc04 100644 --- a/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h
@@ -113,17 +113,17 @@ // a fling). Called by the compositor (impl) thread. virtual void DidAnimateForInputOnCompositorThread() = 0; - // Tells the scheduler that the renderer process has been backgrounded, i.e., - // there are no critical, user facing activities (visual, audio, etc...) - // driven by this process. A stricter condition than |OnRendererHidden()|, the - // process is assumed to be foregrounded when the scheduler is constructed. + // Tells the scheduler about the change of renderer visibility status (e.g. + // "all widgets are hidden" condition). Used mostly for metric purposes. // Must be called on the main thread. - virtual void OnRendererBackgrounded() = 0; + virtual void SetRendererHidden(bool hidden) = 0; - // Tells the scheduler that the renderer process has been foregrounded. - // This is the assumed state when the scheduler is constructed. - // Must be called on the main thread. - virtual void OnRendererForegrounded() = 0; + // Tells the scheduler about the change of renderer background status, i.e., + // there are no critical, user facing activities (visual, audio, etc...) + // driven by this process. A stricter condition than |SetRendererHidden()|, + // the process is assumed to be foregrounded when the scheduler is + // constructed. Must be called on the main thread. + virtual void SetRendererBackgrounded(bool backgrounded) = 0; // Tells the scheduler that the render process should be suspended. This can // only be done when the renderer is backgrounded. The renderer will be @@ -180,7 +180,7 @@ virtual void VirtualTimeResumed() = 0; // Sets whether to allow suspension of timers after the backgrounded signal is - // received via OnRendererBackgrounded. Defaults to disabled. + // received via SetRendererBackgrounded(true). Defaults to disabled. virtual void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) = 0; // Sets the default blame context to which top level work should be
diff --git a/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h index b06b8e6..aa89af4 100644 --- a/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/test/fake_renderer_scheduler.h
@@ -37,8 +37,8 @@ void DidHandleInputEventOnMainThread(const WebInputEvent& web_input_event, WebInputEventResult result) override; void DidAnimateForInputOnCompositorThread() override; - void OnRendererBackgrounded() override; - void OnRendererForegrounded() override; + void SetRendererHidden(bool hidden) override; + void SetRendererBackgrounded(bool backgrounded) override; void SuspendRenderer() override; void ResumeRenderer() override; void AddPendingNavigation(NavigatingFrameType type) override;
diff --git a/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h b/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h index 74e531a..14ba4dbe 100644 --- a/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h +++ b/third_party/WebKit/public/platform/scheduler/test/mock_renderer_scheduler.h
@@ -42,8 +42,8 @@ MOCK_METHOD2(DidHandleInputEventOnMainThread, void(const WebInputEvent&, WebInputEventResult)); MOCK_METHOD0(DidAnimateForInputOnCompositorThread, void()); - MOCK_METHOD0(OnRendererBackgrounded, void()); - MOCK_METHOD0(OnRendererForegrounded, void()); + MOCK_METHOD1(SetRendererHidden, void(bool)); + MOCK_METHOD1(SetRendererBackgrounded, void(bool)); MOCK_METHOD0(SuspendRenderer, void()); MOCK_METHOD0(ResumeRenderer, void()); MOCK_METHOD1(AddPendingNavigation, void(NavigatingFrameType));
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 6bfd8528..7a6cf3a 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -23979,6 +23979,31 @@ <int value="557" label="place-content"/> <int value="558" label="place-items"/> <int value="559" label="transform-box"/> + <int value="560" label="place-self"/> + <int value="561" label="scroll-snap-align"/> + <int value="562" label="scroll-padding"/> + <int value="563" label="scroll-padding-top"/> + <int value="564" label="scroll-padding-right"/> + <int value="565" label="scroll-padding-bottom"/> + <int value="566" label="scroll-padding-left"/> + <int value="567" label="scroll-padding-block"/> + <int value="568" label="scroll-padding-block-start"/> + <int value="569" label="scroll-padding-block-end"/> + <int value="570" label="scroll-padding-inline"/> + <int value="571" label="scroll-padding-inline-start"/> + <int value="572" label="scroll-padding-inline-end"/> + <int value="573" label="scroll-snap-margin"/> + <int value="574" label="scroll-snap-margin-top"/> + <int value="575" label="scroll-snap-margin-right"/> + <int value="576" label="scroll-snap-margin-bottom"/> + <int value="577" label="scroll-snap-margin-left"/> + <int value="578" label="scroll-snap-margin-block"/> + <int value="579" label="scroll-snap-margin-block-start"/> + <int value="580" label="scroll-snap-margin-block-end"/> + <int value="581" label="scroll-snap-margin-inline"/> + <int value="582" label="scroll-snap-margin-inline-start"/> + <int value="583" label="scroll-snap-margin-inline-end"/> + <int value="584" label="scroll-snap-stop"/> </enum> <enum name="MappedEditingCommands" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 51751a9..d379da6 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -94155,6 +94155,15 @@ label="Time spent in tasks of a particular type starting from the first minute after backgrounding the renderer. The renderer is expected to be mostly idle during this period."/> + <suffix name="Hidden" + label="Time spent in tasks of a particular type when the renderer is + hidden."/> + <suffix name="Visible" + label="Time spent in tasks of a particular type when the renderer is + visible."/> + <suffix name="HiddenMusic" + label="Time spent in tasks of a particular type when the renderer is + hidden and is playing audible sound."/> <affected-histogram name="RendererScheduler.TaskDurationPerQueueType2"/> </histogram_suffixes>
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py index 092b13c..3480b0c 100644 --- a/tools/perf/benchmarks/battor.py +++ b/tools/perf/benchmarks/battor.py
@@ -48,6 +48,10 @@ def Name(cls): return 'battor.trivial_pages' + def GetExpectations(self): + return page_sets.TrivialStoryExpectations() + + @benchmark.Enabled('mac') @benchmark.Owner(emails=['charliea@chromium.org']) class BattOrSteadyStatePages(_BattOrBenchmark): @@ -59,3 +63,6 @@ @classmethod def Name(cls): return 'battor.steady_state' + + def GetExpectations(self): + return page_sets.IdleAfterLoadingStoryExpectations()
diff --git a/tools/perf/page_sets/idle_after_loading_stories.py b/tools/perf/page_sets/idle_after_loading_stories.py index fc2248c..7f1a8a7 100644 --- a/tools/perf/page_sets/idle_after_loading_stories.py +++ b/tools/perf/page_sets/idle_after_loading_stories.py
@@ -7,9 +7,7 @@ # Chrome has high idle CPU usage on these sites, even after they have quiesced. SITES = [ # https://bugs.chromium.org/p/chromium/issues/detail?id=505990 - # TODO(charliea): Temporarily disable this site, since it causes tracing to - # explode from too much data. https://crbug.com/647398 - # 'http://abcnews.go.com/', + 'http://abcnews.go.com/', # https://bugs.chromium.org/p/chromium/issues/detail?id=505601 'http://www.slideshare.net/patrickmeenan', @@ -53,3 +51,9 @@ # https://crbug.com/638365. for url in SITES: self.AddStory(_BasePage(self, url, wait_in_seconds, url)) + + +class IdleAfterLoadingStoryExpectations(story.expectations.StoryExpectations): + def SetExpectations(self): + self.DisableStory( + 'http://abcnews.go.com/', [story.expectations.ALL], 'crbug.com/505990')
diff --git a/tools/perf/page_sets/trivial_sites.py b/tools/perf/page_sets/trivial_sites.py index ae951d7..409c26d3 100644 --- a/tools/perf/page_sets/trivial_sites.py +++ b/tools/perf/page_sets/trivial_sites.py
@@ -153,3 +153,8 @@ self, shared_state, wait_in_seconds, measure_memory)) self.AddStory(TrivialAnimationPage( self, shared_state, wait_in_seconds, measure_memory)) + + +class TrivialStoryExpectations(story.expectations.StoryExpectations): + def SetExpectations(self): + pass # No tests are disabled.
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc index c5899f2aa0..77236d3 100644 --- a/ui/app_list/views/search_box_view.cc +++ b/ui/app_list/views/search_box_view.cc
@@ -44,7 +44,7 @@ namespace { -constexpr int kPadding = 16; +constexpr int kPadding = 12; constexpr int kInnerPadding = 24; constexpr int kPreferredWidth = 360; constexpr int kPreferredWidthFullscreen = 544; @@ -53,7 +53,7 @@ constexpr SkColor kHintTextColor = SkColorSetARGBMacro(0xFF, 0xA0, 0xA0, 0xA0); constexpr int kBackgroundBorderCornerRadius = 2; -constexpr int kBackgroundBorderCornerRadiusFullscreen = 20; +constexpr int kBackgroundBorderCornerRadiusFullscreen = 24; constexpr int kGoogleIconSize = 24; constexpr int kMicIconSize = 24; @@ -180,6 +180,9 @@ content_container_->AddChildView(google_icon_); search_box_->set_placeholder_text_color(kDefaultSearchboxColor); + search_box_->set_placeholder_text_draw_flags( + gfx::Canvas::TEXT_ALIGN_CENTER); + search_box_->SetFontList(search_box_->GetFontList().DeriveWithSizeDelta(2)); } else { back_button_ = new SearchBoxImageButton(this); ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); @@ -230,6 +233,9 @@ } void SearchBoxView::SetShadow(const gfx::ShadowValue& shadow) { + if (is_fullscreen_app_list_enabled_) + return; + SetBorder(base::MakeUnique<views::ShadowBorder>(shadow)); Layout(); }
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index 7b36a34b..7e9dbae11 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -272,6 +272,7 @@ selection_text_color_(SK_ColorWHITE), selection_background_color_(SK_ColorBLUE), placeholder_text_color_(kDefaultPlaceholderTextColor), + placeholder_text_draw_flags_(gfx::Canvas::DefaultCanvasTextAlignment()), invalid_(false), text_input_type_(ui::TEXT_INPUT_TYPE_TEXT), text_input_flags_(0), @@ -1970,11 +1971,12 @@ // Draw placeholder text if needed. gfx::RenderText* render_text = GetRenderText(); if (text().empty() && !GetPlaceholderText().empty()) { - canvas->DrawStringRect(GetPlaceholderText(), GetFontList(), - ui::MaterialDesignController::IsSecondaryUiMaterial() - ? SkColorSetA(GetTextColor(), 0x83) - : placeholder_text_color_, - render_text->display_rect()); + canvas->DrawStringRectWithFlags( + GetPlaceholderText(), GetFontList(), + ui::MaterialDesignController::IsSecondaryUiMaterial() + ? SkColorSetA(GetTextColor(), 0x83) + : placeholder_text_color_, + render_text->display_rect(), placeholder_text_draw_flags_); } render_text->Draw(canvas);
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h index 27639d4..bc57114 100644 --- a/ui/views/controls/textfield/textfield.h +++ b/ui/views/controls/textfield/textfield.h
@@ -162,6 +162,10 @@ placeholder_text_color_ = color; } + void set_placeholder_text_draw_flags(int flags) { + placeholder_text_draw_flags_ = flags; + } + // Sets whether to indicate the textfield has invalid content. void SetInvalid(bool invalid); bool invalid() const { return invalid_; } @@ -472,6 +476,9 @@ // TODO(estade): remove this when Harmony/MD is default. SkColor placeholder_text_color_; + // The draw flags specified for |placeholder_text_|. + int placeholder_text_draw_flags_; + // True when the contents are deemed unacceptable and should be indicated as // such. bool invalid_;