diff --git a/DEPS b/DEPS index ce63a9f..a5a1df9 100644 --- a/DEPS +++ b/DEPS
@@ -138,11 +138,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '08a8496135c5d3570e7d86f9fb902bd45f6e997f', + 'skia_revision': 'd30e039d07f1c7d2090a9422e43c000fa55c5e45', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '8588d1575543e17087081281e2b29c7b001db294', + 'v8_revision': '4ffaaa6ad4ac090ef4d2a31cdc31af4ceab9fe0a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -150,15 +150,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '12f38c49d0ba6bec94808f072a3e29e0df85f081', + 'angle_revision': 'bf826481548182905654cc71a76cd584561ab2e0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '26621d54a086fcf2775e9eed85992f22660fcef1', + 'swiftshader_revision': 'd188b1ad9839bdbdc72248e75f2dc6b864eb0b5e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '92eba93b33c823f2df281aea5ff5204b5907383c', + 'pdfium_revision': '89d1c7c0916ab66a8aec96853c6748e63f3f5ebc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -201,7 +201,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'e502dbcca0143f5ea1a82b62ef81817d0f0c961f', + 'catapult_revision': '2c7abe0de5aa57ec3937351805319d7d356c02d6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -269,7 +269,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'shaderc_revision': 'c21dd10cf1969ae4721e3af7db621076de27bc17', + 'shaderc_revision': '7b84ab7b2ffc31811518b03832a674c8eb1c5a76', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -807,7 +807,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '15e76240d795225e0198b888dcd005ae6aab726e', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f496c5c1c52c9feebd202fb2c61d7ebe7d7062a0', 'condition': 'checkout_linux', }, @@ -1058,7 +1058,7 @@ }, 'src/third_party/libjpeg_turbo': - Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '2a34770be9715cfc1badff10fceba52dd393b094', + Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'd78acdd58d99e49d9b7c1d97c347d4a9239c3f6b', 'src/third_party/liblouis/src': { 'url': Var('chromium_git') + '/external/liblouis-github.git' + '@' + '97ce1c67fccbd3668291b7e63c06161c095d49f2', @@ -1187,7 +1187,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '74222959994106084c1d1f69566e631aab30806f', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f80e84c5cc7e3536e739644c42ab47c8de2640de', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1355,7 +1355,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '856ca198e21cab0b39933658f095762e0e5e1660', + Var('webrtc_git') + '/src.git' + '@' + 'e112bb84ef1fbf523f974a21a70ef0388b2070d2', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1396,7 +1396,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f8393e0eb8714b07fa7f7a1c55fb6ff6952f86d6', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@231d2ee261e7ada45bcb5d50521e1cbe8da083ff', 'condition': 'checkout_src_internal', },
diff --git a/WATCHLISTS b/WATCHLISTS index ace0367..4425981 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1414,6 +1414,12 @@ '|ios/chrome/browser/ui/payments'\ '|ios/web/public/payments' }, + 'pdf': { + 'filepath': 'components/pdf'\ + '|chrome/browser/pdf'\ + '|chrome/browser/ui/pdf'\ + '|pdf' + }, 'pepper_api': { 'filepath': 'ppapi/api'\ '|ppapi/c', @@ -2478,6 +2484,7 @@ 'danyao+paymentswatch@chromium.org'], 'payments_ios': ['mahmadi+paymentsioswatch@chromium.org', 'danyao+paymentswatch@chromium.org'], + 'pdf': ['pdf-reviews@chromium.org'], 'pepper_api': ['binji+watch@chromium.org', 'bradnelson+warch@chromium.org', 'ihf+watch@chromium.org',
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc index f9fe6febd..c211c39 100644 --- a/ash/app_list/app_list_controller_impl.cc +++ b/ash/app_list/app_list_controller_impl.cc
@@ -1420,6 +1420,11 @@ void AppListControllerImpl::NotifyHomeLauncherAnimationTransition( AnimationTrigger trigger, bool launcher_will_show) { + // The AppListView may not exist if this is happening after tablet mode + // has started, but before the view is created. + if (!presenter_.GetView()) + return; + presenter_.GetView()->OnTabletModeAnimationTransitionNotified( CalculateAnimationTransitionForMetrics(trigger, launcher_will_show)); }
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc index f487772..8c9dd74 100644 --- a/ash/app_list/app_list_controller_impl_unittest.cc +++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -12,6 +12,8 @@ #include "ash/app_list/views/search_box_view.h" #include "ash/home_screen/home_launcher_gesture_handler.h" #include "ash/home_screen/home_screen_controller.h" +#include "ash/ime/ime_controller.h" +#include "ash/ime/test_ime_controller_client.h" #include "ash/keyboard/ash_keyboard_controller.h" #include "ash/public/cpp/presentation_time_recorder.h" #include "ash/shelf/shelf.h" @@ -28,6 +30,7 @@ #include "ui/events/test/event_generator.h" #include "ui/message_center/message_center.h" #include "ui/message_center/views/message_popup_view.h" +#include "ui/views/controls/textfield/textfield_test_api.h" namespace ash { @@ -180,6 +183,45 @@ GetAppListView()->GetAppListBackgroundShieldForTest()->GetTransform()); } +// Verify that when the emoji panel shows and AppListView is in Peeking state, +// AppListView's rounded corners should be hidden (see https://crbug.com/950468) +TEST_F(AppListControllerImplTest, HideRoundingCornersWhenEmojiShows) { + // Set IME client. Otherwise the emoji panel is unable to show. + ImeController* ime_controller = Shell::Get()->ime_controller(); + TestImeControllerClient client; + ime_controller->SetClient(client.CreateInterfacePtr()); + + // Show the app list view and right-click on the search box with mouse. So the + // text field's context menu shows. + ShowAppListNow(); + app_list::SearchBoxView* search_box_view = + GetAppListView()->app_list_main_view()->search_box_view(); + gfx::Point center_point = search_box_view->GetBoundsInScreen().CenterPoint(); + ui::test::EventGenerator* event_generator = GetEventGenerator(); + event_generator->MoveMouseTo(center_point); + event_generator->ClickRightButton(); + + // Expect that the first item in the context menu should be "Emoji". Show the + // emoji panel. + auto text_field_api = + std::make_unique<views::TextfieldTestApi>(search_box_view->search_box()); + ASSERT_EQ("Emoji", + base::UTF16ToUTF8( + text_field_api->context_menu_contents()->GetLabelAt(0))); + text_field_api->context_menu_contents()->ActivatedAt(0); + + // Wait for enough time. Then expect that AppListView is pushed up. + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(gfx::Point(0, 0), GetAppListView()->GetBoundsInScreen().origin()); + + // AppListBackgroundShield is translated to hide the rounded corners. + gfx::Transform expected_transform; + expected_transform.Translate(0, -app_list::kAppListBackgroundRadius); + EXPECT_EQ( + expected_transform, + GetAppListView()->GetAppListBackgroundShieldForTest()->GetTransform()); +} + // Verifies that in clamshell mode the bounds of AppListView are correct when // the AppListView is in PEEKING state and the virtual keyboard is enabled (see // https://crbug.com/944233).
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc index 370d05ba..ede47e9 100644 --- a/ash/app_list/app_list_presenter_delegate_unittest.cc +++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -153,19 +153,14 @@ class AppListPresenterDelegateTest : public AppListPresenterDelegateZeroStateTest { public: - AppListPresenterDelegateTest() = default; - ~AppListPresenterDelegateTest() override = default; - - // testing::Test: - void SetUp() override { - AppListPresenterDelegateZeroStateTest::SetUp(); - + AppListPresenterDelegateTest() { // Zeros state changes expected UI behavior. Most test cases in this suite // are the expected UI behavior with zero state being disabled. // TODO(jennyz): Add new test cases for zero state, crbug.com/925195. scoped_feature_list_.InitAndDisableFeature( app_list_features::kEnableZeroStateSuggestions); } + ~AppListPresenterDelegateTest() override = default; private: base::test::ScopedFeatureList scoped_feature_list_; @@ -1376,13 +1371,14 @@ class AppListPresenterDelegateHomeLauncherTest : public AppListPresenterDelegateTest { public: - AppListPresenterDelegateHomeLauncherTest() = default; + AppListPresenterDelegateHomeLauncherTest() { + scoped_feature_list_.InitWithFeatures( + {app_list_features::kEnableBackgroundBlur}, {}); + } ~AppListPresenterDelegateHomeLauncherTest() override = default; // testing::Test: void SetUp() override { - scoped_feature_list_.InitWithFeatures( - {app_list_features::kEnableBackgroundBlur}, {}); AppListPresenterDelegateTest::SetUp(); GetAppListTestHelper()->WaitUntilIdle(); }
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc index 26b7cd34..d2f5c6e 100644 --- a/ash/app_list/views/app_list_view.cc +++ b/ash/app_list/views/app_list_view.cc
@@ -1881,15 +1881,8 @@ ui::PropertyChangeReason reason) { DCHECK_EQ(GetWidget()->GetNativeView(), window); - // When the virtual keyboard shows, the AppListView is moved upward to avoid - // the overlapping area with the virtual keyboard. As a result, its bottom - // side may be on the display edge. Stop showing the rounded corners under - // this circumstance. - const bool hide_rounded_corners = - app_list_state_ == ash::AppListViewState::kHalf && new_bounds.y() == 0; - gfx::Transform transform; - if (hide_rounded_corners) + if (ShouldHideRoundedCorners(new_bounds)) transform.Translate(0, -kAppListBackgroundRadius); app_list_background_shield_->SetTransform(transform); @@ -2130,13 +2123,10 @@ transform.Translate( 0, -kAppListBackgroundRadius * (app_list_transition_progress - 1)); } - } else if (is_fullscreen() || - (app_list_state_ == ash::AppListViewState::kHalf && - GetBoundsInScreen().y() == 0)) { + } else if (is_fullscreen() || ShouldHideRoundedCorners(GetBoundsInScreen())) { // AppListView::Layout may be called after OnWindowBoundsChanged. It may // reset the transform of |app_list_background_shield_|. So hide the rounded - // corners when AppListView is in Half state and its bottom is on the - // display edge. + // corners here when ShouldHideRoundedCorners returns true. transform.Translate(0, -kAppListBackgroundRadius); } app_list_background_shield_->SetTransform(transform); @@ -2165,6 +2155,16 @@ GetPreferredWidgetYForState(target_state); } +bool AppListView::ShouldHideRoundedCorners(const gfx::Rect& bounds) const { + // When the virtual keyboard shows, the AppListView is moved upward to avoid + // the overlapping area with the virtual keyboard. As a result, its bottom + // side may be on the display edge. Stop showing the rounded corners under + // this circumstance. + return (app_list_state_ == ash::AppListViewState::kPeeking || + app_list_state_ == ash::AppListViewState::kHalf) && + bounds.y() == 0; +} + void AppListView::OnStateTransitionAnimationCompleted() { delegate_->OnStateTransitionAnimationCompleted(app_list_state_); }
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h index 3661178..1d60e60e 100644 --- a/ash/app_list/views/app_list_view.h +++ b/ash/app_list/views/app_list_view.h
@@ -440,6 +440,10 @@ bool ShouldUpdateChildViewsDuringAnimation( ash::AppListViewState target_state) const; + // Returns whether AppList's rounded corners should be hidden based on + // |bounds|. + bool ShouldHideRoundedCorners(const gfx::Rect& bounds) const; + AppListViewDelegate* delegate_; // Weak. Owned by AppListService. AppListModel* const model_; // Not Owned. SearchModel* const search_model_; // Not Owned.
diff --git a/ash/public/cpp/window_finder.h b/ash/public/cpp/window_finder.h index d70139b8..ca154de4 100644 --- a/ash/public/cpp/window_finder.h +++ b/ash/public/cpp/window_finder.h
@@ -20,15 +20,13 @@ namespace ash { // Finds the topmost window at |screen_point| with ignoring |ignore|. If -// |real_topmost| is not nullptr, it will be updated to the topmost visible -// window regardless of |ignore|. If overview is active when this function is -// called, the overview window that contains |screen_point| will be returned. -// Note this overview window might not be visibile (e.g., it represents an aura -// window whose window state is MINIMIZED). +// overview is active when this function is called, the overview window that +// contains |screen_point| will be returned. Note this overview window might not +// be visibile (e.g., it represents an aura window whose window state is +// MINIMIZED). ASH_EXPORT aura::Window* GetTopmostWindowAtPoint( const gfx::Point& screen_point, - const std::set<aura::Window*>& ignore, - aura::Window** real_topmost); + const std::set<aura::Window*>& ignore); } // namespace ash
diff --git a/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc b/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc index 7e769bb..180c157 100644 --- a/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc +++ b/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc
@@ -18,6 +18,8 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/time/default_clock.h" +#include "base/time/time.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_device.h" @@ -187,6 +189,8 @@ } void TrayBluetoothHelperLegacy::StartBluetoothDiscovering() { + discovery_start_timestamp_ = base::DefaultClock::GetInstance()->Now(); + if (HasBluetoothDiscoverySession()) { LOG(WARNING) << "Already have active Bluetooth device discovery session."; return; @@ -200,6 +204,8 @@ } void TrayBluetoothHelperLegacy::StopBluetoothDiscovering() { + discovery_start_timestamp_ = base::Time(); + should_run_discovery_ = false; if (!HasBluetoothDiscoverySession()) { LOG(WARNING) << "No active Bluetooth device discovery session."; @@ -219,6 +225,14 @@ return; } + if (!discovery_start_timestamp_.is_null()) { + device::RecordDeviceSelectionDuration( + base::DefaultClock::GetInstance()->Now() - discovery_start_timestamp_, + device::BluetoothUiSurface::kSystemTray, device->IsPaired(), + device->GetType()); + discovery_start_timestamp_ = base::Time(); + } + // Extra consideration taken for already paired devices, for metrics // collection. if (device->IsPaired()) {
diff --git a/ash/system/bluetooth/tray_bluetooth_helper_legacy.h b/ash/system/bluetooth/tray_bluetooth_helper_legacy.h index 119009e..a9aa123 100644 --- a/ash/system/bluetooth/tray_bluetooth_helper_legacy.h +++ b/ash/system/bluetooth/tray_bluetooth_helper_legacy.h
@@ -17,9 +17,13 @@ #include "device/bluetooth/bluetooth_adapter.h" #include "services/device/public/mojom/bluetooth_system.mojom.h" +namespace base { +class Time; +} // namespace base + namespace device { class BluetoothDiscoverySession; -} +} // namespace device namespace ash { @@ -71,6 +75,11 @@ device::mojom::BluetoothSystem::State last_state_ = device::mojom::BluetoothSystem::State::kUnavailable; + // The time at which discovery started, effectively when the user opened the + // System Tray Bluetooth options with Bluetooth on, or when Bluetooth turned + // on while the Bluetooth options were open. + base::Time discovery_start_timestamp_; + // Object could be deleted during a prolonged Bluetooth operation. base::WeakPtrFactory<TrayBluetoothHelperLegacy> weak_ptr_factory_;
diff --git a/ash/wm/window_finder.cc b/ash/wm/window_finder.cc index e173304..7413d5d3 100644 --- a/ash/wm/window_finder.cc +++ b/ash/wm/window_finder.cc
@@ -51,8 +51,7 @@ const gfx::Point& screen_point, aura::Window* window, aura::WindowTargeter* targeter, - const std::set<aura::Window*> ignore, - aura::Window** real_topmost) { + const std::set<aura::Window*> ignore) { if (!window->IsVisible()) return nullptr; @@ -62,11 +61,8 @@ return nullptr; if (IsTopLevelWindow(window)) { - if (IsWindowTargeted(window, screen_point, targeter)) { - if (real_topmost && !(*real_topmost)) - *real_topmost = window; + if (IsWindowTargeted(window, screen_point, targeter)) return (ignore.find(window) == ignore.end()) ? window : nullptr; - } return nullptr; } @@ -76,7 +72,7 @@ aura::WindowTargeter* child_targeter = (*i)->targeter() ? (*i)->targeter() : targeter; aura::Window* result = GetTopmostWindowAtPointWithinWindow( - screen_point, *i, child_targeter, ignore, real_topmost); + screen_point, *i, child_targeter, ignore); if (result) return result; } @@ -115,18 +111,14 @@ namespace ash { aura::Window* GetTopmostWindowAtPoint(const gfx::Point& screen_point, - const std::set<aura::Window*>& ignore, - aura::Window** real_topmost) { - if (real_topmost) - *real_topmost = nullptr; - aura::Window* root = wm::GetRootWindowAt(screen_point); - // GetTopmostWindowAtPointWithinWindow() always needs to be called to update - // |real_topmost| correctly. - aura::Window* topmost_window = GetTopmostWindowAtPointWithinWindow( - screen_point, root, root->targeter(), ignore, real_topmost); + const std::set<aura::Window*>& ignore) { aura::Window* overview_window = GetToplevelWindowInOverviewAtPoint(screen_point, ignore); - return overview_window ? overview_window : topmost_window; + if (overview_window) + return overview_window; + aura::Window* root = wm::GetRootWindowAt(screen_point); + return GetTopmostWindowAtPointWithinWindow(screen_point, root, + root->targeter(), ignore); } } // namespace ash
diff --git a/ash/wm/window_finder_unittest.cc b/ash/wm/window_finder_unittest.cc index bfc5a3b2..f1fd8d9a 100644 --- a/ash/wm/window_finder_unittest.cc +++ b/ash/wm/window_finder_unittest.cc
@@ -23,8 +23,7 @@ CreateTestWindow(gfx::Rect(0, 0, 100, 100)); std::set<aura::Window*> ignore; - EXPECT_EQ(window1.get(), - GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore, nullptr)); + EXPECT_EQ(window1.get(), GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore)); } TEST_F(WindowFinderTest, MultipleDisplays) { @@ -37,12 +36,10 @@ ASSERT_NE(window1->GetRootWindow(), window2->GetRootWindow()); std::set<aura::Window*> ignore; - EXPECT_EQ(window1.get(), - GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore, nullptr)); + EXPECT_EQ(window1.get(), GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore)); EXPECT_EQ(window2.get(), - GetTopmostWindowAtPoint(gfx::Point(210, 10), ignore, nullptr)); - EXPECT_EQ(nullptr, - GetTopmostWindowAtPoint(gfx::Point(10, 210), ignore, nullptr)); + GetTopmostWindowAtPoint(gfx::Point(210, 10), ignore)); + EXPECT_EQ(nullptr, GetTopmostWindowAtPoint(gfx::Point(10, 210), ignore)); } TEST_F(WindowFinderTest, WindowTargeterWithHitTestRects) { @@ -53,21 +50,14 @@ std::set<aura::Window*> ignore; - aura::Window* real_topmost = nullptr; - EXPECT_EQ(window2.get(), - GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore, &real_topmost)); - EXPECT_EQ(window2.get(), real_topmost); + EXPECT_EQ(window2.get(), GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore)); auto targeter = std::make_unique<aura::WindowTargeter>(); targeter->SetInsets(gfx::Insets(0, 50, 0, 0)); window2->SetEventTargeter(std::move(targeter)); - EXPECT_EQ(window1.get(), - GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore, &real_topmost)); - EXPECT_EQ(window1.get(), real_topmost); - EXPECT_EQ(window2.get(), - GetTopmostWindowAtPoint(gfx::Point(60, 10), ignore, &real_topmost)); - EXPECT_EQ(window2.get(), real_topmost); + EXPECT_EQ(window1.get(), GetTopmostWindowAtPoint(gfx::Point(10, 10), ignore)); + EXPECT_EQ(window2.get(), GetTopmostWindowAtPoint(gfx::Point(60, 10), ignore)); } // Tests that when overview is active, GetTopmostWindowAtPoint() will return @@ -94,15 +84,14 @@ grid->GetOverviewItemContaining(window2.get())->target_bounds()); std::set<aura::Window*> ignore; - aura::Window* real_topmost = nullptr; - EXPECT_EQ(window1.get(), GetTopmostWindowAtPoint(bounds1.CenterPoint(), - ignore, &real_topmost)); - EXPECT_EQ(window2.get(), GetTopmostWindowAtPoint(bounds2.CenterPoint(), - ignore, &real_topmost)); + EXPECT_EQ(window1.get(), + GetTopmostWindowAtPoint(bounds1.CenterPoint(), ignore)); + EXPECT_EQ(window2.get(), + GetTopmostWindowAtPoint(bounds2.CenterPoint(), ignore)); wm::GetWindowState(window1.get())->Minimize(); - EXPECT_EQ(window1.get(), GetTopmostWindowAtPoint(bounds1.CenterPoint(), - ignore, &real_topmost)); + EXPECT_EQ(window1.get(), + GetTopmostWindowAtPoint(bounds1.CenterPoint(), ignore)); } } // namespace ash
diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc index c9ea3c8..879538d 100644 --- a/ash/wm/window_resizer.cc +++ b/ash/wm/window_resizer.cc
@@ -13,7 +13,6 @@ #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h" -#include "ui/aura/window_tracker.h" #include "ui/aura/window_tree_host.h" #include "ui/base/hit_test.h" #include "ui/base/ui_base_types.h" @@ -269,12 +268,15 @@ void WindowResizer::SetBoundsDuringResize(const gfx::Rect& bounds) { aura::Window* window = GetTarget(); DCHECK(window); + auto ptr = weak_ptr_factory_.GetWeakPtr(); const gfx::Rect original_bounds = window->bounds(); window->SetBounds(bounds); - aura::WindowTracker tracker; - tracker.Add(window); - if (tracker.windows().empty()) - return; // Assume we've been destroyed. + + // Resizer can be destroyed when a window is attached during tab dragging. + // crbug.com/970911. + if (!ptr) + return; + if (bounds.size() == original_bounds.size()) return; recorder_->RequestNext();
diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h index 35e9899..bd3495a1 100644 --- a/ash/wm/window_resizer.h +++ b/ash/wm/window_resizer.h
@@ -12,6 +12,7 @@ #include "ash/wm/drag_details.h" #include "ash/wm/window_state.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "ui/wm/public/window_move_client.h" namespace aura { @@ -113,6 +114,8 @@ std::unique_ptr<PresentationTimeRecorder> recorder_; + base::WeakPtrFactory<WindowResizer> weak_ptr_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(WindowResizer); };
diff --git a/base/feature_list.cc b/base/feature_list.cc index 56aa03c..d602ce94 100644 --- a/base/feature_list.cc +++ b/base/feature_list.cc
@@ -15,6 +15,7 @@ #include "base/pickle.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "build/build_config.h" namespace base { @@ -78,7 +79,7 @@ #if defined(DCHECK_IS_CONFIGURABLE) const Feature kDCheckIsFatalFeature{"DcheckIsFatal", - base::FEATURE_DISABLED_BY_DEFAULT}; + FEATURE_DISABLED_BY_DEFAULT}; #endif // defined(DCHECK_IS_CONFIGURABLE) FeatureList::FeatureList() = default; @@ -214,8 +215,8 @@ } // static -std::vector<base::StringPiece> FeatureList::SplitFeatureListString( - base::StringPiece input) { +std::vector<StringPiece> FeatureList::SplitFeatureListString( + StringPiece input) { return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); } @@ -244,9 +245,9 @@ instance_existed_before = true; } - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + std::unique_ptr<FeatureList> feature_list(new FeatureList); feature_list->InitializeFromCommandLine(enable_features, disable_features); - base::FeatureList::SetInstance(std::move(feature_list)); + FeatureList::SetInstance(std::move(feature_list)); return !instance_existed_before; } @@ -268,8 +269,8 @@ // DCHECK is also forced to be FATAL if we are running a death-test. // TODO(asvitkine): If we find other use-cases that need integrating here // then define a proper API/hook for the purpose. - if (base::FeatureList::IsEnabled(kDCheckIsFatalFeature) || - base::CommandLine::ForCurrentProcess()->HasSwitch( + if (FeatureList::IsEnabled(kDCheckIsFatalFeature) || + CommandLine::ForCurrentProcess()->HasSwitch( "gtest_internal_run_death_test")) { logging::LOG_DCHECK = logging::LOG_FATAL; } else { @@ -283,7 +284,7 @@ FeatureList* old_instance = g_feature_list_instance; g_feature_list_instance = nullptr; g_initialized_from_accessor = false; - return base::WrapUnique(old_instance); + return WrapUnique(old_instance); } // static @@ -296,6 +297,8 @@ void FeatureList::FinalizeInitialization() { DCHECK(!initialized_); + // Store the field trial list pointer for DCHECKing. + field_trial_list_ = FieldTrialList::GetInstance(); initialized_ = true; } @@ -341,14 +344,19 @@ OverrideState overridden_state) { for (const auto& value : SplitFeatureListString(feature_list)) { StringPiece feature_name = value; - base::FieldTrial* trial = nullptr; + FieldTrial* trial = nullptr; // The entry may be of the form FeatureName<FieldTrialName - in which case, // this splits off the field trial name and associates it with the override. std::string::size_type pos = feature_name.find('<'); if (pos != std::string::npos) { feature_name.set(value.data(), pos); - trial = base::FieldTrialList::Find(value.substr(pos + 1).as_string()); + trial = FieldTrialList::Find(value.substr(pos + 1).as_string()); +#if !defined(OS_NACL) + // If the below DCHECK fires, it means a non-existent trial name was + // specified via the "Feature<Trial" command-line syntax. + DCHECK(trial) << "trial=" << value.substr(pos + 1); +#endif // !defined(OS_NACL) } RegisterOverride(feature_name, overridden_state, trial); @@ -380,6 +388,13 @@ bool command_line_only) { DCHECK(initialized_); + // Check that the FieldTrialList this is associated with, if any, is the + // active one. If not, it likely indicates that this FeatureList has override + // entries from a freed FieldTrial, which may be caused by an incorrect test + // set up. + if (field_trial_list_) + DCHECK_EQ(field_trial_list_, FieldTrialList::GetInstance()); + enable_overrides->clear(); disable_overrides->clear();
diff --git a/base/feature_list.h b/base/feature_list.h index 74e4e9a..883ac924 100644 --- a/base/feature_list.h +++ b/base/feature_list.h
@@ -21,6 +21,7 @@ namespace base { class FieldTrial; +class FieldTrialList; // Specifies whether a given feature is enabled or disabled by default. enum FeatureState { @@ -296,6 +297,12 @@ Lock feature_identity_tracker_lock_; std::map<std::string, const Feature*> feature_identity_tracker_; + // Tracks the associated FieldTrialList for DCHECKs. This is used to catch + // the scenario where multiple FieldTrialList are used with the same + // FeatureList - which can lead to overrides pointing to invalid FieldTrial + // objects. + base::FieldTrialList* field_trial_list_ = nullptr; + // Whether this object has been fully initialized. This gets set to true as a // result of FinalizeInitialization(). bool initialized_ = false;
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 9236f44..b2335a7 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -179,17 +179,15 @@ #if !defined(OS_NACL) // Returns whether the operation succeeded. -bool DeserializeGUIDFromStringPieces(base::StringPiece first, - base::StringPiece second, - base::UnguessableToken* guid) { +bool DeserializeGUIDFromStringPieces(StringPiece first, + StringPiece second, + UnguessableToken* guid) { uint64_t high = 0; uint64_t low = 0; - if (!base::StringToUint64(first, &high) || - !base::StringToUint64(second, &low)) { + if (!StringToUint64(first, &high) || !StringToUint64(second, &low)) return false; - } - *guid = base::UnguessableToken::Deserialize(high, low); + *guid = UnguessableToken::Deserialize(high, low); return true; } #endif // !defined(OS_NACL) @@ -456,6 +454,9 @@ it->second->Release(); registered_.erase(it->first); } + // Note: If this DCHECK fires in a test that uses ScopedFeatureList, it is + // likely caused by nested ScopedFeatureLists being destroyed in a different + // order than they are initialized. DCHECK_EQ(this, global_); global_ = nullptr; } @@ -688,7 +689,7 @@ // static void FieldTrialList::GetInitiallyActiveFieldTrials( - const base::CommandLine& command_line, + const CommandLine& command_line, FieldTrial::ActiveGroups* active_groups) { DCHECK(global_); DCHECK(global_->create_trials_from_command_line_called_); @@ -796,7 +797,7 @@ // static void FieldTrialList::CreateFeaturesFromCommandLine( - const base::CommandLine& command_line, + const CommandLine& command_line, const char* enable_features_switch, const char* disable_features_switch, FeatureList* feature_list) { @@ -854,10 +855,10 @@ #endif // static -base::ReadOnlySharedMemoryRegion +ReadOnlySharedMemoryRegion FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting() { if (!global_) - return base::ReadOnlySharedMemoryRegion(); + return ReadOnlySharedMemoryRegion(); return global_->readonly_allocator_region_.Duplicate(); } @@ -987,8 +988,7 @@ // Recording for stability debugging has to be done inline as a task posted // to an observer may not get executed before a crash. - base::debug::GlobalActivityTracker* tracker = - base::debug::GlobalActivityTracker::Get(); + debug::GlobalActivityTracker* tracker = debug::GlobalActivityTracker::Get(); if (tracker) { tracker->RecordFieldTrial(field_trial->trial_name(), field_trial->group_name_internal()); @@ -1140,13 +1140,25 @@ } // static -bool FieldTrialList::IsGlobalSetForTesting() { - return global_ != nullptr; +FieldTrialList* FieldTrialList::GetInstance() { + return global_; +} + +// static +FieldTrialList* FieldTrialList::BackupInstanceForTesting() { + FieldTrialList* instance = global_; + global_ = nullptr; + return instance; +} + +// static +void FieldTrialList::RestoreInstanceForTesting(FieldTrialList* instance) { + global_ = instance; } // static std::string FieldTrialList::SerializeSharedMemoryRegionMetadata( - const base::ReadOnlySharedMemoryRegion& shm) { + const ReadOnlySharedMemoryRegion& shm) { std::stringstream ss; #if defined(OS_WIN) // Tell the child process the name of the inherited HANDLE. @@ -1163,7 +1175,7 @@ #error Unsupported OS #endif - base::UnguessableToken guid = shm.GetGUID(); + UnguessableToken guid = shm.GetGUID(); ss << guid.GetHighForSerialization() << "," << guid.GetLowForSerialization(); ss << "," << shm.GetSize(); return ss.str(); @@ -1173,27 +1185,27 @@ (defined(OS_MACOSX) && !defined(OS_IOS)) // static -base::ReadOnlySharedMemoryRegion +ReadOnlySharedMemoryRegion FieldTrialList::DeserializeSharedMemoryRegionMetadata( const std::string& switch_value) { - std::vector<base::StringPiece> tokens = base::SplitStringPiece( - switch_value, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + std::vector<StringPiece> tokens = + SplitStringPiece(switch_value, ",", KEEP_WHITESPACE, SPLIT_WANT_ALL); if (tokens.size() != 4) - return base::ReadOnlySharedMemoryRegion(); + return ReadOnlySharedMemoryRegion(); int field_trial_handle = 0; - if (!base::StringToInt(tokens[0], &field_trial_handle)) - return base::ReadOnlySharedMemoryRegion(); + if (!StringToInt(tokens[0], &field_trial_handle)) + return ReadOnlySharedMemoryRegion(); #if defined(OS_FUCHSIA) zx_handle_t handle = static_cast<zx_handle_t>(field_trial_handle); zx::vmo scoped_handle = zx::vmo(handle); #elif defined(OS_WIN) HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); - if (base::IsCurrentProcessElevated()) { - // base::LaunchElevatedProcess doesn't have a way to duplicate the handle, + if (IsCurrentProcessElevated()) { + // LaunchElevatedProcess doesn't have a way to duplicate the handle, // but this process can since by definition it's not sandboxed. - base::ProcessId parent_pid = base::GetParentProcessId(GetCurrentProcess()); + ProcessId parent_pid = GetParentProcessId(GetCurrentProcess()); HANDLE parent_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, parent_pid); // TODO(https://crbug.com/916461): Duplicating the handle is known to fail // with ERROR_ACCESS_DENIED when the parent process is being torn down. This @@ -1208,52 +1220,49 @@ mac::ScopedMachSendRight scoped_handle = rendezvous->TakeSendRight(field_trial_handle); if (!scoped_handle.is_valid()) - return base::ReadOnlySharedMemoryRegion(); + return ReadOnlySharedMemoryRegion(); #endif - base::UnguessableToken guid; + UnguessableToken guid; if (!DeserializeGUIDFromStringPieces(tokens[1], tokens[2], &guid)) - return base::ReadOnlySharedMemoryRegion(); + return ReadOnlySharedMemoryRegion(); int size; - if (!base::StringToInt(tokens[3], &size)) - return base::ReadOnlySharedMemoryRegion(); + if (!StringToInt(tokens[3], &size)) + return ReadOnlySharedMemoryRegion(); - auto platform_handle = base::subtle::PlatformSharedMemoryRegion::Take( + auto platform_handle = subtle::PlatformSharedMemoryRegion::Take( std::move(scoped_handle), - base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly, + subtle::PlatformSharedMemoryRegion::Mode::kReadOnly, static_cast<size_t>(size), guid); - return base::ReadOnlySharedMemoryRegion::Deserialize( - std::move(platform_handle)); + return ReadOnlySharedMemoryRegion::Deserialize(std::move(platform_handle)); } #elif defined(OS_POSIX) && !defined(OS_NACL) // static -base::ReadOnlySharedMemoryRegion +ReadOnlySharedMemoryRegion FieldTrialList::DeserializeSharedMemoryRegionMetadata( int fd, const std::string& switch_value) { - std::vector<base::StringPiece> tokens = base::SplitStringPiece( - switch_value, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); + std::vector<StringPiece> tokens = + SplitStringPiece(switch_value, ",", KEEP_WHITESPACE, SPLIT_WANT_ALL); if (tokens.size() != 3) return ReadOnlySharedMemoryRegion(); - base::UnguessableToken guid; + UnguessableToken guid; if (!DeserializeGUIDFromStringPieces(tokens[0], tokens[1], &guid)) return ReadOnlySharedMemoryRegion(); int size; - if (!base::StringToInt(tokens[2], &size)) + if (!StringToInt(tokens[2], &size)) return ReadOnlySharedMemoryRegion(); - auto platform_region = base::subtle::PlatformSharedMemoryRegion::Take( - base::ScopedFD(fd), - base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly, + auto platform_region = subtle::PlatformSharedMemoryRegion::Take( + ScopedFD(fd), subtle::PlatformSharedMemoryRegion::Mode::kReadOnly, static_cast<size_t>(size), guid); - return base::ReadOnlySharedMemoryRegion::Deserialize( - std::move(platform_region)); + return ReadOnlySharedMemoryRegion::Deserialize(std::move(platform_region)); } #endif @@ -1263,7 +1272,7 @@ // static bool FieldTrialList::CreateTrialsFromSwitchValue( const std::string& switch_value) { - base::ReadOnlySharedMemoryRegion shm = + ReadOnlySharedMemoryRegion shm = DeserializeSharedMemoryRegionMetadata(switch_value); if (!shm.IsValid()) return false; @@ -1281,7 +1290,7 @@ if (fd == -1) return false; - base::ReadOnlySharedMemoryRegion shm = + ReadOnlySharedMemoryRegion shm = DeserializeSharedMemoryRegionMetadata(fd, switch_value); if (!shm.IsValid()) return false; @@ -1294,8 +1303,8 @@ // static bool FieldTrialList::CreateTrialsFromSharedMemoryRegion( - const base::ReadOnlySharedMemoryRegion& shm_region) { - base::ReadOnlySharedMemoryMapping shm_mapping = + const ReadOnlySharedMemoryRegion& shm_region) { + ReadOnlySharedMemoryMapping shm_mapping = shm_region.MapAt(0, kFieldTrialAllocationSize); if (!shm_mapping.IsValid()) OnOutOfMemory(kFieldTrialAllocationSize); @@ -1306,7 +1315,7 @@ // static bool FieldTrialList::CreateTrialsFromSharedMemoryMapping( - base::ReadOnlySharedMemoryMapping shm_mapping) { + ReadOnlySharedMemoryMapping shm_mapping) { global_->field_trial_allocator_ = std::make_unique<ReadOnlySharedPersistentMemoryAllocator>( std::move(shm_mapping), 0, kAllocatorName); @@ -1347,8 +1356,8 @@ if (global_->field_trial_allocator_ != nullptr) return; - base::MappedReadOnlyRegion shm = - base::ReadOnlySharedMemoryRegion::Create(kFieldTrialAllocationSize); + MappedReadOnlyRegion shm = + ReadOnlySharedMemoryRegion::Create(kFieldTrialAllocationSize); if (!shm.IsValid()) OnOutOfMemory(kFieldTrialAllocationSize);
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h index 5834115..ae6068a3 100644 --- a/base/metrics/field_trial.h +++ b/base/metrics/field_trial.h
@@ -534,7 +534,7 @@ // holding field trial information. // Must be called only after a call to CreateTrialsFromCommandLine(). static void GetInitiallyActiveFieldTrials( - const base::CommandLine& command_line, + const CommandLine& command_line, FieldTrial::ActiveGroups* active_groups); // Use a state string (re: StatesToString()) to augment the current list of @@ -558,24 +558,22 @@ // contain the shared memory handle that contains the field trial allocator. // We need the |field_trial_handle_switch| and |fd_key| arguments to be passed // in since base/ can't depend on content/. - static void CreateTrialsFromCommandLine(const base::CommandLine& cmd_line, + static void CreateTrialsFromCommandLine(const CommandLine& cmd_line, const char* field_trial_handle_switch, int fd_key); // Creates base::Feature overrides from the command line by first trying to // use shared memory and then falling back to the command line if it fails. - static void CreateFeaturesFromCommandLine( - const base::CommandLine& command_line, - const char* enable_features_switch, - const char* disable_features_switch, - FeatureList* feature_list); + static void CreateFeaturesFromCommandLine(const CommandLine& command_line, + const char* enable_features_switch, + const char* disable_features_switch, + FeatureList* feature_list); #if defined(OS_WIN) // On Windows, we need to explicitly pass down any handles to be inherited. // This function adds the shared memory handle to field trial state to the // list of handles to be inherited. - static void AppendFieldTrialHandleIfNeeded( - base::HandlesToInheritVector* handles); + static void AppendFieldTrialHandleIfNeeded(HandlesToInheritVector* handles); #elif defined(OS_FUCHSIA) // TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368). #elif defined(OS_MACOSX) && !defined(OS_IOS) @@ -590,8 +588,7 @@ // descriptor. static int GetFieldTrialDescriptor(); #endif - static base::ReadOnlySharedMemoryRegion - DuplicateFieldTrialSharedMemoryForTesting(); + static ReadOnlySharedMemoryRegion DuplicateFieldTrialSharedMemoryForTesting(); // Adds a switch to the command line containing the field trial state as a // string (if not using shared memory to share field trial state), or the @@ -601,7 +598,7 @@ static void CopyFieldTrialStateToFlags(const char* field_trial_handle_switch, const char* enable_features_switch, const char* disable_features_switch, - base::CommandLine* cmd_line); + CommandLine* cmd_line); // Create a FieldTrial with the given |name| and using 100% probability for // the FieldTrial, force FieldTrial to have the same group string as @@ -667,8 +664,16 @@ GetAllFieldTrialsFromPersistentAllocator( PersistentMemoryAllocator const& allocator); - // Returns true if a global field trial list is set. Only used for testing. - static bool IsGlobalSetForTesting(); + // Returns a pointer to the global instance. This is exposed so that it can + // be used in a DCHECK in FeatureList and ScopedFeatureList test-only logic + // and is not intended to be used widely beyond those cases. + static FieldTrialList* GetInstance(); + + // For testing, sets the global instance to null and returns the previous one. + static FieldTrialList* BackupInstanceForTesting(); + + // For testing, sets the global instance to |instance|. + static void RestoreInstanceForTesting(FieldTrialList* instance); private: // Allow tests to access our innards for testing purposes. @@ -688,13 +693,13 @@ // a GUID. Serialization and deserialization doesn't actually transport the // underlying OS resource - that must be done by the Process launcher. static std::string SerializeSharedMemoryRegionMetadata( - const base::ReadOnlySharedMemoryRegion& shm); + const ReadOnlySharedMemoryRegion& shm); #if defined(OS_WIN) || defined(OS_FUCHSIA) || \ (defined(OS_MACOSX) && !defined(OS_IOS)) - static base::ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata( + static ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata( const std::string& switch_value); #elif defined(OS_POSIX) && !defined(OS_NACL) - static base::ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata( + static ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata( int fd, const std::string& switch_value); #endif @@ -719,7 +724,7 @@ // and creates field trials via CreateTrialsFromSharedMemoryMapping(). Returns // true if successful and false otherwise. static bool CreateTrialsFromSharedMemoryRegion( - const base::ReadOnlySharedMemoryRegion& shm_region); + const ReadOnlySharedMemoryRegion& shm_region); // Expects a mapped piece of shared memory |shm_mapping| that was created from // the browser process's field_trial_allocator and shared via the command @@ -727,7 +732,7 @@ // trials in it, and creates them via CreateFieldTrial(). Returns true if // successful and false otherwise. static bool CreateTrialsFromSharedMemoryMapping( - base::ReadOnlySharedMemoryMapping shm_mapping); + ReadOnlySharedMemoryMapping shm_mapping); // Instantiate the field trial allocator, add all existing field trials to it, // and duplicates its handle to a read-only handle, which gets stored in @@ -794,7 +799,7 @@ // Readonly copy of the region to the allocator. Needs to be a member variable // because it's needed from both CopyFieldTrialStateToFlags() and // AppendFieldTrialHandleIfNeeded(). - base::ReadOnlySharedMemoryRegion readonly_allocator_region_; + ReadOnlySharedMemoryRegion readonly_allocator_region_; // Tracks whether CreateTrialsFromCommandLine() has been called. bool create_trials_from_command_line_called_ = false;
diff --git a/base/metrics/field_trial_params.cc b/base/metrics/field_trial_params.cc index 0680d50..e8eb452 100644 --- a/base/metrics/field_trial_params.cc +++ b/base/metrics/field_trial_params.cc
@@ -4,32 +4,91 @@ #include "base/metrics/field_trial_params.h" +#include <set> +#include <utility> +#include <vector> + #include "base/feature_list.h" #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_param_associator.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/stringprintf.h" namespace base { bool AssociateFieldTrialParams(const std::string& trial_name, const std::string& group_name, const FieldTrialParams& params) { - return base::FieldTrialParamAssociator::GetInstance() - ->AssociateFieldTrialParams(trial_name, group_name, params); + return FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( + trial_name, group_name, params); +} + +bool AssociateFieldTrialParamsFromString( + const std::string& params_string, + FieldTrialParamsDecodeStringFunc decode_data_func) { + // Format: Trial1.Group1:k1/v1/k2/v2,Trial2.Group2:k1/v1/k2/v2 + std::set<std::pair<std::string, std::string>> trial_groups; + for (StringPiece experiment_group : + SplitStringPiece(params_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL)) { + std::vector<StringPiece> experiment = SplitStringPiece( + experiment_group, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL); + if (experiment.size() != 2) { + DLOG(ERROR) << "Experiment and params should be separated by ':'"; + return false; + } + + std::vector<std::string> group_parts = + SplitString(experiment[0], ".", TRIM_WHITESPACE, SPLIT_WANT_ALL); + if (group_parts.size() != 2) { + DLOG(ERROR) << "Trial and group name should be separated by '.'"; + return false; + } + + std::vector<std::string> key_values = + SplitString(experiment[1], "/", TRIM_WHITESPACE, SPLIT_WANT_ALL); + if (key_values.size() % 2 != 0) { + DLOG(ERROR) << "Param name and param value should be separated by '/'"; + return false; + } + std::string trial = decode_data_func(group_parts[0]); + std::string group = decode_data_func(group_parts[1]); + auto trial_group = std::make_pair(trial, group); + if (trial_groups.find(trial_group) != trial_groups.end()) { + DLOG(ERROR) << StringPrintf( + "A (trial, group) pair listed more than once. (%s, %s)", + trial.c_str(), group.c_str()); + return false; + } + trial_groups.insert(trial_group); + std::map<std::string, std::string> params; + for (size_t i = 0; i < key_values.size(); i += 2) { + std::string key = decode_data_func(key_values[i]); + std::string value = decode_data_func(key_values[i + 1]); + params[key] = value; + } + bool result = AssociateFieldTrialParams(trial, group, params); + if (!result) { + DLOG(ERROR) << "Failed to associate field trial params for group \"" + << group << "\" in trial \"" << trial << "\""; + return false; + } + } + return true; } bool GetFieldTrialParams(const std::string& trial_name, FieldTrialParams* params) { - return base::FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams( + return FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams( trial_name, params); } -bool GetFieldTrialParamsByFeature(const base::Feature& feature, +bool GetFieldTrialParamsByFeature(const Feature& feature, FieldTrialParams* params) { - if (!base::FeatureList::IsEnabled(feature)) + if (!FeatureList::IsEnabled(feature)) return false; - base::FieldTrial* trial = base::FeatureList::GetFieldTrial(feature); + FieldTrial* trial = FeatureList::GetFieldTrial(feature); if (!trial) return false; @@ -47,25 +106,25 @@ return std::string(); } -std::string GetFieldTrialParamValueByFeature(const base::Feature& feature, +std::string GetFieldTrialParamValueByFeature(const Feature& feature, const std::string& param_name) { - if (!base::FeatureList::IsEnabled(feature)) + if (!FeatureList::IsEnabled(feature)) return std::string(); - base::FieldTrial* trial = base::FeatureList::GetFieldTrial(feature); + FieldTrial* trial = FeatureList::GetFieldTrial(feature); if (!trial) return std::string(); return GetFieldTrialParamValue(trial->trial_name(), param_name); } -int GetFieldTrialParamByFeatureAsInt(const base::Feature& feature, +int GetFieldTrialParamByFeatureAsInt(const Feature& feature, const std::string& param_name, int default_value) { std::string value_as_string = GetFieldTrialParamValueByFeature(feature, param_name); int value_as_int = 0; - if (!base::StringToInt(value_as_string, &value_as_int)) { + if (!StringToInt(value_as_string, &value_as_int)) { if (!value_as_string.empty()) { DLOG(WARNING) << "Failed to parse field trial param " << param_name << " with string value " << value_as_string @@ -78,13 +137,13 @@ return value_as_int; } -double GetFieldTrialParamByFeatureAsDouble(const base::Feature& feature, +double GetFieldTrialParamByFeatureAsDouble(const Feature& feature, const std::string& param_name, double default_value) { std::string value_as_string = GetFieldTrialParamValueByFeature(feature, param_name); double value_as_double = 0; - if (!base::StringToDouble(value_as_string, &value_as_double)) { + if (!StringToDouble(value_as_string, &value_as_double)) { if (!value_as_string.empty()) { DLOG(WARNING) << "Failed to parse field trial param " << param_name << " with string value " << value_as_string @@ -97,7 +156,7 @@ return value_as_double; } -bool GetFieldTrialParamByFeatureAsBool(const base::Feature& feature, +bool GetFieldTrialParamByFeatureAsBool(const Feature& feature, const std::string& param_name, bool default_value) { std::string value_as_string = @@ -134,7 +193,7 @@ return GetFieldTrialParamByFeatureAsBool(*feature, name, default_value); } -void LogInvalidEnumValue(const base::Feature& feature, +void LogInvalidEnumValue(const Feature& feature, const std::string& param_name, const std::string& value_as_string, int default_value_as_int) {
diff --git a/base/metrics/field_trial_params.h b/base/metrics/field_trial_params.h index b2e838f..a9bd0c54 100644 --- a/base/metrics/field_trial_params.h +++ b/base/metrics/field_trial_params.h
@@ -17,6 +17,9 @@ // Key-value mapping type for field trial parameters. typedef std::map<std::string, std::string> FieldTrialParams; +// Param string decoding function for AssociateFieldTrialParamsFromString(). +typedef std::string (*FieldTrialParamsDecodeStringFunc)(const std::string& str); + // Associates the specified set of key-value |params| with the field trial // specified by |trial_name| and |group_name|. Fails and returns false if the // specified field trial already has params associated with it or the trial @@ -25,6 +28,13 @@ const std::string& group_name, const FieldTrialParams& params); +// Provides a mechanism to associate multiple set of params to multiple groups +// with a formatted string as returned by FieldTrialList::AllParamsToString(). +// |decode_data_func| allows specifying a custom decoding function. +BASE_EXPORT bool AssociateFieldTrialParamsFromString( + const std::string& params_string, + FieldTrialParamsDecodeStringFunc decode_data_func); + // Retrieves the set of key-value |params| for the specified field trial, based // on its selected group. If the field trial does not exist or its selected // group does not have any parameters associated with it, returns false and
diff --git a/base/test/scoped_feature_list.cc b/base/test/scoped_feature_list.cc index 0cc910c..646f9fe 100644 --- a/base/test/scoped_feature_list.cc +++ b/base/test/scoped_feature_list.cc
@@ -14,6 +14,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/test/mock_entropy_provider.h" namespace base { namespace test { @@ -32,6 +33,17 @@ return output; } +std::vector<StringPiece> GetFeatureVectorFromFeaturesAndParams( + const std::vector<ScopedFeatureList::FeatureAndParams>& + features_and_params) { + std::vector<StringPiece> output; + for (const auto& entry : features_and_params) { + output.push_back(entry.feature.name); + } + + return output; +} + // Extracts a feature name from a feature state string. For example, given // the input "*MyLovelyFeature<SomeFieldTrial", returns "MyLovelyFeature". StringPiece GetFeatureName(StringPiece feature) { @@ -69,8 +81,9 @@ StringPiece feature_name = GetFeatureName(feature); if (Contains(merged_features->enabled_feature_list, feature_name) || - Contains(merged_features->disabled_feature_list, feature_name)) + Contains(merged_features->disabled_feature_list, feature_name)) { continue; + } if (override_state == FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE) { merged_features->enabled_feature_list.push_back(feature); @@ -82,25 +95,46 @@ } } +// Hex encode params so that special characters do not break formatting. +std::string HexEncodeString(const std::string& input) { + return HexEncode(input.data(), input.size()); +} + +// Inverse of HexEncodeString(). +std::string HexDecodeString(const std::string& input) { + std::vector<uint8_t> bytes; + bool result = HexStringToBytes(input, &bytes); + DCHECK(result); + return std::string(reinterpret_cast<const char*>(&bytes[0]), bytes.size()); +} + } // namespace ScopedFeatureList::ScopedFeatureList() = default; ScopedFeatureList::~ScopedFeatureList() { + Reset(); +} + +void ScopedFeatureList::Reset() { // If one of the Init() functions was never called, don't reset anything. if (!init_called_) return; - auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance(); - for (const auto& field_trial_override : field_trial_overrides_) { - if (field_trial_override) { - field_trial_param_associator->ClearParamsForTesting( - field_trial_override->trial_name(), - field_trial_override->group_name()); - } - } + init_called_ = false; FeatureList::ClearInstanceForTesting(); + + if (field_trial_list_) { + field_trial_list_.reset(); + + // Restore params to how they were before. + FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); + AssociateFieldTrialParamsFromString(original_params_, &HexDecodeString); + + FieldTrialList::RestoreInstanceForTesting(original_field_trial_list_); + original_field_trial_list_ = nullptr; + } if (original_feature_list_) FeatureList::RestoreInstanceForTesting(std::move(original_feature_list_)); } @@ -130,15 +164,15 @@ void ScopedFeatureList::InitWithFeatures( const std::vector<Feature>& enabled_features, const std::vector<Feature>& disabled_features) { - InitWithFeaturesAndFieldTrials(enabled_features, {}, disabled_features); + InitWithFeaturesImpl(enabled_features, {}, disabled_features); } void ScopedFeatureList::InitAndEnableFeature(const Feature& feature) { - InitWithFeaturesAndFieldTrials({feature}, {}, {}); + InitWithFeaturesImpl({feature}, {}, {}); } void ScopedFeatureList::InitAndDisableFeature(const Feature& feature) { - InitWithFeaturesAndFieldTrials({}, {}, {feature}); + InitWithFeaturesImpl({}, {}, {feature}); } void ScopedFeatureList::InitWithFeatureState(const Feature& feature, @@ -150,49 +184,78 @@ } } -void ScopedFeatureList::InitWithFeaturesAndFieldTrials( +void ScopedFeatureList::InitWithFeaturesImpl( const std::vector<Feature>& enabled_features, - const std::vector<FieldTrial*>& trials_for_enabled_features, + const std::vector<FeatureAndParams>& enabled_features_and_params, const std::vector<Feature>& disabled_features) { - DCHECK_LE(trials_for_enabled_features.size(), enabled_features.size()); + DCHECK(enabled_features.empty() || enabled_features_and_params.empty()); Features merged_features; - merged_features.enabled_feature_list = GetFeatureVector(enabled_features); + if (!enabled_features_and_params.empty()) { + merged_features.enabled_feature_list = + GetFeatureVectorFromFeaturesAndParams(enabled_features_and_params); + } else { + merged_features.enabled_feature_list = GetFeatureVector(enabled_features); + } merged_features.disabled_feature_list = GetFeatureVector(disabled_features); - FeatureList* feature_list = FeatureList::GetInstance(); - - // |current_enabled_features| and |current_disabled_features| must declare out - // of if scope to avoid them out of scope before JoinString calls because - // |merged_features| may contains StringPiece which holding pointer points to - // |current_enabled_features| and |current_disabled_features|. std::string current_enabled_features; std::string current_disabled_features; + FeatureList* feature_list = FeatureList::GetInstance(); if (feature_list) { - FeatureList::GetInstance()->GetFeatureOverrides(¤t_enabled_features, - ¤t_disabled_features); - OverrideFeatures(current_enabled_features, - FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE, - &merged_features); - OverrideFeatures(current_disabled_features, - FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE, - &merged_features); + feature_list->GetFeatureOverrides(¤t_enabled_features, + ¤t_disabled_features); } - // Add the field trial overrides. This assumes that |enabled_features| are at - // the begining of |merged_features.enabled_feature_list|, in the same order. - auto trial_it = trials_for_enabled_features.begin(); + // Save off the existing field trials and params. + std::string existing_trial_state; + FieldTrialList::AllStatesToString(&existing_trial_state, true); + original_params_ = FieldTrialList::AllParamsToString(true, &HexEncodeString); + + // Back up the current field trial list, to be restored in Reset(). + original_field_trial_list_ = FieldTrialList::BackupInstanceForTesting(); + + // Create a field trial list, to which we'll add trials corresponding to the + // features that have params, before restoring the field trial state from the + // previous instance, further down in this function. + field_trial_list_ = + std::make_unique<FieldTrialList>(std::make_unique<MockEntropyProvider>()); + + // Associate override params. This needs to be done before trial state gets + // restored, as that will activate trials, locking down param association. + auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance(); + std::vector<std::string> features_with_trial; auto feature_it = merged_features.enabled_feature_list.begin(); - std::vector<std::unique_ptr<std::string>> features_with_trial; - features_with_trial.reserve(trials_for_enabled_features.size()); - while (trial_it != trials_for_enabled_features.end()) { - features_with_trial.push_back(std::make_unique<std::string>( - feature_it->as_string() + "<" + (*trial_it)->trial_name())); - // |features_with_trial| owns the string, and feature_it points to it. - *feature_it = *(features_with_trial.back()); - ++trial_it; + for (const auto& enabled_feature : enabled_features_and_params) { + const std::string feature_name = enabled_feature.feature.name; + const std::string trial_name = + "scoped_feature_list_trial_for_" + feature_name; + + scoped_refptr<FieldTrial> field_trial_override = + FieldTrialList::CreateFieldTrial(trial_name, kTrialGroup); + DCHECK(field_trial_override); + + field_trial_param_associator->ClearParamsForTesting(trial_name, + kTrialGroup); + bool success = field_trial_param_associator->AssociateFieldTrialParams( + trial_name, kTrialGroup, enabled_feature.params); + DCHECK(success); + + features_with_trial.push_back(feature_name + "<" + trial_name); + *feature_it = features_with_trial.back(); ++feature_it; } + // Restore other field trials. Note: We don't need to do anything for params + // here because the param associator already has the right state, which has + // been backed up via |original_params_| to be restored later. + FieldTrialList::CreateTrialsFromString(existing_trial_state, {}); + + OverrideFeatures(current_enabled_features, + FeatureList::OverrideState::OVERRIDE_ENABLE_FEATURE, + &merged_features); + OverrideFeatures(current_disabled_features, + FeatureList::OverrideState::OVERRIDE_DISABLE_FEATURE, + &merged_features); std::string enabled = JoinString(merged_features.enabled_feature_list, ","); std::string disabled = JoinString(merged_features.disabled_feature_list, ","); @@ -201,47 +264,14 @@ void ScopedFeatureList::InitAndEnableFeatureWithParameters( const Feature& feature, - const std::map<std::string, std::string>& feature_parameters) { + const FieldTrialParams& feature_parameters) { InitWithFeaturesAndParameters({{feature, feature_parameters}}, {}); } void ScopedFeatureList::InitWithFeaturesAndParameters( const std::vector<FeatureAndParams>& enabled_features, const std::vector<Feature>& disabled_features) { - DCHECK(field_trial_overrides_.empty()); - - if (!FieldTrialList::IsGlobalSetForTesting()) { - field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); - } - - // Enabled features and field trials to use with - // InitWithFeaturesAndFieldTrials. - std::vector<Feature> features; - std::vector<FieldTrial*> field_trials; - - auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance(); - - // TODO(crbug.com/794021) Remove this unique field trial name hack when there - // is a cleaner solution. - // Ensure that each call to this method uses a distinct field trial name. - // Otherwise, nested calls might fail due to the shared FieldTrialList - // already having the field trial registered. - static int num_calls = 0; - for (auto& enabled_feature : enabled_features) { - ++num_calls; - std::string trial_name = - "scoped_feature_list_trial_name" + base::NumberToString(num_calls); - scoped_refptr<FieldTrial> field_trial_override = - base::FieldTrialList::CreateFieldTrial(trial_name, kTrialGroup); - field_trial_overrides_.push_back(field_trial_override); - DCHECK(field_trial_overrides_.back()); - field_trial_param_associator->AssociateFieldTrialParams( - trial_name, kTrialGroup, enabled_feature.params); - features.push_back(enabled_feature.feature); - field_trials.push_back(field_trial_override.get()); - } - - InitWithFeaturesAndFieldTrials(features, field_trials, disabled_features); + InitWithFeaturesImpl({}, enabled_features, disabled_features); } } // namespace test
diff --git a/base/test/scoped_feature_list.h b/base/test/scoped_feature_list.h index 5d965bc..5a637a6 100644 --- a/base/test/scoped_feature_list.h +++ b/base/test/scoped_feature_list.h
@@ -13,25 +13,26 @@ #include "base/feature_list.h" #include "base/memory/ref_counted.h" #include "base/metrics/field_trial.h" +#include "base/metrics/field_trial_params.h" namespace base { namespace test { // ScopedFeatureList resets the global FeatureList instance to a new empty -// instance and restores the original instance upon destruction. +// instance and restores the original instance upon destruction. When using the +// non-deprecated APIs, a corresponding FieldTrialList is also created. +// // Note: Re-using the same object is not allowed. To reset the feature // list and initialize it anew, destroy an existing scoped list and init // a new one. // -// ScopedFeatureList needs to be initialized (via one of Init... methods) -// before running code that inspects the state of features. In practice this -// means: -// - In browser tests, one of Init... methods should be called from the -// overriden ::testing::Test::SetUp method. For example: -// void SetUp() override { -// scoped_feature_list_.InitAndEnableFeature(features::kMyFeatureHere); -// InProcessBrowserTest::SetUp(); -// } +// ScopedFeatureList needs to be initialized (via one of Init*() methods) +// before running code that inspects the state of features, such as in the +// constructor of the test harness. +// +// If multiple instances of this class are used in a nested fashion, they +// should be destroyed in the opposite order of their Init*() methods being +// called. class ScopedFeatureList final { public: ScopedFeatureList(); @@ -39,9 +40,12 @@ struct FeatureAndParams { const Feature& feature; - const std::map<std::string, std::string>& params; + const FieldTrialParams& params; }; + // Resets the instance to a non-initialized state. + void Reset(); + // WARNING: This method will reset any globally configured features to their // default values, which can hide feature interaction bugs. Please use // sparingly. https://crbug.com/713390 @@ -82,7 +86,7 @@ // currently one. void InitAndEnableFeatureWithParameters( const Feature& feature, - const std::map<std::string, std::string>& feature_parameters); + const FieldTrialParams& feature_parameters); // Initializes and registers a FeatureList instance based on present // FeatureList and overridden with the given enabled features and the @@ -108,13 +112,12 @@ // Any feature overrides already present in the global FeatureList will // continue to apply, unless they conflict with the overrides passed into this // method. - // Field trials will apply to the enabled features, in the same order. The - // number of trials must be less (or equal) than the number of enabled - // features. - // Trials are expected to outlive the ScopedFeatureList. - void InitWithFeaturesAndFieldTrials( + // Features to enable may be specified through either |enabled_features| or + // |enabled_feature_and_params|, but not both (i.e. one of these must be + // empty). + void InitWithFeaturesImpl( const std::vector<Feature>& enabled_features, - const std::vector<FieldTrial*>& trials_for_enabled_features, + const std::vector<FeatureAndParams>& enabled_features_and_params, const std::vector<Feature>& disabled_features); // Initializes and registers a FeatureList instance based on present @@ -126,7 +129,8 @@ bool init_called_ = false; std::unique_ptr<FeatureList> original_feature_list_; - std::vector<scoped_refptr<FieldTrial>> field_trial_overrides_; + base::FieldTrialList* original_field_trial_list_; + std::string original_params_; std::unique_ptr<base::FieldTrialList> field_trial_list_; DISALLOW_COPY_AND_ASSIGN(ScopedFeatureList);
diff --git a/base/test/scoped_feature_list_unittest.cc b/base/test/scoped_feature_list_unittest.cc index df21a07..7e251f6 100644 --- a/base/test/scoped_feature_list_unittest.cc +++ b/base/test/scoped_feature_list_unittest.cc
@@ -167,7 +167,10 @@ EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2)); EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); - EXPECT_EQ(trial.get(), FeatureList::GetFieldTrial(kTestFeature1)); + EXPECT_EQ(trial.get()->trial_name(), + FeatureList::GetFieldTrial(kTestFeature1)->trial_name()); + EXPECT_EQ(trial.get()->group_name(), + FeatureList::GetFieldTrial(kTestFeature1)->group_name()); EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature2)); } @@ -240,6 +243,38 @@ EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); } +TEST_F(ScopedFeatureListTest, ParamsWithSpecialCharsPreserved) { + // Check that special characters in param names and values are preserved. + const char kParam[] = ";_\\<:>/_!?"; + const char kValue[] = ",;:/'!?"; + FieldTrialParams params0 = {{kParam, kValue}}; + + test::ScopedFeatureList feature_list0; + feature_list0.InitWithFeaturesAndParameters({{kTestFeature1, params0}}, {}); + EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + + { + const char kValue1[] = "normal"; + FieldTrialParams params1 = {{kParam, kValue1}}; + test::ScopedFeatureList feature_list1; + feature_list1.InitWithFeaturesAndParameters({{kTestFeature1, params1}}, {}); + + EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + } + EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + + { + const char kValue2[] = "[<(2)>]"; + FieldTrialParams params2 = {{kParam, kValue2}}; + test::ScopedFeatureList feature_list2; + feature_list2.InitWithFeaturesAndParameters({{kTestFeature2, params2}}, {}); + + EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam)); + EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + } + EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); +} + TEST_F(ScopedFeatureListTest, EnableFeatureOverrideDisable) { test::ScopedFeatureList feature_list1; feature_list1.InitWithFeatures({}, {kTestFeature1});
diff --git a/base/time/time_win.cc b/base/time/time_win.cc index ffb4329..9bfdba08 100644 --- a/base/time/time_win.cc +++ b/base/time/time_win.cc
@@ -31,6 +31,7 @@ // will only increase the system-wide timer if we're not running on battery // power. +#include "base/feature_list.h" #include "base/time/time.h" #include <windows.h> @@ -84,12 +85,28 @@ g_initial_time = CurrentWallclockMicroseconds(); } +const base::Feature kSlowDCTimerInterruptsFeature{ + "SlowDCTimerInterrups", base::FEATURE_DISABLED_BY_DEFAULT}; + // The two values that ActivateHighResolutionTimer uses to set the systemwide // timer interrupt frequency on Windows. It controls how precise timers are // but also has a big impact on battery life. -const int kMinTimerIntervalHighResMs = 1; -const int kMinTimerIntervalLowResMs = 4; -// Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active. +// Used when running on AC power - plugged in - when a fast timer is wanted. +UINT MinTimerIntervalHighResMs() { + return 1; +} + +UINT MinTimerIntervalLowResMs() { + // Traditionally Chrome has used an interval of 4 ms when raising the timer + // interrupt frequency on battery power. However even 4 ms is too short an + // interval on modern CPUs - it wastes non-trivial power - so this experiment + // tests an interval of 8 ms, recommended by Intel. + static const UINT s_interval = + base::FeatureList::IsEnabled(kSlowDCTimerInterruptsFeature) ? 8 : 4; + return s_interval; +} + +// Track if MinTimerIntervalHighResMs() or MinTimerIntervalLowResMs() is active. bool g_high_res_timer_enabled = false; // How many times the high resolution timer has been called. uint32_t g_high_res_timer_count = 0; @@ -204,11 +221,11 @@ // call timeEndPeriod with the same value used in timeBeginPeriod and // therefore undo the period effect. if (enable) { - timeEndPeriod(kMinTimerIntervalLowResMs); - timeBeginPeriod(kMinTimerIntervalHighResMs); + timeEndPeriod(MinTimerIntervalLowResMs()); + timeBeginPeriod(MinTimerIntervalHighResMs()); } else { - timeEndPeriod(kMinTimerIntervalHighResMs); - timeBeginPeriod(kMinTimerIntervalLowResMs); + timeEndPeriod(MinTimerIntervalHighResMs()); + timeBeginPeriod(MinTimerIntervalLowResMs()); } } @@ -220,8 +237,8 @@ const uint32_t max = std::numeric_limits<uint32_t>::max(); AutoLock lock(*GetHighResLock()); - UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs - : kMinTimerIntervalLowResMs; + UINT period = g_high_res_timer_enabled ? MinTimerIntervalHighResMs() + : MinTimerIntervalLowResMs(); if (activating) { DCHECK_NE(g_high_res_timer_count, max); ++g_high_res_timer_count; @@ -238,7 +255,7 @@ timeEndPeriod(period); } } - return (period == kMinTimerIntervalHighResMs); + return period == MinTimerIntervalHighResMs(); } // static
diff --git a/base/trace_event/event_name_filter_unittest.cc b/base/trace_event/event_name_filter_unittest.cc index d0b32d11..230e274 100644 --- a/base/trace_event/event_name_filter_unittest.cc +++ b/base/trace_event/event_name_filter_unittest.cc
@@ -5,6 +5,7 @@ #include "base/trace_event/event_name_filter.h" #include "base/memory/ptr_util.h" +#include "base/trace_event/thread_instruction_count.h" #include "base/trace_event/trace_event_impl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -13,8 +14,8 @@ const TraceEvent& MakeTraceEvent(const char* name) { static TraceEvent event; - event.Reset(0, TimeTicks(), ThreadTicks(), 'b', nullptr, name, "", 0, 0, - nullptr, 0); + event.Reset(0, TimeTicks(), ThreadTicks(), ThreadInstructionCount(), 'b', + nullptr, name, "", 0, 0, nullptr, 0); return event; }
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h index 50030ec..ac241e4 100644 --- a/base/trace_event/trace_event.h +++ b/base/trace_event/trace_event.h
@@ -22,6 +22,7 @@ #include "base/trace_event/builtin_categories.h" #include "base/trace_event/common/trace_event_common.h" #include "base/trace_event/heap_profiler.h" +#include "base/trace_event/thread_instruction_count.h" #include "base/trace_event/trace_arguments.h" #include "base/trace_event/trace_category.h" #include "base/trace_event/trace_log.h" @@ -377,28 +378,28 @@ // Implementation detail: internal macro to create static category and add // event if the category is enabled. -#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMPS( \ - category_group, name, id, thread_id, begin_timestamp, end_timestamp, \ - thread_end_timestamp, flags, ...) \ - do { \ - INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ - if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \ - trace_event_internal::TraceID trace_event_trace_id((id)); \ - unsigned int trace_event_flags = \ - flags | trace_event_trace_id.id_flags(); \ - const unsigned char* uid_category_group_enabled = \ - INTERNAL_TRACE_EVENT_UID(category_group_enabled); \ - auto handle = \ - trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \ - TRACE_EVENT_PHASE_COMPLETE, uid_category_group_enabled, name, \ - trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \ - thread_id, begin_timestamp, \ - trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \ - trace_event_internal::kNoId, ##__VA_ARGS__); \ - TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION_EXPLICIT( \ - uid_category_group_enabled, name, handle, end_timestamp, \ - thread_end_timestamp); \ - } \ +#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMPS( \ + category_group, name, id, thread_id, begin_timestamp, end_timestamp, \ + thread_end_timestamp, flags, ...) \ + do { \ + INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \ + if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \ + trace_event_internal::TraceID trace_event_trace_id((id)); \ + unsigned int trace_event_flags = \ + flags | trace_event_trace_id.id_flags(); \ + const unsigned char* uid_category_group_enabled = \ + INTERNAL_TRACE_EVENT_UID(category_group_enabled); \ + auto handle = \ + trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \ + TRACE_EVENT_PHASE_COMPLETE, uid_category_group_enabled, name, \ + trace_event_trace_id.scope(), trace_event_trace_id.raw_id(), \ + thread_id, begin_timestamp, \ + trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \ + trace_event_internal::kNoId, ##__VA_ARGS__); \ + TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION_EXPLICIT( \ + uid_category_group_enabled, name, handle, end_timestamp, \ + thread_end_timestamp, base::trace_event::ThreadInstructionCount()); \ + } \ } while (0) // The linked ID will not be mangled. @@ -705,12 +706,13 @@ const char* name, base::trace_event::TraceEventHandle handle); -void BASE_EXPORT -UpdateTraceEventDurationExplicit(const unsigned char* category_group_enabled, - const char* name, - base::trace_event::TraceEventHandle handle, - const base::TimeTicks& now, - const base::ThreadTicks& thread_now); +void BASE_EXPORT UpdateTraceEventDurationExplicit( + const unsigned char* category_group_enabled, + const char* name, + base::trace_event::TraceEventHandle handle, + const base::TimeTicks& now, + const base::ThreadTicks& thread_now, + base::trace_event::ThreadInstructionCount thread_instruction_now); // These AddTraceEvent and AddTraceEventWithThreadIdAndTimestamp template // functions are defined here instead of in the macro, because the arg_values
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc index ee3e21d..658aff3 100644 --- a/base/trace_event/trace_event_impl.cc +++ b/base/trace_event/trace_event_impl.cc
@@ -35,6 +35,7 @@ TraceEvent::TraceEvent(int thread_id, TimeTicks timestamp, ThreadTicks thread_timestamp, + ThreadInstructionCount thread_instruction_count, char phase, const unsigned char* category_group_enabled, const char* name, @@ -45,6 +46,7 @@ unsigned int flags) : timestamp_(timestamp), thread_timestamp_(thread_timestamp), + thread_instruction_count_(thread_instruction_count), scope_(scope), id_(id), category_group_enabled_(category_group_enabled), @@ -65,6 +67,7 @@ // Only reset fields that won't be initialized in Reset(int, ...), or that may // hold references to other objects. duration_ = TimeDelta::FromInternalValue(-1); + thread_instruction_delta_ = ThreadInstructionDelta(); args_.Reset(); parameter_copy_storage_.Reset(); } @@ -72,6 +75,7 @@ void TraceEvent::Reset(int thread_id, TimeTicks timestamp, ThreadTicks thread_timestamp, + ThreadInstructionCount thread_instruction_count, char phase, const unsigned char* category_group_enabled, const char* name, @@ -90,6 +94,7 @@ thread_id_ = thread_id; flags_ = flags; bind_id_ = bind_id; + thread_instruction_count_ = thread_instruction_count; phase_ = phase; InitArgs(args); @@ -103,7 +108,8 @@ } void TraceEvent::UpdateDuration(const TimeTicks& now, - const ThreadTicks& thread_now) { + const ThreadTicks& thread_now, + ThreadInstructionCount thread_instruction_now) { DCHECK_EQ(duration_.ToInternalValue(), -1); duration_ = now - timestamp_; @@ -111,6 +117,11 @@ // initialized when it was recorded. if (thread_timestamp_ != ThreadTicks()) thread_duration_ = thread_now - thread_timestamp_; + + if (!thread_instruction_count_.is_null()) { + thread_instruction_delta_ = + thread_instruction_now - thread_instruction_count_; + } } void TraceEvent::EstimateTraceMemoryOverhead( @@ -191,6 +202,10 @@ if (thread_duration != -1) StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration); } + if (!thread_instruction_count_.is_null()) { + int64_t thread_instructions = thread_instruction_delta_.ToInternalValue(); + StringAppendF(out, ",\"tidelta\":%" PRId64, thread_instructions); + } } // Output tts if thread_timestamp is valid.
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h index 97cd581..161cd6d 100644 --- a/base/trace_event/trace_event_impl.h +++ b/base/trace_event/trace_event_impl.h
@@ -23,6 +23,7 @@ #include "base/synchronization/lock.h" #include "base/threading/thread_local.h" #include "base/trace_event/common/trace_event_common.h" +#include "base/trace_event/thread_instruction_count.h" #include "base/trace_event/trace_arguments.h" #include "base/trace_event/trace_event_memory_overhead.h" #include "build/build_config.h" @@ -60,6 +61,7 @@ TraceEvent(int thread_id, TimeTicks timestamp, ThreadTicks thread_timestamp, + ThreadInstructionCount thread_instruction_count, char phase, const unsigned char* category_group_enabled, const char* name, @@ -88,6 +90,7 @@ void Reset(int thread_id, TimeTicks timestamp, ThreadTicks thread_timestamp, + ThreadInstructionCount thread_instruction_count, char phase, const unsigned char* category_group_enabled, const char* name, @@ -97,7 +100,9 @@ TraceArguments* args, unsigned int flags); - void UpdateDuration(const TimeTicks& now, const ThreadTicks& thread_now); + void UpdateDuration(const TimeTicks& now, + const ThreadTicks& thread_now, + ThreadInstructionCount thread_instruction_now); void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead); @@ -116,11 +121,17 @@ TimeTicks timestamp() const { return timestamp_; } ThreadTicks thread_timestamp() const { return thread_timestamp_; } + ThreadInstructionCount thread_instruction_count() const { + return thread_instruction_count_; + } char phase() const { return phase_; } int thread_id() const { return thread_id_; } int process_id() const { return process_id_; } TimeDelta duration() const { return duration_; } TimeDelta thread_duration() const { return thread_duration_; } + ThreadInstructionDelta thread_instruction_delta() const { + return thread_instruction_delta_; + } const char* scope() const { return scope_; } unsigned long long id() const { return id_; } unsigned int flags() const { return flags_; } @@ -162,6 +173,8 @@ ThreadTicks thread_timestamp_ = ThreadTicks(); TimeDelta duration_ = TimeDelta::FromInternalValue(-1); TimeDelta thread_duration_ = TimeDelta(); + ThreadInstructionCount thread_instruction_count_ = ThreadInstructionCount(); + ThreadInstructionDelta thread_instruction_delta_ = ThreadInstructionDelta(); // scope_ and id_ can be used to store phase-specific data. // The following should be default-initialized to the expression // trace_event_internal::kGlobalScope, which is nullptr, but its definition
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc index fe765a0..d5e9241 100644 --- a/base/trace_event/trace_log.cc +++ b/base/trace_event/trace_log.cc
@@ -40,6 +40,7 @@ #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/memory_dump_provider.h" #include "base/trace_event/process_memory_dump.h" +#include "base/trace_event/thread_instruction_count.h" #include "base/trace_event/trace_buffer.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" @@ -98,6 +99,11 @@ : ThreadTicks(); } +ThreadInstructionCount ThreadInstructionNow() { + return ThreadInstructionCount::IsSupported() ? ThreadInstructionCount::Now() + : ThreadInstructionCount(); +} + template <typename T> void InitializeMetadataEvent(TraceEvent* trace_event, int thread_id, @@ -108,13 +114,14 @@ return; TraceArguments args(arg_name, value); - trace_event->Reset( - thread_id, TimeTicks(), ThreadTicks(), TRACE_EVENT_PHASE_METADATA, - CategoryRegistry::kCategoryMetadata->state_ptr(), metadata_name, - trace_event_internal::kGlobalScope, // scope - trace_event_internal::kNoId, // id - trace_event_internal::kNoId, // bind_id - &args, TRACE_EVENT_FLAG_NONE); + trace_event->Reset(thread_id, TimeTicks(), ThreadTicks(), + ThreadInstructionCount(), TRACE_EVENT_PHASE_METADATA, + CategoryRegistry::kCategoryMetadata->state_ptr(), + metadata_name, + trace_event_internal::kGlobalScope, // scope + trace_event_internal::kNoId, // id + trace_event_internal::kNoId, // bind_id + &args, TRACE_EVENT_FLAG_NONE); } class AutoThreadLocalBoolean { @@ -1178,6 +1185,7 @@ TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp); ThreadTicks thread_now = ThreadNow(); + ThreadInstructionCount thread_instruction_now = ThreadInstructionNow(); ThreadLocalEventBuffer* thread_local_event_buffer = nullptr; if (*category_group_enabled & RECORDING_MODE) { @@ -1233,9 +1241,9 @@ auto trace_event_override = add_trace_event_override_.load(std::memory_order_relaxed); if (trace_event_override) { - TraceEvent new_trace_event(thread_id, offset_event_timestamp, thread_now, - phase, category_group_enabled, name, scope, id, - bind_id, args, flags); + TraceEvent new_trace_event( + thread_id, offset_event_timestamp, thread_now, thread_instruction_now, + phase, category_group_enabled, name, scope, id, bind_id, args, flags); trace_event_override( &new_trace_event, @@ -1249,8 +1257,8 @@ bool disabled_by_filters = false; if (*category_group_enabled & TraceCategory::ENABLED_FOR_FILTERING) { auto new_trace_event = std::make_unique<TraceEvent>( - thread_id, offset_event_timestamp, thread_now, phase, - category_group_enabled, name, scope, id, bind_id, args, flags); + thread_id, offset_event_timestamp, thread_now, thread_instruction_now, + phase, category_group_enabled, name, scope, id, bind_id, args, flags); disabled_by_filters = true; ForEachCategoryFilter( @@ -1281,7 +1289,8 @@ if (filtered_trace_event) { *trace_event = std::move(*filtered_trace_event); } else { - trace_event->Reset(thread_id, offset_event_timestamp, thread_now, phase, + trace_event->Reset(thread_id, offset_event_timestamp, thread_now, + thread_instruction_now, phase, category_group_enabled, name, scope, id, bind_id, args, flags); } @@ -1312,10 +1321,11 @@ int thread_id = static_cast<int>(base::PlatformThread::CurrentId()); ThreadTicks thread_now = ThreadNow(); TimeTicks now = OffsetNow(); + ThreadInstructionCount thread_instruction_now = ThreadInstructionNow(); AutoLock lock(lock_); auto trace_event = std::make_unique<TraceEvent>( - thread_id, now, thread_now, TRACE_EVENT_PHASE_METADATA, - category_group_enabled, name, + thread_id, now, thread_now, thread_instruction_now, + TRACE_EVENT_PHASE_METADATA, category_group_enabled, name, trace_event_internal::kGlobalScope, // scope trace_event_internal::kNoId, // id trace_event_internal::kNoId, // bind_id @@ -1394,7 +1404,8 @@ return; UpdateTraceEventDurationExplicit(category_group_enabled, name, handle, - OffsetNow(), ThreadNow()); + OffsetNow(), ThreadNow(), + ThreadInstructionNow()); } void TraceLog::UpdateTraceEventDurationExplicit( @@ -1402,7 +1413,8 @@ const char* name, TraceEventHandle handle, const TimeTicks& now, - const ThreadTicks& thread_now) { + const ThreadTicks& thread_now, + ThreadInstructionCount thread_instruction_now) { char category_group_enabled_local = *category_group_enabled; if (!category_group_enabled_local) return; @@ -1424,7 +1436,7 @@ auto update_duration_callback = update_duration_callback_.load(std::memory_order_relaxed); if (update_duration_callback) { - update_duration_callback(handle, now, thread_now); + update_duration_callback(handle, now, thread_now, thread_instruction_now); return; } } @@ -1437,7 +1449,7 @@ if (trace_event) { DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE); - trace_event->UpdateDuration(now, thread_now); + trace_event->UpdateDuration(now, thread_now, thread_instruction_now); #if defined(OS_ANDROID) trace_event->SendToATrace(); #endif @@ -1802,10 +1814,12 @@ const char* name, base::trace_event::TraceEventHandle handle, const base::TimeTicks& now, - const base::ThreadTicks& thread_now) { + const base::ThreadTicks& thread_now, + base::trace_event::ThreadInstructionCount thread_instruction_now) { return base::trace_event::TraceLog::GetInstance() ->UpdateTraceEventDurationExplicit(category_group_enabled, name, handle, - now, thread_now); + now, thread_now, + thread_instruction_now); } ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h index 360e1234..55f6825 100644 --- a/base/trace_event/trace_log.h +++ b/base/trace_event/trace_log.h
@@ -200,9 +200,11 @@ bool thread_will_flush, TraceEventHandle* handle); using OnFlushCallback = void (*)(); - using UpdateDurationCallback = void (*)(TraceEventHandle handle, - const TimeTicks& now, - const ThreadTicks& thread_now); + using UpdateDurationCallback = + void (*)(TraceEventHandle handle, + const TimeTicks& now, + const ThreadTicks& thread_now, + ThreadInstructionCount thread_instruction_now); // The callbacks will be called up until the point where the flush is // finished, i.e. must be callable until OutputCallback is called with // has_more_events==false. @@ -291,7 +293,8 @@ const char* name, TraceEventHandle handle, const TimeTicks& now, - const ThreadTicks& thread_now); + const ThreadTicks& thread_now, + ThreadInstructionCount thread_instruction_now); void EndFilteredEvent(const unsigned char* category_group_enabled, const char* name,
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 094f83a6..ad3ab3f5 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8910690471883428096 \ No newline at end of file +8910661150919848928 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 6c574847..15175047 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8910690961961271888 \ No newline at end of file +8910657347225830192 \ No newline at end of file
diff --git a/cc/trees/layer_tree_host_pixeltest_readback.cc b/cc/trees/layer_tree_host_pixeltest_readback.cc index 3c7c03f..76e0ab0 100644 --- a/cc/trees/layer_tree_host_pixeltest_readback.cc +++ b/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -29,9 +29,6 @@ }; struct ReadbackTestConfig { - ReadbackTestConfig(LayerTreeTest::RendererType renderer_type_, - ReadbackType readback_type_) - : renderer_type(renderer_type_), readback_type(readback_type_) {} LayerTreeTest::RendererType renderer_type; ReadbackType readback_type; }; @@ -191,7 +188,11 @@ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } -TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer) { +using LayerTreeHostReadbackPixelTestMaybeVulkan = + LayerTreeHostReadbackPixelTest; + +TEST_P(LayerTreeHostReadbackPixelTestMaybeVulkan, + ReadbackSubtreeSurroundsTargetLayer) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE); @@ -379,7 +380,7 @@ base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png"))); } -TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootOrFirstLayer) { +TEST_P(LayerTreeHostReadbackPixelTestMaybeVulkan, ReadbackNonRootOrFirstLayer) { // This test has 3 render passes with the copy request on the render pass in // the middle. This test caught an issue where copy requests on non-root // non-first render passes were being treated differently from the first @@ -415,15 +416,40 @@ base::FilePath(FILE_PATH_LITERAL("green.png"))); } -INSTANTIATE_TEST_SUITE_P( - , - LayerTreeHostReadbackPixelTest, - ::testing::Values( - ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE), - ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE))); +// TODO(crbug.com/963446): Enable these tests for Skia Vulkan using texture +// readback. +ReadbackTestConfig const kTestConfigs[] = { + ReadbackTestConfig{LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP}, + ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_TEXTURE}, + ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_BITMAP}, + ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE}, + ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP}, +#if defined(ENABLE_CC_VULKAN_TESTS) + ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_VK, READBACK_BITMAP}, +#endif +}; + +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostReadbackPixelTest, + ::testing::ValuesIn(kTestConfigs)); + +// TODO(crbug.com/974283): These tests are crashing with vulkan when TSan or +// MSan are used. +ReadbackTestConfig const kMaybeVulkanTestConfigs[] = { + ReadbackTestConfig{LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP}, + ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_TEXTURE}, + ReadbackTestConfig{LayerTreeTest::RENDERER_GL, READBACK_BITMAP}, + ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE}, + ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP}, +#if defined(ENABLE_CC_VULKAN_TESTS) && !defined(THREAD_SANITIZER) && \ + !defined(MEMORY_SANITIZER) + ReadbackTestConfig{LayerTreeTest::RENDERER_SKIA_VK, READBACK_BITMAP}, +#endif +}; + +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostReadbackPixelTestMaybeVulkan, + ::testing::ValuesIn(kMaybeVulkanTestConfigs)); class LayerTreeHostReadbackDeviceScalePixelTest : public LayerTreeHostReadbackPixelTest { @@ -510,15 +536,9 @@ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } -INSTANTIATE_TEST_SUITE_P( - , - LayerTreeHostReadbackDeviceScalePixelTest, - ::testing::Values( - ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE), - ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE))); +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostReadbackDeviceScalePixelTest, + ::testing::ValuesIn(kTestConfigs)); class LayerTreeHostReadbackColorSpacePixelTest : public LayerTreeHostReadbackPixelTest { @@ -556,15 +576,9 @@ base::FilePath(FILE_PATH_LITERAL("srgb_green_in_p3.png"))); } -INSTANTIATE_TEST_SUITE_P( - , - LayerTreeHostReadbackColorSpacePixelTest, - ::testing::Values( - ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE), - ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP), - ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE))); +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostReadbackColorSpacePixelTest, + ::testing::ValuesIn(kTestConfigs)); } // namespace } // namespace cc
diff --git a/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/cc/trees/layer_tree_host_pixeltest_scrollbars.cc index ba7f209..1e6cc926 100644 --- a/cc/trees/layer_tree_host_pixeltest_scrollbars.cc +++ b/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -89,10 +89,17 @@ gfx::Rect rect_; }; +LayerTreeTest::RendererType const kRendererTypes[] = { + LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL, +#if defined(ENABLE_CC_VULKAN_TESTS) + LayerTreeTest::RENDERER_SKIA_VK, +#endif +}; + INSTANTIATE_TEST_SUITE_P(, LayerTreeHostScrollbarsPixelTest, - ::testing::Values(LayerTreeTest::RENDERER_GL, - LayerTreeTest::RENDERER_SKIA_GL)); + ::testing::ValuesIn(kRendererTypes)); TEST_P(LayerTreeHostScrollbarsPixelTest, NoScale) { scoped_refptr<SolidColorLayer> background = @@ -189,7 +196,8 @@ scale_transform.Scale(scale, scale); layer->SetTransform(scale_transform); - if (renderer_type() == RENDERER_SKIA_GL) + if (renderer_type() == RENDERER_SKIA_GL || + renderer_type() == RENDERER_SKIA_VK) pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true); RunPixelTest(renderer_type(), background, @@ -256,8 +264,7 @@ INSTANTIATE_TEST_SUITE_P(, LayerTreeHostOverlayScrollbarsPixelTest, - ::testing::Values(LayerTreeTest::RENDERER_GL, - LayerTreeTest::RENDERER_SKIA_GL)); + ::testing::ValuesIn(kRendererTypes)); // Simulate increasing the thickness of a painted overlay scrollbar. Ensure that // the scrollbar border remains crisp.
diff --git a/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/cc/trees/layer_tree_host_pixeltest_synchronous.cc index fac28b3..fd1c4cd 100644 --- a/cc/trees/layer_tree_host_pixeltest_synchronous.cc +++ b/cc/trees/layer_tree_host_pixeltest_synchronous.cc
@@ -57,7 +57,12 @@ INSTANTIATE_TEST_SUITE_P(, LayerTreeHostSynchronousPixelTest, ::testing::Values(LayerTreeTest::RENDERER_GL, - LayerTreeTest::RENDERER_SKIA_GL)); + LayerTreeTest::RENDERER_SKIA_GL +#if defined(ENABLE_CC_VULKAN_TESTS) + , + LayerTreeTest::RENDERER_SKIA_VK +#endif + )); TEST_P(LayerTreeHostSynchronousPixelTest, OneContentLayerZeroCopy) { use_zero_copy_ = true;
diff --git a/cc/trees/layer_tree_host_pixeltest_tiles.cc b/cc/trees/layer_tree_host_pixeltest_tiles.cc index c9ab5ac..17ff346 100644 --- a/cc/trees/layer_tree_host_pixeltest_tiles.cc +++ b/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -172,6 +172,7 @@ scoped_refptr<PictureLayer> picture_layer_; }; +// TODO(crbug.com/963446): Enable these tests for Vulkan. INSTANTIATE_TEST_SUITE_P( , LayerTreeHostTilesTestPartialInvalidation, @@ -198,6 +199,7 @@ using LayerTreeHostTilesTestPartialInvalidationMultiThread = LayerTreeHostTilesTestPartialInvalidation; +// TODO(crbug.com/963446): Enable these tests for Vulkan. INSTANTIATE_TEST_SUITE_P( , LayerTreeHostTilesTestPartialInvalidationMultiThread, @@ -227,6 +229,7 @@ using LayerTreeHostTilesTestPartialInvalidationLowBitDepth = LayerTreeHostTilesTestPartialInvalidation; +// TODO(crbug.com/963446): Enable these tests for Vulkan. INSTANTIATE_TEST_SUITE_P( , LayerTreeHostTilesTestPartialInvalidationLowBitDepth,
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml new file mode 100644 index 0000000..7e27743 --- /dev/null +++ b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml
@@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2019 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/dialog_container_view" + android:background="@color/modern_primary_color"> + <TextView + android:layout_width="match_parent" + android:layout_height="@dimen/bottom_sheet_peek_height" + android:id="@+id/dialog_ungroup_bar" + android:text="@string/tab_grid_dialog_remove_from_group" + android:textAppearance="@style/TextAppearance.WhiteHeadline" + android:background="@color/modern_blue_600" + android:gravity="center" + android:layout_alignParentBottom="true" + android:layout_centerHorizontal="true" + android:visibility="gone"/> +</RelativeLayout> +
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java index c0019425..ae387a8 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
@@ -99,7 +99,7 @@ mTabGridCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, tabModelSelector, mMultiThumbnailCardProvider, titleProvider, true, mMediator::getCreateGroupButtonOnClickListener, gridCardOnClickListenerProvider, - compositorViewHolder, compositorViewHolder.getDynamicResourceLoader(), true, + null, compositorViewHolder, compositorViewHolder.getDynamicResourceLoader(), true, org.chromium.chrome.tab_ui.R.layout.grid_tab_switcher_layout, COMPONENT_NAME); HistoryNavigationLayout navigation = compositorViewHolder.findViewById(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java index 7745039..b274986 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java
@@ -40,15 +40,15 @@ mToolbarPropertyModel = new PropertyModel(TabGridSheetProperties.ALL_KEYS); - mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, - tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null, - null, compositorViewHolder, null, false, R.layout.tab_list_recycler_view_layout, - COMPONENT_NAME); - mMediator = new TabGridDialogMediator(context, this::resetWithListOfTabs, mToolbarPropertyModel, tabModelSelector, tabCreatorManager, resetHandler, animationOriginProvider); + mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, + tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null, + null, mMediator.getTabGridDialogHandler(), compositorViewHolder, null, false, + R.layout.tab_list_recycler_view_layout, COMPONENT_NAME); + mParentLayout = new TabGridDialogParent(context, compositorViewHolder); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java index a12fd4f8..f2f907f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -67,6 +67,7 @@ private final TabGridDialogMediator.ResetHandler mDialogResetHandler; private final GridTabSwitcherMediator.ResetHandler mGridTabSwitcherResetHandler; private final AnimationOriginProvider mAnimationOriginProvider; + private final DialogHandler mTabGridDialogHandler; private int mCurrentTabId = Tab.INVALID_TAB_ID; TabGridDialogMediator(Context context, TabGridDialogMediator.ResetHandler dialogResetHandler, @@ -81,6 +82,7 @@ mDialogResetHandler = dialogResetHandler; mGridTabSwitcherResetHandler = gridTabSwitcherResetHandler; mAnimationOriginProvider = animationOriginProvider; + mTabGridDialogHandler = new DialogHandler(); // Register for tab model. mTabModelObserver = new EmptyTabModelObserver() { @@ -223,4 +225,25 @@ .getCurrentTabModelFilter() .getRelatedTabList(tabId); } + + TabListMediator.TabGridDialogHandler getTabGridDialogHandler() { + return mTabGridDialogHandler; + } + + /** + * A handler that handles TabGridDialog related changes originated from {@link TabListMediator} + * and {@link TabGridItemTouchHelperCallback}. + */ + class DialogHandler implements TabListMediator.TabGridDialogHandler { + @Override + public void updateUngroupBarStatus(@TabGridDialogParent.UngroupBarStatus int status) { + mModel.set(TabGridSheetProperties.UNGROUP_BAR_STATUS, status); + } + + @Override + public void updateDialogContent(int tabId) { + mCurrentTabId = tabId; + updateDialog(); + } + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java index a0fc983..5efa703 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
@@ -12,21 +12,26 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; +import android.support.annotation.IntDef; import android.util.DisplayMetrics; import android.view.Gravity; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.PopupWindow; import android.widget.RelativeLayout; +import android.widget.TextView; -import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ContextUtils; import org.chromium.chrome.browser.widget.ScrimView; import org.chromium.chrome.tab_ui.R; import org.chromium.ui.interpolators.BakedBezierInterpolator; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Parent for TabGridDialog component. * TODO(yuezhanggg): Add animations of card scales up to dialog and dialog scales down to card when @@ -34,6 +39,15 @@ */ public class TabGridDialogParent { private static final int DIALOG_ANIMATION_DURATION = 300; + @IntDef({UngroupBarStatus.SHOW, UngroupBarStatus.HIDE, UngroupBarStatus.HOVERED}) + @Retention(RetentionPolicy.SOURCE) + public @interface UngroupBarStatus { + int SHOW = 0; + int HIDE = 1; + int HOVERED = 2; + int NUM_ENTRIES = 3; + } + private final ComponentCallbacks mComponentCallbacks; private final FrameLayout.LayoutParams mContainerParams; private final ViewGroup mParent; @@ -56,6 +70,8 @@ private int mDialogHeight; private int mSideMargin; private int mTopMargin; + private View mContentView; + private TextView mUngroupBar; TabGridDialogParent(Context context, ViewGroup parent) { mParent = parent; @@ -79,23 +95,22 @@ public void onLowMemory() {} }; ContextUtils.getApplicationContext().registerComponentCallbacks(mComponentCallbacks); - setupDialogContent(context); + setupDialogContent(context, parent); prepareAnimation(); } - private void setupDialogContent(Context context) { + private void setupDialogContent(Context context, ViewGroup parent) { FrameLayout backgroundView = new FrameLayout(context); - mDialogContainerView = new RelativeLayout(context); + mDialogContainerView = (RelativeLayout) LayoutInflater.from(context).inflate( + R.layout.tab_grid_dialog_layout, parent, false); mDialogContainerView.setLayoutParams(mContainerParams); - mDialogContainerView.setBackgroundColor(ApiCompatibilityUtils.getColor( - context.getResources(), org.chromium.chrome.R.color.modern_primary_color)); + mUngroupBar = mDialogContainerView.findViewById(R.id.dialog_ungroup_bar); + backgroundView.addView(mDialogContainerView); + mScrimView = new ScrimView(context, null, backgroundView); mPopupWindow = new PopupWindow(backgroundView, 0, 0); mBlockView = new View(context); - mBlockView.setLayoutParams(new RelativeLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); mBlockView.setOnClickListener(null); - backgroundView.addView(mDialogContainerView); updateDialogWithOrientation(context, context.getResources().getConfiguration().orientation); } @@ -248,9 +263,11 @@ * @param recyclerView The recyclerview to be added to dialog. */ void resetDialog(View toolbarView, View recyclerView) { + mContentView = recyclerView; mDialogContainerView.removeAllViews(); mDialogContainerView.addView(toolbarView); - mDialogContainerView.addView(recyclerView); + mDialogContainerView.addView(mContentView); + mDialogContainerView.addView(mUngroupBar); RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) recyclerView.getLayoutParams(); params.setMargins(0, mToolbarHeight, 0, 0); @@ -294,4 +311,23 @@ public void destroy() { ContextUtils.getApplicationContext().unregisterComponentCallbacks(mComponentCallbacks); } + + /** + * Update the ungroup bar based on {@code status}. + * + * @param status The status in {@link TabGridDialogParent.UngroupBarStatus} that the ungroup bar + * should be updated to. + */ + public void updateUngroupBar(int status) { + if (status == UngroupBarStatus.SHOW) { + mUngroupBar.setVisibility(View.VISIBLE); + mUngroupBar.setAlpha(1f); + mUngroupBar.bringToFront(); + } else if (status == UngroupBarStatus.HIDE) { + mUngroupBar.setVisibility(View.INVISIBLE); + } else if (status == UngroupBarStatus.HOVERED) { + mUngroupBar.setAlpha(0.7f); + mContentView.bringToFront(); + } + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java index 6aadc51f..e59acb4 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java
@@ -32,23 +32,28 @@ private final TabModelSelector mTabModelSelector; private final TabListMediator.TabActionListener mTabClosedListener; private final String mComponentName; + private final TabListMediator.TabGridDialogHandler mTabGridDialogHandler; private float mSwipeToDismissThreshold; private float mMergeThreshold; + private float mUngroupThreshold; private boolean mActionsOnAllRelatedTabs; private int mDragFlags; private int mSelectedTabIndex = TabModel.INVALID_TAB_INDEX; private int mHoveredTabIndex = TabModel.INVALID_TAB_INDEX; + private int mUnGroupTabIndex = TabModel.INVALID_TAB_INDEX; private RecyclerView mRecyclerView; public TabGridItemTouchHelperCallback(TabListModel tabListModel, TabModelSelector tabModelSelector, TabListMediator.TabActionListener tabClosedListener, - String componentName, boolean actionsOnAllRelatedTabs) { + TabListMediator.TabGridDialogHandler tabGridDialogHandler, String componentName, + boolean actionsOnAllRelatedTabs) { super(0, 0); mModel = tabListModel; mTabModelSelector = tabModelSelector; mTabClosedListener = tabClosedListener; mComponentName = componentName; mActionsOnAllRelatedTabs = actionsOnAllRelatedTabs; + mTabGridDialogHandler = tabGridDialogHandler; } /** @@ -59,9 +64,11 @@ * @param mergeThreshold Defines the threshold of how much two items need to * be overlapped in order to be considered as a merge operation. */ - void setupCallback(float swipeToDismissThreshold, float mergeThreshold) { + void setupCallback( + float swipeToDismissThreshold, float mergeThreshold, float ungroupThreshold) { mSwipeToDismissThreshold = swipeToDismissThreshold; mMergeThreshold = mergeThreshold; + mUngroupThreshold = ungroupThreshold; boolean isTabGroupEnabled = FeatureUtilities.isTabGroupsAndroidEnabled(); boolean isTabGroupUiImprovementEnabled = FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled(); @@ -141,8 +148,20 @@ if (mHoveredTabIndex == TabModel.INVALID_TAB_INDEX) { mModel.updateSelectedTabForMergeToGroup(mSelectedTabIndex, false); } + if (mUnGroupTabIndex != TabModel.INVALID_TAB_INDEX) { + TabGroupModelFilter filter = + (TabGroupModelFilter) mTabModelSelector.getTabModelFilterProvider() + .getCurrentTabModelFilter(); + filter.moveTabOutOfGroup(mModel.get(mUnGroupTabIndex).get(TabProperties.TAB_ID)); + mRecyclerView.getAdapter().notifyDataSetChanged(); + } mHoveredTabIndex = TabModel.INVALID_TAB_INDEX; mSelectedTabIndex = TabModel.INVALID_TAB_INDEX; + mUnGroupTabIndex = TabModel.INVALID_TAB_INDEX; + if (mTabGridDialogHandler != null) { + mTabGridDialogHandler.updateUngroupBarStatus( + TabGridDialogParent.UngroupBarStatus.HIDE); + } } } @@ -165,6 +184,19 @@ if (prev_hovered != mHoveredTabIndex) { mModel.updateHoveredTabForMergeToGroup(prev_hovered, false); } + } else if (actionState == ItemTouchHelper.ACTION_STATE_DRAG + && mTabGridDialogHandler != null) { + // Not allow ungrouping the last tab in group. + if (recyclerView.getAdapter().getItemCount() == 1) return; + boolean isHoveredOnUngroupBar = viewHolder.itemView.getBottom() + dY + > recyclerView.getBottom() - mUngroupThreshold; + mUnGroupTabIndex = isHoveredOnUngroupBar ? viewHolder.getAdapterPosition() + : TabModel.INVALID_TAB_INDEX; + mTabGridDialogHandler.updateUngroupBarStatus(isHoveredOnUngroupBar + ? TabGridDialogParent.UngroupBarStatus.HOVERED + : (mSelectedTabIndex == TabModel.INVALID_TAB_INDEX + ? TabGridDialogParent.UngroupBarStatus.HIDE + : TabGridDialogParent.UngroupBarStatus.SHOW)); } } @@ -202,4 +234,9 @@ void setSelectedTabIndexForTest(int index) { mSelectedTabIndex = index; } + + @VisibleForTesting + void setUnGroupTabIndexForTest(int index) { + mUnGroupTabIndex = index; + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java index 219050e..bd7b6dfb 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
@@ -45,7 +45,7 @@ mTabGridCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null, - null, bottomSheetController.getBottomSheet(), null, false, + null, null, bottomSheetController.getBottomSheet(), null, false, R.layout.tab_list_recycler_view_layout, COMPONENT_NAME); mMediator = new TabGridSheetMediator(mContext, bottomSheetController,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java index e4370ea..87239a9 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java
@@ -34,7 +34,9 @@ new PropertyModel.WritableObjectPropertyKey<>(); public static final PropertyModel.WritableObjectPropertyKey<Rect> ANIMATION_SOURCE_RECT = new PropertyModel.WritableObjectPropertyKey<>(); + public static final PropertyModel.WritableIntPropertyKey UNGROUP_BAR_STATUS = + new PropertyModel.WritableIntPropertyKey(); public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER, ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT, - IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_SOURCE_RECT}; + IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_SOURCE_RECT, UNGROUP_BAR_STATUS}; }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java index 890007c6..3f7570c1 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java
@@ -13,6 +13,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.PRIMARY_COLOR; import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.SCRIMVIEW_OBSERVER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.TINT; +import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.UNGROUP_BAR_STATUS; import android.support.annotation.Nullable; import android.view.View; @@ -75,6 +76,8 @@ } } else if (ANIMATION_SOURCE_RECT == propertyKey) { viewHolder.dialogView.setupDialogAnimation(model.get(ANIMATION_SOURCE_RECT)); + } else if (UNGROUP_BAR_STATUS == propertyKey) { + viewHolder.dialogView.updateUngroupBar(model.get(UNGROUP_BAR_STATUS)); } } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java index 72d51a7..bfced2e 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
@@ -77,7 +77,7 @@ TabContentManager tabContentManager = activity.getTabContentManager(); mTabStripCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.STRIP, - mContext, tabModelSelector, null, null, false, null, null, + mContext, tabModelSelector, null, null, false, null, null, null, mTabStripToolbarCoordinator.getTabListContainerView(), null, true, R.layout.tab_list_recycler_view_layout, COMPONENT_NAME);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java index ae45df0..dad0312 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -81,6 +81,7 @@ @Nullable TabListMediator.CreateGroupButtonProvider createGroupButtonProvider, @Nullable TabListMediator .GridCardOnClickListenerProvider gridCardOnClickListenerProvider, + @Nullable TabListMediator.TabGridDialogHandler dialogHandler, @NonNull ViewGroup parentView, @Nullable DynamicResourceLoader dynamicResourceLoader, boolean attachToParent, @LayoutRes int layoutId, String componentName) { TabListModel tabListModel = new TabListModel(); @@ -141,12 +142,17 @@ mMediator = new TabListMediator(tabListModel, tabModelSelector, thumbnailProvider, titleProvider, tabListFaviconProvider, actionOnRelatedTabs, - createGroupButtonProvider, null, gridCardOnClickListenerProvider, componentName); + createGroupButtonProvider, null, gridCardOnClickListenerProvider, dialogHandler, + componentName); if (mMode == TabListMode.GRID) { ItemTouchHelper touchHelper = new ItemTouchHelper(mMediator.getItemTouchHelperCallback( context.getResources().getDimension(R.dimen.swipe_to_dismiss_threshold), - context.getResources().getDimension(R.dimen.tab_grid_merge_threshold))); + context.getResources().getDimension(R.dimen.tab_grid_merge_threshold), + context.getResources().getDimension(R.dimen.bottom_sheet_peek_height))); + touchHelper.attachToRecyclerView(mRecyclerView); + mMediator.registerOrientationListener( + (GridLayoutManager) mRecyclerView.getLayoutManager()); touchHelper.attachToRecyclerView(mRecyclerView); mMediator.registerOrientationListener( (GridLayoutManager) mRecyclerView.getLayoutManager());
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java index ce75e7ae..e9aa6600 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -69,6 +69,26 @@ public interface TitleProvider { String getTitle(Tab tab); } /** + * An interface to handle requests about updating TabGridDialog. + */ + public interface TabGridDialogHandler { + /** + * This method updates the status of the ungroup bar in TabGridDialog. + * + * @param status The status in {@link TabGridDialogParent.UngroupBarStatus} that the ungroup + * bar should be updated to. + */ + void updateUngroupBarStatus(@TabGridDialogParent.UngroupBarStatus int status); + + /** + * This method updates the content of the TabGridDialog. + * + * @param tabId The id of the {@link Tab} that is used to update TabGridDialog. + */ + void updateDialogContent(int tabId); + } + + /** * The object to set to TabProperties.THUMBNAIL_FETCHER for the TabGridViewBinder to obtain * the thumbnail asynchronously. */ @@ -163,6 +183,7 @@ private final CreateGroupButtonProvider mCreateGroupButtonProvider; private final SelectionDelegateProvider mSelectionDelegateProvider; private final GridCardOnClickListenerProvider mGridCardOnClickListenerProvider; + private final TabGridDialogHandler mTabGridDialogHandler; private final String mComponentName; private boolean mActionsOnAllRelatedTabs; private ComponentCallbacks mComponentCallbacks; @@ -279,7 +300,7 @@ @Nullable CreateGroupButtonProvider createGroupButtonProvider, @Nullable SelectionDelegateProvider selectionDelegateProvider, @Nullable GridCardOnClickListenerProvider gridCardOnClickListenerProvider, - String componentName) { + @Nullable TabGridDialogHandler dialogHandler, String componentName) { mTabModelSelector = tabModelSelector; mThumbnailProvider = thumbnailProvider; mModel = model; @@ -289,6 +310,7 @@ mCreateGroupButtonProvider = createGroupButtonProvider; mSelectionDelegateProvider = selectionDelegateProvider; mGridCardOnClickListenerProvider = gridCardOnClickListenerProvider; + mTabGridDialogHandler = dialogHandler; mActionsOnAllRelatedTabs = actionOnRelatedTabs; mTabModelObserver = new EmptyTabModelObserver() { @@ -375,6 +397,30 @@ } @Override + public void didMoveTabOutOfGroup(Tab movedTab, int prevFilterIndex) { + TabGroupModelFilter filter = + (TabGroupModelFilter) mTabModelSelector.getTabModelFilterProvider() + .getCurrentTabModelFilter(); + if (mTabGridDialogHandler != null) { + int curIndex = mModel.indexFromId(movedTab.getId()); + if (!isValidMovePosition(curIndex)) return; + mModel.removeAt(curIndex); + mTabGridDialogHandler.updateDialogContent( + filter.getTabAt(prevFilterIndex).getId()); + return; + } + if (mActionsOnAllRelatedTabs) { + Tab currentSelectedTab = mTabModelSelector.getCurrentTab(); + addTabInfoToModel(movedTab, mModel.size(), + currentSelectedTab.getId() == movedTab.getId()); + boolean isSelected = mTabModelSelector.getCurrentTabId() + == filter.getTabAt(prevFilterIndex).getId(); + updateTab(prevFilterIndex, filter.getTabAt(prevFilterIndex), isSelected, + true, false); + } + } + + @Override public void didMergeTabToGroup(Tab movedTab, int selectedTabIdInGroup) { if (!mActionsOnAllRelatedTabs) return; Pair<Integer, Integer> positions = @@ -489,8 +535,9 @@ } }; - mTabGridItemTouchHelperCallback = new TabGridItemTouchHelperCallback(mModel, - mTabModelSelector, mTabClosedListener, mComponentName, mActionsOnAllRelatedTabs); + mTabGridItemTouchHelperCallback = + new TabGridItemTouchHelperCallback(mModel, mTabModelSelector, mTabClosedListener, + mTabGridDialogHandler, mComponentName, mActionsOnAllRelatedTabs); } private void onTabClosedFrom(int tabId, String fromComponent) { @@ -637,7 +684,6 @@ mModel.get(index).set(TabProperties.IS_SELECTED, isSelected); mModel.get(index).set(TabProperties.TITLE, mTitleProvider.getTitle(tab)); mModel.get(index).set(TabProperties.IS_HIDDEN, false); - Callback<Drawable> faviconCallback = drawable -> { int modelIndex = mModel.indexFromId(tab.getId()); if (modelIndex != Tab.INVALID_TAB_ID && drawable != null) { @@ -656,9 +702,10 @@ /** * @return The callback that hosts the logic for swipe and drag related actions. */ - ItemTouchHelper.SimpleCallback getItemTouchHelperCallback( - final float swipeToDismissThreshold, final float mergeThreshold) { - mTabGridItemTouchHelperCallback.setupCallback(swipeToDismissThreshold, mergeThreshold); + ItemTouchHelper.SimpleCallback getItemTouchHelperCallback(final float swipeToDismissThreshold, + final float mergeThreshold, final float ungroupThreshold) { + mTabGridItemTouchHelperCallback.setupCallback( + swipeToDismissThreshold, mergeThreshold, ungroupThreshold); return mTabGridItemTouchHelperCallback; }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java index bd73e208..86477bf3 100644 --- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java +++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -107,6 +107,10 @@ TabGroupModelFilter mTabGroupModelFilter; @Mock EmptyTabModelFilter mEmptyTabModelFilter; + @Mock + TabListMediator.TabGridDialogHandler mTabGridDialogHandler; + @Mock + TabListMediator.CreateGroupButtonProvider mCreateGroupButtonProvider; @Captor ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; @Captor @@ -150,6 +154,7 @@ doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); doReturn(mTabModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); doReturn(mTab1).when(mTabModelSelector).getCurrentTab(); + doReturn(TAB1_ID).when(mTabModelSelector).getCurrentTabId(); doNothing() .when(mTabModelFilterProvider) .addTabModelFilterObserver(mTabModelObserverCaptor.capture()); @@ -175,7 +180,7 @@ mModel = new TabListModel(); mMediator = new TabListMediator(mModel, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - false, null, null, null, getClass().getSimpleName()); + false, null, null, null, null, getClass().getSimpleName()); } @After @@ -240,11 +245,10 @@ public void sendsMoveTabSignalCorrectlyWithoutGroup() { initAndAssertAllProperties(); FeatureUtilities.setTabGroupsAndroidEnabledForTesting(false); - + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); doReturn(mEmptyTabModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); - mMediator.getItemTouchHelperCallback(0f, 0f).onMove( - mRecyclerView, mViewHolder1, mViewHolder2); + itemTouchHelperCallback.onMove(mRecyclerView, mViewHolder1, mViewHolder2); verify(mTabModel).moveTab(eq(TAB1_ID), eq(2)); } @@ -255,8 +259,7 @@ public void sendsMoveTabSignalCorrectlyWithGroup() { initAndAssertAllProperties(); FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); - TabGridItemTouchHelperCallback itemTouchHelperCallback = - (TabGridItemTouchHelperCallback) mMediator.getItemTouchHelperCallback(0f, 0f); + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTest(true); doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); @@ -275,8 +278,8 @@ doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); - mMediator.getItemTouchHelperCallback(0f, 0f).onMove( - mRecyclerView, mViewHolder1, mViewHolder2); + mMediator.getItemTouchHelperCallback(0f, 0f, 0f) + .onMove(mRecyclerView, mViewHolder1, mViewHolder2); verify(mTabModel).moveTab(eq(TAB1_ID), eq(2)); } @@ -288,8 +291,7 @@ initAndAssertAllProperties(); FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); mMediator.setActionOnAllRelatedTabsForTest(true); - TabGridItemTouchHelperCallback itemTouchHelperCallback = - (TabGridItemTouchHelperCallback) mMediator.getItemTouchHelperCallback(0f, 0f); + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTest(true); itemTouchHelperCallback.setHoveredTabIndexForTest(POSITION1); itemTouchHelperCallback.setSelectedTabIndexForTest(POSITION2); @@ -310,8 +312,7 @@ initAndAssertAllProperties(); FeatureUtilities.setTabGroupsAndroidEnabledForTesting(false); mMediator.setActionOnAllRelatedTabsForTest(true); - TabGridItemTouchHelperCallback itemTouchHelperCallback = - (TabGridItemTouchHelperCallback) mMediator.getItemTouchHelperCallback(0f, 0f); + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTest(true); itemTouchHelperCallback.setHoveredTabIndexForTest(POSITION1); itemTouchHelperCallback.setSelectedTabIndexForTest(POSITION2); @@ -333,8 +334,7 @@ initAndAssertAllProperties(); FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); mMediator.setActionOnAllRelatedTabsForTest(true); - TabGridItemTouchHelperCallback itemTouchHelperCallback = - (TabGridItemTouchHelperCallback) mMediator.getItemTouchHelperCallback(0f, 0f); + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); itemTouchHelperCallback.setActionsOnAllRelatedTabsForTest(true); itemTouchHelperCallback.setHoveredTabIndexForTest(POSITION1); itemTouchHelperCallback.setSelectedTabIndexForTest(POSITION2); @@ -350,6 +350,29 @@ } @Test + @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_ANDROID, + ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) + public void + sendsUngroupSignalCorrectly() { + initAndAssertAllProperties(); + setUpForTabGroupOperation(); + FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true); + + TabGridItemTouchHelperCallback itemTouchHelperCallback = getItemTouchHelperCallback(); + itemTouchHelperCallback.setActionsOnAllRelatedTabsForTest(false); + itemTouchHelperCallback.setUnGroupTabIndexForTest(POSITION1); + itemTouchHelperCallback.getMovementFlags(mRecyclerView, mViewHolder1); + + doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); + doReturn(mAdapter).when(mRecyclerView).getAdapter(); + + // Simulate the ungroup action. + itemTouchHelperCallback.onSelectedChanged(mViewHolder1, ItemTouchHelper.ACTION_STATE_IDLE); + + verify(mTabGroupModelFilter).moveTabOutOfGroup(eq(TAB1_ID)); + } + + @Test public void tabClosure() { initAndAssertAllProperties(); @@ -497,7 +520,10 @@ @Test public void tabMergeIntoGroup() { setUpForTabGroupOperation(); - mMediator.setActionOnAllRelatedTabsForTest(true); + // Setup the mediator with a CreateGroupButtonProvider. + mMediator = new TabListMediator(mModel, mTabModelSelector, + mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, + true, mCreateGroupButtonProvider, null, null, null, getClass().getSimpleName()); // Assume that moveTab in TabModel is finished. Selected tab in the group becomes mTab1. doReturn(mTab1).when(mTabModel).getTabAt(POSITION2); @@ -524,6 +550,90 @@ } @Test + public void tabMoveOutOfGroup_GTS_Moved_Tab_Selected() { + setUpForTabGroupOperation(); + // Setup the mediator with a CreateGroupButtonProvider. + mMediator = new TabListMediator(mModel, mTabModelSelector, + mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, + true, mCreateGroupButtonProvider, null, null, null, getClass().getSimpleName()); + + // Assume that two tabs are in the same group before ungroup. + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab2)); + mMediator.resetWithListOfTabs(tabs, false); + + assertThat(mModel.size(), equalTo(1)); + assertThat(mModel.get(0).get(TabProperties.TAB_ID), equalTo(TAB2_ID)); + assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB2_TITLE)); + + // Assume that TabGroupModelFilter is already updated. + doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION1); + doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION2); + + mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION1); + + assertThat(mModel.size(), equalTo(2)); + assertThat(mModel.get(0).get(TabProperties.TAB_ID), equalTo(TAB2_ID)); + assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB2_TITLE)); + assertThat(mModel.get(0).get(TabProperties.IS_SELECTED), equalTo(false)); + assertThat(mModel.get(1).get(TabProperties.TAB_ID), equalTo(TAB1_ID)); + assertThat(mModel.get(1).get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + assertThat(mModel.get(1).get(TabProperties.IS_SELECTED), equalTo(true)); + } + + @Test + public void tabMoveOutOfGroup_GTS_Origin_Tab_Selected() { + setUpForTabGroupOperation(); + // Setup the mediator with a CreateGroupButtonProvider. + mMediator = new TabListMediator(mModel, mTabModelSelector, + mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, + true, mCreateGroupButtonProvider, null, null, null, getClass().getSimpleName()); + + // Assume that two tabs are in the same group before ungroup. + List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1)); + mMediator.resetWithListOfTabs(tabs, false); + + assertThat(mModel.size(), equalTo(1)); + assertThat(mModel.get(0).get(TabProperties.TAB_ID), equalTo(TAB1_ID)); + assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + + // Assume that TabGroupModelFilter is already updated. + doReturn(mTab1).when(mTabGroupModelFilter).getTabAt(POSITION1); + doReturn(mTab2).when(mTabGroupModelFilter).getTabAt(POSITION2); + + mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab2, POSITION1); + + assertThat(mModel.size(), equalTo(2)); + assertThat(mModel.get(0).get(TabProperties.TAB_ID), equalTo(TAB1_ID)); + assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + assertThat(mModel.get(0).get(TabProperties.IS_SELECTED), equalTo(true)); + assertThat(mModel.get(1).get(TabProperties.TAB_ID), equalTo(TAB2_ID)); + assertThat(mModel.get(1).get(TabProperties.TITLE), equalTo(TAB2_TITLE)); + assertThat(mModel.get(1).get(TabProperties.IS_SELECTED), equalTo(false)); + } + + @Test + public void tabMoveOutOfGroup_Dialog() { + setUpForTabGroupOperation(); + + // Setup the mediator with a DialogHandler. + mMediator = new TabListMediator(mModel, mTabModelSelector, + mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, + true, null, null, null, mTabGridDialogHandler, getClass().getSimpleName()); + + assertThat(mModel.size(), equalTo(2)); + assertThat(mModel.get(0).get(TabProperties.TAB_ID), equalTo(TAB1_ID)); + assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB1_TITLE)); + assertThat(mModel.get(1).get(TabProperties.TAB_ID), equalTo(TAB2_ID)); + assertThat(mModel.get(1).get(TabProperties.TITLE), equalTo(TAB2_TITLE)); + + mTabGroupModelFilterObserverCaptor.getValue().didMoveTabOutOfGroup(mTab1, POSITION1); + + assertThat(mModel.size(), equalTo(1)); + assertThat(mModel.get(0).get(TabProperties.TAB_ID), equalTo(TAB2_ID)); + assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB2_TITLE)); + } + + @Test public void tabMovementWithoutGroup_Forward() { initAndAssertAllProperties(); @@ -690,6 +800,7 @@ doReturn(id).when(tab).getId(); doReturn("").when(tab).getUrl(); doReturn(title).when(tab).getTitle(); + doReturn(true).when(tab).isIncognito(); return tab; } @@ -700,6 +811,10 @@ return viewHolder; } + private TabGridItemTouchHelperCallback getItemTouchHelperCallback() { + return (TabGridItemTouchHelperCallback) mMediator.getItemTouchHelperCallback(0f, 0f, 0f); + } + private void setUpForTabGroupOperation() { doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter(); doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getTabModelFilter(true); @@ -710,8 +825,8 @@ mMediator = new TabListMediator(mModel, mTabModelSelector, mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider, - true, null, null, null, getClass().getSimpleName()); + true, null, null, null, null, getClass().getSimpleName()); initAndAssertAllProperties(); } -} \ No newline at end of file +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java index 5e436d2..de8764a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/AppHooks.java
@@ -470,11 +470,6 @@ } /** - * Starts monitoring network quality. Must be called after native initialization is complete. - */ - public void startMonitoringNetworkQuality() {} - - /** * Starts the observer for listening to system settings changes. Must be called on * ChromeActivity initialization. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index 6fbff6b8..aa05e7bd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1440,7 +1440,6 @@ // TODO(yusufo): Unify initialization. initializeBottomSheet(true); } - AppHooks.get().startMonitoringNetworkQuality(); AppHooks.get().startSystemSettingsObserver(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java index ca958f6b..45b95f0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
@@ -51,6 +51,7 @@ import org.chromium.chrome.browser.webapps.WebappLauncherActivity; import org.chromium.content_public.browser.BrowserStartupController; import org.chromium.ui.widget.Toast; +import org.chromium.webapk.lib.client.WebApkValidator; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -195,6 +196,19 @@ return Action.FINISH_ACTIVITY; } + // Check if we should launch a WebApk to handle the intent. + // For NoTouchMode, prefer to launch PWAs instead of the browser on view intents. + if (FeatureUtilities.isNoTouchModeEnabled() && url != null + && Intent.ACTION_VIEW.equals(mIntent.getAction())) { + String packageName = WebApkValidator.queryFirstWebApkPackage( + ContextUtils.getApplicationContext(), url); + if (packageName != null) { + mActivity.startActivity(WebApkValidator.createWebApkIntentForUrlAndOptionalPackage( + url, packageName)); + return Action.FINISH_ACTIVITY; + } + } + // Check if we should push the user through First Run. if (FirstRunFlowSequencer.launch(mActivity, mIntent, false /* requiresBroadcast */, false /* preferLightweightFre */)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinator.java index 57bfae8..5a0b441 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinator.java
@@ -69,7 +69,7 @@ mHeaderCoordinator = new RevampedContextMenuHeaderCoordinator( activity, params, params.getUrl(), params.isImage()); - ModelListAdapter adapter = new ModelListAdapter(activity) { + ModelListAdapter adapter = new ModelListAdapter() { @Override public boolean areAllItemsEnabled() { return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 1c75797..8799f76 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -76,6 +76,7 @@ import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl; +import org.chromium.chrome.browser.usage_stats.UsageStatsService; import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.content_public.browser.LoadUrlParams; @@ -377,6 +378,10 @@ ApiCompatibilityUtils.getColor(getResources(), R.color.default_primary_color)); } + if (isTaskRoot() && UsageStatsService.isEnabled()) { + UsageStatsService.getInstance().createPageViewObserver(getTabModelSelector(), this); + } + super.finishNativeInitialization(); // We start the Autofill Assistant after the call to super.finishNativeInitialization() as
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java index e161a154..e28a5bb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteCoordinatorImpl.java
@@ -101,7 +101,7 @@ // Start with visibility GONE to ensure that show() is called. // http://crbug.com/517438 list.setVisibility(View.GONE); - ModelListAdapter adapter = new ModelListAdapter(context); + ModelListAdapter adapter = new ModelListAdapter(); list.setAdapter(adapter); list.setClipToPadding(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilter.java index 425c2946b..ef9c7f9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilter.java
@@ -73,6 +73,15 @@ * @param tabModelNewIndex The new index of the {@code movedTab} in the {@link TabModel}. */ void didMoveWithinGroup(Tab movedTab, int tabModelOldIndex, int tabModelNewIndex); + + /** + * This method is called after a tab within a group is moved out of the group. + * + * @param movedTab The tab which has been moved. + * @param prevFilterIndex The index in {@link TabGroupModelFilter} of the group where {@code + * moveTab} is in before ungrouping. + */ + void didMoveTabOutOfGroup(Tab movedTab, int prevFilterIndex); } /** @@ -296,6 +305,47 @@ } } + /** + * This method moves Tab with id as {@code sourceTabId} out of the group it belongs to. + * + * @param sourceTabId The id of the {@link Tab} to get the source group. + */ + public void moveTabOutOfGroup(int sourceTabId) { + TabModel tabModel = getTabModel(); + Tab tab = TabModelUtils.getTabById(tabModel, sourceTabId); + int curIndex = tabModel.indexOf(tab); + TabGroup curTabGroup = mGroupIdToGroupMap.get(tab.getRootId()); + assert curTabGroup.size() > 1; + + if (tab.getId() == tab.getRootId()) { + // If moving tab's id is the root id of the group, find a new root id. + int newRootId = Tab.INVALID_TAB_ID; + if (curIndex != 0 && tabModel.getTabAt(curIndex - 1).getRootId() == tab.getRootId()) { + newRootId = tabModel.getTabAt(curIndex - 1).getId(); + } else if (curIndex != tabModel.getCount() - 1 + && tabModel.getTabAt(curIndex + 1).getRootId() == tab.getRootId()) { + newRootId = tabModel.getTabAt(curIndex + 1).getId(); + } + + assert newRootId != Tab.INVALID_TAB_ID; + + for (int tabId : curTabGroup.getTabIdList()) { + TabModelUtils.getTabById(tabModel, tabId).setRootId(newRootId); + } + resetFilterState(); + } + tab.setRootId(tab.getId()); + // If moving tab is already the last tab in tab model, no move in tab model. + if (curIndex == tabModel.getCount() - 1) { + resetFilterState(); + for (Observer observer : mGroupFilterObserver) { + observer.didMoveTabOutOfGroup(tab, getCount() - 2); + } + return; + } + tabModel.moveTab(tab.getId(), tabModel.getCount()); + } + private int getTabModelDestinationIndex(Tab destinationTab) { List<Integer> destinationGroupedTabIds = mGroupIdToGroupMap.get(destinationTab.getRootId()).getTabIdList(); @@ -491,13 +541,21 @@ @Override public void didMoveTab(Tab tab, int newIndex, int curIndex) { - // Need to cache the flag before resetting the internal data map. + // Need to cache the flags before resetting the internal data map. boolean isMergeTabToGroup = isMergeTabToGroup(tab); - int groupIdBeforeMove = getGroupIdBeforeMove(tab, isMergeTabToGroup); + boolean isMoveTabOutOfGroup = isMoveTabOutOfGroup(tab); + int groupIdBeforeMove = getGroupIdBeforeMove(tab, isMergeTabToGroup || isMoveTabOutOfGroup); assert groupIdBeforeMove != TabGroup.INVALID_GROUP_ID; TabGroup groupBeforeMove = mGroupIdToGroupMap.get(groupIdBeforeMove); - if (isMergeTabToGroup) { + if (isMoveTabOutOfGroup) { + resetFilterState(); + + int prevFilterIndex = mGroupIdToGroupIndexMap.get(groupIdBeforeMove); + for (Observer observer : mGroupFilterObserver) { + observer.didMoveTabOutOfGroup(tab, prevFilterIndex); + } + } else if (isMergeTabToGroup) { resetFilterState(); if (groupBeforeMove != null && groupBeforeMove.size() != 1) return; @@ -507,7 +565,6 @@ } } else { reorder(); - if (isMoveWithinGroup(tab, curIndex, newIndex)) { for (Observer observer : mGroupFilterObserver) { observer.didMoveWithinGroup(tab, curIndex, newIndex); @@ -523,7 +580,12 @@ super.didMoveTab(tab, newIndex, curIndex); } + private boolean isMoveTabOutOfGroup(Tab movedTab) { + return !mGroupIdToGroupMap.containsKey(movedTab.getRootId()); + } + private boolean isMergeTabToGroup(Tab tab) { + if (!mGroupIdToGroupMap.containsKey(tab.getRootId())) return false; TabGroup tabGroup = mGroupIdToGroupMap.get(tab.getRootId()); return !tabGroup.contains(tab.getId()); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java index 9361f6c..5106b603 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java
@@ -8,6 +8,7 @@ import android.graphics.drawable.Drawable; import android.support.annotation.DimenRes; +import org.chromium.base.metrics.RecordUserAction; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; @@ -123,6 +124,7 @@ private void showIdentityDisc(String accountName) { Drawable profileImage = mProfileDataCache.getProfileDataOrDefault(accountName).getImage(); mToolbarManager.enableExperimentalButton(view -> { + RecordUserAction.record("MobileToolbarIdentityDiscTap"); PreferencesLauncher.launchSettingsPage(mContext, SyncAndServicesPreferences.class); }, profileImage, R.string.accessibility_toolbar_btn_identity_disc); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabCountProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabCountProvider.java index 19b6f8a7..5a85cc99 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabCountProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabCountProvider.java
@@ -155,6 +155,11 @@ @Override public void didMoveWithinGroup( Tab movedTab, int tabModelOldIndex, int tabModelNewIndex) {} + + @Override + public void didMoveTabOutOfGroup(Tab moveTab, int oldFilterIndex) { + updateTabCount(); + } }; if (mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter()
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilterUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilterUnitTest.java index 14e0819..063f49b8 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilterUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/tabgroup/TabGroupModelFilterUnitTest.java
@@ -4,7 +4,9 @@ package org.chromium.chrome.browser.tasks.tabgroup; +import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; @@ -224,6 +226,70 @@ } @Test + public void moveTabOutOfGroup_No_Update_TabModel() { + List<Tab> expectedTabModel = + new ArrayList<>(Arrays.asList(mTab1, mTab2, mTab3, mTab4, mTab5, mTab6)); + + mTabGroupModelFilter.moveTabOutOfGroup(TAB6_ID); + + verify(mTabModel, never()).moveTab(anyInt(), anyInt()); + assertArrayEquals(mTabs.toArray(), expectedTabModel.toArray()); + assertThat(mTab6.getRootId(), equalTo(TAB6_ID)); + } + + @Test + public void moveTabOutOfGroup_NonRoot_Tab() { + List<Tab> expectedTabModel = + new ArrayList<>(Arrays.asList(mTab1, mTab2, mTab4, mTab5, mTab6, mTab3)); + assertThat(mTab3.getRootId(), equalTo(TAB2_ID)); + + mTabGroupModelFilter.moveTabOutOfGroup(TAB3_ID); + + verify(mTabModel).moveTab(mTab3.getId(), mTabs.size()); + verify(mTabGroupModelFilterObserver).didMoveTabOutOfGroup(mTab3, POSITION2); + assertThat(mTab3.getRootId(), equalTo(TAB3_ID)); + assertArrayEquals(mTabs.toArray(), expectedTabModel.toArray()); + } + + @Test + public void moveTabOutOfGroup_Root_Tab_First_Tab() { + List<Tab> expectedTabModel = + new ArrayList<>(Arrays.asList(mTab1, mTab3, mTab4, mTab5, mTab6, mTab2)); + assertThat(mTab2.getRootId(), equalTo(TAB2_ID)); + assertThat(mTab3.getRootId(), equalTo(TAB2_ID)); + + mTabGroupModelFilter.moveTabOutOfGroup(TAB2_ID); + + verify(mTabModel).moveTab(mTab2.getId(), mTabs.size()); + verify(mTabGroupModelFilterObserver).didMoveTabOutOfGroup(mTab2, POSITION2); + assertThat(mTab2.getRootId(), equalTo(TAB2_ID)); + assertThat(mTab3.getRootId(), equalTo(TAB3_ID)); + assertArrayEquals(mTabs.toArray(), expectedTabModel.toArray()); + } + + @Test + public void moveTabOutOfGroup_Root_Tab_Not_First_Tab() { + // Move the root tab so that first tab in group is not the root tab. + mTabModel.moveTab(TAB2_ID, POSITION4); + List<Tab> tabModelBeforeUngroup = + new ArrayList<>(Arrays.asList(mTab1, mTab3, mTab2, mTab4, mTab5, mTab6)); + assertArrayEquals(mTabs.toArray(), tabModelBeforeUngroup.toArray()); + + List<Tab> expectedTabModel = + new ArrayList<>(Arrays.asList(mTab1, mTab3, mTab4, mTab5, mTab6, mTab2)); + assertThat(mTab2.getRootId(), equalTo(TAB2_ID)); + assertThat(mTab3.getRootId(), equalTo(TAB2_ID)); + + mTabGroupModelFilter.moveTabOutOfGroup(TAB2_ID); + + verify(mTabModel).moveTab(mTab2.getId(), mTabs.size()); + verify(mTabGroupModelFilterObserver).didMoveTabOutOfGroup(mTab2, POSITION2); + assertThat(mTab2.getRootId(), equalTo(TAB2_ID)); + assertThat(mTab3.getRootId(), equalTo(TAB3_ID)); + assertArrayEquals(mTabs.toArray(), expectedTabModel.toArray()); + } + + @Test public void mergeTabToGroup_No_Update_TabModel() { List<Tab> expectedGroup = new ArrayList<>(Arrays.asList(mTab2, mTab3, mTab4));
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 4184a57..71fd7ff 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-77.0.3824.0_rc-r1-merged.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-77.0.3825.0_rc-r1-merged.afdo.bz2 \ No newline at end of file
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/dialog/TouchlessDialogPresenter.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/dialog/TouchlessDialogPresenter.java index e2ad00e..e641924 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/dialog/TouchlessDialogPresenter.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/dialog/TouchlessDialogPresenter.java
@@ -92,7 +92,7 @@ }); ViewGroup dialogView = (ViewGroup) LayoutInflater.from(mDialog.getContext()) .inflate(R.layout.touchless_dialog_view, null); - ModelListAdapter adapter = new ModelListAdapter(mActivity); + ModelListAdapter adapter = new ModelListAdapter(); adapter.registerType(ListItemType.DEFAULT, () -> LayoutInflater.from(mActivity).inflate(R.layout.dialog_list_item, null), TouchlessDialogPresenter::bindListItem);
diff --git a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java index c74d78df..7882f23cd 100644 --- a/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java +++ b/chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/WebApkValidator.java
@@ -130,24 +130,8 @@ */ private static List<ResolveInfo> resolveInfosForUrlAndOptionalPackage( Context context, String url, @Nullable String applicationPackage) { - Intent intent; - try { - intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); - } catch (Exception e) { - return new LinkedList<>(); - } - - intent.addCategory(Intent.CATEGORY_BROWSABLE); - if (applicationPackage != null) { - intent.setPackage(applicationPackage); - } else { - intent.setComponent(null); - } - Intent selector = intent.getSelector(); - if (selector != null) { - selector.addCategory(Intent.CATEGORY_BROWSABLE); - selector.setComponent(null); - } + Intent intent = createWebApkIntentForUrlAndOptionalPackage(url, applicationPackage); + if (intent == null) return new LinkedList<>(); // StrictMode is relaxed due to https://crbug.com/843092. StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads(); @@ -228,6 +212,36 @@ return verifyCommentSignedWebApk(packageInfo); } + /** + * @param url A Url that might launch a WebApk. + * @param applicationPackage The package of the WebApk to restrict the launch to. + * @return An intent that could launch a WebApk for the provided URL (and package), if such a + * WebApk exists. If package isn't specified, the intent may create a disambiguation + * dialog when started. + */ + public static Intent createWebApkIntentForUrlAndOptionalPackage( + String url, @Nullable String applicationPackage) { + Intent intent; + try { + intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); + } catch (Exception e) { + return null; + } + + intent.addCategory(Intent.CATEGORY_BROWSABLE); + if (applicationPackage != null) { + intent.setPackage(applicationPackage); + } else { + intent.setComponent(null); + } + Intent selector = intent.getSelector(); + if (selector != null) { + selector.addCategory(Intent.CATEGORY_BROWSABLE); + selector.setComponent(null); + } + return intent; + } + /** Determine quickly whether this is definitely not a WebAPK */ private static boolean isNotWebApkQuick(PackageInfo packageInfo) { if (packageInfo.applicationInfo == null || packageInfo.applicationInfo.metaData == null) {
diff --git a/chrome/app/builtin_service_manifests.cc b/chrome/app/builtin_service_manifests.cc index 170afd5..9a8a88d 100644 --- a/chrome/app/builtin_service_manifests.cc +++ b/chrome/app/builtin_service_manifests.cc
@@ -102,27 +102,6 @@ return *manifest; } -#if defined(OS_ANDROID) -const service_manager::Manifest& GetAndroidDownloadManagerManifest() { - static base::NoDestructor<service_manager::Manifest> manifest{ - service_manager::ManifestBuilder() - .WithServiceName("download_manager") - .WithDisplayName("Download Manager") - .WithOptions( - service_manager::ManifestOptionsBuilder() - .WithExecutionMode(service_manager::Manifest::ExecutionMode:: - kInProcessBuiltin) - .WithInstanceSharingPolicy( - service_manager::Manifest::InstanceSharingPolicy:: - kSingleton) - .Build()) - .RequireCapability("network", "network_service") - .RequireCapability("device", "device:wake_lock") - .Build()}; - return *manifest; -} -#endif - } // namespace const std::vector<service_manager::Manifest>& @@ -158,9 +137,7 @@ GetUtilWinManifest(), GetWifiUtilWinManifest(), #endif -#if defined(OS_ANDROID) - GetAndroidDownloadManagerManifest(), -#else +#if !defined(OS_ANDROID) mirroring::GetManifest(), GetProfileImportManifest(), #endif
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index b47d1556..0abb80d 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -607,8 +607,6 @@ "invalidation/deprecated_profile_invalidation_provider_factory.h", "invalidation/profile_invalidation_provider_factory.cc", "invalidation/profile_invalidation_provider_factory.h", - "io_thread.cc", - "io_thread.h", "language/language_model_manager_factory.cc", "language/language_model_manager_factory.h", "language/translate_frame_binder.cc", @@ -2885,6 +2883,8 @@ "enterprise_reporting/prefs.h", "enterprise_reporting/profile_report_generator.cc", "enterprise_reporting/profile_report_generator.h", + "enterprise_reporting/report_generator.cc", + "enterprise_reporting/report_generator.h", "enterprise_reporting/report_scheduler.cc", "enterprise_reporting/report_scheduler.h", "enterprise_reporting/report_uploader.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index ec75847..63df476 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3007,6 +3007,10 @@ flag_descriptions::kEnableBlinkGenPropertyTreesDescription, kOsAll, FEATURE_VALUE_TYPE(blink::features::kBlinkGenPropertyTrees)}, + {"enable-backdrop-filter", flag_descriptions::kEnableCSSBackdropFilterName, + flag_descriptions::kEnableCSSBackdropFilterDescription, kOsAll, + FEATURE_VALUE_TYPE(blink::features::kCSSBackdropFilter)}, + {"enable-display-locking", flag_descriptions::kEnableDisplayLockingName, flag_descriptions::kEnableDisplayLockingDescription, kOsAll, FEATURE_VALUE_TYPE(blink::features::kDisplayLocking)}, @@ -3914,6 +3918,10 @@ flag_descriptions::kCookieDeprecationMessagesDescription, kOsAll, FEATURE_VALUE_TYPE(features::kCookieDeprecationMessages)}, + {"enable-caption-settings", flag_descriptions::kCaptionSettingsName, + flag_descriptions::kCaptionSettingsDescription, kOsAll, + FEATURE_VALUE_TYPE(features::kCaptionSettings)}, + {"ev-details-in-page-info", flag_descriptions::kEvDetailsInPageInfoName, flag_descriptions::kEvDetailsInPageInfoDescription, kOsDesktop, FEATURE_VALUE_TYPE(features::kEvDetailsInPageInfo)},
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc index 396f6ea..ea7e740 100644 --- a/chrome/browser/android/download/download_manager_service.cc +++ b/chrome/browser/android/download/download_manager_service.cc
@@ -42,6 +42,7 @@ #include "content/public/browser/download_request_utils.h" #include "content/public/browser/network_service_instance.h" #include "content/public/browser/notification_service.h" +#include "content/public/browser/system_connector.h" #include "jni/DownloadInfo_jni.h" #include "jni/DownloadItem_jni.h" #include "jni/DownloadManagerService_jni.h" @@ -211,11 +212,6 @@ DownloadManagerService::~DownloadManagerService() {} -void DownloadManagerService::BindServiceRequest( - service_manager::mojom::ServiceRequest request) { - service_binding_.Bind(std::move(request)); -} - void DownloadManagerService::Init(JNIEnv* env, jobject obj, bool is_full_browser_started) { @@ -495,15 +491,6 @@ content::DownloadItemUtils::GetBrowserContext(item)->IsOffTheRecord()); } -void DownloadManagerService::OnDisconnected() { - // Some unit tests recreate |ServiceManagerContext| inside - // |TestServiceManagerContext|. Closing |service_binding_| will prevent DCHECK - // in such tests, because |DownloadManagerService| starts automatically in - // |ServiceManagerContext|. - service_binding_.Close(); - Terminate(); -} - void DownloadManagerService::ResumeDownloadInternal( const std::string& download_guid, bool is_off_the_record, @@ -699,7 +686,7 @@ return; base::FilePath data_dir; base::android::GetDataDirectory(&data_dir); - service_manager::Connector* connector = service_binding_.GetConnector(); + service_manager::Connector* connector = content::GetSystemConnector(); in_progress_manager_ = std::make_unique<download::InProgressDownloadManager>( nullptr, data_dir.Append(chrome::kInitialProfile), base::BindRepeating(&IgnoreOriginSecurityCheck),
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h index a9ae911..9b280f2e 100644 --- a/chrome/browser/android/download/download_manager_service.h +++ b/chrome/browser/android/download/download_manager_service.h
@@ -19,9 +19,6 @@ #include "content/public/browser/download_manager.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -#include "services/service_manager/public/cpp/service.h" -#include "services/service_manager/public/cpp/service_binding.h" -#include "services/service_manager/public/mojom/service.mojom.h" using base::android::JavaParamRef; @@ -36,8 +33,7 @@ // Java object. class DownloadManagerService : public download::AllDownloadEventNotifier::Observer, - public content::NotificationObserver, - public service_manager::Service { + public content::NotificationObserver { public: static void CreateAutoResumptionHandler(); @@ -54,8 +50,6 @@ DownloadManagerService(); ~DownloadManagerService() override; - void BindServiceRequest(service_manager::mojom::ServiceRequest request); - // Called to Initialize this object. If |is_full_browser_started| is false, // it means only the service manager is launched. OnFullBrowserStarted() will // be called later when browser process fully launches. @@ -208,9 +202,6 @@ friend class DownloadManagerServiceTest; friend struct base::DefaultSingletonTraits<DownloadManagerService>; - // service_manager::Service implementation. - void OnDisconnected() final; - // Helper function to start the download resumption. void ResumeDownloadInternal(const std::string& download_guid, bool is_off_the_record, @@ -258,8 +249,6 @@ download::SimpleDownloadManagerCoordinator* coordinator, bool is_off_the_record); - service_manager::ServiceBinding service_binding_{this}; - // Reference to the Java object. base::android::ScopedJavaGlobalRef<jobject> java_ref_;
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.cc b/chrome/browser/android/vr/arcore_device/arcore_impl.cc index 4b02fd4..8b99335 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_impl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
@@ -219,12 +219,14 @@ continue; } - if (DCHECK_IS_ON()) { +#if DCHECK_IS_ON() + { ArTrackableType type; ArTrackable_getType(arcore_session_.get(), trackable.get(), &type); DCHECK(type == ArTrackableType::AR_TRACKABLE_PLANE) << "arcore_planes_ contains a trackable that is not an ArPlane!"; } +#endif ArPlane* ar_plane = ArAsPlane(trackable.get()); // Naked pointer is fine here, ArAsPlane
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc index 55949cc..2b94c590 100644 --- a/chrome/browser/browser_about_handler.cc +++ b/chrome/browser/browser_about_handler.cc
@@ -39,7 +39,8 @@ FixupBrowserAboutURL(url, browser_context); // Check that about: URLs are fixed up to chrome: by url_formatter::FixupURL. - DCHECK((url->IsAboutBlank()) || !url->SchemeIs(url::kAboutScheme)); + DCHECK(url->IsAboutBlank() || url->IsAboutSrcdoc() || + !url->SchemeIs(url::kAboutScheme)); // Only handle chrome://foo/, url_formatter::FixupURL translates about:foo. if (!url->SchemeIs(content::kChromeUIScheme))
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index e6442ab0..1d5ab8c4 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h
@@ -28,7 +28,6 @@ class GpuModeManager; class IconManager; class IntranetRedirectDetector; -class IOThread; class MediaFileSystemRegistry; class NotificationPlatformBridge; class NotificationUIManager; @@ -160,16 +159,6 @@ virtual NotificationUIManager* notification_ui_manager() = 0; virtual NotificationPlatformBridge* notification_platform_bridge() = 0; - // Returns the state object for the thread that we perform I/O - // coordination on (network requests, communication with renderers, - // etc. - // - // Can be NULL close to startup and shutdown. - // - // NOTE: If you want to post a task to the IO thread, see - // browser_task_traits.h. - virtual IOThread* io_thread() = 0; - // Replacement for IOThread (And ChromeNetLog). It owns and manages the // NetworkContext which will use the network service when the network service // is enabled. When the network service is not enabled, its NetworkContext is
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index edb060d..9b35070f 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -49,7 +49,6 @@ #include "chrome/browser/gpu/gpu_mode_manager.h" #include "chrome/browser/icon_manager.h" #include "chrome/browser/intranet_redirect_detector.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/lifetime/switch_utils.h" #include "chrome/browser/media/webrtc/webrtc_event_log_manager.h" @@ -373,12 +372,6 @@ tearing_down_ = true; DCHECK(IsShuttingDown()); - // We need to destroy the MetricsServicesManager, IntranetRedirectDetector, - // NetworkTimeTracker, and SafeBrowsing ClientSideDetectionService - // (owned by the SafeBrowsingService) before the io_thread_ gets destroyed, - // since their destructors can call the URLFetcher destructor, which does a - // PostDelayedTask operation on the IO thread. (The IO thread will handle - // that URLFetcher operation before going away.) metrics_services_manager_.reset(); intranet_redirect_detector_.reset(); if (safe_browsing_service_.get()) @@ -391,7 +384,7 @@ system_notification_helper_.reset(); #if !defined(OS_CHROMEOS) - // Need to clear the desktop notification balloons before the io_thread_ and + // Need to clear the desktop notification balloons before the IO thread and // before the profiles, since if there are any still showing we will access // those things during teardown. notification_ui_manager_.reset(); @@ -407,7 +400,7 @@ battery_metrics_.reset(); - // Need to clear profiles (download managers) before the io_thread_. + // Need to clear profiles (download managers) before the IO thread. { TRACE_EVENT0("shutdown", "BrowserProcessImpl::StartTearDown:ProfileManager"); @@ -470,15 +463,6 @@ // Must outlive the worker threads. webrtc_log_uploader_.reset(); - - // Reset associated state right after actual thread is stopped, - // as io_thread_.global_ cleanup happens in CleanUp on the IO - // thread, i.e. as the thread exits its message loop. - // - // This is important also because in various places, the - // IOThread object being NULL is considered synonymous with the - // IO thread having stopped. - io_thread_.reset(); } #endif // !defined(OS_ANDROID) @@ -665,12 +649,6 @@ return GetMetricsServicesManager()->GetRapporServiceImpl(); } -IOThread* BrowserProcessImpl::io_thread() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(io_thread_.get()); - return io_thread_.get(); -} - SystemNetworkContextManager* BrowserProcessImpl::system_network_context_manager() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -685,7 +663,6 @@ network::NetworkQualityTracker* BrowserProcessImpl::network_quality_tracker() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(io_thread_); if (!network_quality_tracker_) { network_quality_tracker_ = std::make_unique<network::NetworkQualityTracker>( base::BindRepeating(&content::GetNetworkService)); @@ -1168,12 +1145,9 @@ command_line.GetCommandLineString(), chrome::GetChannelName()); } - // Must be created before the IOThread. - // TODO(mmenke): Once IOThread class is no longer needed (not the thread - // itself), this can be created on first use. + // TODO(mmenke): This can be created on first use. if (!SystemNetworkContextManager::GetInstance()) SystemNetworkContextManager::CreateInstance(local_state()); - io_thread_ = std::make_unique<IOThread>(net_log_.get()); } void BrowserProcessImpl::PreMainMessageLoopRun() {
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 7c28d1e5..0285bbdb 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h
@@ -136,7 +136,6 @@ override; metrics::MetricsService* metrics_service() override; rappor::RapporServiceImpl* rappor_service() override; - IOThread* io_thread() override; // TODO(qinmin): Remove this method as callers can retrieve the global // instance from SystemNetworkContextManager directly. SystemNetworkContextManager* system_network_context_manager() override; @@ -246,8 +245,6 @@ std::unique_ptr<metrics_services_manager::MetricsServicesManager> metrics_services_manager_; - std::unique_ptr<IOThread> io_thread_; - bool created_watchdog_thread_ = false; std::unique_ptr<WatchDogThread> watchdog_thread_;
diff --git a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc index 6db7804f..81ae7d8 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_browsertest.cc
@@ -297,7 +297,17 @@ class BrowsingDataRemoverBrowserTest : public InProcessBrowserTest { public: - BrowsingDataRemoverBrowserTest() {} + BrowsingDataRemoverBrowserTest() { + std::vector<base::Feature> enabled_features = { + leveldb::kLevelDBRewriteFeature, + // Ensure that kOnionSoupDOMStorage is enabled because the old + // SessionStorage implementation causes flaky tests. + blink::features::kOnionSoupDOMStorage}; +#if BUILDFLAG(ENABLE_LIBRARY_CDMS) + enabled_features.push_back(media::kExternalClearKeyForTesting); +#endif + feature_list_.InitWithFeatures(enabled_features, {}); + } // Call to use an Incognito browser rather than the default. void UseIncognitoBrowser() { @@ -561,21 +571,11 @@ void SetUpCommandLine(base::CommandLine* command_line) override { InProcessBrowserTest::SetUpCommandLine(command_line); - - std::vector<base::Feature> enabled_features = { - leveldb::kLevelDBRewriteFeature, - // Ensure that kOnionSoupDOMStorage is enabled because the old - // SessionStorage implementation causes flaky tests. - blink::features::kOnionSoupDOMStorage}; - #if BUILDFLAG(ENABLE_LIBRARY_CDMS) // Testing MediaLicenses requires additional command line parameters as // it uses the External Clear Key CDM. RegisterClearKeyCdm(command_line); - enabled_features.push_back(media::kExternalClearKeyForTesting); #endif - - feature_list_.InitWithFeatures(enabled_features, {}); } base::test::ScopedFeatureList feature_list_;
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index 7300be2..67b333f 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -40,7 +40,6 @@ #include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/web_history_service_factory.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/language/url_language_histogram_factory.h" #include "chrome/browser/media/media_device_id_salt.h" #include "chrome/browser/media/media_engagement_service.h"
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 6a55db74..5a676dfa 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -435,7 +435,6 @@ #include "chrome/browser/android/chrome_context_util.h" #include "chrome/browser/android/devtools_manager_delegate_android.h" #include "chrome/browser/android/download/available_offline_content_provider.h" -#include "chrome/browser/android/download/download_manager_service.h" #include "chrome/browser/android/download/intercept_oma_download_navigation_throttle.h" #include "chrome/browser/android/ntp/new_tab_page_url_handler.h" #include "chrome/browser/android/service_tab_launcher.h" @@ -955,9 +954,6 @@ return ratio * (kMaxFSM - kMinFSM) + kMinFSM; } -void StartDownloadManager(service_manager::mojom::ServiceRequest request) { - DownloadManagerService::GetInstance()->BindServiceRequest(std::move(request)); -} #endif // defined(OS_ANDROID) #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -4029,11 +4025,6 @@ std::move(*receiver))); return; } - - if (identity.name() == "download_manager") { - StartDownloadManager(std::move(*receiver)); - return; - } #endif if (identity.name() == heap_profiling::mojom::kServiceName) { @@ -4071,14 +4062,6 @@ return manifests; } -std::vector<std::string> ChromeContentBrowserClient::GetStartupServices() { -#if defined(OS_ANDROID) - return {"download_manager"}; -#else - return {}; -#endif -} - void ChromeContentBrowserClient::OpenURL( content::SiteInstance* site_instance, const content::OpenURLParams& params,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 18c3804..d654bcc8 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -435,7 +435,6 @@ base::Optional<service_manager::Manifest> GetServiceManifestOverlay( base::StringPiece name) override; std::vector<service_manager::Manifest> GetExtraServiceManifests() override; - std::vector<std::string> GetStartupServices() override; void OpenURL( content::SiteInstance* site_instance, const content::OpenURLParams& params,
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc index 82dbc8b..d743651 100644 --- a/chrome/browser/chrome_navigation_browsertest.cc +++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -62,13 +62,10 @@ class ChromeNavigationBrowserTest : public InProcessBrowserTest { public: - ChromeNavigationBrowserTest() {} - ~ChromeNavigationBrowserTest() override {} - - void SetUp() override { + ChromeNavigationBrowserTest() { scoped_feature_list_.InitAndEnableFeature(ukm::kUkmFeature); - InProcessBrowserTest::SetUp(); } + ~ChromeNavigationBrowserTest() override {} void SetUpCommandLine(base::CommandLine* command_line) override { // Backgrounded renderer processes run at a lower priority, causing the @@ -1342,6 +1339,11 @@ class SiteIsolationForPasswordSitesBrowserTest : public ChromeNavigationBrowserTest { public: + SiteIsolationForPasswordSitesBrowserTest() { + feature_list_.InitWithFeatures({features::kSiteIsolationForPasswordSites}, + {features::kSitePerProcess}); + } + std::vector<std::string> GetSavedIsolatedSites() { return GetSavedIsolatedSites(browser()->profile()); } @@ -1385,12 +1387,6 @@ const std::string kSyntheticTrialGroup = "Enabled"; protected: - void SetUp() override { - feature_list_.InitWithFeatures({features::kSiteIsolationForPasswordSites}, - {features::kSitePerProcess}); - ChromeNavigationBrowserTest::SetUp(); - } - void SetUpCommandLine(base::CommandLine* command_line) override { ChromeNavigationBrowserTest::SetUpCommandLine(command_line);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index afb72423..a2621d25 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1077,6 +1077,8 @@ "input_method/input_method_syncer.h", "kerberos/kerberos_credentials_manager.cc", "kerberos/kerberos_credentials_manager.h", + "kiosk_next/kiosk_next_browser_factory.cc", + "kiosk_next/kiosk_next_browser_factory.h", "kiosk_next_home/app_controller_service.cc", "kiosk_next_home/app_controller_service.h", "kiosk_next_home/app_controller_service_factory.cc",
diff --git a/chrome/browser/chromeos/kiosk_next/OWNERS b/chrome/browser/chromeos/kiosk_next/OWNERS new file mode 100644 index 0000000..7fb73f6 --- /dev/null +++ b/chrome/browser/chromeos/kiosk_next/OWNERS
@@ -0,0 +1,3 @@ +file://ash/kiosk_next/OWNERS + +# COMPONENT: UI>Shell>KioskNext
diff --git a/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.cc b/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.cc new file mode 100644 index 0000000..fff341d --- /dev/null +++ b/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.cc
@@ -0,0 +1,180 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/no_destructor.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/browser_navigator_params.h" +#include "chrome/browser/ui/browser_window.h" +#include "components/user_manager/user_manager.h" +#include "ui/base/page_transition_types.h" +#include "ui/base/window_open_disposition.h" +#include "url/gurl.h" + +namespace { + +constexpr size_t kMaxKioskNextBrowsersAllowed = 1; + +Profile* GetActiveUserProfile() { + auto* user = user_manager::UserManager::Get()->GetActiveUser(); + Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user); + DCHECK(profile); + return profile; +} + +Browser* CreateKioskNextBrowser() { + Browser::CreateParams params(GetActiveUserProfile(), true /* user_gesture */); + params.type = Browser::Type::TYPE_POPUP; /* Not a tabbed experience. */ + params.trusted_source = true; + params.initial_show_state = ui::SHOW_STATE_MAXIMIZED; + params.user_gesture = true; + Browser* browser = Browser::Create(params); + DCHECK(browser); + return browser; +} + +void NavigateBrowser(Browser* browser, const GURL& url) { + NavigateParams params(browser, url, ui::PageTransition::PAGE_TRANSITION_LINK); + params.disposition = WindowOpenDisposition::CURRENT_TAB; + Navigate(¶ms); +} + +} // namespace + +KioskNextBrowserList::Entry::Entry(Browser* browser, const GURL& launch_url) + : browser(browser), launch_url(launch_url) {} + +// static +const KioskNextBrowserList& KioskNextBrowserList::Get() { + return KioskNextBrowserFactory::Get()->kiosk_next_browser_list(); +} + +bool KioskNextBrowserList::CanAddBrowser() const { + return lru_browsers_.size() < max_browsers_allowed_; +} + +bool KioskNextBrowserList::IsKioskNextBrowser(const Browser* browser) const { + return GetBrowserEntry(browser) != nullptr; +} + +Browser* KioskNextBrowserList::GetBrowserForWebsite(const GURL& url) const { + for (auto& entry : lru_browsers_) { + if (entry->launch_url == url) + return entry->browser; + } + return nullptr; +} + +const KioskNextBrowserList::Entry* KioskNextBrowserList::GetBrowserEntry( + const Browser* browser) const { + auto iterator = FindBrowser(browser); + + if (iterator != lru_browsers_.end()) + return (*iterator).get(); + return nullptr; +} + +void KioskNextBrowserList::OnBrowserRemoved(Browser* browser) { + auto iterator = FindBrowser(browser); + if (iterator == lru_browsers_.end()) + return; + lru_browsers_.erase(iterator); +} + +void KioskNextBrowserList::OnBrowserSetLastActive(Browser* browser) { + auto iterator = FindBrowser(browser); + if (iterator == lru_browsers_.end()) + return; + + if (browser == lru_browsers_.back()->browser) + return; + + lru_browsers_.push_back(std::move(*iterator)); + lru_browsers_.erase(iterator); +} + +KioskNextBrowserList::KioskNextBrowserList(size_t max_browsers_allowed) + : max_browsers_allowed_(max_browsers_allowed) { + BrowserList::GetInstance()->AddObserver(this); +} + +KioskNextBrowserList::~KioskNextBrowserList() { + if (BrowserList::GetInstance()) + BrowserList::GetInstance()->RemoveObserver(this); +} + +void KioskNextBrowserList::AddBrowser(Browser* browser, const GURL& url) { + DCHECK(CanAddBrowser()); + lru_browsers_.push_back( + std::make_unique<KioskNextBrowserList::Entry>(browser, url)); +} + +void KioskNextBrowserList::RemoveLRUBrowser() { + if (lru_browsers_.size() > 0) { + // TODO(crbug.com/972880) Figure out how to handle the onbeforeunload + // handlers instead of just skipping them. + bool result = lru_browsers_.front()->browser->TryToCloseWindow( + true /* skip_beforeunload */, base::NullCallback()); + + DCHECK(!result); + + lru_browsers_.pop_front(); + } +} + +KioskNextBrowserList::Iterator KioskNextBrowserList::FindBrowser( + const Browser* browser) { + return std::find_if( + lru_browsers_.begin(), lru_browsers_.end(), + [browser](const std::unique_ptr<KioskNextBrowserList::Entry>& entry) { + return browser == entry->browser; + }); +} + +KioskNextBrowserList::ConstIterator KioskNextBrowserList::FindBrowser( + const Browser* browser) const { + return std::find_if( + lru_browsers_.begin(), lru_browsers_.end(), + [browser](const std::unique_ptr<KioskNextBrowserList::Entry>& entry) { + return browser == entry->browser; + }); +} + +// static +KioskNextBrowserFactory* KioskNextBrowserFactory::Get() { + static base::NoDestructor<KioskNextBrowserFactory> instance( + kMaxKioskNextBrowsersAllowed); + return instance.get(); +} + +KioskNextBrowserFactory::KioskNextBrowserFactory(size_t max_browsers) + : browser_list_(max_browsers) {} + +KioskNextBrowserFactory::~KioskNextBrowserFactory() = default; + +Browser* KioskNextBrowserFactory::CreateForWebsite(const GURL& url) { + Browser* browser = browser_list_.GetBrowserForWebsite(url); + if (browser) { + browser_list_.OnBrowserSetLastActive(browser); + browser->window()->Show(); + return browser; + } + + if (!browser_list_.CanAddBrowser()) + browser_list_.RemoveLRUBrowser(); + + DCHECK(browser_list_.CanAddBrowser()); + browser = CreateKioskNextBrowser(); + browser_list_.AddBrowser(browser, url); + + NavigateBrowser(browser, url); + browser->window()->Show(); + return browser; +}
diff --git a/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.h b/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.h new file mode 100644 index 0000000..2c4f55b --- /dev/null +++ b/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.h
@@ -0,0 +1,107 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_KIOSK_NEXT_KIOSK_NEXT_BROWSER_FACTORY_H_ +#define CHROME_BROWSER_CHROMEOS_KIOSK_NEXT_KIOSK_NEXT_BROWSER_FACTORY_H_ + +#include <list> +#include <memory> + +#include "base/no_destructor.h" +#include "chrome/browser/ui/browser_list_observer.h" +#include "url/gurl.h" + +class Browser; + +// This class keeps a list of Browser instances along with their corresponding +// launch URLs. +class KioskNextBrowserList : public BrowserListObserver { + public: + // This struct keeps a browser instance and its associated launch url from + // kiosk next home. + struct Entry { + Entry(Browser* browser, const GURL& launch_url); + + // Unowned. Owned by Views hierarchy (BrowserView). + Browser* const browser; + + const GURL launch_url; + }; + + typedef std::list<std::unique_ptr<Entry>>::iterator Iterator; + typedef std::list<std::unique_ptr<Entry>>::const_iterator ConstIterator; + + // Returns a pointer to the KioskNextBrowserList instance owned by + // KioskNextBrowserFactory. + static const KioskNextBrowserList& Get(); + + // This method is called by KioskNextBrowserFactory to check if the upper + // limit of number of Browsers has been reached. + bool CanAddBrowser() const; + + // Checks if the browser instance is in the list of browsers created by + // KioskNextBrowserFactory. + bool IsKioskNextBrowser(const Browser* browser) const; + + // Returns the corresponding browser if there exists a Browser instance + // that was launched with the particular URL. + Browser* GetBrowserForWebsite(const GURL& url) const; + + // Returns the corresponding Entry if browser is a kiosk next browser. + // Otherwise, return an Entry with nullptr for its |browser|. + const Entry* GetBrowserEntry(const Browser* browser) const; + + // BrowserListObserver: + void OnBrowserRemoved(Browser* browser) override; + void OnBrowserSetLastActive(Browser* browser) override; + + private: + friend class KioskNextBrowserFactory; + + explicit KioskNextBrowserList(size_t max_browsers_allowed); + ~KioskNextBrowserList() override; + + // Called by KioskNextBrowserFactory to add a new browser instance along with + // its launch url. + void AddBrowser(Browser* browser, const GURL& url); + + // Called by KioskNextBrowserFactory when CanAddBrowser() returns false. It + // removes the LRU browser to allow the factory class to continue creating. + void RemoveLRUBrowser(); + + Iterator FindBrowser(const Browser* browser); + ConstIterator FindBrowser(const Browser* browser) const; + + size_t max_browsers_allowed_; + std::list<std::unique_ptr<Entry>> lru_browsers_; + + DISALLOW_COPY_AND_ASSIGN(KioskNextBrowserList); +}; + +class KioskNextBrowserFactory { + public: + // Returns the instance already created for this singleton. Creates a new + // instance if one hasn't already been created yet. + static KioskNextBrowserFactory* Get(); + + ~KioskNextBrowserFactory(); + + Browser* CreateForWebsite(const GURL& url); + + const KioskNextBrowserList& kiosk_next_browser_list() const { + return browser_list_; + } + + private: + friend class KioskNextBrowserFactoryTest; + friend class base::NoDestructor<KioskNextBrowserFactory>; + + explicit KioskNextBrowserFactory(size_t max_browsers_allowed); + + KioskNextBrowserList browser_list_; + + DISALLOW_COPY_AND_ASSIGN(KioskNextBrowserFactory); +}; + +#endif // CHROME_BROWSER_CHROMEOS_KIOSK_NEXT_KIOSK_NEXT_BROWSER_FACTORY_H_
diff --git a/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory_browsertest.cc b/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory_browsertest.cc new file mode 100644 index 0000000..bfa7a65 --- /dev/null +++ b/chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory_browsertest.cc
@@ -0,0 +1,70 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "chrome/browser/chromeos/kiosk_next/kiosk_next_browser_factory.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/test/browser_test.h" +#include "ui/base/ui_base_types.h" +#include "url/gurl.h" + +namespace { +const GURL kUrl1("https://www.url1.com"); +const GURL kUrl2("https://www.url2.com"); +const GURL kUrl3("https://www.url3.com"); +} // namespace + +class KioskNextBrowserFactoryTest : public InProcessBrowserTest { + public: + KioskNextBrowserFactoryTest() {} + ~KioskNextBrowserFactoryTest() override = default; + + KioskNextBrowserList& GetBrowserList() { + return browser_factory_.browser_list_; + } + + protected: + KioskNextBrowserFactory browser_factory_{2 /* max_browsers_allowed */}; + + DISALLOW_COPY_AND_ASSIGN(KioskNextBrowserFactoryTest); +}; + +IN_PROC_BROWSER_TEST_F(KioskNextBrowserFactoryTest, TestBrowserParams) { + // Adds a new KioskNextBrowser instance. + Browser* browser = browser_factory_.CreateForWebsite(kUrl1); + EXPECT_NE(browser, nullptr); + EXPECT_EQ(browser->initial_show_state(), ui::SHOW_STATE_MAXIMIZED); + EXPECT_FALSE(browser->is_type_tabbed()); + EXPECT_TRUE(GetBrowserList().IsKioskNextBrowser(browser)); + EXPECT_EQ(GetBrowserList().GetBrowserForWebsite(kUrl1), browser); +} + +IN_PROC_BROWSER_TEST_F(KioskNextBrowserFactoryTest, TestFactoryCreateMethods) { + ASSERT_TRUE(GetBrowserList().CanAddBrowser()); + EXPECT_EQ(GetBrowserList().GetBrowserForWebsite(kUrl1), nullptr); + + // Adds a new KioskNextBrowser instance. + browser_factory_.CreateForWebsite(kUrl1); + EXPECT_TRUE(GetBrowserList().CanAddBrowser()); + Browser* browser_2 = browser_factory_.CreateForWebsite(kUrl2); + EXPECT_NE(browser_2, nullptr); + EXPECT_EQ(GetBrowserList().GetBrowserEntry(browser_2)->browser, browser_2); + + EXPECT_FALSE(GetBrowserList().CanAddBrowser()); + Browser* browser_3 = browser_factory_.CreateForWebsite(kUrl3); + EXPECT_EQ(GetBrowserList().GetBrowserForWebsite(kUrl3), browser_3); + + // The LRU browser has been removed. + EXPECT_EQ(GetBrowserList().GetBrowserForWebsite(kUrl1), nullptr); + + // Make browser_3 is the lru browser. + GetBrowserList().OnBrowserSetLastActive(browser_2); + + browser_factory_.CreateForWebsite(kUrl1); + + // LRU browser has been removed. + EXPECT_EQ(GetBrowserList().GetBrowserForWebsite(kUrl3), nullptr); +}
diff --git a/chrome/browser/chromeos/printing/printer_info.h b/chrome/browser/chromeos/printing/printer_info.h index 35d4dcd7..b8cfd02e 100644 --- a/chrome/browser/chromeos/printing/printer_info.h +++ b/chrome/browser/chromeos/printing/printer_info.h
@@ -9,6 +9,7 @@ #include <vector> #include "base/callback_forward.h" +#include "printing/backend/cups_jobs.h" namespace chromeos { @@ -18,7 +19,7 @@ // from the printer. |autoconf| indicates if we think we can compute the // printer capabilites without a PPD. using PrinterInfoCallback = - base::Callback<void(bool success, + base::Callback<void(::printing::PrinterQueryResult result, const std::string& make, const std::string& model, const std::string& make_and_model,
diff --git a/chrome/browser/chromeos/printing/printer_info_cups.cc b/chrome/browser/chromeos/printing/printer_info_cups.cc index d21d0172..431166f 100644 --- a/chrome/browser/chromeos/printing/printer_info_cups.cc +++ b/chrome/browser/chromeos/printing/printer_info_cups.cc
@@ -16,7 +16,6 @@ #include "base/task/task_traits.h" #include "base/task_runner_util.h" #include "base/version.h" -#include "printing/backend/cups_jobs.h" namespace { @@ -28,6 +27,13 @@ const std::array<const char* const, 4> kMultiWordManufacturers{ {"FUJI XEROX", "KODAK FUNAI", "KONICA MINOLTA", "TEXAS INSTRUMENTS"}}; +// Wraps a PrinterQueryResult and a PrinterInfo so that we can use +// PostTaskAndResplyWithResult. +struct QueryResult { + ::printing::PrinterQueryResult result; + ::printing::PrinterInfo printer_info; +}; + // Returns the length of the portion of |make_and_model| representing the // manufacturer. This is either a value from kMultiWordManufacaturers or the // first token. If there is only one token or less, we assume that it does not @@ -78,31 +84,34 @@ // Dispatches an IPP request to |host| to retrieve printer information. Returns // a nullptr if the request fails. -std::unique_ptr<::printing::PrinterInfo> QueryPrinterImpl( - const std::string& host, - const int port, - const std::string& path, - bool encrypted) { - auto info = std::make_unique<::printing::PrinterInfo>(); - if (!::printing::GetPrinterInfo(host, port, path, encrypted, info.get())) { +QueryResult QueryPrinterImpl(const std::string& host, + const int port, + const std::string& path, + bool encrypted) { + QueryResult result; + result.result = ::printing::GetPrinterInfo(host, port, path, encrypted, + &result.printer_info); + if (result.result != ::printing::PrinterQueryResult::SUCCESS) { LOG(ERROR) << "Could not retrieve printer info"; - return nullptr; } - return info; + return result; } // Handles the request for |info|. Parses make and model information before // calling |callback|. void OnPrinterQueried(const chromeos::PrinterInfoCallback& callback, - std::unique_ptr<::printing::PrinterInfo> info) { - if (!info) { + const QueryResult& query_result) { + const ::printing::PrinterQueryResult& result = query_result.result; + const ::printing::PrinterInfo& printer_info = query_result.printer_info; + if (result != ::printing::PrinterQueryResult::SUCCESS) { VLOG(1) << "Could not reach printer"; - callback.Run(false, std::string(), std::string(), std::string(), {}, false); + callback.Run(result, std::string(), std::string(), std::string(), {}, + false); return; } - base::StringPiece make_and_model(info->make_and_model); + base::StringPiece make_and_model(printer_info.make_and_model); base::StringPiece make; base::StringPiece model; @@ -115,8 +124,9 @@ model = make_and_model; } - callback.Run(true, make.as_string(), model.as_string(), info->make_and_model, - info->document_formats, IsAutoconf(*info)); + callback.Run(result, make.as_string(), model.as_string(), + printer_info.make_and_model, printer_info.document_formats, + IsAutoconf(printer_info)); } } // namespace
diff --git a/chrome/browser/chromeos/printing/printer_info_stub.cc b/chrome/browser/chromeos/printing/printer_info_stub.cc index 66ccd18..bcd2caed 100644 --- a/chrome/browser/chromeos/printing/printer_info_stub.cc +++ b/chrome/browser/chromeos/printing/printer_info_stub.cc
@@ -17,9 +17,11 @@ const PrinterInfoCallback& callback) { DCHECK(!host.empty()); - base::PostTask(FROM_HERE, - base::BindOnce(callback, false, "Foo", "Bar", "Foo Bar", - std::vector<std::string>{}, false)); + base::PostTask( + FROM_HERE, + base::BindOnce(callback, printing::PrinterQueryResult::UNKNOWN_FAILURE, + "Foo", "Bar", "Foo Bar", std::vector<std::string>{}, + false)); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc index 20337c8..0ed732b 100644 --- a/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc +++ b/chrome/browser/chromeos/usb/cros_usb_detector_unittest.cc
@@ -155,6 +155,7 @@ } void TearDown() override { + scoped_feature_list_.Reset(); crostini_test_helper_.reset(); BrowserWithTestWindowTest::TearDown(); }
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc index d53321e..bdabb5f 100644 --- a/chrome/browser/client_hints/client_hints_browsertest.cc +++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -12,6 +12,7 @@ #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/mock_entropy_provider.h" #include "build/build_config.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" @@ -136,7 +137,8 @@ public testing::WithParamInterface<bool> { public: ClientHintsBrowserTest() - : http_server_(net::EmbeddedTestServer::TYPE_HTTP), + : field_trial_list_(std::make_unique<base::MockEntropyProvider>()), + http_server_(net::EmbeddedTestServer::TYPE_HTTP), https_server_(net::EmbeddedTestServer::TYPE_HTTPS), https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS), expect_client_hints_on_main_frame_(false), @@ -410,6 +412,7 @@ return main_frame_ua_observed_; } + base::FieldTrialList field_trial_list_; base::test::ScopedFeatureList scoped_feature_list_; std::string intercept_iframe_resource_; @@ -1712,8 +1715,6 @@ const net::EffectiveConnectionType web_effective_connection_type_override_ = net::EFFECTIVE_CONNECTION_TYPE_3G; - - base::test::ScopedFeatureList scoped_feature_list_override_; }; // Make sure that when NetInfo holdback experiment is enabled, the NetInfo APIs
diff --git a/chrome/browser/data_saver/data_saver_holdback_browsertest.cc b/chrome/browser/data_saver/data_saver_holdback_browsertest.cc index 362c159..cf004b6 100644 --- a/chrome/browser/data_saver/data_saver_holdback_browsertest.cc +++ b/chrome/browser/data_saver/data_saver_holdback_browsertest.cc
@@ -52,24 +52,10 @@ } void ConfigureHoldbackExperiment() { - base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); - const std::string kTrialName = "TrialFoo"; - const std::string kGroupName = "GroupFoo"; // Value not used - - scoped_refptr<base::FieldTrial> trial = - base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); - std::map<std::string, std::string> params; params["holdback_web"] = GetParam() ? "true" : "false"; - ASSERT_TRUE( - base::FieldTrialParamAssociator::GetInstance() - ->AssociateFieldTrialParams(kTrialName, kGroupName, params)); - - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - feature_list->RegisterFieldTrialOverride( - features::kDataSaverHoldback.name, - base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); - scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); + scoped_feature_list_.InitWithFeaturesAndParameters( + {{features::kDataSaverHoldback, {params}}}, {}); } private:
diff --git a/chrome/browser/enterprise_reporting/report_generator.cc b/chrome/browser/enterprise_reporting/report_generator.cc new file mode 100644 index 0000000..9f1d61b --- /dev/null +++ b/chrome/browser/enterprise_reporting/report_generator.cc
@@ -0,0 +1,110 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise_reporting/report_generator.h" + +#include <utility> + +#include "base/base_paths.h" +#include "base/files/file_path.h" +#include "base/path_service.h" +#include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile_attributes_entry.h" +#include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/channel_info.h" +#include "components/policy/core/common/cloud/cloud_policy_util.h" +#include "components/version_info/channel.h" +#include "components/version_info/version_info.h" + +#if defined(OS_WIN) +#include "base/win/wmi.h" +#endif + +namespace em = enterprise_management; + +namespace enterprise_reporting { +namespace { + +std::string GetChromePath() { + base::FilePath path; + base::PathService::Get(base::DIR_EXE, &path); + return path.AsUTF8Unsafe(); +} + +} // namespace + +ReportGenerator::ReportGenerator() = default; +ReportGenerator::~ReportGenerator() = default; + +std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>> +ReportGenerator::Generate() { + CreateBasicRequest(); + requests_.push_back( + std::make_unique<em::ChromeDesktopReportRequest>(basic_request_)); + return std::move(requests_); +} + +void ReportGenerator::CreateBasicRequest() { + basic_request_.set_computer_name(this->GetMachineName()); + basic_request_.set_os_user_name(GetOSUserName()); + basic_request_.set_serial_number(GetSerialNumber()); + basic_request_.set_allocated_os_report(GetOSReport().release()); + basic_request_.set_allocated_browser_report(GetBrowserReport().release()); + for (auto& profile : GetProfiles()) { + basic_request_.mutable_browser_report()->add_profile_info_list()->Swap( + profile.get()); + } +} + +std::unique_ptr<em::OSReport> ReportGenerator::GetOSReport() { + auto report = std::make_unique<em::OSReport>(); + report->set_name(policy::GetOSPlatform()); + report->set_arch(policy::GetOSArchitecture()); + report->set_version(policy::GetOSVersion()); + return report; +} + +std::string ReportGenerator::GetMachineName() { + return policy::GetMachineName(); +} + +std::string ReportGenerator::GetOSUserName() { + return policy::GetOSUsername(); +} + +std::string ReportGenerator::GetSerialNumber() { +#if defined(OS_WIN) + return base::UTF16ToUTF8( + base::win::WmiComputerSystemInfo::Get().serial_number()); +#else + return std::string(); +#endif +} + +std::unique_ptr<em::BrowserReport> ReportGenerator::GetBrowserReport() { + auto report = std::make_unique<em::BrowserReport>(); + report->set_browser_version(version_info::GetVersionNumber()); + report->set_channel(policy::ConvertToProtoChannel(chrome::GetChannel())); + report->set_executable_path(GetChromePath()); + return report; +} + +std::vector<std::unique_ptr<em::ChromeUserProfileInfo>> +ReportGenerator::GetProfiles() { + std::vector<std::unique_ptr<em::ChromeUserProfileInfo>> profiles; + for (auto* entry : g_browser_process->profile_manager() + ->GetProfileAttributesStorage() + .GetAllProfilesAttributes()) { + profiles.push_back(std::make_unique<em::ChromeUserProfileInfo>()); + profiles.back()->set_id(entry->GetPath().AsUTF8Unsafe()); + profiles.back()->set_name(base::UTF16ToUTF8(entry->GetName())); + profiles.back()->set_is_full_report(false); + } + return profiles; +} + +} // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise_reporting/report_generator.h b/chrome/browser/enterprise_reporting/report_generator.h new file mode 100644 index 0000000..1881c6f24 --- /dev/null +++ b/chrome/browser/enterprise_reporting/report_generator.h
@@ -0,0 +1,63 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ENTERPRISE_REPORTING_REPORT_GENERATOR_H_ +#define CHROME_BROWSER_ENTERPRISE_REPORTING_REPORT_GENERATOR_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "components/policy/proto/device_management_backend.pb.h" + +namespace em = enterprise_management; + +namespace enterprise_reporting { + +class ReportGenerator { + public: + ReportGenerator(); + ~ReportGenerator(); + + std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>> Generate(); + + protected: + // Creates a basic request that will be used by all Profiles. + void CreateBasicRequest(); + + // Returns an OS report contains basic OS information includes OS name, OS + // architecture and OS version. + virtual std::unique_ptr<em::OSReport> GetOSReport(); + + // Returns the name of computer. + virtual std::string GetMachineName(); + + // Returns the name of OS user. + virtual std::string GetOSUserName(); + + // Returns the Serial number of the device. It's Windows only field and empty + // on other platforms. + virtual std::string GetSerialNumber(); + + // Returns a browser report contains browser related information includes + // browser version, channel and executable path. + virtual std::unique_ptr<em::BrowserReport> GetBrowserReport(); + + // Returns the list of Profiles that is owned by current Browser instance. It + // only contains Profile's path and name. + std::vector<std::unique_ptr<em::ChromeUserProfileInfo>> GetProfiles(); + + private: + std::vector<std::unique_ptr<em::ChromeDesktopReportRequest>> requests_; + + // Basic information that is shared among requests. + em::ChromeDesktopReportRequest basic_request_; + + DISALLOW_COPY_AND_ASSIGN(ReportGenerator); +}; + +} // namespace enterprise_reporting + +#endif // CHROME_BROWSER_ENTERPRISE_REPORTING_REPORT_GENERATOR_H_
diff --git a/chrome/browser/enterprise_reporting/report_generator_unittest.cc b/chrome/browser/enterprise_reporting/report_generator_unittest.cc new file mode 100644 index 0000000..7a91250 --- /dev/null +++ b/chrome/browser/enterprise_reporting/report_generator_unittest.cc
@@ -0,0 +1,131 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise_reporting/report_generator.h" + +#include <set> + +#include "base/logging.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#include "chrome/browser/profiles/profile_attributes_storage.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "components/account_id/account_id.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace em = enterprise_management; + +namespace enterprise_reporting { +namespace { +#if !defined(OS_CHROMEOS) +// We only upload serial number on Windows. +void VerifySerialNumber(const std::string& serial_number) { +#if defined(OS_WIN) + EXPECT_NE(std::string(), serial_number); +#else + EXPECT_EQ(std::string(), serial_number); +#endif +} + +const char kProfile1[] = "Profile"; +#endif +} // namespace + +#if !defined(OS_CHROMEOS) +class ReportGeneratorTest : public ::testing::Test { + public: + ReportGeneratorTest() + : profile_manager_(TestingBrowserProcess::GetGlobal()) {} + ~ReportGeneratorTest() override = default; + + void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); } + + // Creates |number| of Profiles. Returns the set of their names. The profile + // names begin with Profile|start_index|. Profile instances are created if + // |is_active| is true. Otherwise, information is only put into + // ProfileAttributesStorage. + std::set<std::string> CreateProfiles(int number, + bool is_active, + int start_index = 0) { + std::set<std::string> profile_names; + for (int i = start_index; i < number; i++) { + std::string profile_name = + std::string(kProfile1) + base::NumberToString(i); + if (is_active) { + profile_manager_.CreateTestingProfile(profile_name); + } else { + profile_manager_.profile_attributes_storage()->AddProfile( + profile_manager()->profiles_dir().AppendASCII(profile_name), + base::ASCIIToUTF16(profile_name), std::string(), base::string16(), + 0, std::string(), EmptyAccountId()); + } + profile_names.insert(profile_name); + } + profile_manager_.CreateGuestProfile(); + profile_manager_.CreateSystemProfile(); + return profile_names; + } + + TestingProfileManager* profile_manager() { return &profile_manager_; } + + private: + content::TestBrowserThreadBundle thread_bundle_; + TestingProfileManager profile_manager_; + + DISALLOW_COPY_AND_ASSIGN(ReportGeneratorTest); +}; + +TEST_F(ReportGeneratorTest, GenerateBasicReport) { + int profile_number = 2; + auto profile_names = CreateProfiles(profile_number, /*is_active=*/false); + + ReportGenerator generator; + auto requests = generator.Generate(); + EXPECT_EQ(1u, requests.size()); + + auto* basic_request = requests[0].get(); + EXPECT_NE(std::string(), basic_request->computer_name()); + EXPECT_NE(std::string(), basic_request->os_user_name()); + VerifySerialNumber(basic_request->serial_number()); + + EXPECT_TRUE(basic_request->has_os_report()); + auto& os_report = basic_request->os_report(); + EXPECT_NE(std::string(), os_report.name()); + EXPECT_NE(std::string(), os_report.arch()); + EXPECT_NE(std::string(), os_report.version()); + + EXPECT_TRUE(basic_request->has_browser_report()); + auto& browser_report = basic_request->browser_report(); + EXPECT_NE(std::string(), browser_report.browser_version()); + EXPECT_NE(std::string(), browser_report.executable_path()); + EXPECT_TRUE(browser_report.has_channel()); + + EXPECT_EQ(profile_number, browser_report.profile_info_list_size()); + for (int i = 0; i < profile_number; i++) { + auto profile_info = browser_report.profile_info_list(i); + std::string profile_name = profile_info.name(); + + // Verify that the profile id is set as profile path. + EXPECT_EQ(profile_manager() + ->profiles_dir() + .AppendASCII(profile_name) + .AsUTF8Unsafe(), + profile_info.id()); + + // Verify that the basic report does not contain any full Profile report. + EXPECT_FALSE(profile_info.is_full_report()); + + // Verify the profile name is one of the profiles that were created above. + auto it = profile_names.find(profile_name); + EXPECT_NE(profile_names.end(), it); + profile_names.erase(it); + } +} +#endif + +} // namespace enterprise_reporting
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc index 126cac8..cb018673 100644 --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -128,6 +128,7 @@ settings_api::PrefType::PREF_TYPE_BOOLEAN; (*s_whitelist)[bookmarks::prefs::kShowBookmarkBar] = settings_api::PrefType::PREF_TYPE_BOOLEAN; + #if defined(OS_LINUX) && !defined(OS_CHROMEOS) (*s_whitelist)[::prefs::kUseCustomChromeFrame] = settings_api::PrefType::PREF_TYPE_BOOLEAN; @@ -578,6 +579,8 @@ #if defined(GOOGLE_CHROME_BUILD) (*s_whitelist)[::prefs::kMediaRouterEnableCloudServices] = settings_api::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kUserFeedbackAllowed] = + settings_api::PrefType::PREF_TYPE_BOOLEAN; #endif // defined(GOOGLE_CHROME_BUILD) // Media Remoting settings.
diff --git a/chrome/browser/extensions/app_data_migrator_unittest.cc b/chrome/browser/extensions/app_data_migrator_unittest.cc index fba4794..e79ca1ef 100644 --- a/chrome/browser/extensions/app_data_migrator_unittest.cc +++ b/chrome/browser/extensions/app_data_migrator_unittest.cc
@@ -145,8 +145,7 @@ const Extension* ext, storage::FileSystemContext* fs_context, Profile* profile) { - profile->GetExtensionSpecialStoragePolicy()->GrantRightsForExtension(ext, - profile); + profile->GetExtensionSpecialStoragePolicy()->GrantRightsForExtension(ext); base::FilePath path(FILE_PATH_LITERAL("test.txt")); GURL extension_url =
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc index eb0d4128..ced1a58b 100644 --- a/chrome/browser/extensions/extension_action_runner.cc +++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -373,18 +373,18 @@ const base::Callback<void(ToolbarActionsBarBubbleDelegate::CloseAction)>& callback) { Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); - ToolbarActionsBar* toolbar_actions_bar = - browser ? browser->window()->GetToolbarActionsBar() : nullptr; - if (toolbar_actions_bar) { - if (default_bubble_close_action_for_testing_) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(callback, *default_bubble_close_action_for_testing_)); - } else { - toolbar_actions_bar->ShowToolbarActionBubble( - std::make_unique<BlockedActionBubbleDelegate>(callback, - extension->id())); - } + ExtensionsContainer* const extensions_container = + browser ? browser->window()->GetExtensionsContainer() : nullptr; + if (!extensions_container) + return; + if (default_bubble_close_action_for_testing_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(callback, *default_bubble_close_action_for_testing_)); + } else { + extensions_container->ShowToolbarActionBubble( + std::make_unique<BlockedActionBubbleDelegate>(callback, + extension->id())); } }
diff --git a/chrome/browser/extensions/extension_context_menu_model.cc b/chrome/browser/extensions/extension_context_menu_model.cc index 5c168f5..0d2a26a 100644 --- a/chrome/browser/extensions/extension_context_menu_model.cc +++ b/chrome/browser/extensions/extension_context_menu_model.cc
@@ -192,7 +192,8 @@ const Extension* extension, Browser* browser, ButtonVisibility button_visibility, - PopupDelegate* delegate) + PopupDelegate* delegate, + bool can_show_icon_in_toolbar) : SimpleMenuModel(this), extension_id_(extension->id()), is_component_(Manifest::IsComponentLocation(extension->location())), @@ -200,7 +201,8 @@ profile_(browser->profile()), delegate_(delegate), action_type_(NO_ACTION), - button_visibility_(button_visibility) { + button_visibility_(button_visibility), + can_show_icon_in_toolbar_(can_show_icon_in_toolbar) { InitMenu(extension, button_visibility); } @@ -231,7 +233,12 @@ return extension_items_->IsCommandIdVisible(command_id); } - // Standard menu items are always visible. + // The command is hidden in app windows because they don't + // support showing extensions in the app window frame. + if (command_id == TOGGLE_VISIBILITY) + return can_show_icon_in_toolbar_; + + // Standard menu items are visible. return true; }
diff --git a/chrome/browser/extensions/extension_context_menu_model.h b/chrome/browser/extensions/extension_context_menu_model.h index 4ec65a1..93aee70 100644 --- a/chrome/browser/extensions/extension_context_menu_model.h +++ b/chrome/browser/extensions/extension_context_menu_model.h
@@ -102,7 +102,8 @@ ExtensionContextMenuModel(const Extension* extension, Browser* browser, ButtonVisibility visibility, - PopupDelegate* delegate); + PopupDelegate* delegate, + bool can_show_icon_in_toolbar); ~ExtensionContextMenuModel() override; // SimpleMenuModel::Delegate: @@ -166,6 +167,8 @@ // The visibility of the button at the time the menu opened. ButtonVisibility button_visibility_; + const bool can_show_icon_in_toolbar_; + // Menu matcher for context menu items specified by the extension. std::unique_ptr<ContextMenuMatcher> extension_items_;
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc index c45d6c77..1f9c0f8 100644 --- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc +++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -91,8 +91,8 @@ std::unique_ptr<ExtensionContextMenuModel> BuildMenu() { return std::make_unique<ExtensionContextMenuModel>( - extension_.get(), browser_, ExtensionContextMenuModel::VISIBLE, - nullptr); + extension_.get(), browser_, ExtensionContextMenuModel::VISIBLE, nullptr, + true /* can_show_icon_in_toolbar */); } void AddContextItem(MenuItem::Context context) { @@ -381,7 +381,8 @@ "extension", manifest_keys::kPageAction, Manifest::EXTERNAL_POLICY); ExtensionContextMenuModel menu(extension, GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); ExtensionSystem* system = ExtensionSystem::Get(profile()); system->management_policy()->UnregisterAllProviders(); @@ -433,7 +434,8 @@ service()->AddExtension(extension.get()); ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); // A component extension's context menu should not include options for // managing extensions or removing it, and should only include an option for @@ -462,7 +464,8 @@ .SetLocation(Manifest::COMPONENT) .Build(); ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); service()->AddExtension(extension.get()); EXPECT_TRUE(extensions::OptionsPageInfo::HasOptionsPage(extension.get())); EXPECT_NE(-1, menu.GetIndexOfCommandId(ExtensionContextMenuModel::OPTIONS)); @@ -614,7 +617,8 @@ AddExtension("extension", manifest_keys::kPageAction, Manifest::INTERNAL); ExtensionContextMenuModel menu(extension, GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); EXPECT_TRUE(menu.IsCommandIdVisible(ExtensionContextMenuModel::HOME_PAGE)); EXPECT_TRUE(menu.IsCommandIdVisible(ExtensionContextMenuModel::OPTIONS)); EXPECT_TRUE( @@ -660,7 +664,8 @@ { // Even page actions should have a visibility option. ExtensionContextMenuModel menu(page_action, browser, - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); int index = menu.GetIndexOfCommandId(visibility_command); EXPECT_NE(-1, index); EXPECT_EQ(hide_string, menu.GetLabelAt(index)); @@ -668,7 +673,8 @@ { ExtensionContextMenuModel menu(browser_action, browser, - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); int index = menu.GetIndexOfCommandId(visibility_command); EXPECT_NE(-1, index); EXPECT_EQ(hide_string, menu.GetLabelAt(index)); @@ -687,7 +693,7 @@ // string. ExtensionContextMenuModel menu(browser_action, browser, ExtensionContextMenuModel::OVERFLOWED, - nullptr); + nullptr, true); int index = menu.GetIndexOfCommandId(visibility_command); EXPECT_NE(-1, index); EXPECT_EQ(show_string, menu.GetLabelAt(index)); @@ -698,7 +704,7 @@ // popup, we should use a "Keep button in toolbar" string. ExtensionContextMenuModel menu( browser_action, browser, - ExtensionContextMenuModel::TRANSITIVELY_VISIBLE, nullptr); + ExtensionContextMenuModel::TRANSITIVELY_VISIBLE, nullptr, true); int index = menu.GetIndexOfCommandId(visibility_command); EXPECT_NE(-1, index); EXPECT_EQ(keep_string, menu.GetLabelAt(index)); @@ -720,7 +726,8 @@ // reflects what normally happens (Chrome closes the menu when the uninstall // dialog shows up). ExtensionContextMenuModel menu(extension, GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); menu.ExecuteCommand(ExtensionContextMenuModel::UNINSTALL, 0); } uninstalled_observer.WaitForExtensionUninstalled(); @@ -756,7 +763,8 @@ extension, UserScript::DOCUMENT_IDLE, increment_run_count); ExtensionContextMenuModel menu(extension, GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); EXPECT_NE(-1, menu.GetIndexOfCommandId( ExtensionContextMenuModel::PAGE_ACCESS_SUBMENU)); @@ -869,7 +877,7 @@ Manifest::INTERNAL, "http://www.example.com/*"); ExtensionContextMenuModel single_host_menu( single_host_extension, GetBrowser(), ExtensionContextMenuModel::VISIBLE, - nullptr); + nullptr, true); EXPECT_NE(-1, single_host_menu.GetIndexOfCommandId( ExtensionContextMenuModel::PAGE_ACCESS_SUBMENU)); } @@ -881,7 +889,8 @@ "page_action", manifest_keys::kPageAction, Manifest::INTERNAL); ASSERT_TRUE(page_action); ExtensionContextMenuModel menu(page_action, GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); int inspect_popup_index = menu.GetIndexOfCommandId(ExtensionContextMenuModel::INSPECT_POPUP); EXPECT_GE(0, inspect_popup_index); @@ -890,7 +899,8 @@ const Extension* browser_action = AddExtension( "browser_action", manifest_keys::kBrowserAction, Manifest::INTERNAL); ExtensionContextMenuModel menu(browser_action, GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); int inspect_popup_index = menu.GetIndexOfCommandId(ExtensionContextMenuModel::INSPECT_POPUP); EXPECT_GE(0, inspect_popup_index); @@ -901,7 +911,8 @@ const Extension* no_action = AddExtension( "no_action", nullptr, Manifest::INTERNAL); ExtensionContextMenuModel menu(no_action, GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); int inspect_popup_index = menu.GetIndexOfCommandId(ExtensionContextMenuModel::INSPECT_POPUP); EXPECT_EQ(-1, inspect_popup_index); @@ -1099,7 +1110,8 @@ web_contents_tester->NavigateAndCommit(test_case.current_url); ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); EXPECT_EQ(test_case.selected_entry.has_value(), !test_case.expected_entries.empty()) @@ -1186,7 +1198,8 @@ AddTab(GURL("https://a.com")); ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); EXPECT_EQ(CommandState::kEnabled, GetPageAccessCommandState(menu, kOnClick)); EXPECT_EQ(CommandState::kDisabled, GetPageAccessCommandState(menu, kOnSite)); EXPECT_EQ(CommandState::kDisabled, @@ -1228,7 +1241,8 @@ { ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); // Without withholding host permissions, the menu should be visible on // a.com... @@ -1256,7 +1270,8 @@ { // ... but not on b.com, where it doesn't want to run. ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); EXPECT_FALSE(HasPageAccessSubmenu(menu)); EXPECT_TRUE(HasCantAccessPageEntry(menu)); } @@ -1270,7 +1285,8 @@ { ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); EXPECT_TRUE(HasPageAccessSubmenu(menu)); EXPECT_FALSE(HasCantAccessPageEntry(menu)); EXPECT_EQ(CommandState::kEnabled, @@ -1296,7 +1312,8 @@ } ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); // Somewhat strangely, this also removes the access controls, because we don't // show it for sites the extension doesn't want to run on. EXPECT_FALSE(HasPageAccessSubmenu(menu)); @@ -1327,7 +1344,8 @@ AddTab(a_com); ExtensionContextMenuModel menu(extension.get(), GetBrowser(), - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); EXPECT_EQ(CommandState::kEnabled, GetPageAccessCommandState(menu, kOnClick)); EXPECT_EQ(CommandState::kEnabled, GetPageAccessCommandState(menu, kOnSite)); @@ -1368,7 +1386,8 @@ Browser* browser = GetBrowser(); ExtensionContextMenuModel menu(extension.get(), browser, - ExtensionContextMenuModel::VISIBLE, nullptr); + ExtensionContextMenuModel::VISIBLE, nullptr, + true); const ExtensionContextMenuModel::MenuEntries kLearnMore = ExtensionContextMenuModel::PAGE_ACCESS_LEARN_MORE; @@ -1400,7 +1419,7 @@ // The menu is constructed, but never shown. ExtensionContextMenuModel menu(extension.get(), GetBrowser(), ExtensionContextMenuModel::VISIBLE, - nullptr); + nullptr, true); } tester.ExpectTotalCount(kHistogramName, 0); } @@ -1411,7 +1430,7 @@ // The menu is constructed and shown, but no action is taken. ExtensionContextMenuModel menu(extension.get(), GetBrowser(), ExtensionContextMenuModel::VISIBLE, - nullptr); + nullptr, true); menu.OnMenuWillShow(&menu); menu.MenuClosed(&menu); } @@ -1426,7 +1445,7 @@ // The menu is constructed, shown, and an action taken. ExtensionContextMenuModel menu(extension.get(), GetBrowser(), ExtensionContextMenuModel::VISIBLE, - nullptr); + nullptr, true); menu.OnMenuWillShow(&menu); menu.ExecuteCommand(ExtensionContextMenuModel::MANAGE_EXTENSIONS, 0); menu.MenuClosed(&menu); @@ -1474,4 +1493,25 @@ 1 /* expected_count */); } +TEST_F(ExtensionContextMenuModelTest, HideToggleVisibility) { + InitializeEmptyExtensionService(); + scoped_refptr<const Extension> extension = + ExtensionBuilder("extension").Build(); + InitializeAndAddExtension(*extension); + { + ExtensionContextMenuModel menu(extension.get(), GetBrowser(), + ExtensionContextMenuModel::VISIBLE, nullptr, + true /* can_show_icon_in_toolbar */); + EXPECT_TRUE( + menu.IsCommandIdVisible(ExtensionContextMenuModel::TOGGLE_VISIBILITY)); + } + { + ExtensionContextMenuModel menu(extension.get(), GetBrowser(), + ExtensionContextMenuModel::VISIBLE, nullptr, + false /* can_show_icon_in_toolbar */); + EXPECT_FALSE( + menu.IsCommandIdVisible(ExtensionContextMenuModel::TOGGLE_VISIBILITY)); + } +} + } // namespace extensions
diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc index 8e36fd61c..ae366015 100644 --- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc +++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
@@ -22,6 +22,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/result_codes.h" #include "content/public/common/url_constants.h" +#include "content/public/test/no_renderer_crashes_assertion.h" #include "content/public/test/test_utils.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_registry.h" @@ -142,6 +143,7 @@ std::string first_extension_id_; std::string second_extension_id_; std::unique_ptr<NotificationDisplayServiceTester> display_service_; + content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes_; }; IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, Basic) {
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index b26a5be..33b54e1 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -890,7 +890,7 @@ // TODO(kalman): Convert ExtensionSpecialStoragePolicy to a // BrowserContextKeyedService and use ExtensionRegistryObserver. profile_->GetExtensionSpecialStoragePolicy()->GrantRightsForExtension( - extension.get(), profile_); + extension.get()); // TODO(kalman): This is broken. The crash reporter is process-wide so doesn't // work properly multi-profile. Besides which, it should be using
diff --git a/chrome/browser/extensions/extension_special_storage_policy.cc b/chrome/browser/extensions/extension_special_storage_policy.cc index 71740d0..ceb0e41e 100644 --- a/chrome/browser/extensions/extension_special_storage_policy.cc +++ b/chrome/browser/extensions/extension_special_storage_policy.cc
@@ -18,15 +18,12 @@ #include "base/task/task_traits.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/common/url_constants.h" #include "components/content_settings/core/browser/cookie_settings.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" -#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/storage_partition.h" #include "content/public/common/url_constants.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" @@ -34,8 +31,6 @@ #include "extensions/common/manifest_handlers/app_isolation_info.h" #include "extensions/common/manifest_handlers/content_capabilities_handler.h" #include "extensions/common/permissions/permissions_data.h" -#include "storage/browser/quota/quota_manager.h" -#include "third_party/blink/public/mojom/quota/quota_types.mojom.h" #include "url/origin.h" using content::BrowserThread; @@ -43,46 +38,6 @@ using extensions::Extension; using storage::SpecialStoragePolicy; -namespace { - -void ReportQuotaUsage(blink::mojom::QuotaStatusCode code, - int64_t usage, - int64_t quota) { - if (code == blink::mojom::QuotaStatusCode::kOk) { - // We're interested in the amount of space hosted apps are using. Record it - // when the extension is granted the unlimited storage permission (once per - // extension load, so on average once per run). - UMA_HISTOGRAM_MEMORY_KB("Extensions.HostedAppUnlimitedStorageUsage", usage); - } -} - -// Log the usage for a hosted app with unlimited storage. -void LogHostedAppUnlimitedStorageUsage( - scoped_refptr<const Extension> extension, - content::BrowserContext* browser_context) { - GURL launch_url = - extensions::AppLaunchInfo::GetLaunchWebURL(extension.get()).GetOrigin(); - content::StoragePartition* partition = - browser_context ? // |browser_context| can be NULL in unittests. - content::BrowserContext::GetStoragePartitionForSite(browser_context, - launch_url) : - NULL; - if (partition) { - // We only have to query for kStorageTypePersistent data usage, because apps - // cannot ask for any more temporary storage, according to - // https://developers.google.com/chrome/whitepapers/storage. - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO, base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&storage::QuotaManager::GetUsageAndQuotaForWebApps, - partition->GetQuotaManager(), - url::Origin::Create(launch_url), - blink::mojom::StorageType::kPersistent, - base::Bind(&ReportQuotaUsage))); - } -} - -} // namespace - ExtensionSpecialStoragePolicy::ExtensionSpecialStoragePolicy( content_settings::CookieSettings* cookie_settings) : cookie_settings_(cookie_settings) { @@ -169,8 +124,7 @@ } void ExtensionSpecialStoragePolicy::GrantRightsForExtension( - const extensions::Extension* extension, - content::BrowserContext* browser_context) { + const extensions::Extension* extension) { base::AutoLock locker(lock_); DCHECK(extension); @@ -194,8 +148,6 @@ if (extension->permissions_data()->HasAPIPermission( APIPermission::kUnlimitedStorage) && unlimited_extensions_.Add(extension)) { - if (extension->is_hosted_app()) - LogHostedAppUnlimitedStorageUsage(extension, browser_context); change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED; }
diff --git a/chrome/browser/extensions/extension_special_storage_policy.h b/chrome/browser/extensions/extension_special_storage_policy.h index 59926272..c370b63 100644 --- a/chrome/browser/extensions/extension_special_storage_policy.h +++ b/chrome/browser/extensions/extension_special_storage_policy.h
@@ -15,10 +15,6 @@ #include "storage/browser/quota/special_storage_policy.h" #include "url/gurl.h" -namespace content { -class BrowserContext; -} - namespace content_settings { class CookieSettings; } @@ -47,8 +43,7 @@ CreateDeleteCookieOnExitPredicate() override; // Methods used by the ExtensionService to populate this class. - void GrantRightsForExtension(const extensions::Extension* extension, - content::BrowserContext* browser_context); + void GrantRightsForExtension(const extensions::Extension* extension); void RevokeRightsForExtension(const extensions::Extension* extension); void RevokeRightsForAllExtensions();
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc index 44d3fe55..23c0e153 100644 --- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc +++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -204,7 +204,7 @@ TEST_F(ExtensionSpecialStoragePolicyTest, AppWithProtectedStorage) { scoped_refptr<Extension> extension(CreateProtectedApp()); - policy_->GrantRightsForExtension(extension.get(), NULL); + policy_->GrantRightsForExtension(extension.get()); ExtensionSet protecting_extensions; protecting_extensions.Insert(extension); ExtensionSet empty_set; @@ -225,7 +225,7 @@ TEST_F(ExtensionSpecialStoragePolicyTest, AppWithUnlimitedStorage) { scoped_refptr<Extension> extension(CreateUnlimitedApp()); - policy_->GrantRightsForExtension(extension.get(), NULL); + policy_->GrantRightsForExtension(extension.get()); ExtensionSet protecting_extensions; protecting_extensions.Insert(extension); ExtensionSet empty_set; @@ -257,7 +257,7 @@ const GURL kHttpUrl("http://foo"); const GURL kExtensionUrl("chrome-extension://bar"); scoped_refptr<Extension> app(CreateRegularApp()); - policy_->GrantRightsForExtension(app.get(), NULL); + policy_->GrantRightsForExtension(app.get()); EXPECT_FALSE(policy_->HasIsolatedStorage(kHttpUrl)); EXPECT_FALSE(policy_->HasIsolatedStorage(kExtensionUrl)); @@ -267,8 +267,8 @@ TEST_F(ExtensionSpecialStoragePolicyTest, OverlappingApps) { scoped_refptr<Extension> protected_app(CreateProtectedApp()); scoped_refptr<Extension> unlimited_app(CreateUnlimitedApp()); - policy_->GrantRightsForExtension(protected_app.get(), NULL); - policy_->GrantRightsForExtension(unlimited_app.get(), NULL); + policy_->GrantRightsForExtension(protected_app.get()); + policy_->GrantRightsForExtension(unlimited_app.get()); ExtensionSet protecting_extensions; ExtensionSet empty_set; protecting_extensions.Insert(protected_app); @@ -366,14 +366,14 @@ for (size_t i = 0; i < base::size(apps); ++i) { SCOPED_TRACE(testing::Message() << "i: " << i); observer.ExpectGrant(apps[i]->id(), change_flags[i]); - policy_->GrantRightsForExtension(apps[i].get(), NULL); + policy_->GrantRightsForExtension(apps[i].get()); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(observer.IsCompleted()); } for (size_t i = 0; i < base::size(apps); ++i) { SCOPED_TRACE(testing::Message() << "i: " << i); - policy_->GrantRightsForExtension(apps[i].get(), NULL); + policy_->GrantRightsForExtension(apps[i].get()); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(observer.IsCompleted()); }
diff --git a/chrome/browser/extensions/navigation_observer_browsertest.cc b/chrome/browser/extensions/navigation_observer_browsertest.cc index 39aafe2..290bbff 100644 --- a/chrome/browser/extensions/navigation_observer_browsertest.cc +++ b/chrome/browser/extensions/navigation_observer_browsertest.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/navigation_observer.h" #include "chrome/test/base/ui_test_utils.h" +#include "content/public/test/no_renderer_crashes_assertion.h" #include "extensions/browser/extension_dialog_auto_confirm.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" @@ -21,6 +22,11 @@ // re-enable it. IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PromptToReEnableExtensionsOnNavigation) { + // TODO(lukasza): https://crbug.com/970917: We should not terminate a renderer + // that hosts a disabled extension. Once that is fixed, we should remove + // ScopedAllowRendererCrashes below. + content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; + NavigationObserver::SetAllowedRepeatedPromptingForTesting(true); base::ScopedClosureRunner reset_repeated_prompting(base::BindOnce([]() { NavigationObserver::SetAllowedRepeatedPromptingForTesting(false);
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc index 89944c3..d850c27 100644 --- a/chrome/browser/feedback/show_feedback_page.cc +++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -12,7 +12,9 @@ #include "chrome/browser/ui/chrome_pages.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" #include "components/feedback/feedback_util.h" +#include "components/prefs/pref_service.h" #include "extensions/browser/api/feedback_private/feedback_private_api.h" #if defined(OS_CHROMEOS) @@ -43,7 +45,6 @@ } } #endif - } // namespace void ShowFeedbackPage(Browser* browser, @@ -63,7 +64,9 @@ LOG(ERROR) << "Cannot invoke feedback: No profile found!"; return; } - + if (!profile->GetPrefs()->GetBoolean(prefs::kUserFeedbackAllowed)) { + return; + } // Record an UMA histogram to know the most frequent feedback request source. UMA_HISTOGRAM_ENUMERATION("Feedback.RequestSource", source, kFeedbackSourceCount);
diff --git a/chrome/browser/feedback/show_feedback_page_unittest.cc b/chrome/browser/feedback/show_feedback_page_unittest.cc new file mode 100644 index 0000000..4deb6c1e --- /dev/null +++ b/chrome/browser/feedback/show_feedback_page_unittest.cc
@@ -0,0 +1,24 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/test/metrics/histogram_tester.h" +#include "chrome/browser/ui/chrome_pages.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/browser_with_test_window_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ShowFeedbackPageTest = BrowserWithTestWindowTest; + +TEST_F(ShowFeedbackPageTest, UserFeedbackDisallowed) { + base::HistogramTester histogram_tester; + std::string unused; + chrome::ShowFeedbackPage(browser(), chrome::kFeedbackSourceBrowserCommand, + unused, unused, unused, unused); + histogram_tester.ExpectTotalCount("Feedback.RequestSource", 1); + browser()->profile()->GetPrefs()->SetBoolean(prefs::kUserFeedbackAllowed, + false); + chrome::ShowFeedbackPage(browser(), chrome::kFeedbackSourceBrowserCommand, + unused, unused, unused, unused); + histogram_tester.ExpectTotalCount("Feedback.RequestSource", 1); +}
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 7dcbf9ec..7d41a4c2 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -934,6 +934,11 @@ "expiry_milestone": 76 }, { + "name": "enable-caption-settings", + "owners": [ "evliu" ], + "expiry_milestone": 80 + }, + { "name": "enable-chrome-duet", "owners": [ "mdjones" ], "expiry_milestone": 79 @@ -1237,6 +1242,11 @@ "expiry_milestone": 74 }, { + "name": "enable-backdrop-filter", + "owners": [ "masonfreed", "paint-dev@chromium.org" ], + "expiry_milestone": 78 + }, + { "name": "enable-layout-ng", "owners": [ "layout-dev@chromium.org" ], "expiry_milestone": 80
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index c6b89da..1d258bc 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -263,6 +263,10 @@ "eligibility requirements for showing app banners, such as having a " "manifest, are met."; +const char kCaptionSettingsName[] = "Caption Settings"; +const char kCaptionSettingsDescription[] = + "Enable the ability to customize captions."; + const char kClickToOpenPDFName[] = "Click to open embedded PDFs"; const char kClickToOpenPDFDescription[] = "When the PDF plugin is unavailable, show a click-to-open placeholder for " @@ -660,6 +664,10 @@ "Enable a new compositing mode where Blink generates the compositor " "property trees."; +const char kEnableCSSBackdropFilterName[] = "Enable backdrop-filter"; +const char kEnableCSSBackdropFilterDescription[] = + "Enable a new CSS property called backdrop-filter."; + const char kEnableDisplayLockingName[] = "Enable Display Locking"; const char kEnableDisplayLockingDescription[] = "Enable Display Locking JavaScript API. The syntax and the APIs exposed "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 5c160602..d017453 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -167,6 +167,9 @@ extern const char kBypassAppBannerEngagementChecksName[]; extern const char kBypassAppBannerEngagementChecksDescription[]; +extern const char kCaptionSettingsName[]; +extern const char kCaptionSettingsDescription[]; + extern const char kClickToOpenPDFName[]; extern const char kClickToOpenPDFDescription[]; @@ -399,6 +402,9 @@ extern const char kEnableBlinkGenPropertyTreesName[]; extern const char kEnableBlinkGenPropertyTreesDescription[]; +extern const char kEnableCSSBackdropFilterName[]; +extern const char kEnableCSSBackdropFilterDescription[]; + extern const char kEnableDisplayLockingName[]; extern const char kEnableDisplayLockingDescription[];
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc deleted file mode 100644 index 0acae565..0000000 --- a/chrome/browser/io_thread.cc +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/io_thread.h" - -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/task/post_task.h" -#include "base/time/time.h" -#include "base/trace_event/trace_event.h" -#include "build/build_config.h" -#include "chrome/common/pref_names.h" -#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h" -#include "components/net_log/chrome_net_log.h" -#include "components/prefs/pref_service.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" -#include "net/cert/cert_database.h" - -using content::BrowserThread; - -// The IOThread object must outlive any tasks posted to the IO thread before the -// Quit task, so base::Bind() calls are not refcounted. - -namespace { - -#if defined(OS_MACOSX) -void ObserveKeychainEvents() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - net::CertDatabase::GetInstance()->StartListeningForKeychainEvents(); -} -#endif - -} // namespace - -// |local_state| is passed in explicitly in order to (1) reduce implicit -// dependencies and (2) make IOThread more flexible for testing. -IOThread::IOThread(net_log::ChromeNetLog* net_log) : net_log_(net_log) { - scoped_refptr<base::SingleThreadTaskRunner> io_thread_proxy = - base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}); - - BrowserThread::SetIOThreadDelegate(this); -} - -IOThread::~IOThread() { - // This isn't needed for production code, but in tests, IOThread may - // be multiply constructed. - BrowserThread::SetIOThreadDelegate(nullptr); -} - -net_log::ChromeNetLog* IOThread::net_log() { - return net_log_; -} - -void IOThread::Init() { - TRACE_EVENT0("startup", "IOThread::InitAsync"); - DCHECK_CURRENTLY_ON(BrowserThread::IO); - -#if defined(OS_MACOSX) - // Start observing Keychain events. This needs to be done on the UI thread, - // as Keychain services requires a CFRunLoop. - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&ObserveKeychainEvents)); -#endif -} - -void IOThread::CleanUp() { - if (net_log_) - net_log_->ShutDownBeforeThreadPool(); -} - -// static -void IOThread::RegisterPrefs(PrefRegistrySimple* registry) { - data_reduction_proxy::RegisterPrefs(registry); -}
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h deleted file mode 100644 index c33614a7..0000000 --- a/chrome/browser/io_thread.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_IO_THREAD_H_ -#define CHROME_BROWSER_IO_THREAD_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <memory> -#include <string> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "build/build_config.h" -#include "chrome/common/buildflags.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/browser_thread_delegate.h" - -class PrefRegistrySimple; - -namespace net_log { -class ChromeNetLog; -} - -// Contains state associated with, initialized and cleaned up on, and -// primarily used on, the IO thread. -// -// If you are looking to interact with the IO thread (e.g. post tasks -// to it or check if it is the current thread), see -// content::BrowserThread. -class IOThread : public content::BrowserThreadDelegate { - public: - // |net_log| must either outlive the IOThread or be NULL. - explicit IOThread(net_log::ChromeNetLog* net_log); - - ~IOThread() override; - - static void RegisterPrefs(PrefRegistrySimple* registry); - - net_log::ChromeNetLog* net_log(); - - private: - // BrowserThreadDelegate implementation, runs on the IO thread. - // This handles initialization and destruction of state that must - // live on the IO thread. - void Init() override; - void CleanUp() override; - - // The NetLog is owned by the browser process, to allow logging from other - // threads during shutdown, but is used most frequently on the IOThread. - net_log::ChromeNetLog* net_log_; - - DISALLOW_COPY_AND_ASSIGN(IOThread); -}; - -#endif // CHROME_BROWSER_IO_THREAD_H_
diff --git a/chrome/browser/io_thread_browsertest.cc b/chrome/browser/io_thread_browsertest.cc index ab40906..d807c88 100644 --- a/chrome/browser/io_thread_browsertest.cc +++ b/chrome/browser/io_thread_browsertest.cc
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/io_thread.h" - #include <map> #include <memory>
diff --git a/chrome/browser/media/media_engagement_score_unittest.cc b/chrome/browser/media/media_engagement_score_unittest.cc index 0e85003..e0220e3 100644 --- a/chrome/browser/media/media_engagement_score_unittest.cc +++ b/chrome/browser/media/media_engagement_score_unittest.cc
@@ -161,8 +161,6 @@ void OverrideFieldTrial(int min_visits, double lower_threshold, double upper_threshold) { - field_trial_list_.reset(); - field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting(); std::map<std::string, std::string> params; @@ -187,7 +185,6 @@ private: std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; - std::unique_ptr<base::FieldTrialList> field_trial_list_; }; // Test Mojo serialization.
diff --git a/chrome/browser/media/unified_autoplay_browsertest.cc b/chrome/browser/media/unified_autoplay_browsertest.cc index 3008f00..893b99b 100644 --- a/chrome/browser/media/unified_autoplay_browsertest.cc +++ b/chrome/browser/media/unified_autoplay_browsertest.cc
@@ -419,10 +419,10 @@ ~UnifiedAutoplaySettingBrowserTest() override = default; void SetUpOnMainThread() override { + UnifiedAutoplayBrowserTest::SetUpOnMainThread(); scoped_feature_list_.InitWithFeatures( {media::kAutoplayDisableSettings, media::kAutoplayWhitelistSettings}, {}); - UnifiedAutoplayBrowserTest::SetUpOnMainThread(); } bool AutoplayAllowed(const content::ToRenderFrameHost& adapter) {
diff --git a/chrome/browser/metrics/chrome_feature_list_creator.cc b/chrome/browser/metrics/chrome_feature_list_creator.cc index 77738f3..23c9b9a 100644 --- a/chrome/browser/metrics/chrome_feature_list_creator.cc +++ b/chrome/browser/metrics/chrome_feature_list_creator.cc
@@ -168,13 +168,18 @@ browser_field_trials_ = std::make_unique<ChromeBrowserFieldTrials>(local_state_.get()); - // Initialize FieldTrialList to support FieldTrials. This is intentionally - // leaked since it needs to live for the duration of the browser process and - // there's no benefit in cleaning it up at exit. - base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList( - metrics_services_manager_->CreateEntropyProvider()); - ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); - ignore_result(leaked_field_trial_list); + // Initialize FieldTrialList to support FieldTrials. If an instance already + // exists, this is likely a test scenario with a ScopedFeatureList active, + // so use that one to apply any overrides. + if (!base::FieldTrialList::GetInstance()) { + // Note: This is intentionally leaked since it needs to live for the + // duration of the browser process and there's no benefit in cleaning it up + // at exit. + base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList( + metrics_services_manager_->CreateEntropyProvider()); + ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); + ignore_result(leaked_field_trial_list); + } auto feature_list = std::make_unique<base::FeatureList>();
diff --git a/chrome/browser/metrics/ukm_browsertest.cc b/chrome/browser/metrics/ukm_browsertest.cc index 61468a7..225eaeda 100644 --- a/chrome/browser/metrics/ukm_browsertest.cc +++ b/chrome/browser/metrics/ukm_browsertest.cc
@@ -158,14 +158,10 @@ is_unified_consent_enabled ? unified_consent::UnifiedConsentFeatureState::kEnabled : unified_consent::UnifiedConsentFeatureState::kDisabled) { - } - - void SetUp() override { // Explicitly enable UKM and disable the MetricsReporting (which should // not affect UKM). scoped_feature_list_.InitWithFeatures({ukm::kUkmFeature}, {internal::kMetricsReportingFeature}); - SyncTest::SetUp(); } bool ukm_enabled() const { @@ -300,7 +296,7 @@ ukm::UkmService* ukm_service() const { return g_browser_process->GetMetricsServicesManager()->GetUkmService(); } - base::test::ScopedFeatureList scoped_feature_list_; + #if BUILDFLAG(ENABLE_DICE_SUPPORT) // ScopedAccountConsistencyDice is required for unified consent to be enabled. // Note that it uses forced field trials to enable DICE which disable metrics @@ -309,6 +305,8 @@ const std::unique_ptr<ScopedAccountConsistencyDice> scoped_dice_; #endif const unified_consent::ScopedUnifiedConsent scoped_unified_consent_; + base::test::ScopedFeatureList scoped_feature_list_; + DISALLOW_COPY_AND_ASSIGN(UkmBrowserTestBase); };
diff --git a/chrome/browser/net/dns_probe_browsertest.cc b/chrome/browser/net/dns_probe_browsertest.cc index 726323ec..d1241af 100644 --- a/chrome/browser/net/dns_probe_browsertest.cc +++ b/chrome/browser/net/dns_probe_browsertest.cc
@@ -12,7 +12,6 @@ #include "base/threading/thread_restrictions.h" #include "base/time/default_tick_clock.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/net/dns_probe_service_factory.h" #include "chrome/browser/net/dns_probe_test_util.h" #include "chrome/browser/net/net_error_tab_helper.h"
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc index cd8e2608..315fe08 100644 --- a/chrome/browser/net/system_network_context_manager.cc +++ b/chrome/browser/net/system_network_context_manager.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/component_updater/crl_set_component_installer.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/ssl/ssl_config_service_manager.h"
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc index 91b3b41..6fff588 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -872,8 +872,14 @@ static_cast<int>(FrameData::MediaStatus::kNotPlayed)); } +// Flaky on Mac. http://crbug.com/972822 +#if defined(OS_MACOSX) +#define MAYBE_AdFrameSizeInterventionMediaStatusPlayed DISABLED_AdFrameSizeInterventionMediaStatusPlayed +#else +#define MAYBE_AdFrameSizeInterventionMediaStatusPlayed AdFrameSizeInterventionMediaStatusPlayed +#endif IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest, - AdFrameSizeInterventionMediaStatusPlayed) { + MAYBE_AdFrameSizeInterventionMediaStatusPlayed) { base::HistogramTester histogram_tester; ukm::TestAutoSetUkmRecorder ukm_recorder; embedded_test_server()->ServeFilesFromSourceDirectory(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 21457c6..07848b7 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1016,6 +1016,9 @@ { key::kAllowPopupsDuringPageUnload, prefs::kAllowPopupsDuringPageUnload, base::Value::Type::BOOLEAN }, + { key::kUserFeedbackAllowed, + prefs::kUserFeedbackAllowed, + base::Value::Type::BOOLEAN }, #if defined(OS_WIN) || defined(OS_MACOSX) || \ (defined(OS_LINUX) && !defined(OS_CHROMEOS))
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index c382b8f..57ac99a 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc
@@ -70,7 +70,6 @@ #include "chrome/browser/extensions/updater/extension_updater.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/interstitials/security_interstitial_page_test_utils.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/media_stream_devices_controller.h" #include "chrome/browser/media/webrtc/webrtc_event_log_manager.h"
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 25d03118..4fba9d1 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -26,7 +26,6 @@ #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/gpu/gpu_mode_manager.h" #include "chrome/browser/intranet_redirect_detector.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/media/media_device_id_salt.h" #include "chrome/browser/media/media_engagement_service.h" @@ -88,6 +87,7 @@ #include "components/browsing_data/core/pref_names.h" #include "components/certificate_transparency/pref_names.h" #include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h" #include "components/dom_distiller/core/distilled_page_prefs.h" #include "components/feature_engagement/buildflags.h" #include "components/flags_ui/pref_service_flags_storage.h" @@ -521,6 +521,7 @@ void RegisterLocalState(PrefRegistrySimple* registry) { // Please keep this list alphabetized. browser_shutdown::RegisterPrefs(registry); + data_reduction_proxy::RegisterPrefs(registry); BrowserProcessImpl::RegisterPrefs(registry); ChromeContentBrowserClient::RegisterLocalStatePrefs(registry); ChromeMetricsServiceClient::RegisterPrefs(registry); @@ -531,7 +532,6 @@ GpuModeManager::RegisterPrefs(registry); identity::IdentityManager::RegisterLocalStatePrefs(registry); IntranetRedirectDetector::RegisterPrefs(registry); - IOThread::RegisterPrefs(registry); language::GeoLanguageProvider::RegisterLocalStatePrefs(registry); language::UlpLanguageCodeLocator::RegisterLocalStatePrefs(registry); network_time::NetworkTimeTracker::RegisterPrefs(registry);
diff --git a/chrome/browser/previews/previews_lite_page_browsertest.cc b/chrome/browser/previews/previews_lite_page_browsertest.cc index 1a706aee..01b3f3a 100644 --- a/chrome/browser/previews/previews_lite_page_browsertest.cc +++ b/chrome/browser/previews/previews_lite_page_browsertest.cc
@@ -2023,8 +2023,8 @@ ~CoinFlipHoldbackExperimentBrowserTest() override = default; void SetUp() override { - ukm_feature_list_.InitAndEnableFeature(ukm::kUkmFeature); PreviewsLitePageAndPageHintsBrowserTest::SetUp(); + ukm_feature_list_.InitAndEnableFeature(ukm::kUkmFeature); } void SetUpCommandLine(base::CommandLine* cmd) override {
diff --git a/chrome/browser/previews/previews_offline_helper_unittest.cc b/chrome/browser/previews/previews_offline_helper_unittest.cc index 1c70a773..f4334ab 100644 --- a/chrome/browser/previews/previews_offline_helper_unittest.cc +++ b/chrome/browser/previews/previews_offline_helper_unittest.cc
@@ -376,7 +376,6 @@ // we instead set the freshness duration to negative to make any newly saved // offline page stale. TEST_F(PreviewsOfflinePagesIntegrationTest, TestOfflinePagesDBQuery_Expired) { - base::FieldTrialList field_trial_list(nullptr); ASSERT_TRUE(base::AssociateFieldTrialParams( "ClientSidePreviews", "Enabled", {{"offline_preview_freshness_duration_in_days", "-1"}}));
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc index abd5e5e..28ab69d 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.cc +++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -31,7 +31,6 @@ #include "chrome/browser/download/chrome_download_manager_delegate.h" #include "chrome/browser/download/download_core_service.h" #include "chrome/browser/download/download_core_service_factory.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/permissions/permission_manager.h" #include "chrome/browser/permissions/permission_manager_factory.h" #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc index 9f53f36..3a70f5f 100644 --- a/chrome/browser/profiles/off_the_record_profile_io_data.cc +++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -16,7 +16,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/custom_handlers/protocol_handler_registry.h" #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/net/chrome_network_delegate.h" #include "chrome/browser/net/profile_network_context_service.h" #include "chrome/browser/net/profile_network_context_service_factory.h" @@ -122,8 +121,8 @@ content::CookieStoreConfig cookie_config; // Enable cookies for chrome-extension URLs. cookie_config.cookieable_schemes.push_back(extensions::kExtensionScheme); - extensions_cookie_store_ = content::CreateCookieStore( - cookie_config, profile_params->io_thread->net_log()); + extensions_cookie_store_ = + content::CreateCookieStore(cookie_config, g_browser_process->net_log()); } net::CookieStore* OffTheRecordProfileIOData::GetExtensionsCookieStore() const {
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc index 4e66556..6fe886e 100644 --- a/chrome/browser/profiles/profile_impl_io_data.cc +++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -30,7 +30,6 @@ #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_io_data.h" #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h" #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings_factory.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/net/chrome_network_delegate.h" #include "chrome/browser/net/profile_network_context_service.h" #include "chrome/browser/net/profile_network_context_service_factory.h" @@ -226,8 +225,8 @@ cookie_config.crypto_delegate = cookie_config::GetCookieCryptoDelegate(); // Enable cookies for chrome-extension URLs. cookie_config.cookieable_schemes.push_back(extensions::kExtensionScheme); - extensions_cookie_store_ = content::CreateCookieStore( - cookie_config, profile_params->io_thread->net_log()); + extensions_cookie_store_ = + content::CreateCookieStore(cookie_config, g_browser_process->net_log()); } net::CookieStore* ProfileImplIOData::GetExtensionsCookieStore() const {
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index bad56f3..75d93e5 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc
@@ -31,7 +31,6 @@ #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/custom_handlers/protocol_handler_registry.h" #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/net/chrome_network_delegate.h" #include "chrome/browser/net/profile_network_context_service.h" #include "chrome/browser/net/profile_network_context_service_factory.h" @@ -252,8 +251,6 @@ std::unique_ptr<ProfileParams> params(new ProfileParams); params->path = profile->GetPath(); - params->io_thread = g_browser_process->io_thread(); - params->cookie_settings = CookieSettingsFactory::GetForProfile(profile); params->host_content_settings_map = HostContentSettingsMapFactory::GetForProfile(profile);
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h index 6951921..f5f1545 100644 --- a/chrome/browser/profiles/profile_io_data.h +++ b/chrome/browser/profiles/profile_io_data.h
@@ -20,7 +20,6 @@ #include "base/synchronization/lock.h" #include "build/build_config.h" #include "chrome/browser/custom_handlers/protocol_handler_registry.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/storage_partition_descriptor.h" #include "chrome/common/buildflags.h" @@ -202,7 +201,6 @@ ~ProfileParams(); base::FilePath path; - IOThread* io_thread = nullptr; scoped_refptr<content_settings::CookieSettings> cookie_settings; scoped_refptr<HostContentSettingsMap> host_content_settings_map;
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc index 8d8578f9..debc7ad 100644 --- a/chrome/browser/profiles/profile_manager_unittest.cc +++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -24,7 +24,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/history/history_service_factory.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js index 230cfbbe..20f9dff 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js
@@ -217,7 +217,7 @@ /** @private @return {boolean} */ LogStore.prototype.shouldSkipOutput_ = function() { var ChromeVoxState = chrome.extension.getBackgroundPage()['ChromeVoxState']; - if (ChromeVoxState.instance.currentRange && + if (ChromeVoxState.instance && ChromeVoxState.instance.currentRange && ChromeVoxState.instance.currentRange.start && ChromeVoxState.instance.currentRange.start.node && ChromeVoxState.instance.currentRange.start.node.root) {
diff --git a/chrome/browser/resources/chromeos/login/supervision_onboarding.js b/chrome/browser/resources/chromeos/login/supervision_onboarding.js index 559765c..0303dcf 100644 --- a/chrome/browser/resources/chromeos/login/supervision_onboarding.js +++ b/chrome/browser/resources/chromeos/login/supervision_onboarding.js
@@ -245,10 +245,13 @@ /* * Properties to hide the main dialogs used to present the flow. Only one * of them can be shown at a time. + * Note: One of them needs to be visible when the element is being + * initialized, otherwise we risk having our width and height set to 0 by + * the display manager. */ - hideContent_: {type: Boolean, value: true}, - hideLoadingDialog_: {type: Boolean, value: true}, + hideLoadingDialog_: {type: Boolean, value: false}, hideRetryDialog_: {type: Boolean, value: true}, + hideContent_: {type: Boolean, value: true}, /* * Properties to hide the buttons that can trigger flow actions.
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.html b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.html index 64e541d..0d0a8da 100644 --- a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.html +++ b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.html
@@ -3,8 +3,8 @@ <link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/multidevice_setup_shared_css.html"> <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="post_oobe_delegate.html"> <dom-module id="multidevice-setup-post-oobe"> @@ -27,19 +27,19 @@ forward-button-disabled="{{forwardButtonDisabled_}}" cancel-button-text-id="{{cancelButtonTextId_}}" backward-button-text-id="{{backwardButtonTextId_}}"> - <paper-button id="backward-button" + <cr-button id="backward-button" slot="backward-button" class="cancel-button"> [[i18n(backwardButtonTextId_)]] - </paper-button> - <paper-button id="cancel-button" + </cr-button> + <cr-button id="cancel-button" slot="cancel-button" class="cancel-button"> [[i18n(cancelButtonTextId_)]] - </paper-button> - <paper-button id="forward-button" + </cr-button> + <cr-button id="forward-button" slot="forward-button" class="action-button" disabled$="[[forwardButtonDisabled_]]"> [[i18n(forwardButtonTextId_)]] - </paper-button> + </cr-button> </multidevice-setup> </template> <script src="multidevice_setup_post_oobe.js">
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js index f5d3811..878b4b0 100644 --- a/chrome/browser/resources/local_ntp/customize.js +++ b/chrome/browser/resources/local_ntp/customize.js
@@ -95,6 +95,7 @@ COLORS_DEFAULT: 'colors-default', COLORS_MENU: 'colors-menu', CUSTOMIZATION_MENU: 'customization-menu', + CUSTOM_BG: 'custom-bg', CUSTOM_LINKS_RESTORE_DEFAULT: 'custom-links-restore-default', CUSTOM_LINKS_RESTORE_DEFAULT_TEXT: 'custom-links-restore-default-text', DEFAULT_WALLPAPERS: 'edit-bg-default-wallpapers', @@ -225,6 +226,12 @@ customize.colorMenuLoaded = false; /** + * The original NTP background. Used to restore from image previews. + * @type {string} + */ +customize.originalBackground = ''; + +/** * Sets the visibility of the settings menu and individual options depending on * their respective features. */ @@ -651,8 +658,32 @@ }; /** - * Apply styling to a selected tile in the richer picker and enable the done - * button. + * Preview an image as a custom backgrounds. + * @param {!Element} tile The tile that was selected. + */ +customize.richerPicker_previewImage = function(tile) { + customize.originalBackground = + $(customize.IDS.CUSTOM_BG).style.backgroundImage; + + // TODO(crbug/971853): add browertests for previews. + // Set preview images at 720p by replacing the params in the url. + const re = /w\d+\-h\d+/; + $(customize.IDS.CUSTOM_BG).style.backgroundImage = + tile.style.backgroundImage.replace(re, 'w1280-h720'); +}; + +/** + * Remove a preview image of a custom backgrounds. + * @param {!Element} tile The tile that was deselected. + */ +customize.richerPicker_unpreviewImage = function(tile) { + $(customize.IDS.CUSTOM_BG).style.backgroundImage = + customize.originalBackground; +}; + +/** + * Apply styling to a selected tile in the richer picker and enable the + * done button. * @param {?Element} tile The tile to apply styling to. */ customize.richerPicker_selectTile = function(tile) { @@ -671,6 +702,8 @@ selectedCheck.classList.add(customize.CLASSES.SELECTED_CHECK); tile.appendChild(selectedCircle); tile.appendChild(selectedCheck); + + customize.richerPicker_previewImage(tile); }; /** @@ -696,6 +729,8 @@ --i; } } + + customize.richerPicker_unpreviewImage(tile); }; /**
diff --git a/chrome/browser/resources/settings/about_page/about_page.html b/chrome/browser/resources/settings/about_page/about_page.html index 82136b5..9656740c 100644 --- a/chrome/browser/resources/settings/about_page/about_page.html +++ b/chrome/browser/resources/settings/about_page/about_page.html
@@ -217,6 +217,7 @@ label="$i18n{aboutGetHelpUsingChrome}" external></cr-link-row> <if expr="_google_chrome"> <cr-link-row class="hr" id="reportIssue" on-click="onReportIssueTap_" + hidden="[[!prefs.feedback_allowed.value]]" label="$i18n{aboutReportAnIssue}"></cr-link-row> </if> <if expr="chromeos">
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js index f22bdd00..7e2c35f3 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
@@ -143,6 +143,18 @@ type: Number, value: 1000, }, + + /** + * The time in milliseconds at which discovery was started attempt (when the + * page was opened with Bluetooth on, or when Bluetooth turned on while the + * page was active). + * @private {?number} + */ + discoveryStartTimestampMs_: { + type: Number, + value: null, + }, + }, observers: [ @@ -392,6 +404,10 @@ this.openDialog_(); } + if (isPaired !== undefined && device.transport !== undefined) { + this.recordDeviceSelectionDuration_(isPaired, device.transport); + } + const address = device.address; this.bluetoothPrivate.connect(address, result => { if (isPaired) { @@ -492,10 +508,12 @@ this.updateTimerId_ = window.setInterval(this.refreshBluetoothList_.bind(this), this.listUpdateFrequencyMs); + this.discoveryStartTimestampMs_ = Date.now(); return; } window.clearInterval(this.updateTimerId_); this.updateTimerId_ = undefined; + this.discoveryStartTimestampMs_ = null; this.deviceList_ = []; }, @@ -542,5 +560,31 @@ } chrome.bluetoothPrivate.recordReconnection(success); - } + }, + + /** + * Record metrics for how long it took between when discovery started on the + * Settings page, and the user selected the device they wanted to connect to. + * @param {!boolean} wasPaired If the selected device was already + * paired. + * @param {!chrome.bluetooth.Transport} transport The transport type + * of the device. + * @private + */ + recordDeviceSelectionDuration_: function(wasPaired, transport) { + if (!this.discoveryStartTimestampMs_) { + // It's not necessarily an error that |discoveryStartTimestampMs_| isn't + // present; it's intentionally cleared after the first device selection + // (see further on in this method). Recording subsequent device selections + // after the first would provide inflated durations that don't truly + // reflect how long it took for the user to find the device they're + // looking for. + return; + } + + chrome.bluetoothPrivate.recordDeviceSelection( + Date.now() - this.discoveryStartTimestampMs_, wasPaired, transport); + + this.discoveryStartTimestampMs_ = null; + }, });
diff --git a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html index 5c35676..a712eee 100644 --- a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html +++ b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html
@@ -34,14 +34,11 @@ on-keys-pressed="onKeysPress_"></iron-a11y-keys> <cr-input id="newWord" value="{{newWordValue_}}" placeholder="$i18n{addDictionaryWordLabel}" - invalid="[[isWordInvalid_(newWordValue_)]]" - error-message="[[isWordInvalid_(newWordValue_, - '$i18nPolymer{addDictionaryWordDuplicateError}', - '$i18nPolymer{addDictionaryWordLengthError}')]]" + invalid="[[isWordInvalid_(newWordValue_, words_.*)]]" + error-message="[[getErrorMessage_(newWordValue_, words_.*)]]" spellcheck="false"> - <cr-button on-click="onAddWordTap_" - disabled="[[disableAddButton_(newWordValue_)]]" id="addWord" - slot="suffix"> + <cr-button on-click="onAddWordTap_" id="addWord" slot="suffix" + disabled$="[[disableAddButton_(newWordValue_, words_.*)]]"> $i18n{addDictionaryWordButton} </cr-button> </cr-input>
diff --git a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js index 6417661..cb66b2e 100644 --- a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js +++ b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
@@ -18,7 +18,10 @@ properties: { /** @private {string} */ - newWordValue_: String, + newWordValue_: { + type: String, + value: '', + }, /** * Needed by GlobalScrollTargetBehavior. @@ -66,33 +69,81 @@ }, /** + * Adds the word in the new-word input to the dictionary. + * @private + */ + addWordFromInput_: function() { + // Spaces are allowed, but removing leading and trailing whitespace. + const word = this.getTrimmedNewWord_(); + this.newWordValue_ = ''; + if (word) { + this.languageSettingsPrivate.addSpellcheckWord(word); + } + }, + + /** * Check if the field is empty or invalid. - * @param {string} word * @return {boolean} * @private */ - disableAddButton_: function(word) { - return word.trim().length == 0 || this.isWordInvalid_(word); + disableAddButton_: function() { + return this.getTrimmedNewWord_().length == 0 || this.isWordInvalid_(); + }, + + /** + * @return {string} + * @private + */ + getErrorMessage_: function() { + if (this.newWordIsTooLong_()) { + return loadTimeData.getString('addDictionaryWordLengthError'); + } + if (this.newWordAlreadyAdded_()) { + return loadTimeData.getString('addDictionaryWordDuplicateError'); + } + return ''; + }, + + /** + * @return {string} + * @private + */ + getTrimmedNewWord_: function() { + return this.newWordValue_.trim(); }, /** * If the word is invalid, returns true (or a message if one is provided). * Otherwise returns false. - * @param {string} word - * @param {string} duplicateError - * @param {string} lengthError - * @return {string|boolean} + * @return {boolean} * @private */ - isWordInvalid_: function(word, duplicateError, lengthError) { - const trimmedWord = word.trim(); - if (this.words_.indexOf(trimmedWord) != -1) { - return duplicateError || true; - } else if (trimmedWord.length > MAX_CUSTOM_DICTIONARY_WORD_BYTES) { - return lengthError || true; - } + isWordInvalid_: function() { + return this.newWordAlreadyAdded_() || this.newWordIsTooLong_(); + }, - return false; + /** + * @return {boolean} + * @private + */ + newWordAlreadyAdded_: function() { + return this.words_.includes(this.getTrimmedNewWord_()); + }, + + /** + * @return {boolean} + * @private + */ + newWordIsTooLong_: function() { + return this.getTrimmedNewWord_().length > MAX_CUSTOM_DICTIONARY_WORD_BYTES; + }, + + /** + * Handles tapping on the Add Word button. + */ + onAddWordTap_: function(e) { + this.addWordFromInput_(); + this.$.newWord.focus(); }, /** @@ -120,7 +171,7 @@ } for (const word of added) { - if (this.words_.indexOf(word) == -1) { + if (!this.words_.includes(word)) { this.unshift('words_', word); } } @@ -134,12 +185,6 @@ Polymer.dom.flush(); this.$$('#list').notifyResize(); } - - // Update input enable to reflect new additions/removals. - // TODO(hsuregan): Remove hack when notifyPath() or notifySplices() - // is successful at creating DOM changes when applied to words_ (when - // attached to input newWord), OR when array changes are registered. - this.$.addWord.disabled = !this.$.newWord.validate(); }, /** @@ -147,8 +192,7 @@ * @param {!CustomEvent<!{key: string}>} e */ onKeysPress_: function(e) { - if (e.detail.key == 'enter' && - !this.disableAddButton_(this.newWordValue_)) { + if (e.detail.key == 'enter' && !this.disableAddButton_()) { this.addWordFromInput_(); } else if (e.detail.key == 'esc') { e.detail.keyboardEvent.target.value = ''; @@ -156,32 +200,10 @@ }, /** - * Handles tapping on the Add Word button. - */ - onAddWordTap_: function(e) { - this.addWordFromInput_(); - this.$.newWord.focus(); - }, - - /** * Handles tapping on a "Remove word" icon button. * @param {!{model: !{item: string}}} e */ onRemoveWordTap_: function(e) { this.languageSettingsPrivate.removeSpellcheckWord(e.model.item); }, - - /** - * Adds the word in the new-word input to the dictionary. - */ - addWordFromInput_: function() { - // Spaces are allowed, but removing leading and trailing whitespace. - const word = this.newWordValue_.trim(); - this.newWordValue_ = ''; - if (!word) { - return; - } - - this.languageSettingsPrivate.addSpellcheckWord(word); - }, });
diff --git a/chrome/browser/resources/settings/multidevice_page/BUILD.gn b/chrome/browser/resources/settings/multidevice_page/BUILD.gn index fb06950..f00e9cb 100644 --- a/chrome/browser/resources/settings/multidevice_page/BUILD.gn +++ b/chrome/browser/resources/settings/multidevice_page/BUILD.gn
@@ -4,18 +4,25 @@ import("//third_party/closure_compiler/compile_js.gni") +# Note: This file is not chromeos only because multidevice_browser_proxy is +# required by site_settings:site_list. + js_type_check("closure_compile") { deps = [ ":multidevice_browser_proxy", ":multidevice_constants", - ":multidevice_feature_behavior", - ":multidevice_feature_item", - ":multidevice_feature_toggle", - ":multidevice_page", - ":multidevice_smartlock_subpage", - ":multidevice_subpage", - ":multidevice_tether_item", ] + if (is_chromeos) { + deps += [ + ":multidevice_feature_behavior", + ":multidevice_feature_item", + ":multidevice_feature_toggle", + ":multidevice_page", + ":multidevice_smartlock_subpage", + ":multidevice_subpage", + ":multidevice_tether_item", + ] + } } js_library("multidevice_browser_proxy") { @@ -31,77 +38,79 @@ ] } -js_library("multidevice_feature_behavior") { - deps = [ - ":multidevice_constants", - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:i18n_behavior", - ] -} +if (is_chromeos) { + js_library("multidevice_feature_behavior") { + deps = [ + ":multidevice_constants", + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:i18n_behavior", + ] + } -js_library("multidevice_feature_item") { - deps = [ - ":multidevice_constants", - ":multidevice_feature_behavior", - "..:route", - "//ui/webui/resources/js:cr", - ] -} + js_library("multidevice_feature_item") { + deps = [ + ":multidevice_constants", + ":multidevice_feature_behavior", + "..:route", + "//ui/webui/resources/js:cr", + ] + } -js_library("multidevice_feature_toggle") { - deps = [ - ":multidevice_constants", - ":multidevice_feature_behavior", - ] -} + js_library("multidevice_feature_toggle") { + deps = [ + ":multidevice_constants", + ":multidevice_feature_behavior", + ] + } -js_library("multidevice_page") { - deps = [ - ":multidevice_browser_proxy", - ":multidevice_constants", - ":multidevice_feature_behavior", - "..:route", - "../controls:password_prompt_dialog", - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:web_ui_listener_behavior", - ] -} + js_library("multidevice_page") { + deps = [ + ":multidevice_browser_proxy", + ":multidevice_constants", + ":multidevice_feature_behavior", + "..:route", + "../controls:password_prompt_dialog", + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:web_ui_listener_behavior", + ] + } -js_library("multidevice_radio_button") { - deps = [ - "//third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted", - "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button_behavior", - "//ui/webui/resources/cr_elements/policy:cr_policy_indicator", - ] -} + js_library("multidevice_radio_button") { + deps = [ + "//third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted", + "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button_behavior", + "//ui/webui/resources/cr_elements/policy:cr_policy_indicator", + ] + } -js_library("multidevice_smartlock_subpage") { - deps = [ - ":multidevice_constants", - ":multidevice_feature_behavior", - "../prefs:prefs_behavior", - "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button", - "//ui/webui/resources/js:cr", - ] -} + js_library("multidevice_smartlock_subpage") { + deps = [ + ":multidevice_constants", + ":multidevice_feature_behavior", + "../prefs:prefs_behavior", + "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button", + "//ui/webui/resources/js:cr", + ] + } -js_library("multidevice_subpage") { - deps = [ - ":multidevice_constants", - ":multidevice_feature_behavior", - "..:route", - "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior", - ] - externs_list = [ "$externs_path/networking_private.js" ] - extra_sources = [ "$interfaces_path/networking_private_interface.js" ] -} + js_library("multidevice_subpage") { + deps = [ + ":multidevice_constants", + ":multidevice_feature_behavior", + "..:route", + "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior", + ] + externs_list = [ "$externs_path/networking_private.js" ] + extra_sources = [ "$interfaces_path/networking_private_interface.js" ] + } -js_library("multidevice_tether_item") { - deps = [ - ":multidevice_feature_behavior", - "..:route", - "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", - ] - externs_list = [ "$externs_path/networking_private.js" ] - extra_sources = [ "$interfaces_path/networking_private_interface.js" ] + js_library("multidevice_tether_item") { + deps = [ + ":multidevice_feature_behavior", + "..:route", + "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types", + ] + externs_list = [ "$externs_path/networking_private.js" ] + extra_sources = [ "$interfaces_path/networking_private_interface.js" ] + } }
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc index 3fbcb03a..6166e88 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win_unittest.cc
@@ -7,6 +7,7 @@ #include <map> #include <string> +#include "base/metrics/field_trial.h" #include "base/win/windows_version.h" #include "components/variations/variations_params_manager.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc index 6e25b28..c5bf5083 100644 --- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc +++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc
@@ -10,14 +10,12 @@ #include "base/strings/stringprintf.h" #include "base/test/scoped_feature_list.h" #include "base/time/time.h" -#include "components/variations/variations_params_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" namespace safe_browsing { -const char kTrialName[] = "trial"; // A SHA256 hash for "mydomain.com". const char kDomainHash[] = "0a79eaf6adb7b1e60d3fa548aa63105f525a00448efbb59ee965b9351a90ac31"; @@ -30,16 +28,14 @@ // start off with all features disabled. class SettingsResetPromptConfigTest : public ::testing::Test { protected: - typedef std::map<std::string, std::string> Parameters; + typedef base::FieldTrialParams Parameters; // Sets the settings reset prompt feature parameters, which has the // side-effect of also enabling the feature. void SetFeatureParams(const Parameters& params) { - static std::set<std::string> features = {kSettingsResetPrompt.name}; - - params_manager_.ClearAllVariationParams(); - params_manager_.SetVariationParamsWithFeatureAssociations(kTrialName, - params, features); + scoped_feature_list_.Reset(); + scoped_feature_list_.InitAndEnableFeatureWithParameters( + kSettingsResetPrompt, params); } Parameters GetDefaultFeatureParams() { @@ -50,7 +46,6 @@ {"time_between_prompts_seconds", "3600"}}; } - variations::testing::VariationParamsManager params_manager_; base::test::ScopedFeatureList scoped_feature_list_; };
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 376c5c6..0f4a3d7 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1123,6 +1123,7 @@ "toolbar/recent_tabs_sub_menu_model.cc", "toolbar/recent_tabs_sub_menu_model.h", "toolbar/toolbar_action_view_controller.h", + "toolbar/toolbar_action_view_delegate.cc", "toolbar/toolbar_action_view_delegate.h", "toolbar/toolbar_actions_bar.cc", "toolbar/toolbar_actions_bar.h",
diff --git a/chrome/browser/ui/ash/kiosk_next_shell_client_browsertest.cc b/chrome/browser/ui/ash/kiosk_next_shell_client_browsertest.cc index 866beffc..4b91f7b 100644 --- a/chrome/browser/ui/ash/kiosk_next_shell_client_browsertest.cc +++ b/chrome/browser/ui/ash/kiosk_next_shell_client_browsertest.cc
@@ -37,10 +37,8 @@ class KioskNextShellClientTest : public OobeBaseTest { public: - // OobeBaseTest: - void SetUp() override { + KioskNextShellClientTest() : OobeBaseTest() { feature_list_.InitAndEnableFeature(ash::features::kKioskNextShell); - OobeBaseTest::SetUp(); } void Login(const std::string& username) { @@ -143,11 +141,8 @@ // to the KioskNextShellLaunch test. class KioskNextShellClientMashDisabledTest : public KioskNextShellClientTest { public: - // KioskNextShellClientTest: - void SetUp() override { + KioskNextShellClientMashDisabledTest() : KioskNextShellClientTest() { feature_list_.InitAndDisableFeature(features::kSingleProcessMash); - - KioskNextShellClientTest::SetUp(); } private:
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc index b7ffef0..43f2426 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -410,7 +410,7 @@ void BrowserShortcutLauncherItemController::OnBrowserClosing(Browser* browser) { DCHECK(browser); // Reset pointers to the closed browser, but leave menu indices intact. - for (auto it : app_menu_items_) { + for (auto& it : app_menu_items_) { if (it.first == browser) it.first = nullptr; }
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc new file mode 100644 index 0000000..c178158 --- /dev/null +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc
@@ -0,0 +1,58 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h" + +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" + +using BrowserShortcutLauncherItemControllerTest = InProcessBrowserTest; +IN_PROC_BROWSER_TEST_F(BrowserShortcutLauncherItemControllerTest, AppMenu) { + BrowserShortcutLauncherItemController* controller = + ChromeLauncherController::instance() + ->GetBrowserShortcutLauncherItemController(); + ASSERT_TRUE(controller); + + BrowserList* browser_list = BrowserList::GetInstance(); + EXPECT_EQ(browser_list->size(), 1U); + + Browser* browser1 = CreateBrowser(browser()->profile()); + EXPECT_EQ(browser_list->size(), 2U); + + ui_test_utils::NavigateToURL(browser(), + GURL("data:text/html,<title>0</title>")); + ui_test_utils::NavigateToURL(browser1, + GURL("data:text/html,<title>1</title>")); + auto items = controller->GetAppMenuItems(ui::EF_NONE); + ASSERT_EQ(items.size(), 2U); + EXPECT_EQ(base::ASCIIToUTF16("0"), items[0].first); + EXPECT_EQ(base::ASCIIToUTF16("1"), items[1].first); + + // Close the window and wait for all asynchronous window teardown. + browser1->window()->Close(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(browser_list->size(), 1U); + // Selecting the app menu item for the closed browser window should not crash. + controller->ExecuteCommand(/*from_context_menu=*/false, /*command_id=*/1, + ui::EF_NONE, display::kInvalidDisplayId); + + // Create and close a window, but don't allow asynchronous teardown to occur. + browser1 = CreateBrowser(browser()->profile()); + EXPECT_EQ(browser_list->size(), 2U); + browser1->window()->Close(); + EXPECT_EQ(browser_list->size(), 2U); + // The app menu should not list the browser window while it is closing. + items = controller->GetAppMenuItems(ui::EF_NONE); + EXPECT_EQ(items.size(), 1U); + // Now, allow the asynchronous teardown to occur. + EXPECT_EQ(browser_list->size(), 2U); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(browser_list->size(), 1U); +}
diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc index 699daff..6d26c7f 100644 --- a/chrome/browser/ui/browser_ui_prefs.cc +++ b/chrome/browser/ui/browser_ui_prefs.cc
@@ -124,4 +124,5 @@ registry->RegisterBooleanPref(prefs::kEnterpriseHardwarePlatformAPIEnabled, false); registry->RegisterBooleanPref(prefs::kAllowPopupsDuringPageUnload, false); + registry->RegisterBooleanPref(prefs::kUserFeedbackAllowed, true); }
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h index 3acdf53..f0c296f 100644 --- a/chrome/browser/ui/browser_window.h +++ b/chrome/browser/ui/browser_window.h
@@ -35,6 +35,7 @@ class Browser; class DownloadShelf; class ExclusiveAccessContext; +class ExtensionsContainer; class FindBar; class GURL; class LocationBar; @@ -276,8 +277,13 @@ virtual void FocusToolbar() = 0; // Returns the ToolbarActionsBar associated with the window, if any. + // TODO(pbos): Replace usages of |GetToolbarActionsBar| with + // |GetExtensionsContainer|. virtual ToolbarActionsBar* GetToolbarActionsBar() = 0; + // Returns the ExtensionsContainer associated with the window, if any. + virtual ExtensionsContainer* GetExtensionsContainer() = 0; + // Called from toolbar subviews during their show/hide animations. virtual void ToolbarSizeChanged(bool is_animating) = 0;
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc index 2d664ea..085f424 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.cc +++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -216,7 +216,8 @@ // Reconstruct the menu every time because the menu's contents are dynamic. context_menu_model_.reset(new extensions::ExtensionContextMenuModel( - extension(), browser_, visibility, this)); + extension(), browser_, visibility, this, + view_delegate_->CanShowIconInToolbar())); return context_menu_model_.get(); }
diff --git a/chrome/browser/ui/extensions/extensions_container.h b/chrome/browser/ui/extensions/extensions_container.h index 1f54184e0..46d643e 100644 --- a/chrome/browser/ui/extensions/extensions_container.h +++ b/chrome/browser/ui/extensions/extensions_container.h
@@ -10,6 +10,7 @@ #include "base/callback_forward.h" class ToolbarActionViewController; +class ToolbarActionsBarBubbleDelegate; // An interface for containers in the toolbar that host extensions. class ExtensionsContainer { @@ -48,6 +49,14 @@ virtual void PopOutAction(ToolbarActionViewController* action, bool is_sticky, const base::Closure& closure) = 0; + + // Displays the given |bubble| once the toolbar is no longer animating. + virtual void ShowToolbarActionBubble( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) = 0; + + // Same as above, but uses PostTask() in all cases. + virtual void ShowToolbarActionBubbleAsync( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) = 0; }; #endif // CHROME_BROWSER_UI_EXTENSIONS_EXTENSIONS_CONTAINER_H_
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc index 1a8d194..ac96d4b 100644 --- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc +++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -286,15 +286,16 @@ HostedAppTest() : app_browser_(nullptr), app_(nullptr), - https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { + scoped_feature_list_.InitWithFeatures( + {}, {predictors::kSpeculativePreconnectFeature}); + } ~HostedAppTest() override {} void SetUp() override { https_server_.AddDefaultHandlers(GetChromeTestDataDir()); app_type_ = GetParam(); - scoped_feature_list_.InitWithFeatures( - {}, {predictors::kSpeculativePreconnectFeature}); extensions::ExtensionBrowserTest::SetUp(); }
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc index 83ca105..545296d 100644 --- a/chrome/browser/ui/page_info/page_info_unittest.cc +++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -18,6 +18,8 @@ #include "build/build_config.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/infobars/mock_infobar_service.h" +#include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h" +#include "chrome/browser/ssl/chrome_ssl_host_state_delegate_factory.h" #include "chrome/browser/ui/page_info/page_info_ui.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" @@ -931,9 +933,9 @@ } #endif -// Tests that metrics for the "Re-Enable Warnings" button on PageInfo are being -// logged correctly. -TEST_F(PageInfoTest, ReEnableWarningsMetrics) { +// Tests that "Re-Enable Warnings" button on PageInfo both removes certificate +// exceptions and logs metrics correctly. +TEST_F(PageInfoTest, ReEnableWarnings) { struct TestCase { const std::string url; const bool button_visible; @@ -949,25 +951,22 @@ "interstitial.ssl.did_user_revoke_decisions2"; for (const auto& test : kTestCases) { base::HistogramTester histograms; + ChromeSSLHostStateDelegate* ssl_state = + ChromeSSLHostStateDelegateFactory::GetForProfile(profile()); + const std::string host = GURL(test.url).host(); + + ssl_state->RevokeUserAllowExceptionsHard(host); ResetMockUI(); SetURL(test.url); if (test.button_visible) { // In the case where the button should be visible, add an exception to // the profile settings for the site (since the exception is what // will make the button visible). - HostContentSettingsMap* content_settings = - HostContentSettingsMapFactory::GetForProfile(profile()); - std::unique_ptr<base::DictionaryValue> dict = - std::unique_ptr<base::DictionaryValue>(new base::DictionaryValue()); - dict->SetKey( - "testkey", - base::Value(content::SSLHostStateDelegate::CertJudgment::ALLOWED)); - content_settings->SetWebsiteSettingDefaultScope( - url(), GURL(), CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, - std::string(), std::move(dict)); + ssl_state->AllowCert(host, *cert(), net::ERR_CERT_DATE_INVALID); page_info(); if (test.button_clicked) { page_info()->OnRevokeSSLErrorBypassButtonPressed(); + EXPECT_FALSE(ssl_state->HasAllowException(host)); ClearPageInfo(); histograms.ExpectTotalCount(kGenericHistogram, 1); histograms.ExpectBucketCount( @@ -977,6 +976,7 @@ 1); } else { // Case where button is visible but not clicked. ClearPageInfo(); + EXPECT_TRUE(ssl_state->HasAllowException(host)); histograms.ExpectTotalCount(kGenericHistogram, 1); histograms.ExpectBucketCount( kGenericHistogram, @@ -987,6 +987,7 @@ } else { page_info(); ClearPageInfo(); + EXPECT_FALSE(ssl_state->HasAllowException(host)); // Button is not visible, so check histogram is empty after opening and // closing page info. histograms.ExpectTotalCount(kGenericHistogram, 0);
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc index a8864bc..a111149a 100644 --- a/chrome/browser/ui/toolbar/app_menu_model.cc +++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -178,7 +178,8 @@ SetIcon(GetIndexOfCommandId(IDC_HELP_PAGE_VIA_MENU), rb.GetNativeImageNamed(IDR_HELP_MENU)); } - AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK); + if (browser->profile()->GetPrefs()->GetBoolean(prefs::kUserFeedbackAllowed)) + AddItemWithStringId(IDC_FEEDBACK, IDS_FEEDBACK); } DISALLOW_COPY_AND_ASSIGN(HelpMenuModel);
diff --git a/chrome/browser/ui/toolbar/media_router_contextual_menu.cc b/chrome/browser/ui/toolbar/media_router_contextual_menu.cc index 46f5d650..89bc9fda 100644 --- a/chrome/browser/ui/toolbar/media_router_contextual_menu.cc +++ b/chrome/browser/ui/toolbar/media_router_contextual_menu.cc
@@ -76,8 +76,12 @@ menu_model_->AddCheckItemWithStringId( IDC_MEDIA_ROUTER_CLOUD_SERVICES_TOGGLE, IDS_MEDIA_ROUTER_CLOUD_SERVICES_TOGGLE); - menu_model_->AddItemWithStringId(IDC_MEDIA_ROUTER_REPORT_ISSUE, - IDS_MEDIA_ROUTER_REPORT_ISSUE); + + if (browser->profile()->GetPrefs()->GetBoolean( + prefs::kUserFeedbackAllowed)) { + menu_model_->AddItemWithStringId(IDC_MEDIA_ROUTER_REPORT_ISSUE, + IDS_MEDIA_ROUTER_REPORT_ISSUE); + } } }
diff --git a/chrome/browser/ui/toolbar/toolbar_action_view_delegate.cc b/chrome/browser/ui/toolbar/toolbar_action_view_delegate.cc new file mode 100644 index 0000000..35647a5 --- /dev/null +++ b/chrome/browser/ui/toolbar/toolbar_action_view_delegate.cc
@@ -0,0 +1,9 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h" + +bool ToolbarActionViewDelegate::CanShowIconInToolbar() const { + return true; +}
diff --git a/chrome/browser/ui/toolbar/toolbar_action_view_delegate.h b/chrome/browser/ui/toolbar/toolbar_action_view_delegate.h index 74b99f59..f64cfef6 100644 --- a/chrome/browser/ui/toolbar/toolbar_action_view_delegate.h +++ b/chrome/browser/ui/toolbar/toolbar_action_view_delegate.h
@@ -24,6 +24,9 @@ // Returns true if a context menu is running. virtual bool IsMenuRunning() const = 0; + // Whether the container supports showing extensions outside of the menu. + virtual bool CanShowIconInToolbar() const; + // Called when a popup is shown. If |by_user| is true, then this was through // a direct user action (as oppposed to, e.g., an API call). virtual void OnPopupShown(bool by_user) {}
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h index e46bf85..8ceb350c 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -193,13 +193,6 @@ void AddObserver(ToolbarActionsBarObserver* observer); void RemoveObserver(ToolbarActionsBarObserver* observer); - // Displays the given |bubble| once the toolbar is no longer animating. - void ShowToolbarActionBubble( - std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble); - // Same as above, but uses PostTask() in all cases. - void ShowToolbarActionBubbleAsync( - std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble); - // Returns the underlying toolbar actions, but does not order them. Primarily // for use in testing. const ToolbarActions& toolbar_actions_unordered() const { @@ -248,6 +241,10 @@ void PopOutAction(ToolbarActionViewController* action, bool is_sticky, const base::Closure& closure) override; + void ShowToolbarActionBubble( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; + void ShowToolbarActionBubbleAsync( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; private: // Returns the insets by which the icon area bounds (See GetIconAreaRect())
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc index 64368f8..50c92f8 100644 --- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc +++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -9,17 +9,24 @@ #include "base/path_service.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/extensions/chrome_test_extension_loader.h" +#include "chrome/browser/extensions/extension_action_runner.h" +#include "chrome/browser/extensions/scripting_permissions_modifier.h" #include "chrome/browser/ui/test/test_browser_dialog.h" #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/extensions/extensions_menu_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/webui_url_constants.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/test/test_navigation_observer.h" +#include "net/dns/mock_host_resolver.h" #include "ui/views/test/button_test_api.h" #include "ui/views/test/widget_test.h" +#include "ui/views/window/dialog_client_view.h" class ExtensionsMenuViewBrowserTest : public DialogBrowserTest { protected: @@ -36,6 +43,11 @@ DialogBrowserTest::SetUp(); } + void SetUpOnMainThread() override { + DialogBrowserTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + } + void ShowUi(const std::string& name) override { ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, 0); @@ -130,7 +142,7 @@ } IN_PROC_BROWSER_TEST_F(ExtensionsMenuViewBrowserTest, - TriggeringExtensionClosesMenu) { + ActivationWithReloadNeeded_Accept) { LoadTestExtension("extensions/trigger_actions/browser_action"); ShowUi(""); VerifyUi(); @@ -186,5 +198,68 @@ browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL()); } +class ActivateWithReloadExtensionsMenuBrowserTest + : public ExtensionsMenuViewBrowserTest, + public ::testing::WithParamInterface<bool> {}; + +IN_PROC_BROWSER_TEST_P(ActivateWithReloadExtensionsMenuBrowserTest, + ActivateWithReload) { + ASSERT_TRUE(embedded_test_server()->Start()); + LoadTestExtension("extensions/blocked_actions/content_scripts"); + auto extension = extensions_.back(); + extensions::ScriptingPermissionsModifier modifier(browser()->profile(), + extension); + modifier.SetWithholdHostPermissions(true); + + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("example.com", "/empty.html")); + + ShowUi(""); + VerifyUi(); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + extensions::ExtensionActionRunner* action_runner = + extensions::ExtensionActionRunner::GetForWebContents(web_contents); + + EXPECT_TRUE(action_runner->WantsToRun(extension.get())); + + TriggerSingleExtensionButton(); + + auto* const action_bubble = BrowserView::GetBrowserViewForBrowser(browser()) + ->toolbar() + ->extensions_container() + ->action_bubble_public_for_testing(); + ASSERT_TRUE(action_bubble); + + views::DialogClientView* const dialog_client_view = + action_bubble->GetDialogClientView(); + + const bool accept_reload_dialog = GetParam(); + if (accept_reload_dialog) { + content::TestNavigationObserver observer(web_contents); + dialog_client_view->AcceptWindow(); + EXPECT_TRUE(web_contents->IsLoading()); + // Wait for reload to finish. + observer.WaitForNavigationFinished(); + EXPECT_TRUE(observer.last_navigation_succeeded()); + // After reload the extension should be allowed to run. + EXPECT_FALSE(action_runner->WantsToRun(extension.get())); + } else { + dialog_client_view->CancelWindow(); + EXPECT_FALSE(web_contents->IsLoading()); + EXPECT_TRUE(action_runner->WantsToRun(extension.get())); + } +} + +INSTANTIATE_TEST_SUITE_P(AcceptDialog, + ActivateWithReloadExtensionsMenuBrowserTest, + testing::Values(true)); + +INSTANTIATE_TEST_SUITE_P(CancelDialog, + ActivateWithReloadExtensionsMenuBrowserTest, + testing::Values(false)); + // TODO(pbos): Add test coverage that makes sure removing popped-out extensions // properly disposes of the popup.
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc index b8676d1..d963686 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -9,6 +9,8 @@ #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" #include "chrome/browser/ui/views/extensions/extensions_menu_view.h" #include "chrome/browser/ui/views/extensions/extensions_toolbar_button.h" +#include "chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h" +#include "ui/views/widget/widget_observer.h" ExtensionsToolbarContainer::ExtensionsToolbarContainer(Browser* browser) : ToolbarIconContainerView(/*uses_highlight=*/true), @@ -21,7 +23,13 @@ CreateActions(); } -ExtensionsToolbarContainer::~ExtensionsToolbarContainer() = default; +ExtensionsToolbarContainer::~ExtensionsToolbarContainer() { + if (active_bubble_) + active_bubble_->GetWidget()->Close(); + // We should synchronously receive the OnWidgetClosing() event, so we should + // always have cleared the active bubble by now. + DCHECK(!active_bubble_); +} void ExtensionsToolbarContainer::UpdateAllIcons() { extensions_button_->UpdateIcon(); @@ -44,7 +52,9 @@ bool ExtensionsToolbarContainer::IsActionVisibleOnToolbar( const ToolbarActionViewController* action) const { return model_->IsActionPinned(action->GetId()) || - action == popped_out_action_; + action == popped_out_action_ || + (active_bubble_ && + action->GetId() == active_bubble_->GetAnchorActionId()); } void ExtensionsToolbarContainer::UndoPopOut() { @@ -92,6 +102,34 @@ closure.Run(); } +void ExtensionsToolbarContainer::ShowToolbarActionBubble( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> controller) { + // TODO(pbos): Make sure we finish animations before showing the bubble. + + auto iter = icons_.find(controller->GetAnchorActionId()); + + views::View* const anchor_view = iter != icons_.end() + ? static_cast<View*>(iter->second.get()) + : extensions_button_; + + anchor_view->SetVisible(true); + + active_bubble_ = new ToolbarActionsBarBubbleViews( + anchor_view, gfx::Point(), anchor_view != extensions_button_, + std::move(controller)); + views::BubbleDialogDelegateView::CreateBubble(active_bubble_) + ->AddObserver(this); + active_bubble_->Show(); +} + +void ExtensionsToolbarContainer::ShowToolbarActionBubbleAsync( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&ExtensionsToolbarContainer::ShowToolbarActionBubble, + weak_ptr_factory_.GetWeakPtr(), std::move(bubble))); +} + void ExtensionsToolbarContainer::OnToolbarActionAdded( const ToolbarActionsModel::ActionId& action_id, int index) { @@ -219,3 +257,27 @@ // TODO(pbos): Implement return false; } + +void ExtensionsToolbarContainer::OnWidgetClosing(views::Widget* widget) { + ClearActiveBubble(widget); +} + +void ExtensionsToolbarContainer::OnWidgetDestroying(views::Widget* widget) { + ClearActiveBubble(widget); +} + +void ExtensionsToolbarContainer::ClearActiveBubble(views::Widget* widget) { + DCHECK(active_bubble_); + DCHECK_EQ(active_bubble_->GetWidget(), widget); + ToolbarActionViewController* const action = + GetActionForId(active_bubble_->GetAnchorActionId()); + // TODO(pbos): Note that this crashes if a bubble anchors to the menu and not + // to an extension that gets popped out. This should be fixed, but a test + // should first be added to make sure that it's covered. + CHECK(action); + active_bubble_ = nullptr; + widget->RemoveObserver(this); + // Note that we only hide this view if it's not visible for other reasons + // than displaying the bubble. + icons_[action->GetId()]->SetVisible(IsActionVisibleOnToolbar(action)); +}
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h index 919e980..3998230 100644 --- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h +++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
@@ -9,6 +9,7 @@ #include <memory> #include <vector> +#include "base/optional.h" #include "chrome/browser/ui/extensions/extensions_container.h" #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" #include "chrome/browser/ui/views/toolbar/toolbar_action_view.h" @@ -17,6 +18,7 @@ class Browser; class ExtensionsToolbarButton; class ToolbarActionViewController; +class ToolbarActionsBarBubbleViews; // Container for extensions shown in the toolbar. These include pinned // extensions and extensions that are 'popped out' transitively to show dialogs @@ -29,7 +31,8 @@ class ExtensionsToolbarContainer : public ToolbarIconContainerView, public ExtensionsContainer, public ToolbarActionsModel::Observer, - public ToolbarActionView::Delegate { + public ToolbarActionView::Delegate, + public views::WidgetObserver { public: explicit ExtensionsToolbarContainer(Browser* browser); ~ExtensionsToolbarContainer() override; @@ -38,6 +41,10 @@ return extensions_button_; } + ToolbarActionsBarBubbleViews* action_bubble_public_for_testing() { + return active_bubble_; + } + // ToolbarIconContainerView: void UpdateAllIcons() override; @@ -54,6 +61,9 @@ // popped out actions, extensions button). void ReorderViews(); + // Clears the |active_bubble_|, and unregisters the container as an observer. + void ClearActiveBubble(views::Widget* widget); + // ExtensionsContainer: ToolbarActionViewController* GetActionForId( const std::string& action_id) override; @@ -67,6 +77,10 @@ void PopOutAction(ToolbarActionViewController* action, bool is_sticky, const base::Closure& closure) override; + void ShowToolbarActionBubble( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; + void ShowToolbarActionBubbleAsync( + std::unique_ptr<ToolbarActionsBarBubbleDelegate> bubble) override; // ToolbarActionsModel::Observer: void OnToolbarActionAdded(const ToolbarActionsModel::ActionId& action_id, @@ -97,6 +111,10 @@ const gfx::Point& press_pt, const gfx::Point& p) override; + // views::WidgetObserver: + void OnWidgetClosing(views::Widget* widget) override; + void OnWidgetDestroying(views::Widget* widget) override; + Browser* const browser_; ToolbarActionsModel* const model_; ScopedObserver<ToolbarActionsModel, ToolbarActionsModel::Observer> @@ -116,6 +134,11 @@ // The action that triggered the current popup, if any. ToolbarActionViewController* popup_owner_ = nullptr; + // The extension bubble that is actively showing, if any. + ToolbarActionsBarBubbleViews* active_bubble_ = nullptr; + + base::WeakPtrFactory<ExtensionsToolbarContainer> weak_ptr_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(ExtensionsToolbarContainer); };
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index c90d55c..77939df 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -83,6 +83,7 @@ #include "chrome/browser/ui/views/download/download_shelf_view.h" #include "chrome/browser/ui/views/exclusive_access_bubble_views.h" #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h" +#include "chrome/browser/ui/views/extensions/extensions_toolbar_container.h" #include "chrome/browser/ui/views/find_bar_host.h" #include "chrome/browser/ui/views/frame/app_menu_button.h" #include "chrome/browser/ui/views/frame/browser_view_layout.h" @@ -1167,6 +1168,12 @@ return container ? container->toolbar_actions_bar() : nullptr; } +ExtensionsContainer* BrowserView::GetExtensionsContainer() { + if (toolbar_ && toolbar_->extensions_container()) + return toolbar_->extensions_container(); + return GetToolbarActionsBar(); +} + void BrowserView::ToolbarSizeChanged(bool is_animating) { if (is_animating) contents_web_view_->SetFastResize(true);
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index fcfaa4fa..b2ddd63 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -347,6 +347,7 @@ void ResetToolbarTabState(content::WebContents* contents) override; void FocusToolbar() override; ToolbarActionsBar* GetToolbarActionsBar() override; + ExtensionsContainer* GetExtensionsContainer() override; void ToolbarSizeChanged(bool is_animating) override; void TabDraggingStatusChanged(bool is_dragging) override; void FocusAppMenu() override;
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.cc b/chrome/browser/ui/views/frame/hosted_app_button_container.cc index 86b16a7..a997957 100644 --- a/chrome/browser/ui/views/frame/hosted_app_button_container.cc +++ b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
@@ -309,6 +309,10 @@ return base::Optional<int>(); } +bool HostedAppButtonContainer::CanShowIconInToolbar() const { + return false; +} + std::unique_ptr<ToolbarActionsBar> HostedAppButtonContainer::CreateToolbarActionsBar( ToolbarActionsBarDelegate* delegate,
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.h b/chrome/browser/ui/views/frame/hosted_app_button_container.h index 90f18cb..f499ac9c 100644 --- a/chrome/browser/ui/views/frame/hosted_app_button_container.h +++ b/chrome/browser/ui/views/frame/hosted_app_button_container.h
@@ -91,6 +91,7 @@ // BrowserActionsContainer::Delegate: views::LabelButton* GetOverflowReferenceView() override; base::Optional<int> GetMaxBrowserActionsWidth() const override; + bool CanShowIconInToolbar() const override; std::unique_ptr<ToolbarActionsBar> CreateToolbarActionsBar( ToolbarActionsBarDelegate* delegate, Browser* browser,
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc index 029b90d..32636250 100644 --- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc +++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc
@@ -31,6 +31,13 @@ TOTAL_COUNT = 2 // Add new types above this line. }; +SkColor GetColorfromTheme() { + const ui::NativeTheme* native_theme = + ui::NativeTheme::GetInstanceForNativeUi(); + return native_theme->GetSystemColor( + ui::NativeTheme::kColorId_DefaultIconColor); +} + gfx::ImageSkia CreateDeviceIcon(DeviceIconType icon_type) { const gfx::VectorIcon* vector_icon; switch (icon_type) { @@ -43,8 +50,9 @@ default: vector_icon = &kSendTabToSelfIcon; } - SkColor icon_color = ui::NativeTheme::kColorId_DefaultIconColor; - return gfx::CreateVectorIcon(*vector_icon, kPrimaryIconSize, icon_color); + + return gfx::CreateVectorIcon(*vector_icon, kPrimaryIconSize, + GetColorfromTheme()); } std::unique_ptr<views::ImageView> CreateIconView(
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 38b857f8..5beddf2b 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -2237,8 +2237,8 @@ &tabs_, animator_->GetCurrentTabStates(), available_width, controller_->GetActiveIndex()); - new_tab_button_bounds_.set_origin( - gfx::Point(trailing_x + TabToNewTabButtonSpacing(), 0)); + new_tab_button_bounds_.set_origin(gfx::Point( + std::min(available_width, trailing_x) + TabToNewTabButtonSpacing(), 0)); } new_tab_button_->SetBoundsRect(new_tab_button_bounds_);
diff --git a/chrome/browser/ui/views/tabs/window_finder_chromeos.cc b/chrome/browser/ui/views/tabs/window_finder_chromeos.cc index 41b6284..0745fb8 100644 --- a/chrome/browser/ui/views/tabs/window_finder_chromeos.cc +++ b/chrome/browser/ui/views/tabs/window_finder_chromeos.cc
@@ -9,5 +9,5 @@ gfx::NativeWindow WindowFinder::GetLocalProcessWindowAtPoint( const gfx::Point& screen_point, const std::set<gfx::NativeWindow>& ignore) { - return ash::GetTopmostWindowAtPoint(screen_point, ignore, nullptr); + return ash::GetTopmostWindowAtPoint(screen_point, ignore); }
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc index 602247c..d6cb4c61 100644 --- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc +++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -49,6 +49,13 @@ #include "ui/views/widget/widget.h" //////////////////////////////////////////////////////////////////////////////// +// BrowserActionsContainer::Delegate + +bool BrowserActionsContainer::Delegate::CanShowIconInToolbar() const { + return true; +} + +//////////////////////////////////////////////////////////////////////////////// // BrowserActionsContainer::DropPosition struct BrowserActionsContainer::DropPosition { @@ -149,6 +156,10 @@ return main_container_ != nullptr; } +bool BrowserActionsContainer::CanShowIconInToolbar() const { + return delegate_->CanShowIconInToolbar(); +} + void BrowserActionsContainer::OnToolbarActionViewDragDone() { toolbar_actions_bar_->OnDragEnded(); }
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.h b/chrome/browser/ui/views/toolbar/browser_actions_container.h index 0258578..cba1af2 100644 --- a/chrome/browser/ui/views/toolbar/browser_actions_container.h +++ b/chrome/browser/ui/views/toolbar/browser_actions_container.h
@@ -124,6 +124,9 @@ // empty value means there is no maximum. virtual base::Optional<int> GetMaxBrowserActionsWidth() const = 0; + // Whether the container supports showing extensions outside of the menu. + virtual bool CanShowIconInToolbar() const; + // Creates a ToolbarActionsBar for the BrowserActionsContainer to use. virtual std::unique_ptr<ToolbarActionsBar> CreateToolbarActionsBar( ToolbarActionsBarDelegate* delegate, @@ -225,6 +228,7 @@ // Overridden from ToolbarActionView::Delegate: content::WebContents* GetCurrentWebContents() override; bool ShownInsideMenu() const override; + bool CanShowIconInToolbar() const override; void OnToolbarActionViewDragDone() override; views::LabelButton* GetOverflowReferenceView() override; gfx::Size GetToolbarActionSize() override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc index e14c087..73dabfe 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -47,6 +47,13 @@ } // namespace //////////////////////////////////////////////////////////////////////////////// +// ToolbarActionView::Delegate + +bool ToolbarActionView::Delegate::CanShowIconInToolbar() const { + return true; +} + +//////////////////////////////////////////////////////////////////////////////// // ToolbarActionView const char ToolbarActionView::kClassName[] = "ToolbarActionView"; @@ -298,6 +305,10 @@ return menu_ != nullptr; } +bool ToolbarActionView::CanShowIconInToolbar() const { + return delegate_->CanShowIconInToolbar(); +} + void ToolbarActionView::OnPopupShown(bool by_user) { // If this was through direct user action, we press the menu button. if (by_user) {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_view.h index 2b6db8a0..58d7491 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_action_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
@@ -41,6 +41,9 @@ // Whether the container for this button is shown inside a menu. virtual bool ShownInsideMenu() const = 0; + // Whether the container supports showing extensions outside of the menu. + virtual bool CanShowIconInToolbar() const; + // Notifies that a drag completed. virtual void OnToolbarActionViewDragDone() = 0; @@ -115,6 +118,7 @@ views::FocusManager* GetFocusManagerForAccelerator() override; views::Button* GetReferenceButtonForPopup() override; bool IsMenuRunning() const override; + bool CanShowIconInToolbar() const override; void OnPopupShown(bool by_user) override; void OnPopupClosed() override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc index f6e7ff6..741dc25 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
@@ -54,6 +54,10 @@ GetWidget()->Show(); } +std::string ToolbarActionsBarBubbleViews::GetAnchorActionId() { + return delegate_->GetAnchorActionId(); +} + std::unique_ptr<views::View> ToolbarActionsBarBubbleViews::CreateExtraView() { std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo> extra_view_info = delegate_->GetExtraViewInfo();
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h index 89cb1c8..1e105f7 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h +++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
@@ -32,6 +32,7 @@ ~ToolbarActionsBarBubbleViews() override; void Show(); + std::string GetAnchorActionId(); const views::Label* body_text() const { return body_text_; } const views::Label* item_list() const { return item_list_; }
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 71aabddc..0e60e35 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -59,7 +59,6 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/system/system_clock.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_metrics.h"
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc index 1743e638..b594b454 100644 --- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc +++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
@@ -511,7 +511,6 @@ } TEST_F(InterventionsInternalsPageHandlerTest, GetFlagsEctForceFieldtrialValue) { - base::FieldTrialList field_trial_list_(nullptr); const std::string trial_name = "NetworkQualityEstimator"; const std::string group_name = "Enabled"; const std::string expected_ect = "Slow-2G";
diff --git a/chrome/browser/ui/webui/net_export_ui.cc b/chrome/browser/ui/webui/net_export_ui.cc index 1b9b3d8..35f21ae 100644 --- a/chrome/browser/ui/webui/net_export_ui.cc +++ b/chrome/browser/ui/webui/net_export_ui.cc
@@ -22,7 +22,6 @@ #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/download/download_prefs.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/net/net_export_helper.h" #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/platform_util.h"
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc index 92f899d7..3a017464 100644 --- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc +++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -20,7 +20,6 @@ #include "base/threading/thread_restrictions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/io_thread.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc index 60c15ce..c5914fac 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -59,6 +59,8 @@ namespace { +using printing::PrinterQueryResult; + // These values are written to logs. New enum values can be added, but existing // enums must never be renumbered or deleted and reused. enum PpdSourceForHistogram { kUser = 0, kScs = 1, kPpdSourceMax }; @@ -106,7 +108,7 @@ // Behavior for querying a non-IPP uri is undefined and disallowed. if (!IsIppUri(printer_uri) || !optional.has_value()) { PRINTER_LOG(ERROR) << "Printer uri is invalid: " << printer_uri; - callback.Run(false, "", "", "", {}, false); + callback.Run(PrinterQueryResult::UNKNOWN_FAILURE, "", "", "", {}, false); return; } @@ -459,7 +461,8 @@ if (printer_address.empty()) { // Run the failure callback. - OnAutoconfQueried(callback_id, false, "", "", "", {}, false); + OnAutoconfQueried(callback_id, PrinterQueryResult::UNKNOWN_FAILURE, "", "", + "", {}, false); return; } @@ -484,12 +487,13 @@ void CupsPrintersHandler::OnAutoconfQueriedDiscovered( Printer printer, - bool success, + PrinterQueryResult result, const std::string& make, const std::string& model, const std::string& make_and_model, const std::vector<std::string>& document_formats, bool ipp_everywhere) { + const bool success = result == PrinterQueryResult::SUCCESS; RecordIppQuerySuccess(success); if (success) { @@ -528,14 +532,23 @@ void CupsPrintersHandler::OnAutoconfQueried( const std::string& callback_id, - bool success, + PrinterQueryResult result, const std::string& make, const std::string& model, const std::string& make_and_model, const std::vector<std::string>& document_formats, bool ipp_everywhere) { + const bool success = result == PrinterQueryResult::SUCCESS; RecordIppQuerySuccess(success); + if (result == PrinterQueryResult::UNREACHABLE) { + PRINTER_LOG(DEBUG) << "Could not reach printer"; + base::DictionaryValue reject; + reject.SetString("message", "Unable to reach printer"); + RejectJavascriptCallback(base::Value(callback_id), reject); + return; + } + if (!success) { PRINTER_LOG(DEBUG) << "Could not query printer"; base::DictionaryValue reject;
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h index f790bfc..42c17f4 100644 --- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h
@@ -20,6 +20,7 @@ #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h" #include "chromeos/printing/ppd_provider.h" #include "chromeos/printing/printer_configuration.h" +#include "printing/backend/cups_jobs.h" #include "ui/shell_dialogs/select_file_dialog.h" namespace base { @@ -79,7 +80,7 @@ // Everywhere driver should be attempted. If |success| is false, the values of // |make|, |model|, |make_and_model|, and |ipp_everywhere| are not specified. void OnAutoconfQueried(const std::string& callback_id, - bool success, + printing::PrinterQueryResult result, const std::string& make, const std::string& model, const std::string& make_and_model, @@ -89,7 +90,7 @@ // Handles the callback for HandleGetPrinterInfo for a discovered printer. void OnAutoconfQueriedDiscovered( Printer printer, - bool success, + printing::PrinterQueryResult result, const std::string& make, const std::string& model, const std::string& make_and_model,
diff --git a/chrome/browser/usb/usb_blocklist_unittest.cc b/chrome/browser/usb/usb_blocklist_unittest.cc index e5e9665..bcea7606 100644 --- a/chrome/browser/usb/usb_blocklist_unittest.cc +++ b/chrome/browser/usb/usb_blocklist_unittest.cc
@@ -3,6 +3,8 @@ // found in the LICENSE file. #include "chrome/browser/usb/usb_blocklist.h" + +#include "base/strings/string_piece.h" #include "components/variations/variations_params_manager.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/vr/test/fake_xr_session_request_consent_manager.cc b/chrome/browser/vr/test/fake_xr_session_request_consent_manager.cc index 6eac1495..4f8f769 100644 --- a/chrome/browser/vr/test/fake_xr_session_request_consent_manager.cc +++ b/chrome/browser/vr/test/fake_xr_session_request_consent_manager.cc
@@ -49,6 +49,15 @@ confirm_dialog->CloseDialog(); break; } + + // Allow the dialog to close cleanly. + base::RunLoop dialog_clean_close_loop( + base::RunLoop::Type::kNestableTasksAllowed); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, dialog_clean_close_loop.QuitWhenIdleClosure(), + kConsentDialogDisplayingTime); + dialog_clean_close_loop.Run(); + return confirm_dialog; }
diff --git a/chrome/browser/vr/test/xr_browser_test.cc b/chrome/browser/vr/test/xr_browser_test.cc index 7f22461..54ddc20e 100644 --- a/chrome/browser/vr/test/xr_browser_test.cc +++ b/chrome/browser/vr/test/xr_browser_test.cc
@@ -243,7 +243,7 @@ } bool result; - DLOG(ERROR) << "Run JavaScript: " << js_expression; + DLOG(INFO) << "Run JavaScript: " << js_expression; EXPECT_TRUE(content::ExecuteScriptAndExtractBool( web_contents, "window.domAutomationController.send(" + js_expression + ")", &result))
diff --git a/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc b/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc index b3a1079..f1ee1c3 100644 --- a/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc +++ b/chrome/browser/vr/webxr_vr_consent_dialog_browser_test.cc
@@ -47,7 +47,7 @@ IN_PROC_BROWSER_TEST_F( WebXrVrConsentDialogBrowserTest, - DISABLED_TestWebXrVrSucceedsWhenUserClicksConsentDialogAllowButton) { + TestWebXrVrSucceedsWhenUserClicksConsentDialogAllowButton) { SetupFakeConsentManager( FakeXRSessionRequestConsentManager::UserResponse::kClickAllowButton); @@ -70,24 +70,24 @@ IN_PROC_BROWSER_TEST_F( WebXrVrConsentDialogBrowserTest, - DISABLED_TestWebXrVrFailsWhenUserClicksConsentDialogCancelButton) { + TestWebXrVrFailsWhenUserClicksConsentDialogCancelButton) { SetupFakeConsentManager( FakeXRSessionRequestConsentManager::UserResponse::kClickCancelButton); LoadUrlAndAwaitInitialization(GetFileUrlForHtmlTestFile( - "webxr_test_presentation_promise_rejected_if_don_canceled")); - ExecuteStepAndWait("onImmersiveRequestWithDon()"); + "webxr_test_presentation_promise_rejected_if_consent_not_granted")); + ExecuteStepAndWait("onImmersiveRequestWithConsent()"); EndTest(); } IN_PROC_BROWSER_TEST_F(WebXrVrConsentDialogBrowserTest, - DISABLED_TestWebXrVrFailsWhenUserClosesConsentDialog) { + TestWebXrVrFailsWhenUserClosesConsentDialog) { SetupFakeConsentManager( FakeXRSessionRequestConsentManager::UserResponse::kCloseDialog); LoadUrlAndAwaitInitialization(GetFileUrlForHtmlTestFile( - "webxr_test_presentation_promise_rejected_if_don_canceled")); - ExecuteStepAndWait("onImmersiveRequestWithDon()"); + "webxr_test_presentation_promise_rejected_if_consent_not_granted")); + ExecuteStepAndWait("onImmersiveRequestWithConsent()"); EndTest(); }
diff --git a/chrome/browser/webauth_interactive_uitest.cc b/chrome/browser/webauth_interactive_uitest.cc index 2320aca..821b33b86 100644 --- a/chrome/browser/webauth_interactive_uitest.cc +++ b/chrome/browser/webauth_interactive_uitest.cc
@@ -133,8 +133,12 @@ // tab/window, and have the user believe that they are interacting with that // trusted site. virtual_device_factory->mutable_state()->simulate_press_callback = - base::BindRepeating([](Browser* browser) { chrome::NewTab(browser); }, - browser()); + base::BindRepeating( + [](Browser* browser, device::VirtualFidoDevice* device) { + chrome::NewTab(browser); + return true; + }, + browser()); ASSERT_TRUE(content::ExecuteScriptAndExtractString(initial_web_contents, register_script, &result)); EXPECT_THAT(result, ::testing::HasSubstr(kFocusErrorSubstring)); @@ -176,12 +180,13 @@ // Requesting "direct" attestation will trigger a permissions prompt. virtual_device_factory->mutable_state()->simulate_press_callback = - base::BindLambdaForTesting([&]() { + base::BindLambdaForTesting([&](device::VirtualFidoDevice* device) { dialog_model_ = AuthenticatorRequestScheduler::GetRequestDelegateForTest( initial_web_contents) ->WeakDialogModelForTesting(); dialog_model_->AddObserver(this); + return true; }); const std::string get_assertion_with_attestation_script =
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index b32338b..a97bcd1 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -134,6 +134,10 @@ const base::Feature kBundledConnectionHelpFeature{ "BundledConnectionHelp", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enables the UI to configure caption settings. +const base::Feature kCaptionSettings{"CaptionSettings", + base::FEATURE_DISABLED_BY_DEFAULT}; + #if !defined(OS_ANDROID) // Enables logging UKMs for background tab activity by TabActivityWatcher. const base::Feature kTabMetricsLogging{"TabMetricsLogging",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h index 099548f..4c06713 100644 --- a/chrome/common/chrome_features.h +++ b/chrome/common/chrome_features.h
@@ -84,6 +84,9 @@ COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kBundledConnectionHelpFeature; +COMPONENT_EXPORT(CHROME_FEATURES) +extern const base::Feature kCaptionSettings; + #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX) COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCertDualVerificationTrialFeature;
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 358090b..d93967a 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -126,6 +126,9 @@ // are only restored on startup if kRestoreOnStartup is 4. const char kURLsToRestoreOnStartup[] = "session.startup_urls"; +// Boolean that is true when user feedback to Google is allowed. +const char kUserFeedbackAllowed[] = "feedback_allowed"; + // Stores the email address associated with the google account of the custodian // of the supervised user, set when the supervised user is created. const char kSupervisedUserCustodianEmail[] = "profile.managed.custodian_email";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index a44dedb..e344fca 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -59,6 +59,7 @@ extern const char kSupervisedUserSharedSettings[]; extern const char kSupervisedUserWhitelists[]; extern const char kURLsToRestoreOnStartup[]; +extern const char kUserFeedbackAllowed[]; #if BUILDFLAG(ENABLE_RLZ) extern const char kRlzPingDelaySeconds[];
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc index 71b495b..413b525d 100644 --- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc +++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -42,6 +42,10 @@ #include "third_party/blink/public/web/web_widget.h" #include "ui/events/keycodes/keyboard_codes.h" +#if defined(OS_WIN) +#include "third_party/blink/public/web/win/web_font_rendering.h" +#endif + using autofill::FillingStatus; using autofill::FormTracker; using autofill::PasswordForm; @@ -291,6 +295,13 @@ void SetUp() override { ChromeRenderViewTest::SetUp(); +#if defined(OS_WIN) + // Autofill uses the system font to render suggestion previews. On Windows + // an extra step is required to ensure that the system font is configured. + blink::WebFontRendering::SetMenuFontMetrics( + base::ASCIIToUTF16("Arial").c_str(), 12); +#endif + // TODO(crbug/862989): Remove workaround preventing non-test classes to bind // fake_driver_ or fake_pw_client_. password_autofill_agent_->GetPasswordManagerDriver();
diff --git a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc index 5f3875af..c07409e 100644 --- a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc +++ b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
@@ -25,21 +25,12 @@ std::map<std::string, std::string> feature_params; feature_params[std::string(safe_browsing::kTagAndAttributeParamName)] = "div,foo,div,baz,div,attr2,div,attr3,div,longattr4,div,attr5,div,attr6"; - variations::AssociateVariationParams( - safe_browsing::kThreatDomDetailsTagAndAttributeFeature.name, "Group", - feature_params); - base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial( - safe_browsing::kThreatDomDetailsTagAndAttributeFeature.name, "Group"); - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - feature_list->InitializeFromCommandLine( - safe_browsing::kThreatDomDetailsTagAndAttributeFeature.name, - std::string()); - feature_list->AssociateReportingFieldTrial( - safe_browsing::kThreatDomDetailsTagAndAttributeFeature.name, - base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial); std::unique_ptr<base::test::ScopedFeatureList> scoped_list( new base::test::ScopedFeatureList); - scoped_list->InitWithFeatureList(std::move(feature_list)); + scoped_list->InitWithFeaturesAndParameters( + {{safe_browsing::kThreatDomDetailsTagAndAttributeFeature, + feature_params}}, + {}); return scoped_list; }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 8a88340..89448fc 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2138,6 +2138,7 @@ "../browser/ui/ash/keyboard/keyboard_controller_browsertest.cc", "../browser/ui/ash/keyboard/keyboard_end_to_end_browsertest.cc", "../browser/ui/ash/launcher/arc_app_launcher_browsertest.cc", + "../browser/ui/ash/launcher/browser_shortcut_launcher_item_controller_browsertest.cc", "../browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc", "../browser/ui/ash/launcher/chrome_launcher_controller_test_util.cc", "../browser/ui/ash/launcher/chrome_launcher_controller_test_util.h", @@ -2194,6 +2195,7 @@ } if (enable_kiosk_next) { sources += [ + "../browser/chromeos/kiosk_next/kiosk_next_browser_factory_browsertest.cc", "../browser/chromeos/kiosk_next_home/kiosk_next_home_browsertest.cc", "../browser/ui/ash/kiosk_next_shell_client_browsertest.cc", ] @@ -3466,6 +3468,7 @@ "../browser/download/download_commands_unittest.cc", "../browser/download/download_shelf_unittest.cc", "../browser/enterprise_reporting/profile_report_generator_unittest.cc", + "../browser/enterprise_reporting/report_generator_unittest.cc", "../browser/enterprise_reporting/report_scheduler_unittest.cc", "../browser/enterprise_reporting/report_uploader_unittest.cc", "../browser/enterprise_reporting/request_timer_unittest.cc", @@ -3713,6 +3716,9 @@ "../utility/importer/firefox_importer_unittest_utils.h", "../utility/importer/firefox_importer_unittest_utils_mac.cc", "../utility/importer/safari_importer_unittest.mm", + + # Android uses different way of showing feedback page + "../browser/feedback/show_feedback_page_unittest.cc", ] if (is_posix || is_fuchsia) { sources += [ "../browser/process_singleton_posix_unittest.cc" ]
diff --git a/chrome/test/base/chrome_unit_test_suite.cc b/chrome/test/base/chrome_unit_test_suite.cc index 0918712..e28d9c0 100644 --- a/chrome/test/base/chrome_unit_test_suite.cc +++ b/chrome/test/base/chrome_unit_test_suite.cc
@@ -43,6 +43,30 @@ namespace { +class ChromeContentBrowserClientWithoutNetworkServiceInitialization + : public ChromeContentBrowserClient { + public: + // content::ContentBrowserClient: + // Skip some production Network Service code that doesn't work in unit tests. + void OnNetworkServiceCreated( + network::mojom::NetworkService* network_service) override {} + // Overridden to skip a call to ProfileIOData::FromResourceContext downstream + // of ProxyingURLLoaderFactory, which assumes the ResourceContext is a + // ProfileIOData::ResourceContext, but in unit tests it's a mock. + bool WillCreateURLLoaderFactory( + content::BrowserContext* browser_context, + content::RenderFrameHost* frame, + int render_process_id, + bool is_navigation, + bool is_download, + const url::Origin& request_initiator, + network::mojom::URLLoaderFactoryRequest* factory_request, + network::mojom::TrustedURLLoaderHeaderClientPtrInfo* header_client, + bool* bypass_redirect_checks) override { + return false; + } +}; + // Creates a TestingBrowserProcess for each test. class ChromeUnitTestSuiteInitializer : public testing::EmptyTestEventListener { public: @@ -53,7 +77,8 @@ content_client_.reset(new ChromeContentClient); content::SetContentClient(content_client_.get()); - browser_content_client_.reset(new ChromeContentBrowserClient()); + browser_content_client_.reset( + new ChromeContentBrowserClientWithoutNetworkServiceInitialization()); content::SetBrowserClientForTesting(browser_content_client_.get()); utility_content_client_.reset(new ChromeContentUtilityClient()); content::SetUtilityClientForTesting(utility_content_client_.get());
diff --git a/chrome/test/base/run_all_unittests.cc b/chrome/test/base/run_all_unittests.cc index 80ffb261..1c48bb0 100644 --- a/chrome/test/base/run_all_unittests.cc +++ b/chrome/test/base/run_all_unittests.cc
@@ -11,7 +11,6 @@ #include "chrome/test/base/chrome_unit_test_suite.h" #include "content/public/test/unittest_test_suite.h" #include "mojo/core/embedder/scoped_ipc_support.h" -#include "services/network/public/cpp/features.h" #if defined(OS_WIN) #include "chrome/install_static/test/scoped_install_details.h" @@ -22,9 +21,7 @@ // unit_tests don't currently work with the Network Service enabled. // https://crbug.com/966633. - content::UnitTestTestSuite test_suite( - new ChromeUnitTestSuite(argc, argv), - network::features::kNetworkServiceFeatureName); + content::UnitTestTestSuite test_suite(new ChromeUnitTestSuite(argc, argv)); base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart); mojo::core::ScopedIPCSupport ipc_support(
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc index 9adf436..357352a 100644 --- a/chrome/test/base/test_browser_window.cc +++ b/chrome/test/base/test_browser_window.cc
@@ -152,6 +152,10 @@ return nullptr; } +ExtensionsContainer* TestBrowserWindow::GetExtensionsContainer() { + return nullptr; +} + content::KeyboardEventProcessingResult TestBrowserWindow::PreHandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) {
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h index 919853e..6499a88 100644 --- a/chrome/test/base/test_browser_window.h +++ b/chrome/test/base/test_browser_window.h
@@ -103,6 +103,7 @@ void ResetToolbarTabState(content::WebContents* contents) override {} void FocusToolbar() override {} ToolbarActionsBar* GetToolbarActionsBar() override; + ExtensionsContainer* GetExtensionsContainer() override; void ToolbarSizeChanged(bool is_animating) override {} void TabDraggingStatusChanged(bool is_dragging) override {} void FocusAppMenu() override {}
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index f055e01..6fe5698 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc
@@ -86,7 +86,6 @@ app_locale_("en"), is_shutting_down_(false), local_state_(nullptr), - io_thread_(nullptr), rappor_service_(nullptr), platform_part_(new TestingBrowserProcessPlatformPart()), test_network_connection_tracker_( @@ -146,10 +145,6 @@ return rappor_service_; } -IOThread* TestingBrowserProcess::io_thread() { - return io_thread_; -} - SystemNetworkContextManager* TestingBrowserProcess::system_network_context_manager() { return nullptr; @@ -477,10 +472,6 @@ local_state_ = local_state; } -void TestingBrowserProcess::SetIOThread(IOThread* io_thread) { - io_thread_ = io_thread; -} - void TestingBrowserProcess::ShutdownBrowserPolicyConnector() { if (browser_policy_connector_) browser_policy_connector_->Shutdown();
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index 55d8e75d..11595f4f 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h
@@ -25,7 +25,6 @@ #include "printing/buildflags/buildflags.h" class BackgroundModeManager; -class IOThread; class NotificationPlatformBridge; class NotificationUIManager; class PrefService; @@ -75,7 +74,6 @@ override; metrics::MetricsService* metrics_service() override; rappor::RapporServiceImpl* rappor_service() override; - IOThread* io_thread() override; SystemNetworkContextManager* system_network_context_manager() override; scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory() override; @@ -144,7 +142,6 @@ // afterwards (using ScopedTestingLocalState, for example). void SetLocalState(PrefService* local_state); void SetProfileManager(ProfileManager* profile_manager); - void SetIOThread(IOThread* io_thread); void SetSafeBrowsingService(safe_browsing::SafeBrowsingService* sb_service); void SetRulesetService( std::unique_ptr<subresource_filter::RulesetService> ruleset_service); @@ -204,7 +201,6 @@ // The following objects are not owned by TestingBrowserProcess: PrefService* local_state_; - IOThread* io_thread_; scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; rappor::RapporServiceImpl* rappor_service_;
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 35e96b4..51d72b8 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -31,6 +31,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h" #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.h" +#include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/favicon/favicon_service_factory.h" @@ -103,6 +104,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/cookie_store_factory.h" +#include "content/public/browser/network_service_instance.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/storage_partition.h" @@ -117,7 +119,6 @@ #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_test_util.h" #include "services/identity/public/cpp/identity_test_utils.h" -#include "services/network/public/cpp/features.h" #include "services/network/test/test_network_connection_tracker.h" #include "services/service_manager/public/cpp/service.h" #include "testing/gmock/include/gmock/gmock.h" @@ -1105,12 +1106,14 @@ network_context_.get(), mojo::MakeRequest(&network_context_ptr)); return network_context_ptr; } - if (base::FeatureList::IsEnabled(network::features::kNetworkService)) { - network::mojom::NetworkContextPtr network_context; - network_context_request_ = mojo::MakeRequest(&network_context); - return network_context; - } - return nullptr; + network::mojom::NetworkContextPtr network_context; + network::mojom::NetworkContextParamsPtr context_params = + network::mojom::NetworkContextParams::New(); + context_params->user_agent = GetUserAgent(); + context_params->accept_language = "en-us,en"; + content::GetNetworkService()->CreateNetworkContext( + MakeRequest(&network_context), std::move(context_params)); + return network_context; } TestingProfile::Builder::Builder()
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h index e754e915..77868e6 100644 --- a/chrome/test/base/testing_profile.h +++ b/chrome/test/base/testing_profile.h
@@ -428,9 +428,6 @@ std::unique_ptr<net::CookieStore, content::BrowserThread::DeleteOnIOThread> extensions_cookie_store_; - // Holds a dummy network context request to avoid triggering connection error - // handler. - network::mojom::NetworkContextRequest network_context_request_; std::unique_ptr<network::mojom::NetworkContext> network_context_; mojo::BindingSet<network::mojom::NetworkContext> network_context_bindings_;
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 07833926..8fd9782 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3325,6 +3325,16 @@ ] }, + "UserFeedbackAllowed": { + "os": ["win", "linux", "mac", "chromeos"], + "can_be_recommended": false, + "test_policy": { "UserFeedbackAllowed": false }, + "pref_mappings": [ + { "pref": "feedback_allowed" } + ] + }, + + "ArcEnabled": { "os": ["chromeos"], "can_be_recommended": false,
diff --git a/chrome/test/data/webui/settings/edit_dictionary_page_test.js b/chrome/test/data/webui/settings/edit_dictionary_page_test.js index bfb6a4d..f99918e 100644 --- a/chrome/test/data/webui/settings/edit_dictionary_page_test.js +++ b/chrome/test/data/webui/settings/edit_dictionary_page_test.js
@@ -91,6 +91,22 @@ 'none'); // Make sure add-word button actually clickable. }); + test('add duplicate word', function() { + const WORD = 'unique'; + languageSettingsPrivate.onCustomDictionaryChanged.callListeners([WORD], []); + editDictPage.$.newWord.value = `${WORD} ${WORD}`; + Polymer.dom.flush(); + assertFalse(editDictPage.$.addWord.disabled); + + editDictPage.$.newWord.value = WORD; + Polymer.dom.flush(); + assertTrue(editDictPage.$.addWord.disabled); + + languageSettingsPrivate.onCustomDictionaryChanged.callListeners([], [WORD]); + Polymer.dom.flush(); + assertFalse(editDictPage.$.addWord.disabled); + }); + test('spellcheck edit dictionary page message when empty', function() { assertTrue(!!editDictPage); return languageSettingsPrivate.whenCalled('getSpellcheckWords')
diff --git a/chrome/test/data/webui/signin_browsertest.h b/chrome/test/data/webui/signin_browsertest.h index 6fe2d56b..c2a25a6 100644 --- a/chrome/test/data/webui/signin_browsertest.h +++ b/chrome/test/data/webui/signin_browsertest.h
@@ -21,9 +21,9 @@ void EnableUnity(); private: + std::unique_ptr<ScopedAccountConsistency> scoped_account_consistency_; std::unique_ptr<unified_consent::ScopedUnifiedConsent> scoped_unified_consent_; - std::unique_ptr<ScopedAccountConsistency> scoped_account_consistency_; DISALLOW_COPY_AND_ASSIGN(SigninBrowserTest); };
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_consent_not_granted.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_consent_not_granted.html new file mode 100644 index 0000000..121e4022 --- /dev/null +++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_consent_not_granted.html
@@ -0,0 +1,25 @@ +<!doctype html> +<!-- +Used to test that the promise returned by WebXR's requestSession rejects if +the user denies permission on a consent dialog. +--> +<html> + <head> + <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css"> + </head> + <body> + <canvas id="webgl-canvas"></canvas> + <script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script> + <script src="../resources/webxr_e2e.js"></script> + <script src="../resources/webxr_boilerplate.js"></script> + <script> + function onImmersiveRequestWithConsent() { + navigator.xr.requestSession('immersive-vr').then(() => { + assert_unreached("requestPresent promise shouldn't resolve when consent not granted"); + }).catch(() => { + done(); + }); + } + </script> + </body> +</html>
diff --git a/chromecast/external_mojo/external_service_support/BUILD.gn b/chromecast/external_mojo/external_service_support/BUILD.gn index 46f0562e..4a34e42 100644 --- a/chromecast/external_mojo/external_service_support/BUILD.gn +++ b/chromecast/external_mojo/external_service_support/BUILD.gn
@@ -26,6 +26,7 @@ ] deps = [ "//base", + "//base:base_static", ] }
diff --git a/chromecast/external_mojo/external_service_support/chromium_service.cc b/chromecast/external_mojo/external_service_support/chromium_service.cc index c74d207..74773e3e 100644 --- a/chromecast/external_mojo/external_service_support/chromium_service.cc +++ b/chromecast/external_mojo/external_service_support/chromium_service.cc
@@ -55,8 +55,13 @@ void ChromiumServiceWrapper::OnBindInterface( const std::string& interface_name, mojo::ScopedMessagePipeHandle interface_pipe) { - chromium_service_->OnBindInterface(service_manager::BindSourceInfo(), - interface_name, std::move(interface_pipe)); + chromium_service_->OnBindInterface( + service_manager::BindSourceInfo( + service_manager::Identity("unique", base::Token::CreateRandom(), + base::Token::CreateRandom(), + base::Token::CreateRandom()), + service_manager::CapabilitySet()), + interface_name, std::move(interface_pipe)); } service_manager::mojom::ServiceRequest CreateChromiumServiceRequest(
diff --git a/chromecast/external_mojo/external_service_support/process_setup.cc b/chromecast/external_mojo/external_service_support/process_setup.cc index a7ff784..f8359abd 100644 --- a/chromecast/external_mojo/external_service_support/process_setup.cc +++ b/chromecast/external_mojo/external_service_support/process_setup.cc
@@ -7,7 +7,9 @@ #include <locale.h> #include <signal.h> +#include "base/base_switches.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/logging.h" #include "build/build_config.h" @@ -23,11 +25,17 @@ #endif base::CommandLine::Init(argc, argv); + logging::LoggingSettings settings; settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR; logging::InitLogging(settings); + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + base::FeatureList::InitializeInstance( + command_line->GetSwitchValueASCII(switches::kEnableFeatures), + command_line->GetSwitchValueASCII(switches::kDisableFeatures)); + CHECK_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN)); }
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc index c19970a..eb3d1b7 100644 --- a/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -597,8 +597,8 @@ MockAutofillDownloadManager* download_manager_; TestPersonalDataManager personal_data_; std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_; - base::test::ScopedFeatureList scoped_feature_list_; variations::testing::VariationParamsManager variation_params_; + base::test::ScopedFeatureList scoped_feature_list_; private: int ToHistogramSample(AutofillMetrics::CardUploadDecisionMetric metric) {
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc index bfd515ac..532876a 100644 --- a/components/autofill/core/browser/payments/payments_client_unittest.cc +++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -574,6 +574,9 @@ // headers. Also, the variations header provider may have been registered to // observe some other field trial list, so reset it. variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); + // Note: This needs a base::FieldTrialList instance because it does not use + // ScopedFeatureList, which provides its own, unlike other tests that do via + // DisableAutofillSendExperimentIdsInPaymentsRPCs(). base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartGettingUploadDetails(); @@ -590,7 +593,6 @@ // observe some other field trial list, so reset it. DisableAutofillSendExperimentIdsInPaymentsRPCs(); variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); - base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartGettingUploadDetails(); @@ -702,6 +704,9 @@ // headers. Also, the variations header provider may have been registered to // observe some other field trial list, so reset it. variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); + // Note: This needs a base::FieldTrialList instance because it does not use + // ScopedFeatureList, which provides its own, unlike other tests that do via + // DisableAutofillSendExperimentIdsInPaymentsRPCs(). base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartUploading(/*include_cvc=*/true); @@ -719,7 +724,6 @@ // observe some other field trial list, so reset it. DisableAutofillSendExperimentIdsInPaymentsRPCs(); variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); - base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartUploading(/*include_cvc=*/true); @@ -734,6 +738,9 @@ // headers. Also, the variations header provider may have been registered to // observe some other field trial list, so reset it. variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); + // Note: This needs a base::FieldTrialList instance because it does not use + // ScopedFeatureList, which provides its own, unlike other tests that do via + // DisableAutofillSendExperimentIdsInPaymentsRPCs(). base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartUnmasking(); @@ -751,7 +758,6 @@ // observe some other field trial list, so reset it. DisableAutofillSendExperimentIdsInPaymentsRPCs(); variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); - base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartUnmasking(); @@ -767,7 +773,6 @@ // observe some other field trial list, so reset it. EnableAutofillSendExperimentIdsInPaymentsRPCs(); variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); - base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartMigrating(/*has_cardholder_name=*/true); IssueOAuthToken(); @@ -784,7 +789,6 @@ // observe some other field trial list, so reset it. DisableAutofillSendExperimentIdsInPaymentsRPCs(); variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting(); - base::FieldTrialList field_trial_list_(nullptr); CreateFieldTrialWithId("AutofillTest", "Group", 369); StartMigrating(/*has_cardholder_name=*/true);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc index b80e6d3..494a2bb 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -278,7 +278,13 @@ GetConfiguredProxiesForHttp()); } -TEST_F(DataReductionProxyConfigTest, TestOnNetworkChanged) { +// Flaky on Linux. http://crbug.com/973385 +#if defined(OS_LINUX) +#define MAYBE_TestOnNetworkChanged DISABLED_TestOnNetworkChanged +#else +#define MAYBE_TestOnNetworkChanged TestOnNetworkChanged +#endif +TEST_F(DataReductionProxyConfigTest, MAYBE_TestOnNetworkChanged) { // The test manually controls the fetch of warmup URL and the response. test_context_->DisableWarmupURLFetchCallback();
diff --git a/components/offline_pages/core/prefetch/prefetch_request_test_base.cc b/components/offline_pages/core/prefetch/prefetch_request_test_base.cc index 76a72d3..66ac5618 100644 --- a/components/offline_pages/core/prefetch/prefetch_request_test_base.cc +++ b/components/offline_pages/core/prefetch/prefetch_request_test_base.cc
@@ -31,9 +31,6 @@ PrefetchRequestTestBase::~PrefetchRequestTestBase() {} void PrefetchRequestTestBase::SetUp() { - field_trial_list_ = std::make_unique<base::FieldTrialList>( - std::make_unique<base::MockEntropyProvider>()); - test_url_loader_factory_.SetInterceptor( base::BindLambdaForTesting([&](const network::ResourceRequest& request) { last_resource_request_ = request; @@ -41,23 +38,11 @@ } void PrefetchRequestTestBase::SetUpExperimentOption() { - const std::string kTrialName = "trial_name"; - const std::string kGroupName = "group_name"; - - scoped_refptr<base::FieldTrial> trial = - base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName); - std::map<std::string, std::string> params; params[kPrefetchingOfflinePagesExperimentsOption] = kExperimentValueSetInFieldTrial; - base::AssociateFieldTrialParams(kTrialName, kGroupName, params); - - std::unique_ptr<base::FeatureList> feature_list = - std::make_unique<base::FeatureList>(); - feature_list->RegisterFieldTrialOverride( - kPrefetchingOfflinePagesFeature.name, - base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); - scoped_feature_list_.InitWithFeatureList(std::move(feature_list)); + scoped_feature_list_.InitAndEnableFeatureWithParameters( + kPrefetchingOfflinePagesFeature, params); } void PrefetchRequestTestBase::RespondWithNetError(int net_error) {
diff --git a/components/offline_pages/core/prefetch/prefetch_request_test_base.h b/components/offline_pages/core/prefetch/prefetch_request_test_base.h index a6a81eb..63b2fe5f 100644 --- a/components/offline_pages/core/prefetch/prefetch_request_test_base.h +++ b/components/offline_pages/core/prefetch/prefetch_request_test_base.h
@@ -62,7 +62,6 @@ test_shared_url_loader_factory_; network::ResourceRequest last_resource_request_; - std::unique_ptr<base::FieldTrialList> field_trial_list_; base::test::ScopedFeatureList scoped_feature_list_; };
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index c67d867d..1a7a698 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -15651,6 +15651,26 @@ If this policy is set, the user cannot change or override it.''', }, { + 'name': 'UserFeedbackAllowed', + 'type': 'main', + 'schema': { + 'type': 'boolean', + }, + 'supported_on': ['chrome.*:77-', 'chrome_os:77-'], + 'features': { + 'dynamic_refresh': True, + 'per_profile': True, + }, + 'example_value': True, + 'id': 570, + 'caption': '''Allow user feedback''', + 'tags': [], + 'desc': '''Allow user feedback. + If the policy is set to false, users can not send feedback to Google. + + If the policy is unset or set to true, users can send feedback to Google via Menu->Help->Report an Issue or key combination.''' + }, + { 'name': 'SamlPasswordExpirationAdvanceWarningDays', 'type': 'int', 'schema': { @@ -16840,6 +16860,6 @@ ], 'placeholders': [], 'deleted_policy_ids': [412, 546, 562], - 'highest_id_currently_used': 569, + 'highest_id_currently_used': 570, 'highest_atomic_group_id_currently_used': 37 }
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc index 1d2074f..87a8c630a 100644 --- a/components/signin/core/browser/gaia_cookie_manager_service.cc +++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -251,9 +251,11 @@ return base::JoinString(results, ","); } -void GaiaCookieManagerService::ExternalCcResultFetcher::Start() { +void GaiaCookieManagerService::ExternalCcResultFetcher::Start( + base::OnceClosure callback) { DCHECK(!helper_->external_cc_result_fetched_); m_external_cc_result_start_time_ = base::Time::Now(); + callback_ = std::move(callback); CleanupTransientState(); results_.clear(); @@ -440,11 +442,7 @@ time_to_check_connections); helper_->external_cc_result_fetched_ = true; - // Since the ExternalCCResultFetcher is only Started in place of calling - // StartFetchingMergeSession, we can assume we need to call - // StartFetchingMergeSession. If this assumption becomes invalid, a Callback - // will need to be passed to Start() and Run() here. - helper_->StartFetchingMergeSession(); + std::move(callback_).Run(); } GaiaCookieManagerService::GaiaCookieManagerService( @@ -507,11 +505,7 @@ } if (requests_.size() == 1) { fetcher_retries_ = 0; - // Unretained is safe because GaiaCookieManagerService owns the helper. - oauth_multilogin_helper_ = std::make_unique<signin::OAuthMultiloginHelper>( - signin_client_, token_service_, account_ids, - base::BindOnce(&GaiaCookieManagerService::OnSetAccountsFinished, - base::Unretained(this))); + StartSetAccounts(); } } @@ -770,7 +764,9 @@ if (!external_cc_result_fetched_ && !external_cc_result_fetcher_.IsRunning()) { - external_cc_result_fetcher_.Start(); + external_cc_result_fetcher_.Start( + base::BindOnce(&GaiaCookieManagerService::StartFetchingMergeSession, + weak_ptr_factory_.GetWeakPtr())); return; } @@ -973,6 +969,32 @@ gaia_auth_fetcher_->StartListAccounts(); } +void GaiaCookieManagerService::StartSetAccounts() { + DCHECK(!requests_.empty()); + DCHECK_EQ(GaiaCookieRequestType::SET_ACCOUNTS, + requests_.front().request_type()); + DCHECK(!requests_.front().accounts().empty()); + + if (!external_cc_result_fetched_ && + !external_cc_result_fetcher_.IsRunning()) { + external_cc_result_fetcher_.Start( + base::BindOnce(&GaiaCookieManagerService::StartSetAccounts, + weak_ptr_factory_.GetWeakPtr())); + return; + } + + // TODO(triploblastic): remove this block in the second part of the fix. + std::vector<std::string> account_ids; + for (const auto& id : requests_.front().accounts()) + account_ids.push_back(id.first.id); + + oauth_multilogin_helper_ = std::make_unique<signin::OAuthMultiloginHelper>( + signin_client_, token_service_, account_ids, + external_cc_result_fetcher_.GetExternalCcResult(), + base::BindOnce(&GaiaCookieManagerService::OnSetAccountsFinished, + weak_ptr_factory_.GetWeakPtr())); +} + void GaiaCookieManagerService::OnSetAccountsFinished( signin::SetAccountsInCookieResult result) { MarkListAccountsStale(); @@ -1009,18 +1031,7 @@ weak_ptr_factory_.GetWeakPtr())); break; case GaiaCookieRequestType::SET_ACCOUNTS: { - DCHECK(!requests_.front().accounts().empty()); - - // TODO(triploblastic): remove this block in the second part of the fix. - std::vector<std::string> account_ids; - for (const auto& id : requests_.front().accounts()) - account_ids.push_back(id.first.id); - - oauth_multilogin_helper_ = - std::make_unique<signin::OAuthMultiloginHelper>( - signin_client_, token_service_, account_ids, - base::BindOnce(&GaiaCookieManagerService::OnSetAccountsFinished, - weak_ptr_factory_.GetWeakPtr())); + StartSetAccounts(); break; } case GaiaCookieRequestType::LOG_OUT:
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.h b/components/signin/core/browser/gaia_cookie_manager_service.h index 77055d1c..a9f6f468 100644 --- a/components/signin/core/browser/gaia_cookie_manager_service.h +++ b/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -173,7 +173,7 @@ // Start fetching the external CC result. If a fetch is already in progress // it is canceled. - void Start(); + void Start(base::OnceClosure callback); // Are external URLs still being checked? bool IsRunning(); @@ -210,6 +210,7 @@ LoaderToToken loaders_; ResultMap results_; base::Time m_external_cc_result_start_time_; + base::OnceClosure callback_; DISALLOW_COPY_AND_ASSIGN(ExternalCcResultFetcher); }; @@ -358,6 +359,9 @@ // Virtual for testing purpose. virtual void StartFetchingLogOut(); + // Starts setting account using multilogin endpoint. + void StartSetAccounts(); + // Start the next request, if needed. void HandleNextRequest();
diff --git a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc index 5a27c8f..60a6773 100644 --- a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc +++ b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -807,7 +807,9 @@ InstrumentedGaiaCookieManagerService helper(token_service(), signin_client()); GaiaCookieManagerService::ExternalCcResultFetcher result_fetcher(&helper); EXPECT_CALL(helper, StartFetchingMergeSession()); - result_fetcher.Start(); + result_fetcher.Start(base::BindOnce( + &InstrumentedGaiaCookieManagerService::StartFetchingMergeSession, + base::Unretained(&helper))); // Simulate a successful completion of GetCheckConnctionInfo. SimulateGetCheckConnectionInfoSuccess( @@ -832,7 +834,9 @@ InstrumentedGaiaCookieManagerService helper(token_service(), signin_client()); GaiaCookieManagerService::ExternalCcResultFetcher result_fetcher(&helper); EXPECT_CALL(helper, StartFetchingMergeSession()); - result_fetcher.Start(); + result_fetcher.Start(base::BindOnce( + &InstrumentedGaiaCookieManagerService::StartFetchingMergeSession, + base::Unretained(&helper))); // Simulate a successful completion of GetCheckConnctionInfo. SimulateGetCheckConnectionInfoSuccess( @@ -861,7 +865,9 @@ InstrumentedGaiaCookieManagerService helper(token_service(), signin_client()); GaiaCookieManagerService::ExternalCcResultFetcher result_fetcher(&helper); EXPECT_CALL(helper, StartFetchingMergeSession()); - result_fetcher.Start(); + result_fetcher.Start(base::BindOnce( + &InstrumentedGaiaCookieManagerService::StartFetchingMergeSession, + base::Unretained(&helper))); // Simulate a successful completion of GetCheckConnctionInfo. SimulateGetCheckConnectionInfoSuccess( @@ -903,7 +909,9 @@ TEST_F(GaiaCookieManagerServiceTest, UbertokenSuccessFetchesExternalCCOnce) { InstrumentedGaiaCookieManagerService helper(token_service(), signin_client()); - helper.external_cc_result_fetcher_for_testing()->Start(); + helper.external_cc_result_fetcher_for_testing()->Start(base::BindOnce( + &InstrumentedGaiaCookieManagerService::StartFetchingMergeSession, + base::Unretained(&helper))); EXPECT_CALL(helper, StartFetchingUbertoken()); helper.AddAccountToCookie(
diff --git a/components/signin/core/browser/oauth_multilogin_helper.cc b/components/signin/core/browser/oauth_multilogin_helper.cc index 230678c..ab38dc09 100644 --- a/components/signin/core/browser/oauth_multilogin_helper.cc +++ b/components/signin/core/browser/oauth_multilogin_helper.cc
@@ -42,10 +42,12 @@ SigninClient* signin_client, OAuth2TokenService* token_service, const std::vector<std::string>& account_ids, + const std::string& external_cc_result, base::OnceCallback<void(signin::SetAccountsInCookieResult)> callback) : signin_client_(signin_client), token_service_(token_service), account_ids_(account_ids), + external_cc_result_(external_cc_result), callback_(std::move(callback)), weak_ptr_factory_(this) { DCHECK(signin_client_); @@ -102,7 +104,8 @@ DCHECK_EQ(token_id_pairs_.size(), account_ids_.size()); gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(this, gaia::GaiaSource::kChrome); - gaia_auth_fetcher_->StartOAuthMultilogin(token_id_pairs_); + gaia_auth_fetcher_->StartOAuthMultilogin(token_id_pairs_, + external_cc_result_); } void OAuthMultiloginHelper::OnOAuthMultiloginFinished(
diff --git a/components/signin/core/browser/oauth_multilogin_helper.h b/components/signin/core/browser/oauth_multilogin_helper.h index 5fcda19..69064a9 100644 --- a/components/signin/core/browser/oauth_multilogin_helper.h +++ b/components/signin/core/browser/oauth_multilogin_helper.h
@@ -39,6 +39,7 @@ SigninClient* signin_client, OAuth2TokenService* token_service, const std::vector<std::string>& account_ids, + const std::string& external_cc_result, base::OnceCallback<void(signin::SetAccountsInCookieResult)> callback); ~OAuthMultiloginHelper() override; @@ -74,6 +75,8 @@ // Account ids to set in the cookie. const std::vector<std::string> account_ids_; + // See GaiaCookieManagerService::ExternalCcResultFetcher for details. + const std::string external_cc_result_; // Access tokens, in the same order as the account ids. std::vector<GaiaAuthFetcher::MultiloginTokenIDPair> token_id_pairs_;
diff --git a/components/signin/core/browser/oauth_multilogin_helper_unittest.cc b/components/signin/core/browser/oauth_multilogin_helper_unittest.cc index ce0059202..e76e385 100644 --- a/components/signin/core/browser/oauth_multilogin_helper_unittest.cc +++ b/components/signin/core/browser/oauth_multilogin_helper_unittest.cc
@@ -26,6 +26,8 @@ const char kAccessToken[] = "access_token_1"; const char kAccessToken2[] = "access_token_2"; +const char kExternalCcResult[] = "youtube:OK"; + constexpr int kMaxFetcherRetries = 3; const char kMultiloginSuccessResponse[] = @@ -76,6 +78,35 @@ } )"; +const char kMultiloginSuccessResponseWithSecondaryDomain[] = + R"()]}' + { + "status": "OK", + "cookies":[ + { + "name":"SID", + "value":"SID_value", + "domain":".youtube.com", + "path":"/", + "isSecure":true, + "isHttpOnly":false, + "priority":"HIGH", + "maxAge":63070000 + }, + { + "name":"FOO", + "value":"FOO_value", + "domain":".google.com", + "path":"/", + "isSecure":true, + "isHttpOnly":false, + "priority":"HIGH", + "maxAge":63070000 + } + ] + } + )"; + const char kMultiloginRetryResponse[] = R"()]}' { @@ -140,7 +171,15 @@ std::unique_ptr<OAuthMultiloginHelper> CreateHelper( const std::vector<std::string> account_ids) { return std::make_unique<OAuthMultiloginHelper>( - &test_signin_client_, token_service(), account_ids, + &test_signin_client_, token_service(), account_ids, std::string(), + base::BindOnce(&OAuthMultiloginHelperTest::OnOAuthMultiloginFinished, + base::Unretained(this))); + } + + std::unique_ptr<OAuthMultiloginHelper> CreateHelperWithExternalCcResult( + const std::vector<std::string> account_ids) { + return std::make_unique<OAuthMultiloginHelper>( + &test_signin_client_, token_service(), account_ids, kExternalCcResult, base::BindOnce(&OAuthMultiloginHelperTest::OnOAuthMultiloginFinished, base::Unretained(this))); } @@ -154,6 +193,11 @@ "?source=ChromiumBrowser"; } + std::string multilogin_url_with_external_cc_result() const { + return GaiaUrls::GetInstance()->oauth_multilogin_url().spec() + + "?source=ChromiumBrowser&externalCcResult=" + kExternalCcResult; + } + MockCookieManager* cookie_manager() { return mock_cookie_manager_; } MockTokenService* token_service() { return &mock_token_service_; } @@ -236,6 +280,43 @@ EXPECT_EQ(signin::SetAccountsInCookieResult::kSuccess, result_); } +// Multiple cookies in the multilogin response. +TEST_F(OAuthMultiloginHelperTest, SuccessWithExternalCcResult) { + token_service()->AddAccount(kAccountId); + std::unique_ptr<OAuthMultiloginHelper> helper = + CreateHelperWithExternalCcResult({kAccountId}); + + // Configure mock cookie manager: + // - check that the cookie is the expected one + // - immediately invoke the callback + EXPECT_CALL( + *cookie_manager(), + SetCanonicalCookie(CookieMatcher("SID", "SID_value", ".youtube.com"), + "https", testing::_, testing::_)) + .WillOnce(::testing::Invoke(RunSetCookieCallbackWithSuccess)); + EXPECT_CALL( + *cookie_manager(), + SetCanonicalCookie(CookieMatcher("FOO", "FOO_value", ".google.com"), + "https", testing::_, testing::_)) + .WillOnce(::testing::Invoke(RunSetCookieCallbackWithSuccess)); + + // Issue access token. + OAuth2AccessTokenConsumer::TokenResponse success_response; + success_response.access_token = kAccessToken; + token_service()->IssueAllTokensForAccount(kAccountId, success_response); + + // Multilogin call. + EXPECT_FALSE(callback_called_); + EXPECT_TRUE( + url_loader()->IsPending(multilogin_url_with_external_cc_result())); + url_loader()->AddResponse(multilogin_url_with_external_cc_result(), + kMultiloginSuccessResponseWithSecondaryDomain); + EXPECT_FALSE( + url_loader()->IsPending(multilogin_url_with_external_cc_result())); + EXPECT_TRUE(callback_called_); + EXPECT_EQ(signin::SetAccountsInCookieResult::kSuccess, result_); +} + // Failure to get the access token. TEST_F(OAuthMultiloginHelperTest, OneAccountAccessTokenFailure) { token_service()->AddAccount(kAccountId);
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc index ba77b0ff..edd414b 100644 --- a/components/translate/core/browser/translate_prefs.cc +++ b/components/translate/core/browser/translate_prefs.cc
@@ -91,9 +91,6 @@ #endif }; -const base::Feature kCompactTranslateInfobarIOS{ - "CompactTranslateInfobarIOS", base::FEATURE_ENABLED_BY_DEFAULT}; - DenialTimeUpdate::DenialTimeUpdate(PrefService* prefs, const std::string& language, size_t max_denial_count)
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h index 1acf50e..2f010c6b 100644 --- a/components/translate/core/browser/translate_prefs.h +++ b/components/translate/core/browser/translate_prefs.h
@@ -46,9 +46,6 @@ // Enable the "Translate" item in the overflow menu on Mobile. extern const base::Feature kTranslateMobileManualTrigger; -// Enables the new compact Translate infobar on iOS. -extern const base::Feature kCompactTranslateInfobarIOS; - // Minimum number of times the user must accept a translation before we show // a shortcut to the "Always Translate" functionality. #if defined(OS_ANDROID) || defined(OS_IOS)
diff --git a/components/url_formatter/url_fixer.cc b/components/url_formatter/url_fixer.cc index 3afc7008..502f598 100644 --- a/components/url_formatter/url_fixer.cc +++ b/components/url_formatter/url_fixer.cc
@@ -563,11 +563,11 @@ return GURL(); } - // 'about:blank' is special-cased in various places in the code so it - // shouldn't be transformed into 'chrome://blank' as the code below will do. + // 'about:blank' and 'about:srcdoc' are special-cased in various places in the + // code and shouldn't use the chrome: scheme. if (base::LowerCaseEqualsASCII(scheme, url::kAboutScheme)) { GURL about_url(base::ToLowerASCII(trimmed)); - if (about_url.IsAboutBlank()) + if (about_url.IsAboutBlank() || about_url.IsAboutSrcdoc()) return about_url; }
diff --git a/components/url_formatter/url_fixer_unittest.cc b/components/url_formatter/url_fixer_unittest.cc index 05a2b54..91c2115 100644 --- a/components/url_formatter/url_fixer_unittest.cc +++ b/components/url_formatter/url_fixer_unittest.cc
@@ -311,9 +311,9 @@ if (url.length() <= 8) return false; if (std::string("file:///") != url.substr(0, 8)) - return false; // no file:/// prefix + return false; // no file:/// prefix if (url.find('\\') != std::string::npos) - return false; // contains backslashes + return false; // contains backslashes base::FilePath derived_path; net::FileURLToFilePath(GURL(url), &derived_path); @@ -339,6 +339,11 @@ {"about:version", "chrome://version/"}, {"about:blank", "about:blank"}, {"About:blaNk", "about:blank"}, + {"about:blank#blah", "about:blank#blah"}, + {"about:blank/#blah", "about:blank/#blah"}, + {"about:srcdoc", "about:srcdoc"}, + {"about:srcdoc#blah", "about:srcdoc#blah"}, + {"about:srcdoc/#blah", "about:srcdoc/#blah"}, {"about:usr:pwd@hst:20/pth?qry#ref", "chrome://hst/pth?qry#ref"}, {"about://usr:pwd@hst/pth?qry#ref", "chrome://hst/pth?qry#ref"}, {"chrome:usr:pwd@hst/pth?qry#ref", "chrome://hst/pth?qry#ref"}, @@ -398,7 +403,6 @@ {"chrome-devtools://bundled/devtools/inspector.html?ws=ws://localhost:9222/" "guid", "devtools://bundled/devtools/inspector.html?ws=ws://localhost:9222/guid"}, - }; TEST(URLFixerTest, FixupURL) {
diff --git a/components/variations/field_trial_config/field_trial_util.cc b/components/variations/field_trial_config/field_trial_util.cc index 43f914a..2c85d68 100644 --- a/components/variations/field_trial_config/field_trial_util.cc +++ b/components/variations/field_trial_config/field_trial_util.cc
@@ -15,12 +15,10 @@ #include "base/command_line.h" #include "base/feature_list.h" #include "base/metrics/field_trial.h" -#include "base/strings/string_split.h" -#include "base/strings/stringprintf.h" +#include "base/metrics/field_trial_params.h" #include "base/strings/utf_string_conversions.h" #include "base/system/sys_info.h" #include "components/variations/field_trial_config/fieldtrial_testing_config.h" -#include "components/variations/variations_associated_data.h" #include "components/variations/variations_seed_processor.h" #include "net/base/escape.h" #include "ui/base/device_form_factor.h" @@ -89,12 +87,12 @@ const VariationsSeedProcessor::UIStringOverrideCallback& callback, base::FeatureList* feature_list) { if (experiment.params_size != 0) { - std::map<std::string, std::string> params; + base::FieldTrialParams params; for (size_t i = 0; i < experiment.params_size; ++i) { const FieldTrialTestingExperimentParams& param = experiment.params[i]; params[param.key] = param.value; } - AssociateVariationParams(study_name, experiment.name, params); + base::AssociateFieldTrialParams(study_name, experiment.name, params); } base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(study_name, experiment.name); @@ -188,55 +186,8 @@ } bool AssociateParamsFromString(const std::string& varations_string) { - // Format: Trial1.Group1:k1/v1/k2/v2,Trial2.Group2:k1/v1/k2/v2 - std::set<std::pair<std::string, std::string>> trial_groups; - for (const base::StringPiece& experiment_group : base::SplitStringPiece( - varations_string, ",", - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { - std::vector<base::StringPiece> experiment = base::SplitStringPiece( - experiment_group, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - if (experiment.size() != 2) { - DLOG(ERROR) << "Experiment and params should be separated by ':'"; - return false; - } - - std::vector<std::string> group_parts = base::SplitString( - experiment[0], ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - if (group_parts.size() != 2) { - DLOG(ERROR) << "Trial and group name should be separated by '.'"; - return false; - } - - std::vector<std::string> key_values = base::SplitString( - experiment[1], "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - if (key_values.size() % 2 != 0) { - DLOG(ERROR) << "Param name and param value should be separated by '/'"; - return false; - } - std::string trial = UnescapeValue(group_parts[0]); - std::string group = UnescapeValue(group_parts[1]); - auto trial_group = std::make_pair(trial, group); - if (trial_groups.find(trial_group) != trial_groups.end()) { - DLOG(ERROR) << base::StringPrintf( - "A (trial, group) pair listed more than once. (%s, %s)", - trial.c_str(), group.c_str()); - return false; - } - trial_groups.insert(trial_group); - std::map<std::string, std::string> params; - for (size_t i = 0; i < key_values.size(); i += 2) { - std::string key = UnescapeValue(key_values[i]); - std::string value = UnescapeValue(key_values[i + 1]); - params[key] = value; - } - bool result = AssociateVariationParams(trial, group, params); - if (!result) { - DLOG(ERROR) << "Failed to associate variation params for group \"" - << group << "\" in trial \"" << trial << "\""; - return false; - } - } - return true; + return base::AssociateFieldTrialParamsFromString(varations_string, + &UnescapeValue); } void AssociateParamsFromFieldTrialConfig(
diff --git a/components/variations/variations_params_manager.h b/components/variations/variations_params_manager.h index 2c61c52..0d63420 100644 --- a/components/variations/variations_params_manager.h +++ b/components/variations/variations_params_manager.h
@@ -11,7 +11,6 @@ #include <string> #include "base/macros.h" -#include "base/metrics/field_trial.h" namespace base { class CommandLine; @@ -26,6 +25,10 @@ namespace variations { namespace testing { +// NOTE: THIS CLASS IS DEPRECATED. Please use ScopedFeatureList instead, which +// provides equivalent functionality. +// TODO(asvitkine): Migrate callers and remove this class. +// // Use this class as a member in your test class to set variation params for // your tests. You can directly set the parameters in the constructor (if they // are used by other members upon construction). You can change them later
diff --git a/components/viz/service/display_embedder/output_surface_provider_impl.cc b/components/viz/service/display_embedder/output_surface_provider_impl.cc index f617eac..c01f3bc 100644 --- a/components/viz/service/display_embedder/output_surface_provider_impl.cc +++ b/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -173,9 +173,10 @@ if (IsFatalOrSurfaceFailure(context_result)) { #if defined(OS_CHROMEOS) || defined(IS_CHROMECAST) - // TODO(kylechar): Chrome OS can't disable GPU compositing. This needs - // to be handled similar to Android. - CHECK(false); + // GL compositing is expected to always work on Chrome OS so we should + // never encounter fatal context error. This could be an unrecoverable + // hardware error or a bug. + LOG(FATAL) << "Unexpected fatal context error"; #elif !defined(OS_ANDROID) gpu_service_impl_->DisableGpuCompositing(); #endif
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index 2d853dec..275413c 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc
@@ -885,8 +885,12 @@ bool should_start_service_manager_only = start_service_manager_only; if (!service_manager_environment_) { if (delegate_->ShouldCreateFeatureList()) { - DCHECK(!field_trial_list_); - field_trial_list_ = SetUpFieldTrialsAndFeatureList(); + // This is intentionally leaked since it needs to live for the duration + // of the process and there's no benefit in cleaning it up at exit. + base::FieldTrialList* leaked_field_trial_list = + SetUpFieldTrialsAndFeatureList().release(); + ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); + ignore_result(leaked_field_trial_list); delegate_->PostFieldTrialInitialization(); }
diff --git a/content/app/content_main_runner_impl.h b/content/app/content_main_runner_impl.h index 513ff1f..6f1803aa 100644 --- a/content/app/content_main_runner_impl.h +++ b/content/app/content_main_runner_impl.h
@@ -62,7 +62,6 @@ std::unique_ptr<discardable_memory::DiscardableSharedMemoryManager> discardable_shared_memory_manager_; std::unique_ptr<StartupDataImpl> startup_data_; - std::unique_ptr<base::FieldTrialList> field_trial_list_; std::unique_ptr<base::PowerMonitor> power_monitor_; std::unique_ptr<ServiceManagerEnvironment> service_manager_environment_; #endif // !defined(CHROME_MULTIPLE_DLL_CHILD)
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index da8cd31..e19a600 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -619,6 +619,13 @@ "cache_storage/cache_storage_scheduler_types.h", "cache_storage/cache_storage_trace_utils.cc", "cache_storage/cache_storage_trace_utils.h", + "cache_storage/cross_sequence/cross_sequence_cache_storage.cc", + "cache_storage/cross_sequence/cross_sequence_cache_storage.h", + "cache_storage/cross_sequence/cross_sequence_cache_storage_cache.cc", + "cache_storage/cross_sequence/cross_sequence_cache_storage_cache.h", + "cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc", + "cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h", + "cache_storage/cross_sequence/cross_sequence_utils.h", "cache_storage/legacy/legacy_cache_storage.cc", "cache_storage/legacy/legacy_cache_storage.h", "cache_storage/legacy/legacy_cache_storage_cache.cc",
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc index 25af4dc..549931e 100644 --- a/content/browser/accessibility/web_contents_accessibility_android.cc +++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -338,9 +338,9 @@ RenderWidgetHostViewAndroid* old_rwhva, RenderWidgetHostViewAndroid* new_rwhva) { if (old_rwhva) - old_rwhva->set_web_contents_accessibility(nullptr); + old_rwhva->SetWebContentsAccessibility(nullptr); if (new_rwhva) - new_rwhva->set_web_contents_accessibility(accessibility_.get()); + new_rwhva->SetWebContentsAccessibility(accessibility_.get()); } WebContentsAccessibilityAndroid::WebContentsAccessibilityAndroid(
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc index 50b2232..33b6420 100644 --- a/content/browser/background_fetch/background_fetch_data_manager.cc +++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -57,9 +57,8 @@ void BackgroundFetchDataManager::InitializeOnIOThread() { DCHECK_CURRENTLY_ON(BrowserThread::IO); - // The CacheStorageManager can only be accessed from the IO thread. - cache_manager_ = - base::WrapRefCounted(cache_storage_context_->cache_manager()); + + cache_manager_ = cache_storage_context_->CacheManager(); // Delete inactive registrations still in the DB. Cleanup();
diff --git a/content/browser/cache_storage/cache_storage_context_impl.cc b/content/browser/cache_storage/cache_storage_context_impl.cc index 8bad367..e8eedcc 100644 --- a/content/browser/cache_storage/cache_storage_context_impl.cc +++ b/content/browser/cache_storage/cache_storage_context_impl.cc
@@ -12,6 +12,7 @@ #include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/cache_storage/cache_storage_dispatcher_host.h" #include "content/browser/cache_storage/cache_storage_quota_client.h" +#include "content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h" #include "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -90,9 +91,15 @@ std::move(request), origin); } -CacheStorageManager* CacheStorageContextImpl::cache_manager() const { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - return cache_manager_.get(); +scoped_refptr<CacheStorageManager> CacheStorageContextImpl::CacheManager() { + // If we're shutdown or already on the target sequence, then just return the + // real manager. + if (!cache_manager_ || task_runner_->RunsTasksInCurrentSequence()) + return cache_manager_; + // Otherwise we have to create a cross-sequence wrapper to provide safe + // access. + return base::MakeRefCounted<CrossSequenceCacheStorageManager>(task_runner_, + cache_manager_); } void CacheStorageContextImpl::SetBlobParametersForCache( @@ -123,11 +130,11 @@ base::BindOnce( [](scoped_refptr<CacheStorageContextImpl> context, GetUsageInfoCallback callback) { - if (!context->cache_manager()) { + if (!context->CacheManager()) { std::move(callback).Run(std::vector<StorageUsageInfo>()); return; } - context->cache_manager()->GetAllOriginsUsage( + context->CacheManager()->GetAllOriginsUsage( CacheStorageOwner::kCacheAPI, std::move(callback)); }, base::RetainedRef(this), std::move(callback))); @@ -139,9 +146,9 @@ base::BindOnce( [](scoped_refptr<CacheStorageContextImpl> context, const GURL& origin) { - if (!context->cache_manager()) + if (!context->CacheManager()) return; - context->cache_manager()->DeleteOriginData( + context->CacheManager()->DeleteOriginData( url::Origin::Create(origin), CacheStorageOwner::kCacheAPI); }, @@ -232,9 +239,9 @@ if (!quota_manager_proxy.get()) return; quota_manager_proxy->RegisterClient(new CacheStorageQuotaClient( - cache_manager(), CacheStorageOwner::kCacheAPI)); + CacheManager(), CacheStorageOwner::kCacheAPI)); quota_manager_proxy->RegisterClient(new CacheStorageQuotaClient( - cache_manager(), CacheStorageOwner::kBackgroundFetch)); + CacheManager(), CacheStorageOwner::kBackgroundFetch)); } } // namespace content
diff --git a/content/browser/cache_storage/cache_storage_context_impl.h b/content/browser/cache_storage/cache_storage_context_impl.h index d663c51..4d0b6b7 100644 --- a/content/browser/cache_storage/cache_storage_context_impl.h +++ b/content/browser/cache_storage/cache_storage_context_impl.h
@@ -68,7 +68,11 @@ void AddBinding(blink::mojom::CacheStorageRequest request, const url::Origin& origin); - CacheStorageManager* cache_manager() const; + // Callable on any sequence. If called on the cache_storage target sequence + // the real manager will be returned directly. If called on any other + // sequence then a cross-sequence wrapper object will be created and returned + // instead. + scoped_refptr<CacheStorageManager> CacheManager(); bool is_incognito() const { return is_incognito_; }
diff --git a/content/browser/cache_storage/cache_storage_dispatcher_host.cc b/content/browser/cache_storage/cache_storage_dispatcher_host.cc index 48f943a..eb3a7cd 100644 --- a/content/browser/cache_storage/cache_storage_dispatcher_host.cc +++ b/content/browser/cache_storage/cache_storage_dispatcher_host.cc
@@ -662,11 +662,11 @@ CacheStorageHandle CacheStorageDispatcherHost::OpenCacheStorage( const url::Origin& origin) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!context_ || !context_->cache_manager() || + if (!context_ || !context_->CacheManager() || !OriginCanAccessCacheStorage(origin)) return CacheStorageHandle(); - return context_->cache_manager()->OpenCacheStorage( + return context_->CacheManager()->OpenCacheStorage( origin, CacheStorageOwner::kCacheAPI); }
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc index 1b8871a..64c2c0d 100644 --- a/content/browser/cache_storage/cache_storage_manager_unittest.cc +++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -31,6 +31,7 @@ #include "content/browser/cache_storage/cache_storage_context_impl.h" #include "content/browser/cache_storage/cache_storage_quota_client.h" #include "content/browser/cache_storage/cache_storage_scheduler.h" +#include "content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h" #include "content/browser/cache_storage/legacy/legacy_cache_storage.h" #include "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h" #include "content/common/background_fetch/background_fetch_types.h" @@ -66,6 +67,24 @@ namespace content { namespace cache_storage_manager_unittest { +enum class TestManager { + kLegacy, + kCrossSequence, +}; + +enum class TestStorage { + kDisk, + kMemory, +}; + +struct Param { + Param(TestManager manager, TestStorage storage) + : manager_(manager), storage_(storage) {} + + TestManager manager_; + TestStorage storage_; +}; + using blink::mojom::StorageType; using ResponseHeaderMap = base::flat_map<std::string, std::string>; @@ -247,6 +266,7 @@ } virtual bool MemoryOnly() { return false; } + virtual TestManager ManagerType() { return TestManager::kLegacy; } void BoolCallback(base::RunLoop* run_loop, bool value) { callback_bool_ = value; @@ -336,15 +356,34 @@ quota_manager_proxy_ = new MockCacheStorageQuotaManagerProxy( mock_quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get()); - cache_manager_ = LegacyCacheStorageManager::Create( + auto legacy_manager = LegacyCacheStorageManager::Create( temp_dir_path, base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get(), quota_manager_proxy_, observers_); - cache_manager_->SetBlobParametersForCache( + legacy_manager->SetBlobParametersForCache( blob_storage_context->context()->AsWeakPtr()); + + switch (ManagerType()) { + case TestManager::kLegacy: + cache_manager_ = std::move(legacy_manager); + break; + case TestManager::kCrossSequence: + cache_manager_ = base::MakeRefCounted<CrossSequenceCacheStorageManager>( + base::ThreadTaskRunnerHandle::Get(), std::move(legacy_manager)); + break; + } + } + + void RecreateStorageManager() { + DCHECK(cache_manager_); + auto* legacy_manager = + static_cast<LegacyCacheStorageManager*>(cache_manager_.get()); + cache_manager_ = + LegacyCacheStorageManager::CreateForTesting(legacy_manager); } bool FlushCacheStorageIndex(const url::Origin& origin) { + DCHECK(ManagerType() == TestManager::kLegacy); callback_bool_ = false; base::RunLoop loop; auto* impl = LegacyCacheStorage::From(CacheStorageForOrigin(origin)); @@ -692,6 +731,7 @@ } int64_t GetSizeThenCloseAllCaches(const url::Origin& origin) { + DCHECK(ManagerType() == TestManager::kLegacy); base::RunLoop loop; CacheStorageHandle cache_storage = CacheStorageForOrigin(origin); LegacyCacheStorage::From(cache_storage) @@ -703,6 +743,7 @@ } int64_t Size(const url::Origin& origin) { + DCHECK(ManagerType() == TestManager::kLegacy); base::RunLoop loop; CacheStorageHandle cache_storage = CacheStorageForOrigin(origin); LegacyCacheStorage::From(cache_storage) @@ -747,7 +788,7 @@ scoped_refptr<MockQuotaManager> mock_quota_manager_; scoped_refptr<MockCacheStorageQuotaManagerProxy> quota_manager_proxy_; scoped_refptr<CacheStorageContextImpl::ObserverList> observers_; - scoped_refptr<LegacyCacheStorageManager> cache_manager_; + scoped_refptr<CacheStorageManager> cache_manager_; CacheStorageCacheHandle callback_cache_handle_; int callback_bool_; @@ -772,9 +813,25 @@ }; class CacheStorageManagerTestP : public CacheStorageManagerTest, - public testing::WithParamInterface<bool> { + public testing::WithParamInterface<Param> { public: - bool MemoryOnly() override { return !GetParam(); } + bool MemoryOnly() override { + return GetParam().storage_ == TestStorage::kMemory; + } + TestManager ManagerType() override { return GetParam().manager_; } +}; + +// Some tests must be run on the LegacyCacheStorageManager. This could +// be for a number of reasons: +// * The test needs to use internal APIs on the legacy manager. +// * The test is checking behavior that is only true for "real" manager's +// like that Open() will return the exact same c++ pointer for the +// underlying cache. This assumption is not truee for the cross-sequence +// wrapper. +class CacheStorageManagerLegacyOnlyTestP + : public CacheStorageManagerTest, + public testing::WithParamInterface<TestStorage> { + bool MemoryOnly() override { return GetParam() == TestStorage::kMemory; } }; TEST_F(CacheStorageManagerTest, TestsRunOnIOThread) { @@ -811,7 +868,7 @@ EXPECT_NE(cache_handle.value(), callback_cache_handle_.value()); } -TEST_P(CacheStorageManagerTestP, OpenExistingCache) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, OpenExistingCache) { EXPECT_TRUE(Open(origin1_, "foo")); CacheStorageCacheHandle cache_handle = std::move(callback_cache_handle_); EXPECT_TRUE(Open(origin1_, "foo")); @@ -1056,7 +1113,7 @@ EXPECT_TRUE(StorageMatchAll(origin1_, GURL("http://example.com/foo"))); } -TEST_P(CacheStorageManagerTestP, Chinese) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, Chinese) { EXPECT_TRUE(Open(origin1_, "ä½ å¥½")); CacheStorageCacheHandle cache_handle = std::move(callback_cache_handle_); EXPECT_TRUE(Open(origin1_, "ä½ å¥½")); @@ -1084,8 +1141,7 @@ EXPECT_TRUE(Open(origin2_, "raz")); EXPECT_TRUE(Delete(origin1_, "bar")); quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); EXPECT_EQ(2u, Keys(origin1_)); std::vector<std::string> expected_keys; expected_keys.push_back("foo"); @@ -1097,8 +1153,7 @@ EXPECT_TRUE(Open(origin1_, "foo")); EXPECT_TRUE(Open(origin2_, "baz")); quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); EXPECT_EQ(0u, Keys(origin1_)); } @@ -1399,8 +1454,7 @@ // Create a new CacheStorageManager that hasn't yet loaded the origin. CreateStorageManager(); quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); EXPECT_TRUE(Open(origin1_, kCacheName)); base::RunLoop().RunUntilIdle(); @@ -1472,8 +1526,7 @@ // Create a new CacheStorageManager that hasn't yet loaded the origin. CreateStorageManager(); quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); // Reopening the origin/cache creates a new CacheStorage instance with a new // random key. @@ -1515,7 +1568,7 @@ EXPECT_TRUE(callback_cache_handle_.value()); } -TEST_P(CacheStorageManagerTestP, OpenRunsSerially) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, OpenRunsSerially) { EXPECT_FALSE(Delete(origin1_, "tmp")); // Init storage. CacheStorageHandle cache_storage = CacheStorageForOrigin(origin1_); auto* impl = LegacyCacheStorage::From(cache_storage); @@ -1667,8 +1720,7 @@ // Create a new CacheStorageManager that hasn't yet loaded the origin. CreateStorageManager(); quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); // Create a second value (V2) in the cache. EXPECT_TRUE(Open(origin1_, kCacheName)); @@ -1736,8 +1788,7 @@ // Create a new CacheStorageManager that hasn't yet loaded the origin. CreateStorageManager(); quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); // Reopen the cache and write a second value (V2). EXPECT_TRUE(Open(origin1_, kCacheName)); @@ -1766,7 +1817,7 @@ EXPECT_EQ(cache_size_v2, Size(origin1_)); } -TEST_P(CacheStorageManagerTestP, GetSizeThenCloseAllCaches) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, GetSizeThenCloseAllCaches) { EXPECT_TRUE(Open(origin1_, "foo")); EXPECT_TRUE( CachePut(callback_cache_handle_.value(), GURL("http://example.com/foo"))); @@ -1784,7 +1835,7 @@ CachePut(callback_cache_handle_.value(), GURL("http://example.com/baz"))); } -TEST_P(CacheStorageManagerTestP, GetSizeThenCloseAllCachesTwoOwners) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, GetSizeThenCloseAllCachesTwoOwners) { EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kCacheAPI)); CacheStorageCacheHandle public_handle = std::move(callback_cache_handle_); EXPECT_TRUE(Open(origin1_, "foo", CacheStorageOwner::kBackgroundFetch)); @@ -1801,7 +1852,8 @@ EXPECT_FALSE(CachePut(public_handle.value(), GURL("http://example.com/baz"))); } -TEST_P(CacheStorageManagerTestP, GetSizeThenCloseAllCachesAfterDelete) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, + GetSizeThenCloseAllCachesAfterDelete) { // Tests that doomed caches are also deleted by GetSizeThenCloseAllCaches. EXPECT_TRUE(Open(origin1_, "foo")); EXPECT_TRUE( @@ -1830,8 +1882,10 @@ CachePut(callback_cache_handle_.value(), GURL("http://example.com/foo"))); // Create an unreferenced directory next to the referenced one. + auto* legacy_manager = + static_cast<LegacyCacheStorageManager*>(cache_manager_.get()); base::FilePath origin_path = LegacyCacheStorageManager::ConstructOriginPath( - cache_manager_->root_path(), origin1_, CacheStorageOwner::kCacheAPI); + legacy_manager->root_path(), origin1_, CacheStorageOwner::kCacheAPI); base::FilePath unreferenced_path = origin_path.AppendASCII("bar"); EXPECT_TRUE(CreateDirectory(unreferenced_path)); EXPECT_TRUE(base::DirectoryExists(unreferenced_path)); @@ -1839,8 +1893,7 @@ // Create a new StorageManager so that the next time the cache is opened // the unreferenced directory can be deleted. quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); // Verify that the referenced cache still works. EXPECT_TRUE(Open(origin1_, "foo")); @@ -1887,14 +1940,14 @@ EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count()); } -TEST_P(CacheStorageManagerTestP, SizeStorageAccessed) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, SizeStorageAccessed) { EXPECT_EQ(0, Size(origin1_)); // Size is not part of the web API and should not notify the quota manager of // an access. EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); } -TEST_P(CacheStorageManagerTestP, SizeThenCloseStorageAccessed) { +TEST_P(CacheStorageManagerLegacyOnlyTestP, SizeThenCloseStorageAccessed) { EXPECT_EQ(0, GetSizeThenCloseAllCaches(origin1_)); // GetSizeThenCloseAllCaches is not part of the web API and should not notify // the quota manager of an access. @@ -2341,8 +2394,11 @@ }; class CacheStorageQuotaClientTestP : public CacheStorageQuotaClientTest, - public testing::WithParamInterface<bool> { - bool MemoryOnly() override { return !GetParam(); } + public testing::WithParamInterface<Param> { + bool MemoryOnly() override { + return GetParam().storage_ == TestStorage::kMemory; + } + TestManager ManagerType() override { return GetParam().manager_; } }; TEST_P(CacheStorageQuotaClientTestP, QuotaID) { @@ -2430,8 +2486,7 @@ // Create a new CacheStorageManager that hasn't yet loaded the origin. quota_manager_proxy_->SimulateQuotaManagerDestroyed(); - cache_manager_ = - LegacyCacheStorageManager::CreateForTesting(cache_manager_.get()); + RecreateStorageManager(); quota_client_ = std::make_unique<CacheStorageQuotaClient>( cache_manager_, CacheStorageOwner::kCacheAPI); @@ -2447,13 +2502,26 @@ EXPECT_FALSE(QuotaDoesSupport(StorageType::kUnknown)); } -INSTANTIATE_TEST_SUITE_P(CacheStorageManagerTests, - CacheStorageManagerTestP, - ::testing::Values(false, true)); +INSTANTIATE_TEST_SUITE_P( + CacheStorageManagerTests, + CacheStorageManagerTestP, + ::testing::Values(Param(TestManager::kLegacy, TestStorage::kMemory), + Param(TestManager::kLegacy, TestStorage::kDisk), + Param(TestManager::kCrossSequence, TestStorage::kMemory), + Param(TestManager::kCrossSequence, TestStorage::kDisk))); -INSTANTIATE_TEST_SUITE_P(CacheStorageQuotaClientTests, - CacheStorageQuotaClientTestP, - ::testing::Values(false, true)); +INSTANTIATE_TEST_SUITE_P(CacheStorageManagerTests, + CacheStorageManagerLegacyOnlyTestP, + ::testing::Values(TestStorage::kMemory, + TestStorage::kDisk)); + +INSTANTIATE_TEST_SUITE_P( + CacheStorageQuotaClientTests, + CacheStorageQuotaClientTestP, + ::testing::Values(Param(TestManager::kLegacy, TestStorage::kMemory), + Param(TestManager::kLegacy, TestStorage::kDisk), + Param(TestManager::kCrossSequence, TestStorage::kMemory), + Param(TestManager::kCrossSequence, TestStorage::kDisk))); } // namespace cache_storage_manager_unittest } // namespace content
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.cc b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.cc new file mode 100644 index 0000000..3fc7dff --- /dev/null +++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.cc
@@ -0,0 +1,288 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h" + +#include "content/browser/cache_storage/cache_storage_histogram_utils.h" +#include "content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.h" +#include "content/browser/cache_storage/cross_sequence/cross_sequence_utils.h" + +namespace content { + +// The Inner class is SequenceBound<> to the real target CacheStorage sequence +// by the outer CrossSequenceCacheStorage. All CacheStorage operations are +// proxied to the Inner on the correct sequence via the Post() method. The +// outer storage is responsible for wrapping any callbacks in order to post on +// the outer's original sequence. +class CrossSequenceCacheStorage::Inner { + public: + using OpenCacheAdapterCallback = + base::OnceCallback<void(scoped_refptr<CrossSequenceCacheStorageCache>, + blink::mojom::CacheStorageError)>; + + Inner(const url::Origin& origin, + CacheStorageOwner owner, + scoped_refptr<CacheStorageManager> target_manager) + : handle_(target_manager->OpenCacheStorage(origin, owner)) {} + + void OpenCache(scoped_refptr<CrossSequenceCacheStorageCache> cache_wrapper, + const std::string& cache_name, + int64_t trace_id, + OpenCacheAdapterCallback adapter_callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(adapter_callback) + .Run(std::move(cache_wrapper), + MakeErrorStorage(ErrorStorageType::kStorageHandleNull)); + return; + } + + // Open the cache and set the handle on the wrapper object provided. The + // wrapper will then be sent back to the source sequence to be exposed via + // its own handle. + handle_.value()->OpenCache( + cache_name, trace_id, + base::BindOnce( + [](scoped_refptr<CrossSequenceCacheStorageCache> cache_wrapper, + OpenCacheAdapterCallback adapter_callback, + CacheStorageCacheHandle handle, + blink::mojom::CacheStorageError error) { + // Called on target TaskRunner. + if (handle.value()) + cache_wrapper->SetHandleOnTaskRunner(std::move(handle)); + // Passing |cache_wrapper| back across the sequence boundary is + // safe because we are guaranteed this is the only reference to + // the object. + std::move(adapter_callback).Run(std::move(cache_wrapper), error); + }, + std::move(cache_wrapper), std::move(adapter_callback))); + } + + void HasCache(const std::string& cache_name, + int64_t trace_id, + BoolAndErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run( + false, MakeErrorStorage(ErrorStorageType::kStorageHandleNull)); + return; + } + handle_.value()->HasCache(cache_name, trace_id, std::move(callback)); + } + + void DoomCache(const std::string& cache_name, + int64_t trace_id, + ErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull)); + return; + } + handle_.value()->DoomCache(cache_name, trace_id, std::move(callback)); + } + + void EnumerateCaches(int64_t trace_id, EnumerateCachesCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run(std::vector<std::string>()); + return; + } + handle_.value()->EnumerateCaches(trace_id, std::move(callback)); + } + + void MatchCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull), nullptr); + return; + } + handle_.value()->MatchCache(cache_name, std::move(request), + std::move(match_options), trace_id, + std::move(callback)); + } + + void MatchAllCaches(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull), nullptr); + return; + } + handle_.value()->MatchAllCaches(std::move(request), + std::move(match_options), trace_id, + std::move(callback)); + } + + void WriteToCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull)); + return; + } + handle_.value()->WriteToCache(cache_name, std::move(request), + std::move(response), trace_id, + std::move(callback)); + } + + private: + const CacheStorageHandle handle_; + SEQUENCE_CHECKER(sequence_checker_); +}; + +CrossSequenceCacheStorage::CrossSequenceCacheStorage( + const url::Origin& origin, + CacheStorageOwner owner, + scoped_refptr<base::SequencedTaskRunner> target_task_runner, + scoped_refptr<CacheStorageManager> target_manager) + : CacheStorage(origin), + target_task_runner_(std::move(target_task_runner)), + inner_(target_task_runner_, + origin, + std::move(owner), + std::move(target_manager)), + weak_factory_(this) {} + +CacheStorageHandle CrossSequenceCacheStorage::CreateHandle() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return CacheStorageHandle(weak_factory_.GetWeakPtr()); +} + +void CrossSequenceCacheStorage::AddHandleRef() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + handle_ref_count_ += 1; + if (handle_ref_count_ == 1) + self_ref_ = base::WrapRefCounted(this); +} + +void CrossSequenceCacheStorage::DropHandleRef() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_GT(handle_ref_count_, 0); + handle_ref_count_ -= 1; + if (handle_ref_count_ == 0) + self_ref_.reset(); +} + +void CrossSequenceCacheStorage::OpenCache(const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Create our cross-sequence cache wrapper object first. This will be sent + // down to the target TaskRunner with our open request. It must already + // exist in order for the open request to set the real handle on it on the + // target TaskRunner. If an error occurs the wrapper object is thrown + // away. + auto cache_wrapper = + base::MakeRefCounted<CrossSequenceCacheStorageCache>(target_task_runner_); + + // After the open request sets the real handle on the target TaskRunner our + // cache wrapper will be passed back to this sequence. We then create a + // handle to the wrapper and pass that to the external callback. + auto adapter_callback = base::BindOnce( + [](CacheAndErrorCallback inner_callback, + scoped_refptr<CrossSequenceCacheStorageCache> cache_wrapper, + blink::mojom::CacheStorageError error) { + if (error != blink::mojom::CacheStorageError::kSuccess) { + // Don't create a handle to the wrapper if there was an error. + // The |cache_wrapper| will be destroyed when it goes out of scope. + std::move(inner_callback).Run(CacheStorageCacheHandle(), error); + return; + } + // Called on source TaskRunner (thanks to callback wrapping below). + // Note, CreateHandle() will cause the cache to remain strongly + // referenced and survive even though |cache_wrapper| goes out of + // scope. + std::move(inner_callback).Run(cache_wrapper->CreateHandle(), error); + }, + std::move(callback)); + + // We use our standard wrapping to ensure that we execute our adapter + // callback on the correct current sequence. + adapter_callback = + WrapCallbackForCurrentSequence(std::move(adapter_callback)); + + // Passing |cache_wrapper| across sequence boundaries is safe because + // we are guaranteed this is the only reference to the object. + inner_.Post(FROM_HERE, &Inner::OpenCache, std::move(cache_wrapper), + cache_name, trace_id, std::move(adapter_callback)); +} + +void CrossSequenceCacheStorage::HasCache(const std::string& cache_name, + int64_t trace_id, + BoolAndErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::HasCache, cache_name, trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorage::DoomCache(const std::string& cache_name, + int64_t trace_id, + ErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::DoomCache, cache_name, trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorage::EnumerateCaches( + int64_t trace_id, + EnumerateCachesCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::EnumerateCaches, trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorage::MatchCache( + const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::MatchCache, cache_name, std::move(request), + std::move(match_options), trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorage::MatchAllCaches( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::MatchAllCaches, std::move(request), + std::move(match_options), trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorage::WriteToCache( + const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::WriteToCache, cache_name, std::move(request), + std::move(response), trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +CrossSequenceCacheStorage::~CrossSequenceCacheStorage() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +} // namespace content
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h new file mode 100644 index 0000000..a75301e --- /dev/null +++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h
@@ -0,0 +1,88 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_H_ +#define CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_H_ + +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "base/threading/sequence_bound.h" +#include "content/browser/cache_storage/cache_storage.h" +#include "content/browser/cache_storage/cache_storage_manager.h" + +namespace content { + +// A CacheStorage implementation that can be used from one sequence to access +// a real CacheStorage executing on a different sequence. The +// CrossSequenceCacheStorageManager constructs instances of this class in +// OpenCacheStorage(). Each CrossSequenceCacheStorage is ref-counted and +// the existence of a CacheStorageHandle will cause the instance to hold a +// scoped_refptr to itself. Once all the handles have been dropped the +// self-reference is also dropped allowing the CrossSequenceCacheStorage to +// be destroyed. +class CrossSequenceCacheStorage + : public CacheStorage, + public base::RefCounted<CrossSequenceCacheStorage> { + public: + CrossSequenceCacheStorage( + const url::Origin& origin, + CacheStorageOwner owner, + scoped_refptr<base::SequencedTaskRunner> target_task_runner, + scoped_refptr<CacheStorageManager> target_manager); + + // CacheStorage + CacheStorageHandle CreateHandle() override; + void AddHandleRef() override; + void DropHandleRef() override; + void OpenCache(const std::string& cache_name, + int64_t trace_id, + CacheAndErrorCallback callback) override; + void HasCache(const std::string& cache_name, + int64_t trace_id, + BoolAndErrorCallback callback) override; + void DoomCache(const std::string& cache_name, + int64_t trace_id, + ErrorCallback callback) override; + void EnumerateCaches(int64_t trace_id, + EnumerateCachesCallback callback) override; + void MatchCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) override; + void MatchAllCaches(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheStorageCache::ResponseCallback callback) override; + void WriteToCache(const std::string& cache_name, + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback) override; + + private: + friend class base::RefCounted<CrossSequenceCacheStorage>; + ~CrossSequenceCacheStorage() override; + + const scoped_refptr<base::SequencedTaskRunner> target_task_runner_; + + // The |inner_| object is SequenceBound<> to the target sequence used by the + // real CacheStorage. + class Inner; + base::SequenceBound<Inner> inner_; + + // |self_ref_| holds a reference to the current |this| as long as + // |handle_ref_count_| is greater than zero. The |handle_ref_count_| is + // incremented for every outstanding CacheStorageCacheHandle. + scoped_refptr<CrossSequenceCacheStorage> self_ref_; + int handle_ref_count_ = 0; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<CrossSequenceCacheStorage> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(CrossSequenceCacheStorage); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_H_
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.cc b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.cc new file mode 100644 index 0000000..75d3e9a --- /dev/null +++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.cc
@@ -0,0 +1,249 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.h" + +#include "content/browser/cache_storage/cache_storage_histogram_utils.h" +#include "content/browser/cache_storage/cross_sequence/cross_sequence_utils.h" + +namespace content { + +// The Inner class is SequenceBound<> to the real target CacheStorageCache +// sequence by the outer CrossSequenceCacheStorageCache. All CacheStorageCache +// operations are proxied to the Inner on the correct sequence via the Post() +// method. The outer storage is responsible for wrapping any callbacks in +// order to post on the outer's original sequence. +class CrossSequenceCacheStorageCache::Inner { + public: + void SetHandle(CacheStorageCacheHandle handle) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!handle_.value()); + handle_ = std::move(handle); + } + + void Match(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull), nullptr); + return; + } + handle_.value()->Match(std::move(request), std::move(match_options), + trace_id, std::move(callback)); + } + + void MatchAll(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + ResponsesCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull), + std::vector<blink::mojom::FetchAPIResponsePtr>()); + return; + } + handle_.value()->MatchAll(std::move(request), std::move(match_options), + trace_id, std::move(callback)); + } + + void WriteSideData(ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len) { + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull)); + return; + } + handle_.value()->WriteSideData(std::move(callback), url, + expected_response_time, trace_id, + std::move(buffer), buf_len); + } + + void BatchOperation(std::vector<blink::mojom::BatchOperationPtr> operations, + int64_t trace_id, + VerboseErrorCallback callback, + BadMessageCallback bad_message_callback) { + if (!handle_.value()) { + std::move(callback).Run(blink::mojom::CacheStorageVerboseError::New( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull), nullptr)); + return; + } + handle_.value()->BatchOperation(std::move(operations), trace_id, + std::move(callback), + std::move(bad_message_callback)); + } + + void Keys(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + RequestsCallback callback) { + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull), nullptr); + return; + } + handle_.value()->Keys(std::move(request), std::move(options), trace_id, + std::move(callback)); + } + + void Put(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback) { + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull)); + return; + } + handle_.value()->Put(std::move(request), std::move(response), trace_id, + std::move(callback)); + } + + void GetAllMatchedEntries(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheEntriesCallback callback) { + if (!handle_.value()) { + std::move(callback).Run( + MakeErrorStorage(ErrorStorageType::kStorageHandleNull), + std::vector<CacheEntry>()); + return; + } + handle_.value()->GetAllMatchedEntries(std::move(request), + std::move(match_options), trace_id, + std::move(callback)); + } + + private: + CacheStorageCacheHandle handle_; + SEQUENCE_CHECKER(sequence_checker_); +}; + +CrossSequenceCacheStorageCache::CrossSequenceCacheStorageCache( + scoped_refptr<base::SequencedTaskRunner> target_task_runner) + : inner_(std::move(target_task_runner)), weak_factory_(this) {} + +void CrossSequenceCacheStorageCache::SetHandleOnTaskRunner( + CacheStorageCacheHandle handle) { + // Called on target sequence. + DCHECK(handle.value()); + // Even though we are already on the correct sequence we still have to Post() + // to the inner object. + inner_.Post(FROM_HERE, &Inner::SetHandle, std::move(handle)); +} + +CacheStorageCacheHandle CrossSequenceCacheStorageCache::CreateHandle() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return CacheStorageCacheHandle(weak_factory_.GetWeakPtr()); +} + +void CrossSequenceCacheStorageCache::AddHandleRef() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + handle_ref_count_ += 1; + if (handle_ref_count_ == 1) + self_ref_ = base::WrapRefCounted(this); +} + +void CrossSequenceCacheStorageCache::DropHandleRef() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_GT(handle_ref_count_, 0); + handle_ref_count_ -= 1; + if (handle_ref_count_ == 0) + self_ref_.reset(); +} + +bool CrossSequenceCacheStorageCache::IsUnreferenced() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return handle_ref_count_ == 0; +} + +void CrossSequenceCacheStorageCache::Match( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + ResponseCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::Match, std::move(request), + std::move(match_options), trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageCache::MatchAll( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + ResponsesCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::MatchAll, std::move(request), + std::move(match_options), trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageCache::WriteSideData( + ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::WriteSideData, + WrapCallbackForCurrentSequence(std::move(callback)), url, + expected_response_time, trace_id, std::move(buffer), buf_len); +} + +void CrossSequenceCacheStorageCache::BatchOperation( + std::vector<blink::mojom::BatchOperationPtr> operations, + int64_t trace_id, + VerboseErrorCallback callback, + BadMessageCallback bad_message_callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::BatchOperation, std::move(operations), + trace_id, WrapCallbackForCurrentSequence(std::move(callback)), + WrapCallbackForCurrentSequence(std::move(bad_message_callback))); +} + +void CrossSequenceCacheStorageCache::Keys( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + RequestsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::Keys, std::move(request), std::move(options), + trace_id, WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageCache::Put( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::Put, std::move(request), std::move(response), + trace_id, WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageCache::GetAllMatchedEntries( + blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheEntriesCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::GetAllMatchedEntries, std::move(request), + std::move(match_options), trace_id, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +CrossSequenceCacheStorageCache::~CrossSequenceCacheStorageCache() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +} // namespace content
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.h b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.h new file mode 100644 index 0000000..e7817cf --- /dev/null +++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_cache.h
@@ -0,0 +1,101 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_CACHE_H_ +#define CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_CACHE_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "base/threading/sequence_bound.h" +#include "content/browser/cache_storage/cache_storage_cache.h" + +namespace content { + +// A CacheStorageCache implementation that can be used from one sequence to +// access a real CacheStorageCache executing on a different sequence. +// CrossSequenceCacheStorage objects construct instances of this class in +// OpenCache(). Each CrossSequenceCacheStorageCache is ref-counted and +// the existence of a CacheStorageCacheHandle will cause the instance to hold a +// scoped_refptr to itself. Once all the handles have been dropped the +// self-reference is also dropped allowing the CrossSequenceCacheStorage to +// be destroyed. +class CrossSequenceCacheStorageCache + : public CacheStorageCache, + public base::RefCounted<CrossSequenceCacheStorageCache> { + public: + // Created on the outer source sequence without any reference to a real + // cache yet. SetHandleOnTaskRunner() must be called before any cache + // methods are invoked. + explicit CrossSequenceCacheStorageCache( + scoped_refptr<base::SequencedTaskRunner> target_task_runner); + + // Called on the inner cache's sequence to set the real cache's handle. + void SetHandleOnTaskRunner(CacheStorageCacheHandle handle); + + // CacheStorageCache + CacheStorageCacheHandle CreateHandle() override; + void AddHandleRef() override; + void DropHandleRef() override; + bool IsUnreferenced() const override; + void Match(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + ResponseCallback callback) override; + + void MatchAll(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + ResponsesCallback callback) override; + + void WriteSideData(ErrorCallback callback, + const GURL& url, + base::Time expected_response_time, + int64_t trace_id, + scoped_refptr<net::IOBuffer> buffer, + int buf_len) override; + + void BatchOperation(std::vector<blink::mojom::BatchOperationPtr> operations, + int64_t trace_id, + VerboseErrorCallback callback, + BadMessageCallback bad_message_callback) override; + + void Keys(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr options, + int64_t trace_id, + RequestsCallback callback) override; + + void Put(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::FetchAPIResponsePtr response, + int64_t trace_id, + ErrorCallback callback) override; + + void GetAllMatchedEntries(blink::mojom::FetchAPIRequestPtr request, + blink::mojom::CacheQueryOptionsPtr match_options, + int64_t trace_id, + CacheEntriesCallback callback) override; + + private: + friend class base::RefCounted<CrossSequenceCacheStorageCache>; + ~CrossSequenceCacheStorageCache() override; + + // The |inner_| object is SequenceBound<> to the target sequence used by the + // real CacheStorageCache. + class Inner; + base::SequenceBound<Inner> inner_; + + // |self_ref_| holds a reference to the current |this| as long as + // |handle_ref_count_| is greater than zero. The |handle_ref_count_| is + // incremented for every outstanding CacheStorageCacheHandle. + scoped_refptr<CrossSequenceCacheStorageCache> self_ref_; + int handle_ref_count_ = 0; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<CrossSequenceCacheStorageCache> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(CrossSequenceCacheStorageCache); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_CACHE_H_
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc new file mode 100644 index 0000000..6eb46ac --- /dev/null +++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.cc
@@ -0,0 +1,143 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h" + +#include "content/browser/cache_storage/cache_storage.h" +#include "content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage.h" +#include "content/browser/cache_storage/cross_sequence/cross_sequence_utils.h" + +namespace content { + +// The Inner class is SequenceBound<> to the real target manager sequence by +// the outer CrossSequenceCacheStorageManager. All CacheStorageManager +// operations are proxied to the Inner on the correct sequence via the Post() +// method. The outer manager is responsible for wrapping any callbacks in +// order to post on the outer's original sequence. +class CrossSequenceCacheStorageManager::Inner { + public: + explicit Inner(scoped_refptr<CacheStorageManager> target_manager) + : target_manager_(std::move(target_manager)) {} + + void GetAllOriginsUsage(CacheStorageOwner owner, + CacheStorageContext::GetUsageInfoCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + target_manager_->GetAllOriginsUsage(owner, std::move(callback)); + } + + void GetOriginUsage(const url::Origin& origin_url, + CacheStorageOwner owner, + storage::QuotaClient::GetUsageCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + target_manager_->GetOriginUsage(origin_url, owner, std::move(callback)); + } + + void GetOrigins(CacheStorageOwner owner, + storage::QuotaClient::GetOriginsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + target_manager_->GetOrigins(owner, std::move(callback)); + } + + void GetOriginsForHost(const std::string& host, + CacheStorageOwner owner, + storage::QuotaClient::GetOriginsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + target_manager_->GetOriginsForHost(host, owner, std::move(callback)); + } + + void DeleteOriginData(const url::Origin& origin, + CacheStorageOwner owner, + storage::QuotaClient::DeletionCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + target_manager_->DeleteOriginData(origin, owner, std::move(callback)); + } + + private: + const scoped_refptr<CacheStorageManager> target_manager_; + SEQUENCE_CHECKER(sequence_checker_); +}; + +CrossSequenceCacheStorageManager::CrossSequenceCacheStorageManager( + scoped_refptr<base::SequencedTaskRunner> target_task_runner, + scoped_refptr<CacheStorageManager> target_manager) + : target_task_runner_(std::move(target_task_runner)), + target_manager_(target_manager), + inner_(target_task_runner_, std::move(target_manager_)) {} + +CacheStorageHandle CrossSequenceCacheStorageManager::OpenCacheStorage( + const url::Origin& origin, + CacheStorageOwner owner) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Construct the CrossSequenceCacheStorage object immediately on our current + // sequence. This is necessary in order to return a Handle synchronously. + // The CrossSequenceCacheStorage object will asynchronously open the real + // CacheStorage on the correct sequence. + auto storage = base::MakeRefCounted<CrossSequenceCacheStorage>( + origin, owner, target_task_runner_, target_manager_); + return storage->CreateHandle(); +} + +void CrossSequenceCacheStorageManager::GetAllOriginsUsage( + CacheStorageOwner owner, + CacheStorageContext::GetUsageInfoCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::GetAllOriginsUsage, owner, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageManager::GetOriginUsage( + const url::Origin& origin_url, + CacheStorageOwner owner, + storage::QuotaClient::GetUsageCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::GetOriginUsage, origin_url, owner, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageManager::GetOrigins( + CacheStorageOwner owner, + storage::QuotaClient::GetOriginsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::GetOrigins, owner, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageManager::GetOriginsForHost( + const std::string& host, + CacheStorageOwner owner, + storage::QuotaClient::GetOriginsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::GetOriginsForHost, host, owner, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageManager::DeleteOriginData( + const url::Origin& origin, + CacheStorageOwner owner, + storage::QuotaClient::DeletionCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + inner_.Post(FROM_HERE, &Inner::DeleteOriginData, origin, owner, + WrapCallbackForCurrentSequence(std::move(callback))); +} + +void CrossSequenceCacheStorageManager::DeleteOriginData( + const url::Origin& origin, + CacheStorageOwner owner) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DeleteOriginData(origin, owner, base::DoNothing()); +} + +void CrossSequenceCacheStorageManager::SetBlobParametersForCache( + base::WeakPtr<storage::BlobStorageContext> blob_storage_context) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // This method is used for initialization of a real manager and should not + // be invoked for the cross-sequence wrapper. + NOTREACHED(); +} + +CrossSequenceCacheStorageManager::~CrossSequenceCacheStorageManager() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} + +} // namespace content
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h new file mode 100644 index 0000000..2852fda4 --- /dev/null +++ b/content/browser/cache_storage/cross_sequence/cross_sequence_cache_storage_manager.h
@@ -0,0 +1,69 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_MANAGER_H_ +#define CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_MANAGER_H_ + +#include "base/sequence_checker.h" +#include "base/threading/sequence_bound.h" +#include "content/browser/cache_storage/cache_storage_manager.h" + +namespace content { + +// A CacheStorageManager implementation that can be used from one sequence to +// access the real CacheStorageManager executing on a different sequence. The +// CacheStorageContextImpl will create one of these whenever code calls the +// CacheManager() accessor on the wrong sequence. The cross-sequence wrapper +// manager is ref-counted and will only live as long as that client code keeps +// its reference alive. Each cross-sequence wrapper is locked to the sequence +// on which it was created. +class CONTENT_EXPORT CrossSequenceCacheStorageManager + : public CacheStorageManager { + public: + CrossSequenceCacheStorageManager( + scoped_refptr<base::SequencedTaskRunner> target_task_runner, + scoped_refptr<CacheStorageManager> target_manager); + + // CacheStorageManager + CacheStorageHandle OpenCacheStorage(const url::Origin& origin, + CacheStorageOwner owner) override; + void GetAllOriginsUsage( + CacheStorageOwner owner, + CacheStorageContext::GetUsageInfoCallback callback) override; + void GetOriginUsage(const url::Origin& origin_url, + CacheStorageOwner owner, + storage::QuotaClient::GetUsageCallback callback) override; + void GetOrigins(CacheStorageOwner owner, + storage::QuotaClient::GetOriginsCallback callback) override; + void GetOriginsForHost( + const std::string& host, + CacheStorageOwner owner, + storage::QuotaClient::GetOriginsCallback callback) override; + void DeleteOriginData( + const url::Origin& origin, + CacheStorageOwner owner, + storage::QuotaClient::DeletionCallback callback) override; + void DeleteOriginData(const url::Origin& origin, + CacheStorageOwner owner) override; + void SetBlobParametersForCache( + base::WeakPtr<storage::BlobStorageContext> blob_storage_context) override; + + private: + ~CrossSequenceCacheStorageManager() override; + + const scoped_refptr<base::SequencedTaskRunner> target_task_runner_; + const scoped_refptr<CacheStorageManager> target_manager_; + + // The |inner_| object is SequenceBound<> to the target sequence used by the + // real manager. + class Inner; + base::SequenceBound<Inner> inner_; + + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(CrossSequenceCacheStorageManager); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_CACHE_STORAGE_MANAGER_H_
diff --git a/content/browser/cache_storage/cross_sequence/cross_sequence_utils.h b/content/browser/cache_storage/cross_sequence/cross_sequence_utils.h new file mode 100644 index 0000000..5efc734 --- /dev/null +++ b/content/browser/cache_storage/cross_sequence/cross_sequence_utils.h
@@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_UTILS_H_ +#define CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_UTILS_H_ + +namespace content { + +// Helper function for WrapCallbackForCurrentSequence(). +template <typename... Args> +void RunWrappedCallbackOnTargetSequence( + base::OnceCallback<void(Args...)> callback, + Args... args) { + std::move(callback).Run(std::forward<Args>(args)...); +} + +// Helper function for WrapCallbackForCurrentSequence(). +template <typename... Args> +void RunWrappedCallbackOnOtherSequence( + scoped_refptr<base::SequencedTaskRunner> task_runner, + base::OnceCallback<void(Args...)> callback, + Args... args) { + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&RunWrappedCallbackOnTargetSequence<Args...>, + std::move(callback), std::forward<Args>(args)...)); +} + +// This function wraps a given OnceCallback<> such that it will perform a +// PostTask() to the current sequence when the callback is invoked. +template <typename... Args> +base::OnceCallback<void(Args...)> WrapCallbackForCurrentSequence( + base::OnceCallback<void(Args...)> callback) { + return base::BindOnce(&RunWrappedCallbackOnOtherSequence<Args...>, + base::SequencedTaskRunnerHandle::Get(), + std::move(callback)); +} + +} // namespace content + +#endif // CONTENT_BROWSER_CACHE_STORAGE_CROSS_SEQUENCE_CROSS_SEQUENCE_UTILS_H_
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc index 7c130bec0..4cfcc32 100644 --- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc +++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -9842,8 +9842,14 @@ // When running OpenURL to an invalid URL on a frame proxy it should not spoof // the url by canceling a main frame navigation. // See https://crbug.com/966914. +// Failing on Linux CFI. http://crbug.com/974319 +#if defined(OS_LINUX) +#define MAYBE_CrossProcessIframeToInvalidURLCancelsRedirectSpoof DISABLED_CrossProcessIframeToInvalidURLCancelsRedirectSpoof +#else +#define MAYBE_CrossProcessIframeToInvalidURLCancelsRedirectSpoof CrossProcessIframeToInvalidURLCancelsRedirectSpoof +#endif IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, - CrossProcessIframeToInvalidURLCancelsRedirectSpoof) { + MAYBE_CrossProcessIframeToInvalidURLCancelsRedirectSpoof) { const GURL main_frame_url(embedded_test_server()->GetURL( "a.com", "/cross_site_iframe_factory.html?a(b{sandbox-allow-scripts,sandbox-allow-"
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc index 8702473..a76f403 100644 --- a/content/browser/frame_host/render_frame_message_filter.cc +++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -215,6 +215,12 @@ // Return early if the frame has already been navigated away from. content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); + + // |web_contents| will be null on interstitial pages, which means + // the frame has been navigated away from and it's safe to return early + if (!web_contents) + return; + RenderFrameHostImpl* root_frame_host = render_frame_host; while (root_frame_host->GetParent() != nullptr) root_frame_host = root_frame_host->GetParent();
diff --git a/content/browser/media/hardware_key_media_controller.cc b/content/browser/media/hardware_key_media_controller.cc index 402e55e..cbacde782 100644 --- a/content/browser/media/hardware_key_media_controller.cc +++ b/content/browser/media/hardware_key_media_controller.cc
@@ -9,6 +9,8 @@ #include <vector> #include "base/metrics/histogram_macros.h" +#include "content/browser/browser_main_loop.h" +#include "content/browser/media/media_keys_listener_manager_impl.h" #include "content/public/browser/media_keys_listener_manager.h" #include "services/media_session/public/mojom/constants.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h" @@ -46,7 +48,14 @@ void HardwareKeyMediaController::MediaSessionInfoChanged( media_session::mojom::MediaSessionInfoPtr session_info) { + MediaKeysListenerManagerImpl* media_keys_listener_manager_impl = + BrowserMainLoop::GetInstance()->media_keys_listener_manager(); + DCHECK(media_keys_listener_manager_impl); + session_info_ = std::move(session_info); + media_keys_listener_manager_impl->SetIsMediaPlaying( + session_info_ && session_info_->playback_state == + media_session::mojom::MediaPlaybackState::kPlaying); } void HardwareKeyMediaController::MediaSessionActionsChanged(
diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc index 2c6ae1b..a2e879f9 100644 --- a/content/browser/media/media_keys_listener_manager_impl.cc +++ b/content/browser/media/media_keys_listener_manager_impl.cc
@@ -155,6 +155,16 @@ delegate.OnMediaKeysAccelerator(accelerator); } +void MediaKeysListenerManagerImpl::SetIsMediaPlaying(bool is_playing) { + if (is_media_playing_ == is_playing) + return; + + is_media_playing_ = is_playing; + + if (media_keys_listener_) + media_keys_listener_->SetIsMediaPlaying(is_media_playing_); +} + void MediaKeysListenerManagerImpl::EnsureAuxiliaryServices() { if (auxiliary_services_started_) return; @@ -200,6 +210,8 @@ media_keys_listener_ = ui::MediaKeysListener::Create( this, ui::MediaKeysListener::Scope::kGlobal); DCHECK(media_keys_listener_); + + media_keys_listener_->SetIsMediaPlaying(is_media_playing_); } MediaKeysListenerManagerImpl::ListeningData*
diff --git a/content/browser/media/media_keys_listener_manager_impl.h b/content/browser/media/media_keys_listener_manager_impl.h index 77e6026..361d957d 100644 --- a/content/browser/media/media_keys_listener_manager_impl.h +++ b/content/browser/media/media_keys_listener_manager_impl.h
@@ -60,6 +60,12 @@ // ui::MediaKeysListener::Delegate: void OnMediaKeysAccelerator(const ui::Accelerator& accelerator) override; + // Informs the MediaKeysListener whether or not media is playing. + // TODO(https://crbug.com/974035): Once the MediaKeysListenerManager has been + // refactored to work with system media controls this should no longer be + // needed and should be deleted. + void SetIsMediaPlaying(bool is_playing); + HardwareKeyMediaController* hardware_key_media_controller_for_testing() { return hardware_key_media_controller_.get(); } @@ -118,6 +124,8 @@ // True if auxiliary services have already been started. bool auxiliary_services_started_; + bool is_media_playing_ = false; + #if defined(OS_MACOSX) std::unique_ptr<NowPlayingInfoCenterNotifier> now_playing_info_center_notifier_;
diff --git a/content/browser/media/media_keys_listener_manager_impl_browsertest.cc b/content/browser/media/media_keys_listener_manager_impl_browsertest.cc index 080921c..2469df3 100644 --- a/content/browser/media/media_keys_listener_manager_impl_browsertest.cc +++ b/content/browser/media/media_keys_listener_manager_impl_browsertest.cc
@@ -40,19 +40,25 @@ void StopWatchingMediaKey(ui::KeyboardCode key_code) override { key_codes_.erase(key_code); } + void SetIsMediaPlaying(bool is_playing) override { + is_media_playing_ = is_playing; + } void SimulateAccelerator(ui::Accelerator accelerator) { if (IsWatching(accelerator.key_code())) delegate_->OnMediaKeysAccelerator(accelerator); } - bool IsWatching(ui::KeyboardCode key_code) { + bool IsWatching(ui::KeyboardCode key_code) const { return key_codes_.contains(key_code); } + bool is_media_playing() const { return is_media_playing_; } + private: ui::MediaKeysListener::Delegate* delegate_; base::flat_set<ui::KeyboardCode> key_codes_; + bool is_media_playing_ = false; DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListener); }; @@ -158,6 +164,9 @@ EXPECT_EQ(0, media_controller()->suspend_count()); EXPECT_EQ(0, media_controller()->resume_count()); + // The MediaKeysListener should know that media is playing. + EXPECT_TRUE(media_keys_listener()->is_media_playing()); + // Press the play/pause media key. media_keys_listener()->SimulateAccelerator( ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, 0)); @@ -176,6 +185,9 @@ SetSupportedMediaSessionActions({MediaSessionAction::kPlay}); } + // The MediaKeysListener should know that media is paused. + EXPECT_FALSE(media_keys_listener()->is_media_playing()); + // Press play/pause. media_keys_listener()->SimulateAccelerator( ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, 0));
diff --git a/content/browser/media/session/media_session_browsertest.cc b/content/browser/media/session/media_session_browsertest.cc index c251955..9315f9d 100644 --- a/content/browser/media/session/media_session_browsertest.cc +++ b/content/browser/media/session/media_session_browsertest.cc
@@ -214,8 +214,8 @@ base::Lock visited_urls_lock_; std::set<GURL> visited_urls_; - base::test::ScopedFeatureList disabled_feature_list_; base::test::ScopedFeatureList scoped_feature_list_; + base::test::ScopedFeatureList disabled_feature_list_; DISALLOW_COPY_AND_ASSIGN(MediaSessionBrowserTest); };
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc index 82b6868..90c68dd 100644 --- a/content/browser/network_service_client.cc +++ b/content/browser/network_service_client.cc
@@ -451,6 +451,11 @@ // returning early should this be the case. WebContents* web_contents = WebContents::FromRenderFrameHost(frame); + // |web_contents| will be null on interstitial pages, which means the frame + // has been navigated away from and the function should return early. + if (!web_contents) + return; + RenderFrameHostImpl* root_frame_host = frame; while (root_frame_host->GetParent() != nullptr) root_frame_host = root_frame_host->GetParent(); @@ -531,6 +536,12 @@ base::Unretained(this)))) #endif { + +#if defined(OS_MACOSX) + if (base::MessageLoopCurrentForUI::IsSet()) // Not set in some unit tests. + net::CertDatabase::GetInstance()->StartListeningForKeychainEvents(); +#endif + if (IsOutOfProcessNetworkService()) { net::CertDatabase::GetInstance()->AddObserver(this); memory_pressure_listener_ =
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc index 51056a83..e32f490 100644 --- a/content/browser/renderer_host/code_cache_host_impl.cc +++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -195,7 +195,7 @@ "CodeCacheHostImpl::DidGenerateCacheableMetadataInCacheStorage", TRACE_ID_GLOBAL(trace_id), TRACE_EVENT_FLAG_FLOW_OUT, "url", url.spec()); - if (!cache_storage_context_->cache_manager()) + if (!cache_storage_context_->CacheManager()) return; scoped_refptr<net::IOBuffer> buf = @@ -204,7 +204,7 @@ memcpy(buf->data(), data.data(), data.size()); CacheStorageHandle cache_storage = - cache_storage_context_->cache_manager()->OpenCacheStorage( + cache_storage_context_->CacheManager()->OpenCacheStorage( cache_storage_origin, CacheStorageOwner::kCacheAPI); cache_storage.value()->OpenCache( cache_storage_cache_name, trace_id,
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.cc b/content/browser/renderer_host/render_frame_metadata_provider_impl.cc index 5c3dbee..03a157b 100644 --- a/content/browser/renderer_host/render_frame_metadata_provider_impl.cc +++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.cc
@@ -35,16 +35,37 @@ render_frame_metadata_observer_client_binding_.Bind(std::move(client_request), task_runner_); - if (pending_report_all_frame_submission_.has_value()) { - ReportAllFrameSubmissionsForTesting(*pending_report_all_frame_submission_); - pending_report_all_frame_submission_.reset(); +#if defined(OS_ANDROID) + if (pending_report_all_root_scrolls_for_accessibility_.has_value()) { + ReportAllRootScrollsForAccessibility( + *pending_report_all_root_scrolls_for_accessibility_); + pending_report_all_root_scrolls_for_accessibility_.reset(); + } +#endif + if (pending_report_all_frame_submission_for_testing_.has_value()) { + ReportAllFrameSubmissionsForTesting( + *pending_report_all_frame_submission_for_testing_); + pending_report_all_frame_submission_for_testing_.reset(); } } +#if defined(OS_ANDROID) +void RenderFrameMetadataProviderImpl::ReportAllRootScrollsForAccessibility( + bool enabled) { + if (!render_frame_metadata_observer_ptr_) { + pending_report_all_root_scrolls_for_accessibility_ = enabled; + return; + } + + render_frame_metadata_observer_ptr_->ReportAllRootScrollsForAccessibility( + enabled); +} +#endif + void RenderFrameMetadataProviderImpl::ReportAllFrameSubmissionsForTesting( bool enabled) { if (!render_frame_metadata_observer_ptr_) { - pending_report_all_frame_submission_ = enabled; + pending_report_all_frame_submission_for_testing_ = enabled; return; }
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.h b/content/browser/renderer_host/render_frame_metadata_provider_impl.h index 4516793..51650fd75 100644 --- a/content/browser/renderer_host/render_frame_metadata_provider_impl.h +++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "build/build_config.h" #include "content/common/render_frame_metadata.mojom.h" #include "content/public/browser/render_frame_metadata_provider.h" #include "mojo/public/cpp/bindings/binding.h" @@ -40,6 +41,12 @@ const cc::RenderFrameMetadata& LastRenderFrameMetadata() override; +#if defined(OS_ANDROID) + // Notifies the renderer to begin sending a notification on all root scroll + // changes, which is needed for accessibility on Android. + void ReportAllRootScrollsForAccessibility(bool enabled); +#endif + // Notifies the renderer to begin sending a notification on all frame // submissions. void ReportAllFrameSubmissionsForTesting(bool enabled); @@ -81,7 +88,10 @@ render_frame_metadata_observer_client_binding_; mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer_ptr_; - base::Optional<bool> pending_report_all_frame_submission_; +#if defined(OS_ANDROID) + base::Optional<bool> pending_report_all_root_scrolls_for_accessibility_; +#endif + base::Optional<bool> pending_report_all_frame_submission_for_testing_; base::WeakPtrFactory<RenderFrameMetadataProviderImpl> weak_factory_;
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index f235629..6ac81d6 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -274,6 +274,9 @@ mojom::RenderFrameMetadataObserverClientPtrInfo client_info); ~FakeRenderFrameMetadataObserver() override {} +#if defined(OS_ANDROID) + void ReportAllRootScrollsForAccessibility(bool enabled) override {} +#endif void ReportAllFrameSubmissionsForTesting(bool enabled) override {} private:
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index d1af81a4..8c00e392 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -2519,4 +2519,15 @@ } } +void RenderWidgetHostViewAndroid::SetWebContentsAccessibility( + WebContentsAccessibilityAndroid* web_contents_accessibility) { + web_contents_accessibility_ = web_contents_accessibility; + + if (host()) { + host() + ->render_frame_metadata_provider() + ->ReportAllRootScrollsForAccessibility(!!web_contents_accessibility_); + } +} + } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 3053d08..00f0346 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -350,6 +350,9 @@ void WasEvicted(); + void SetWebContentsAccessibility( + WebContentsAccessibilityAndroid* web_contents_accessibility); + ui::DelegatedFrameHostAndroid* delegated_frame_host_for_testing() { return delegated_frame_host_.get(); } @@ -548,6 +551,8 @@ // either RenderFrameMetadata or CompositorFrameMetadata. base::Optional<DevToolsFrameMetadata> last_devtools_frame_metadata_; + WebContentsAccessibilityAndroid* web_contents_accessibility_ = nullptr; + base::WeakPtrFactory<RenderWidgetHostViewAndroid> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewAndroid);
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h index 903131f..81bdc91 100644 --- a/content/browser/renderer_host/render_widget_host_view_base.h +++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -78,7 +78,6 @@ class SyntheticGestureTarget; class TextInputManager; class TouchSelectionControllerClientManager; -class WebContentsAccessibility; class WebCursor; class DelegatedFrameHost; struct TextInputState; @@ -565,10 +564,6 @@ bool is_fullscreen() { return is_fullscreen_; } - void set_web_contents_accessibility(WebContentsAccessibility* wcax) { - web_contents_accessibility_ = wcax; - } - void set_is_currently_scrolling_viewport( bool is_currently_scrolling_viewport) { is_currently_scrolling_viewport_ = is_currently_scrolling_viewport; @@ -660,8 +655,6 @@ // |content_background_color|. base::Optional<SkColor> default_background_color_; - WebContentsAccessibility* web_contents_accessibility_ = nullptr; - bool is_currently_scrolling_viewport_ = false; private:
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index eb3fb92..325ac18f 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -3256,7 +3256,7 @@ void OpenCacheOnIOThread(int* result, base::OnceClosure continuation) { CacheStorageHandle cache_storage = - cache_storage_context_->cache_manager()->OpenCacheStorage( + cache_storage_context_->CacheManager()->OpenCacheStorage( url::Origin::Create(origin_), CacheStorageOwner::kCacheAPI); cache_storage.value()->OpenCache( cache_name_, /* trace_id = */ 0,
diff --git a/content/browser/startup_helper.cc b/content/browser/startup_helper.cc index eff43f8..aec43ef 100644 --- a/content/browser/startup_helper.cc +++ b/content/browser/startup_helper.cc
@@ -4,6 +4,11 @@ #include "content/browser/startup_helper.h" +#include <algorithm> +#include <memory> +#include <set> +#include <string> + #include "base/base_switches.h" #include "base/command_line.h" #include "base/system/sys_info.h" @@ -16,7 +21,9 @@ namespace content { std::unique_ptr<base::FieldTrialList> SetUpFieldTrialsAndFeatureList() { - auto field_trial_list = std::make_unique<base::FieldTrialList>(nullptr); + std::unique_ptr<base::FieldTrialList> field_trial_list; + if (!base::FieldTrialList::GetInstance()) + field_trial_list = std::make_unique<base::FieldTrialList>(nullptr); const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/content/browser/tracing/startup_tracing_browsertest.cc b/content/browser/tracing/startup_tracing_browsertest.cc index e067ff1..5ce4792 100644 --- a/content/browser/tracing/startup_tracing_browsertest.cc +++ b/content/browser/tracing/startup_tracing_browsertest.cc
@@ -122,8 +122,7 @@ // StartupTraceWriter, which Perfetto will then have to sync copy into // the SMB once the full tracing service starts up. This is to catch common // deadlocks. -IN_PROC_BROWSER_TEST_F(StartupTracingInProcessTest, - DISABLED_TestFilledStartupBuffer) { +IN_PROC_BROWSER_TEST_F(StartupTracingInProcessTest, TestFilledStartupBuffer) { tracing::TraceEventDataSource::GetInstance()->SetupStartupTracing( /*privacy_filtering_enabled=*/false);
diff --git a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc index 93331d0..9343d54 100644 --- a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc +++ b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
@@ -124,11 +124,11 @@ // created. (Needed for the tests that use real certificate, i.e. // RealCertVerifier) net::EmbeddedTestServer::RegisterTestCerts(); + feature_list_.InitWithFeatures({features::kSignedHTTPExchange}, {}); } void SetUp() override { sxg_test_helper_.SetUp(); - feature_list_.InitWithFeatures({features::kSignedHTTPExchange}, {}); CertVerifierBrowserTest::SetUp(); } @@ -209,10 +209,7 @@ bool /* sxg_subresource_prefetch_enabled */>>, public SignedExchangeRequestHandlerBrowserTestBase { public: - SignedExchangeRequestHandlerBrowserTest() = default; - ~SignedExchangeRequestHandlerBrowserTest() = default; - - void SetUp() override { + SignedExchangeRequestHandlerBrowserTest() { bool network_service_enabled; bool sxg_subresource_prefetch_enabled; std::tie(prefetch_enabled_, network_service_enabled, @@ -230,14 +227,14 @@ disabled_features.push_back(features::kSignedExchangeSubresourcePrefetch); } feature_list_.InitWithFeatures(enable_features, disabled_features); - SignedExchangeRequestHandlerBrowserTestBase::SetUp(); } + ~SignedExchangeRequestHandlerBrowserTest() = default; protected: bool PrefetchIsEnabled() const { return prefetch_enabled_; } private: - bool prefetch_enabled_; + bool prefetch_enabled_ = false; base::test::ScopedFeatureList feature_list_; DISALLOW_COPY_AND_ASSIGN(SignedExchangeRequestHandlerBrowserTest);
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index d2e0f60..bdf7225 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -20,6 +20,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/system/sys_info.h" +#include "base/test/bind_test_util.h" #include "base/test/gtest_util.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_mock_time_task_runner.h" @@ -112,6 +113,7 @@ } OriginClaimedAuthorityPair; constexpr char kTestOrigin1[] = "https://a.google.com"; +constexpr char kTestOrigin2[] = "https://acme.org"; constexpr char kTestRelyingPartyId[] = "google.com"; constexpr char kCryptotokenOrigin[] = "chrome-extension://kmendfapggjehodndflmmgagdbamhnfd"; @@ -1327,19 +1329,14 @@ TestGetAssertionCallback callback_receiver; authenticator->GetAssertion(std::move(options), callback_receiver.callback()); - // Delete the |AuthenticatorImpl| during the registration operation to - // simulate a navigation while waiting for the user to press the token. + // Simulate a navigation while waiting for the user to press the token. virtual_device_factory_->mutable_state()->simulate_press_callback = - base::BindRepeating( - [](std::unique_ptr<AuthenticatorImpl>* ptr) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce( - [](std::unique_ptr<AuthenticatorImpl>* ptr) { - ptr->reset(); - }, - ptr)); - }, - &authenticator_impl_); + base::BindLambdaForTesting([&](device::VirtualFidoDevice* device) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindLambdaForTesting( + [&]() { SimulateNavigation(GURL(kTestOrigin2)); })); + return false; + }); run_loop.Run(); } @@ -1399,7 +1396,12 @@ bool pressed = false; virtual_device_factory_->mutable_state()->simulate_press_callback = - base::BindRepeating([](bool* flag) { *flag = true; }, &pressed); + base::BindRepeating( + [](bool* flag, device::VirtualFidoDevice* device) { + *flag = true; + return true; + }, + &pressed); TestGetAssertionCallback callback_receiver; AuthenticatorPtr authenticator = ConnectToAuthenticator();
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc index d68f328..f1a36fe 100644 --- a/content/browser/webauth/webauth_browsertest.cc +++ b/content/browser/webauth/webauth_browsertest.cc
@@ -1112,10 +1112,11 @@ auto* virtual_device_factory = InjectVirtualFidoDeviceFactory(); bool prompt_callback_was_invoked = false; virtual_device_factory->mutable_state()->simulate_press_callback = - base::BindLambdaForTesting([&]() { + base::BindLambdaForTesting([&](device::VirtualFidoDevice* device) { prompt_callback_was_invoked = true; NavigateIframeToURL(shell()->web_contents(), "test_iframe", GURL("/title2.html")); + return true; }); NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/page_with_iframe.html"));
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 9c2457e3..3fdeea8 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -245,6 +245,11 @@ enable_experimental_web_platform_features); WebRuntimeFeatures::EnableFeatureFromString( + "CSSBackdropFilter", + base::FeatureList::IsEnabled(blink::features::kCSSBackdropFilter) || + enable_experimental_web_platform_features); + + WebRuntimeFeatures::EnableFeatureFromString( "FastBorderRadius", base::FeatureList::IsEnabled(blink::features::kFastBorderRadius) || enable_experimental_web_platform_features);
diff --git a/content/common/render_frame_metadata.mojom b/content/common/render_frame_metadata.mojom index f1302d7..6b841dd 100644 --- a/content/common/render_frame_metadata.mojom +++ b/content/common/render_frame_metadata.mojom
@@ -85,17 +85,26 @@ bool has_transparent_background; }; -// This interface is provided by the renderer. It can optionally enable -// notifications for all frame submissions. +// This interface is provided by the renderer. It impacts the frequency with +// which a fully populated RenderFrameMetadata object (above) is delivered to +// the RenderFrameMetadataObserverClient. interface RenderFrameMetadataObserver { - // When |enabled| is set to true, this will notify the associated client of - // all frame submissions. + // When |enabled| is set to true, this will send RenderFrameMetadata to + // the RenderFrameMetadataObserverClient for any frame in which the root + // scroll changes. Used only on Android for accessibility cases. + [EnableIf=is_android] + ReportAllRootScrollsForAccessibility(bool enabled); + // When |enabled| is set to true, this will send RenderFrameMetadata to + // the RenderFrameMetadataObserverClient for all frames. Only used for + // tests. ReportAllFrameSubmissionsForTesting(bool enabled); }; -// This interface is provided by the browser. It is notified of all changes to +// This interface is provided by the browser. It is notified of changes to // RenderFrameMetadata. It can be notified of all frame submissions, via -// RenderFrameMetadataObserver::ReportAllFrameSubmissionsForTesting. +// RenderFrameMetadataObserver::ReportAllFrameSubmissionsForTesting, or of +// additional frames with root scroll offset changes via +// RenderFrameMetadataObserver::ReportAllRootScrollsForAccessibility. interface RenderFrameMetadataObserverClient { // Notified when RenderFrameMetadata has changed. OnRenderFrameMetadataChanged(uint32 frame_token, RenderFrameMetadata metadata);
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index 68a2523..5105923 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -155,8 +155,7 @@ extern int BrowserMain(const MainFunctionParams&); BrowserTestBase::BrowserTestBase() - : field_trial_list_(std::make_unique<base::FieldTrialList>(nullptr)), - expected_exit_code_(0), + : expected_exit_code_(0), enable_pixel_output_(false), use_software_compositing_(false), set_up_called_(false) { @@ -334,7 +333,6 @@ command_line->AppendSwitchASCII(switches::kForceFieldTrials, field_trial_states); } - field_trial_list_.reset(); // Need to wipe feature list clean, since BrowserMain calls // FeatureList::SetInstance, which expects no instance to exist.
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc index 28605e85..3915614 100644 --- a/content/public/test/render_view_test.cc +++ b/content/public/test/render_view_test.cc
@@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/location.h" -#include "base/metrics/field_trial.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "build/build_config.h" @@ -308,10 +307,6 @@ #endif command_line_ = std::make_unique<base::CommandLine>(base::CommandLine::NO_PROGRAM); - field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); - // We don't use the descriptor here anyways so it's ok to pass -1. - base::FieldTrialList::CreateTrialsFromCommandLine( - *command_line_, switches::kFieldTrialHandle, -1); params_ = std::make_unique<MainFunctionParams>(*command_line_); platform_ = std::make_unique<RendererMainPlatformDelegate>(*params_); platform_->PlatformInitialize();
diff --git a/content/public/test/unittest_test_suite.cc b/content/public/test/unittest_test_suite.cc index d158baf..178d3403 100644 --- a/content/public/test/unittest_test_suite.cc +++ b/content/public/test/unittest_test_suite.cc
@@ -56,8 +56,7 @@ } // namespace -UnitTestTestSuite::UnitTestTestSuite(base::TestSuite* test_suite, - const std::string& disabled_features) +UnitTestTestSuite::UnitTestTestSuite(base::TestSuite* test_suite) : test_suite_(test_suite) { base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); std::string enabled = @@ -71,18 +70,6 @@ testing::UnitTest::GetInstance()->listeners(); listeners.Append(new ResetNetworkServiceBetweenTests); - // base::TestSuite will reset the FeatureList, so modify the underlying - // CommandLine object to disable the network service when it's parsed again. - if (!disabled_features.empty()) - disabled += "," + disabled_features; - base::CommandLine new_command_line(command_line->GetProgram()); - base::CommandLine::SwitchMap switches = command_line->GetSwitches(); - switches.erase(switches::kDisableFeatures); - new_command_line.AppendSwitchASCII(switches::kDisableFeatures, disabled); - for (const auto& iter : switches) - new_command_line.AppendSwitchNative(iter.first, iter.second); - *base::CommandLine::ForCurrentProcess() = new_command_line; - // The ThreadPool created by the test launcher is never destroyed. // Similarly, the FeatureList created here is never destroyed so it // can safely be accessed by the ThreadPool. @@ -94,7 +81,6 @@ #if defined(OS_FUCHSIA) // Use headless ozone platform on Fuchsia by default. // TODO(crbug.com/865172): Remove this flag. - command_line = base::CommandLine::ForCurrentProcess(); if (!command_line->HasSwitch(switches::kOzonePlatform)) command_line->AppendSwitchASCII(switches::kOzonePlatform, "headless"); #endif
diff --git a/content/public/test/unittest_test_suite.h b/content/public/test/unittest_test_suite.h index b329f3b2..7b28beb 100644 --- a/content/public/test/unittest_test_suite.h +++ b/content/public/test/unittest_test_suite.h
@@ -27,10 +27,7 @@ class UnitTestTestSuite { public: // Takes ownership of |test_suite|. - // |disabled_features| is an optional comma-separated list of features to - // disable. - UnitTestTestSuite(base::TestSuite* test_suite, - const std::string& disabled_features = std::string()); + explicit UnitTestTestSuite(base::TestSuite* test_suite); ~UnitTestTestSuite(); int Run();
diff --git a/content/renderer/render_frame_metadata_observer_impl.cc b/content/renderer/render_frame_metadata_observer_impl.cc index 31fe9a0..6d72311 100644 --- a/content/renderer/render_frame_metadata_observer_impl.cc +++ b/content/renderer/render_frame_metadata_observer_impl.cc
@@ -59,7 +59,8 @@ } // Allways cache the full metadata, so that it can correctly be sent upon - // ReportAllFrameSubmissionsForTesting. This must only be done after we've + // ReportAllFrameSubmissionsForTesting or + // ReportAllRootScrollsForAccessibility. This must only be done after we've // compared the two for changes. last_render_frame_metadata_ = render_frame_metadata; @@ -67,11 +68,11 @@ // generated for first time and same as the default value, update the default // value to all the observers. if (send_metadata && render_frame_metadata_observer_client_) { - // Sending |root_scroll_offset| outside of tests would leave the browser - // process with out of date information. It is an optional parameter - // which we clear here. auto metadata_copy = render_frame_metadata; #if !defined(OS_ANDROID) + // On non-Android, sending |root_scroll_offset| outside of tests would + // leave the browser process with out of date information. It is an + // optional parameter which we clear here. if (!report_all_frame_submissions_for_testing_enabled_) metadata_copy.root_scroll_offset = base::nullopt; #endif @@ -107,11 +108,26 @@ } } +#if defined(OS_ANDROID) +void RenderFrameMetadataObserverImpl::ReportAllRootScrollsForAccessibility( + bool enabled) { + report_all_root_scrolls_for_accessibility_enabled_ = enabled; + + if (enabled) + SendLastRenderFrameMetadata(); +} +#endif + void RenderFrameMetadataObserverImpl::ReportAllFrameSubmissionsForTesting( bool enabled) { report_all_frame_submissions_for_testing_enabled_ = enabled; - if (!enabled || !last_frame_token_) + if (enabled) + SendLastRenderFrameMetadata(); +} + +void RenderFrameMetadataObserverImpl::SendLastRenderFrameMetadata() { + if (!last_frame_token_) return; // When enabled for testing send the cached metadata. @@ -121,11 +137,10 @@ last_frame_token_, *last_render_frame_metadata_); } -// static bool RenderFrameMetadataObserverImpl::ShouldSendRenderFrameMetadata( const cc::RenderFrameMetadata& rfm1, const cc::RenderFrameMetadata& rfm2, - bool* needs_activation_notification) { + bool* needs_activation_notification) const { if (rfm1.root_background_color != rfm2.root_background_color || rfm1.is_scroll_offset_at_top != rfm2.is_scroll_offset_at_top || rfm1.selection != rfm2.selection || @@ -142,6 +157,9 @@ } #if defined(OS_ANDROID) + bool need_send_root_scroll = + report_all_root_scrolls_for_accessibility_enabled_ && + rfm1.root_scroll_offset != rfm2.root_scroll_offset; if (rfm1.bottom_controls_height != rfm2.bottom_controls_height || rfm1.bottom_controls_shown_ratio != rfm2.bottom_controls_shown_ratio || rfm1.min_page_scale_factor != rfm2.min_page_scale_factor || @@ -149,7 +167,8 @@ rfm1.root_overflow_y_hidden != rfm2.root_overflow_y_hidden || rfm1.scrollable_viewport_size != rfm2.scrollable_viewport_size || rfm1.root_layer_size != rfm2.root_layer_size || - rfm1.has_transparent_background != rfm2.has_transparent_background) { + rfm1.has_transparent_background != rfm2.has_transparent_background || + need_send_root_scroll) { *needs_activation_notification = true; return true; }
diff --git a/content/renderer/render_frame_metadata_observer_impl.h b/content/renderer/render_frame_metadata_observer_impl.h index fc830dc9..c0335ae9 100644 --- a/content/renderer/render_frame_metadata_observer_impl.h +++ b/content/renderer/render_frame_metadata_observer_impl.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_RENDERER_RENDER_FRAME_METADATA_OBSERVER_IMPL_H_ #define CONTENT_RENDERER_RENDER_FRAME_METADATA_OBSERVER_IMPL_H_ +#include "build/build_config.h" #include "cc/trees/render_frame_metadata.h" #include "cc/trees/render_frame_metadata_observer.h" #include "content/common/content_export.h" @@ -39,6 +40,9 @@ bool force_send) override; // mojom::RenderFrameMetadataObserver: +#if defined(OS_ANDROID) + void ReportAllRootScrollsForAccessibility(bool enabled) override; +#endif void ReportAllFrameSubmissionsForTesting(bool enabled) override; private: @@ -50,12 +54,19 @@ // |needs_activation_notification| indicates whether the browser process // expects notification of activation of the assoicated CompositorFrame from // Viz. - static bool ShouldSendRenderFrameMetadata( - const cc::RenderFrameMetadata& rfm1, - const cc::RenderFrameMetadata& rfm2, - bool* needs_activation_notification); + bool ShouldSendRenderFrameMetadata(const cc::RenderFrameMetadata& rfm1, + const cc::RenderFrameMetadata& rfm2, + bool* needs_activation_notification) const; - // When true this will notifiy |render_frame_metadata_observer_client_| of all + void SendLastRenderFrameMetadata(); + +#if defined(OS_ANDROID) + // When true this will notify |render_frame_metadata_observer_client_| of all + // frame submissions that involve a root scroll offset change. + bool report_all_root_scrolls_for_accessibility_enabled_ = false; +#endif + + // When true this will notify |render_frame_metadata_observer_client_| of all // frame submissions. bool report_all_frame_submissions_for_testing_enabled_ = false;
diff --git a/content/renderer/render_frame_metadata_observer_impl_unittest.cc b/content/renderer/render_frame_metadata_observer_impl_unittest.cc index 1f5803a..c569d77 100644 --- a/content/renderer/render_frame_metadata_observer_impl_unittest.cc +++ b/content/renderer/render_frame_metadata_observer_impl_unittest.cc
@@ -156,6 +156,91 @@ run_loop.Run(); } } + +// This test verifies that a request to send root scroll changes for +// accessibility is respected. +TEST_F(RenderFrameMetadataObserverImplTest, SendRootScrollsForAccessibility) { + const uint32_t expected_frame_token = 1337; + viz::CompositorFrameMetadata compositor_frame_metadata; + compositor_frame_metadata.send_frame_token_to_embedder = false; + compositor_frame_metadata.frame_token = expected_frame_token; + cc::RenderFrameMetadata render_frame_metadata; + + observer_impl().OnRenderFrameSubmission(render_frame_metadata, + &compositor_frame_metadata, + false /* force_send */); + // The first RenderFrameMetadata will always get a corresponding frame token + // from Viz because this is the first frame. + EXPECT_TRUE(compositor_frame_metadata.send_frame_token_to_embedder); + { + base::RunLoop run_loop; + EXPECT_CALL(client(), OnRenderFrameMetadataChanged(expected_frame_token, + render_frame_metadata)) + .WillOnce(InvokeClosure(run_loop.QuitClosure())); + run_loop.Run(); + } + + // Submit with a root scroll change and then a scroll offset at top change, we + // should only get one notification, as the root scroll change will not + // trigger one, + render_frame_metadata.root_scroll_offset = gfx::Vector2dF(0.0f, 100.0f); + observer_impl().OnRenderFrameSubmission(render_frame_metadata, + &compositor_frame_metadata, + false /* force_send */); + render_frame_metadata.is_scroll_offset_at_top = + !render_frame_metadata.is_scroll_offset_at_top; + observer_impl().OnRenderFrameSubmission(render_frame_metadata, + &compositor_frame_metadata, + false /* force_send */); + { + base::RunLoop run_loop; + EXPECT_CALL(client(), OnRenderFrameMetadataChanged(expected_frame_token, + render_frame_metadata)) + .WillOnce(InvokeClosure(run_loop.QuitClosure())); + run_loop.Run(); + } + + // Enable reporting for root scroll changes. This will generate one + // notification. + observer_impl().ReportAllRootScrollsForAccessibility(true); + { + base::RunLoop run_loop; + EXPECT_CALL(client(), OnRenderFrameMetadataChanged(expected_frame_token, + render_frame_metadata)) + .WillOnce(InvokeClosure(run_loop.QuitClosure())); + run_loop.Run(); + } + + // Now send a single root scroll change, we should get the notification. + render_frame_metadata.root_scroll_offset = gfx::Vector2dF(0.0f, 200.0f); + observer_impl().OnRenderFrameSubmission(render_frame_metadata, + &compositor_frame_metadata, + false /* force_send */); + { + base::RunLoop run_loop; + // The 0u frame token indicates that the client should not expect + // a corresponding frame token from Viz. + EXPECT_CALL(client(), OnRenderFrameMetadataChanged(expected_frame_token, + render_frame_metadata)) + .WillOnce(InvokeClosure(run_loop.QuitClosure())); + run_loop.Run(); + } + + // Send one more message to ensure that no spurious + // OnRenderFrameMetadataChanged messages were generated. + render_frame_metadata.is_scroll_offset_at_top = + !render_frame_metadata.is_scroll_offset_at_top; + observer_impl().OnRenderFrameSubmission(render_frame_metadata, + &compositor_frame_metadata, + false /* force_send */); + { + base::RunLoop run_loop; + EXPECT_CALL(client(), OnRenderFrameMetadataChanged(expected_frame_token, + render_frame_metadata)) + .WillOnce(InvokeClosure(run_loop.QuitClosure())); + run_loop.Run(); + } +} #endif // This test verifies that a request to force send metadata is respected.
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 73feffe..04575de 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc
@@ -180,6 +180,18 @@ static const char* kOOPIF = "OOPIF"; static const char* kRenderer = "Renderer"; +#if defined(OS_ANDROID) +// With 32 bit pixels, this would mean less than 400kb per buffer. Much less +// than required for, say, nHD. +static const int kSmallScreenPixelThreshold = 1e5; +bool IsSmallScreen(const gfx::Size& size) { + int area = 0; + if (!size.GetCheckedArea().AssignIfValid(&area)) + return false; + return area < kSmallScreenPixelThreshold; +} +#endif + class WebWidgetLockTarget : public content::MouseLockDispatcher::LockTarget { public: explicit WebWidgetLockTarget(blink::WebWidget* webwidget) @@ -3019,7 +3031,8 @@ #if defined(OS_ANDROID) bool using_synchronous_compositor = compositor_deps->UsingSynchronousCompositing(); - bool using_low_memory_policy = base::SysInfo::IsLowEndDevice(); + bool using_low_memory_policy = + base::SysInfo::IsLowEndDevice() && !IsSmallScreen(screen_size); settings.use_stream_video_draw_quad = true; settings.using_synchronous_renderer_compositor = using_synchronous_compositor;
diff --git a/content/renderer/renderer_main_platform_delegate_win.cc b/content/renderer/renderer_main_platform_delegate_win.cc index f59a53d..a93dc0ea 100644 --- a/content/renderer/renderer_main_platform_delegate_win.cc +++ b/content/renderer/renderer_main_platform_delegate_win.cc
@@ -4,13 +4,16 @@ #include "content/renderer/renderer_main_platform_delegate.h" +#include <delayimp.h> #include <dwrite.h> #include <memory> #include "base/command_line.h" +#include "base/debug/alias.h" #include "base/logging.h" #include "base/strings/string16.h" +#include "base/strings/string_util.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" #include "content/child/dwrite_font_proxy/dwrite_font_proxy_init_impl_win.h" @@ -29,6 +32,31 @@ namespace content { +namespace { + +// Delay load failure hook that generates a crash report. By default a failure +// to delay load will trigger an exception handled by the delay load runtime and +// this won't generate a crash report. +extern "C" FARPROC WINAPI DelayLoadFailureHook(unsigned reason, + DelayLoadInfo* dll_info) { + char dll_name[256]; + base::strlcpy(dll_name, dll_info->szDll, base::size(dll_name)); + base::debug::Alias(&dll_name); + + CHECK(false); + return 0; +} + +// Set the delay load failure hook to the function above. +// +// The |__pfnDliFailureHook2| failure notification hook gets called +// automatically by the delay load runtime in case of failure, see +// https://docs.microsoft.com/en-us/cpp/build/reference/failure-hooks?view=vs-2019 +// for more information about this. +extern "C" const PfnDliHook __pfnDliFailureHook2 = DelayLoadFailureHook; + +} // namespace + RendererMainPlatformDelegate::RendererMainPlatformDelegate( const MainFunctionParams& parameters) : parameters_(parameters) {}
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 6408d1c..90aa125a 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -174,6 +174,7 @@ # Failing on Nexus 5 crbug.com/957714 [ android qualcomm-adreno-(tm)-330 ] Pixel_Canvas2DRedBox [ Failure ] +crbug.com/900706 [ android qualcomm-adreno-(tm)-330 ] Pixel_CanvasLowLatency2D [ Failure ] # Failing on Pixel 2 FYI. crbug.com/966069 [ android qualcomm-adreno-(tm)-540 ] Pixel_CanvasLowLatency2D [ Failure ]
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h index 13b5b3b..74028fc 100644 --- a/device/bluetooth/bluetooth_device.h +++ b/device/bluetooth/bluetooth_device.h
@@ -252,7 +252,7 @@ // of, by decoding the bluetooth class information for Classic devices or // by decoding the device's appearance for LE devices. For example, // Microsoft Universal Foldable Keyboard only advertises the appearance. - BluetoothDeviceType GetDeviceType() const; + virtual BluetoothDeviceType GetDeviceType() const; // Indicates whether the device is known to support pairing based on its // device class and address.
diff --git a/device/bluetooth/chromeos/bluetooth_utils.cc b/device/bluetooth/chromeos/bluetooth_utils.cc index 69194dd4e..7b5a658 100644 --- a/device/bluetooth/chromeos/bluetooth_utils.cc +++ b/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -8,10 +8,12 @@ #include "base/feature_list.h" #include "base/metrics/field_trial_params.h" +#include "base/metrics/histogram_functions.h" #include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/time/time.h" #include "chromeos/constants/chromeos_features.h" #include "device/base/features.h" @@ -27,6 +29,9 @@ const size_t kLongTermKeyHexStringLength = 32; +constexpr base::TimeDelta kMaxDeviceSelectionDuration = + base::TimeDelta::FromSeconds(30); + // Get limited number of devices from |devices| and // prioritize paired/connecting devices over other devices. BluetoothAdapter::DeviceList GetLimitedNumDevices( @@ -97,6 +102,13 @@ return result; } +void RecordDeviceSelectionDuration(const std::string& histogram_name, + base::TimeDelta duration) { + base::UmaHistogramCustomTimes( + histogram_name, duration, base::TimeDelta::FromMilliseconds(1) /* min */, + kMaxDeviceSelectionDuration /* max */, 50 /* buckets */); +} + } // namespace device::BluetoothAdapter::DeviceList FilterBluetoothDeviceList( @@ -134,4 +146,51 @@ return long_term_keys; } +void RecordDeviceSelectionDuration(base::TimeDelta duration, + BluetoothUiSurface surface, + bool was_paired, + BluetoothTransport transport) { + // Throw out longtail results of the user taking longer than + // |kMaxDeviceSelectionDuration|. Assume that these thrown out results reflect + // the user not being actively engaged with device connection: leaving the + // page open for a long time, walking away from computer, etc. + if (duration > kMaxDeviceSelectionDuration) + return; + + std::string base_histogram_name = + "Bluetooth.ChromeOS.DeviceSelectionDuration"; + RecordDeviceSelectionDuration(base_histogram_name, duration); + + std::string surface_name = + (surface == BluetoothUiSurface::kSettings ? "Settings" : "SystemTray"); + std::string surface_histogram_name = base_histogram_name + "." + surface_name; + RecordDeviceSelectionDuration(surface_histogram_name, duration); + + std::string paired_name = (was_paired ? "Paired" : "NotPaired"); + std::string paired_histogram_name = + surface_histogram_name + "." + paired_name; + RecordDeviceSelectionDuration(paired_histogram_name, duration); + + if (!was_paired) { + std::string transport_name; + switch (transport) { + case BLUETOOTH_TRANSPORT_CLASSIC: + transport_name = "Classic"; + break; + case BLUETOOTH_TRANSPORT_LE: + transport_name = "BLE"; + break; + case BLUETOOTH_TRANSPORT_DUAL: + transport_name = "Dual"; + break; + default: + return; + } + + std::string transport_histogram_name = + paired_histogram_name + "." + transport_name; + RecordDeviceSelectionDuration(transport_histogram_name, duration); + } +} + } // namespace device
diff --git a/device/bluetooth/chromeos/bluetooth_utils.h b/device/bluetooth/chromeos/bluetooth_utils.h index 32ab5c02..12aa626f 100644 --- a/device/bluetooth/chromeos/bluetooth_utils.h +++ b/device/bluetooth/chromeos/bluetooth_utils.h
@@ -10,6 +10,10 @@ #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_export.h" +namespace base { +class TimeDelta; +} // namespace base + // This file contains common utilities, including filtering bluetooth devices // based on the filter criteria. namespace device { @@ -22,6 +26,11 @@ KNOWN, }; +enum class BluetoothUiSurface { + kSettings, + kSystemTray, +}; + // Return filtered devices based on the filter type and max number of devices. device::BluetoothAdapter::DeviceList DEVICE_BLUETOOTH_EXPORT FilterBluetoothDeviceList(const BluetoothAdapter::DeviceList& devices, @@ -31,6 +40,14 @@ std::vector<std::vector<uint8_t>> DEVICE_BLUETOOTH_EXPORT GetBlockedLongTermKeys(); +// Record how long it took for a user to find and select the device they wished +// to connect to. +void DEVICE_BLUETOOTH_EXPORT +RecordDeviceSelectionDuration(base::TimeDelta duration, + BluetoothUiSurface surface, + bool was_paired, + BluetoothTransport transport); + } // namespace device #endif // DEVICE_BLUETOOTH_CHROMEOS_BLUETOOTH_UTILS_H_
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc index 77eef9e..af2c007 100644 --- a/device/fido/virtual_ctap2_device.cc +++ b/device/fido/virtual_ctap2_device.cc
@@ -84,7 +84,7 @@ // CheckUserVerification implements the first, common steps of // makeCredential and getAssertion from the CTAP2 spec. -CtapDeviceResponseCode CheckUserVerification( +base::Optional<CtapDeviceResponseCode> CheckUserVerification( bool is_make_credential, const AuthenticatorSupportedOptions& options, const base::Optional<std::vector<uint8_t>>& pin_auth, @@ -92,7 +92,7 @@ base::span<const uint8_t> pin_token, base::span<const uint8_t> client_data_hash, UserVerificationRequirement user_verification, - base::RepeatingCallback<void(void)> simulate_press_callback, + base::RepeatingCallback<bool(void)> simulate_press_callback, bool* out_user_verified) { // The following quotes are from the CTAP2 spec: @@ -103,9 +103,9 @@ options.client_pin_availability != AuthenticatorSupportedOptions::ClientPinAvailability::kNotSupported; if (supports_pin && pin_auth && pin_auth->empty()) { - if (simulate_press_callback) { - simulate_press_callback.Run(); - } + if (simulate_press_callback && !simulate_press_callback.Run()) + return base::nullopt; + switch (options.client_pin_availability) { case AuthenticatorSupportedOptions::ClientPinAvailability:: kSupportedAndPinSet: @@ -149,9 +149,9 @@ AuthenticatorSupportedOptions::UserVerificationAvailability:: kSupportedAndConfigured) { // Internal UV is assumed to always succeed. - if (simulate_press_callback) { - simulate_press_callback.Run(); - } + if (simulate_press_callback && !simulate_press_callback.Run()) + return base::nullopt; + uv = true; } else { // UV was requested, but either not supported or not configured. @@ -558,12 +558,24 @@ response_code = OnAuthenticatorGetInfo(&response_data); break; - case CtapRequestCommand::kAuthenticatorMakeCredential: - response_code = OnMakeCredential(request_bytes, &response_data); + case CtapRequestCommand::kAuthenticatorMakeCredential: { + auto opt_response_code = OnMakeCredential(request_bytes, &response_data); + if (!opt_response_code) { + // Simulate timeout due to unresponded User Presence check. + return 0; + } + response_code = *opt_response_code; break; - case CtapRequestCommand::kAuthenticatorGetAssertion: - response_code = OnGetAssertion(request_bytes, &response_data); + } + case CtapRequestCommand::kAuthenticatorGetAssertion: { + auto opt_response_code = OnGetAssertion(request_bytes, &response_data); + if (!opt_response_code) { + // Simulate timeout due to unresponded User Presence check. + return 0; + } + response_code = *opt_response_code; break; + } case CtapRequestCommand::kAuthenticatorGetNextAssertion: response_code = OnGetNextAssertion(request_bytes, &response_data); break; @@ -595,7 +607,7 @@ device_info_->options = options; } -CtapDeviceResponseCode VirtualCtap2Device::OnMakeCredential( +base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnMakeCredential( base::span<const uint8_t> request_bytes, std::vector<uint8_t>* response) { const auto& cbor_request = cbor::Reader::Read(request_bytes); @@ -616,10 +628,14 @@ const AuthenticatorSupportedOptions& options = device_info_->options; bool user_verified; - const CtapDeviceResponseCode uv_error = CheckUserVerification( + const base::Optional<CtapDeviceResponseCode> uv_error = CheckUserVerification( true /* is makeCredential */, options, request.pin_auth, request.pin_protocol, mutable_state()->pin_token, client_data_hash, - request.user_verification, mutable_state()->simulate_press_callback, + request.user_verification, + mutable_state()->simulate_press_callback + ? base::BindRepeating(mutable_state()->simulate_press_callback, + base::Unretained(this)) + : base::RepeatingCallback<bool(void)>(), &user_verified); if (uv_error != CtapDeviceResponseCode::kSuccess) { return uv_error; @@ -643,8 +659,9 @@ // a credentials ends up being created it'll overwrite this one. continue; } - if (mutable_state()->simulate_press_callback) { - mutable_state()->simulate_press_callback.Run(); + if (mutable_state()->simulate_press_callback && + !mutable_state()->simulate_press_callback.Run(this)) { + return base::nullopt; } return CtapDeviceResponseCode::kCtap2ErrCredentialExcluded; } @@ -665,8 +682,9 @@ } // Step 10. - if (!user_verified && mutable_state()->simulate_press_callback) { - mutable_state()->simulate_press_callback.Run(); + if (!user_verified && mutable_state()->simulate_press_callback && + !mutable_state()->simulate_press_callback.Run(this)) { + return base::nullopt; } // Create key to register. @@ -764,7 +782,7 @@ return CtapDeviceResponseCode::kSuccess; } -CtapDeviceResponseCode VirtualCtap2Device::OnGetAssertion( +base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnGetAssertion( base::span<const uint8_t> request_bytes, std::vector<uint8_t>* response) { // Step numbers in this function refer to @@ -787,10 +805,14 @@ const AuthenticatorSupportedOptions& options = device_info_->options; bool user_verified; - const CtapDeviceResponseCode uv_error = CheckUserVerification( + const base::Optional<CtapDeviceResponseCode> uv_error = CheckUserVerification( false /* not makeCredential */, options, request.pin_auth, request.pin_protocol, mutable_state()->pin_token, client_data_hash, - request.user_verification, mutable_state()->simulate_press_callback, + request.user_verification, + mutable_state()->simulate_press_callback + ? base::BindRepeating(mutable_state()->simulate_press_callback, + base::Unretained(this)) + : base::RepeatingCallback<bool(void)>(), &user_verified); if (uv_error != CtapDeviceResponseCode::kSuccess) { return uv_error; @@ -871,8 +893,9 @@ // Step 7. if (request.user_presence_required && !user_verified && - mutable_state()->simulate_press_callback) { - mutable_state()->simulate_press_callback.Run(); + mutable_state()->simulate_press_callback && + !mutable_state()->simulate_press_callback.Run(this)) { + return base::nullopt; } // Step 8.
diff --git a/device/fido/virtual_ctap2_device.h b/device/fido/virtual_ctap2_device.h index 4bb014b..b7853a718 100644 --- a/device/fido/virtual_ctap2_device.h +++ b/device/fido/virtual_ctap2_device.h
@@ -82,10 +82,12 @@ const AuthenticatorSupportedOptions& options); private: - CtapDeviceResponseCode OnMakeCredential(base::span<const uint8_t> request, - std::vector<uint8_t>* response); - CtapDeviceResponseCode OnGetAssertion(base::span<const uint8_t> request, - std::vector<uint8_t>* response); + base::Optional<CtapDeviceResponseCode> OnMakeCredential( + base::span<const uint8_t> request, + std::vector<uint8_t>* response); + base::Optional<CtapDeviceResponseCode> OnGetAssertion( + base::span<const uint8_t> request, + std::vector<uint8_t>* response); CtapDeviceResponseCode OnGetNextAssertion(base::span<const uint8_t> request, std::vector<uint8_t>* response); CtapDeviceResponseCode OnPINCommand(base::span<const uint8_t> request,
diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h index debfd32..397f0b2c 100644 --- a/device/fido/virtual_fido_device.h +++ b/device/fido/virtual_fido_device.h
@@ -73,6 +73,8 @@ using RegistrationsMap = std::map<std::vector<uint8_t>, RegistrationData, fido_parsing_utils::RangeLess>; + using SimulatePressCallback = + base::RepeatingCallback<bool(VirtualFidoDevice*)>; State(); @@ -86,9 +88,10 @@ // Registered keys. Keyed on key handle (a.k.a. "credential ID"). RegistrationsMap registrations; - // If set, this callback is called whenever a "press" is required. It allows - // tests to change the state of the world during processing. - base::RepeatingCallback<void(void)> simulate_press_callback; + // If set, this callback is called whenever a "press" is required. Returning + // `true` will simulate a press and continue the request, returning `false` + // simulates the user not pressing the device and leaves the request idle. + SimulatePressCallback simulate_press_callback; // If true, causes the response from the device to be invalid. bool simulate_invalid_response = false;
diff --git a/device/fido/virtual_u2f_device.cc b/device/fido/virtual_u2f_device.cc index 31322392..6260205 100644 --- a/device/fido/virtual_u2f_device.cc +++ b/device/fido/virtual_u2f_device.cc
@@ -98,10 +98,12 @@ response = ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED); } - // Call |callback| via the |MessageLoop| because |AuthenticatorImpl| doesn't - // support callback hairpinning. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(cb), std::move(response))); + if (response) { + // Call |callback| via the |MessageLoop| because |AuthenticatorImpl| doesn't + // support callback hairpinning. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(cb), std::move(response))); + } return 0; } @@ -119,7 +121,8 @@ } if (mutable_state()->simulate_press_callback) { - mutable_state()->simulate_press_callback.Run(); + if (!mutable_state()->simulate_press_callback.Run(this)) + return base::nullopt; } auto challenge_param = data.first<32>(); @@ -199,7 +202,8 @@ } if (mutable_state()->simulate_press_callback) { - mutable_state()->simulate_press_callback.Run(); + if (!mutable_state()->simulate_press_callback.Run(this)) + return base::nullopt; } if (data.size() < 32 + 32 + 1)
diff --git a/docs/ui/android/mvc_simple_list_tutorial.md b/docs/ui/android/mvc_simple_list_tutorial.md index 98b79d6..cba200e 100644 --- a/docs/ui/android/mvc_simple_list_tutorial.md +++ b/docs/ui/android/mvc_simple_list_tutorial.md
@@ -31,7 +31,7 @@ public class SimpleMenuCoordinator { public SimpleMenuCoordinator(Context context, ListView listView) { - ModelListAdapter adapter = new ModelListAdapter(context); + ModelListAdapter adapter = new ModelListAdapter(); final LayoutInflater layoutInflater = context.getSystemService(LAYOUT_INFLATER_SERVICE);
diff --git a/extensions/browser/api/bluetooth/bluetooth_private_api.cc b/extensions/browser/api/bluetooth/bluetooth_private_api.cc index 0b9acda..d88298e 100644 --- a/extensions/browser/api/bluetooth/bluetooth_private_api.cc +++ b/extensions/browser/api/bluetooth/bluetooth_private_api.cc
@@ -26,6 +26,10 @@ #include "extensions/common/api/bluetooth.h" #include "extensions/common/api/bluetooth_private.h" +#if defined(OS_CHROMEOS) +#include "device/bluetooth/chromeos/bluetooth_utils.h" +#endif + namespace bt = extensions::api::bluetooth; namespace bt_private = extensions::api::bluetooth_private; namespace SetDiscoveryFilter = bt_private::SetDiscoveryFilter; @@ -675,6 +679,8 @@ Respond(Error(kPairingFailed)); } +//////////////////////////////////////////////////////////////////////////////// + BluetoothPrivateRecordPairingFunction::BluetoothPrivateRecordPairingFunction() = default; @@ -693,6 +699,8 @@ RecordPairingTransport(params_->transport); } +//////////////////////////////////////////////////////////////////////////////// + BluetoothPrivateRecordReconnectionFunction:: BluetoothPrivateRecordReconnectionFunction() = default; @@ -716,6 +724,44 @@ //////////////////////////////////////////////////////////////////////////////// +BluetoothPrivateRecordDeviceSelectionFunction:: + BluetoothPrivateRecordDeviceSelectionFunction() = default; + +BluetoothPrivateRecordDeviceSelectionFunction:: + ~BluetoothPrivateRecordDeviceSelectionFunction() = default; + +bool BluetoothPrivateRecordDeviceSelectionFunction::CreateParams() { + params_ = bt_private::RecordDeviceSelection::Params::Create(*args_); + return params_ != nullptr; +} + +void BluetoothPrivateRecordDeviceSelectionFunction::DoWork( + scoped_refptr<device::BluetoothAdapter> adapter) { +#if defined(OS_CHROMEOS) + device::BluetoothTransport transport; + switch (params_->transport) { + case bt::Transport::TRANSPORT_CLASSIC: + transport = device::BLUETOOTH_TRANSPORT_CLASSIC; + break; + case bt::Transport::TRANSPORT_LE: + transport = device::BLUETOOTH_TRANSPORT_LE; + break; + case bt::Transport::TRANSPORT_DUAL: + transport = device::BLUETOOTH_TRANSPORT_DUAL; + break; + default: + transport = device::BLUETOOTH_TRANSPORT_INVALID; + break; + } + + device::RecordDeviceSelectionDuration( + base::TimeDelta::FromMilliseconds(params_->selection_duration_ms), + device::BluetoothUiSurface::kSettings, params_->was_paired, transport); +#endif +} + +//////////////////////////////////////////////////////////////////////////////// + } // namespace api } // namespace extensions
diff --git a/extensions/browser/api/bluetooth/bluetooth_private_api.h b/extensions/browser/api/bluetooth/bluetooth_private_api.h index 57cfaa1d..ec8b0e5 100644 --- a/extensions/browser/api/bluetooth/bluetooth_private_api.h +++ b/extensions/browser/api/bluetooth/bluetooth_private_api.h
@@ -76,6 +76,9 @@ namespace RecordReconnection { struct Params; } // namespace RecordReconnection +namespace RecordDeviceSelection { +struct Params; +} // namespace RecordDeviceSelection } // namespace bluetooth_private class BluetoothPrivateSetAdapterStateFunction @@ -282,6 +285,27 @@ DISALLOW_COPY_AND_ASSIGN(BluetoothPrivateRecordReconnectionFunction); }; +class BluetoothPrivateRecordDeviceSelectionFunction + : public BluetoothExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("bluetoothPrivate.recordDeviceSelection", + BLUETOOTHPRIVATE_RECORDDEVICESELECTION) + + BluetoothPrivateRecordDeviceSelectionFunction(); + + protected: + ~BluetoothPrivateRecordDeviceSelectionFunction() override; + + // BluetoothExtensionFunction: + bool CreateParams() override; + void DoWork(scoped_refptr<device::BluetoothAdapter> adapter) override; + + private: + std::unique_ptr<bluetooth_private::RecordDeviceSelection::Params> params_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothPrivateRecordDeviceSelectionFunction); +}; + } // namespace api } // namespace extensions
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 03f6fd1..bd3b910 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1405,6 +1405,7 @@ LOGINSCREENUI_CLOSE = 1342, DECLARATIVENETREQUEST_GETMATCHEDRULES = 1343, DECLARATIVENETREQUEST_SETACTIONCOUNTASBADGETEXT = 1344, + BLUETOOTHPRIVATE_RECORDDEVICESELECTION = 1345, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/common/api/bluetooth_private.idl b/extensions/common/api/bluetooth_private.idl index 55840a3..62c39d6 100644 --- a/extensions/common/api/bluetooth_private.idl +++ b/extensions/common/api/bluetooth_private.idl
@@ -159,6 +159,11 @@ // Record that a user-initiated reconnection attempt to an already paired // device finished. Do not record cancellations. static void recordReconnection(boolean success); + + // Record that a user selected a device to connect to. + static void recordDeviceSelection(long selectionDurationMs, + boolean wasPaired, + bluetooth.Transport transport); }; interface Events {
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc index 2c84cbd..f580fdf 100644 --- a/google_apis/gaia/gaia_auth_fetcher.cc +++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -732,7 +732,8 @@ } void GaiaAuthFetcher::StartOAuthMultilogin( - const std::vector<MultiloginTokenIDPair>& accounts) { + const std::vector<MultiloginTokenIDPair>& accounts, + const std::string& external_cc_result) { DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; UMA_HISTOGRAM_COUNTS_100("Signin.Multilogin.NumberOfAccounts", @@ -748,8 +749,13 @@ kOAuthMultiBearerHeaderFormat, base::JoinString(authorization_header_parts, ",").c_str()); - std::string parameters = base::StringPrintf( - "?source=%s", net::EscapeUrlEncodedData(source_, true).c_str()); + std::string source_string = net::EscapeUrlEncodedData(source_, true); + std::string parameters = + external_cc_result.empty() + ? base::StringPrintf("?source=%s", source_string.c_str()) + : base::StringPrintf( + "?source=%s&externalCcResult=%s", source_string.c_str(), + net::EscapeUrlEncodedData(external_cc_result, true).c_str()); net::NetworkTrafficAnnotationTag traffic_annotation = net::DefineNetworkTrafficAnnotation("gaia_auth_multilogin", R"(
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h index e77e6a7..8709676 100644 --- a/google_apis/gaia/gaia_auth_fetcher.h +++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -151,7 +151,8 @@ const std::string& service); // Starts a request to get the cookie for list of accounts. - void StartOAuthMultilogin(const std::vector<MultiloginTokenIDPair>& accounts); + void StartOAuthMultilogin(const std::vector<MultiloginTokenIDPair>& accounts, + const std::string& external_cc_result); // Starts a request to list the accounts in the GAIA cookie. void StartListAccounts();
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc index 875e499..8e4afa9 100644 --- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc +++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -346,7 +346,7 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.StartOAuthMultilogin( - std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>()); + std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>(), std::string()); EXPECT_TRUE(auth.HasPendingFetch()); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, @@ -381,7 +381,7 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.StartOAuthMultilogin( - std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>()); + std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>(), std::string()); EXPECT_TRUE(auth.HasPendingFetch()); auth.TestOnURLLoadCompleteInternal(net::ERR_ABORTED, net::HTTP_OK, @@ -416,7 +416,7 @@ TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory()); auth.StartOAuthMultilogin( - std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>()); + std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>(), std::string()); EXPECT_TRUE(auth.HasPendingFetch()); auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK,
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc index 9c6523e0..62a55ca 100644 --- a/gpu/command_buffer/service/external_vk_image_backing.cc +++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -43,11 +43,12 @@ 1 /* levelCount */); } -VkResult CreateExternalVkImage(SharedContextState* context_state, - VkFormat format, - const gfx::Size& size, - bool is_transfer_dst, - VkImage* image) { +VkResult CreateVkImage(SharedContextState* context_state, + VkFormat format, + const gfx::Size& size, + bool is_transfer_dst, + bool is_external, + VkImage* image) { VkExternalMemoryImageCreateInfoKHR external_info = { .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR, .handleTypes = context_state->vk_context_provider() @@ -61,7 +62,7 @@ VkImageCreateInfo create_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = &external_info, + .pNext = is_external ? &external_info : nullptr, .flags = 0, .imageType = VK_IMAGE_TYPE_2D, .format = format, @@ -102,6 +103,28 @@ return kInvalidTypeIndex; } +class ScopedPixelStore { + public: + ScopedPixelStore(gl::GLApi* api, GLenum name, GLint value) + : api_(api), name_(name), value_(value) { + api_->glGetIntegervFn(name_, &old_value_); + if (value_ != old_value_) + api->glPixelStoreiFn(name_, value_); + } + ~ScopedPixelStore() { + if (value_ != old_value_) + api_->glPixelStoreiFn(name_, old_value_); + } + + private: + gl::GLApi* const api_; + const GLenum name_; + const GLint value_; + GLint old_value_; + + DISALLOW_COPY_AND_ASSIGN(ScopedPixelStore); +}; + } // namespace // static @@ -120,8 +143,9 @@ VkFormat vk_format = ToVkFormat(format); VkImage image; bool is_transfer_dst = using_gmb || !pixel_data.empty(); - VkResult result = CreateExternalVkImage(context_state, vk_format, size, - is_transfer_dst, &image); + bool is_external = context_state->support_vulkan_external_object(); + VkResult result = CreateVkImage(context_state, vk_format, size, + is_transfer_dst, is_external, &image); if (result != VK_SUCCESS) { DLOG(ERROR) << "Failed to create external VkImage: " << result; return nullptr; @@ -146,7 +170,7 @@ VkMemoryAllocateInfo mem_alloc_info = { .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = &external_info, + .pNext = is_external ? &external_info : nullptr, .allocationSize = requirements.size, .memoryTypeIndex = FindMemoryTypeIndex( context_state, requirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), @@ -175,8 +199,13 @@ mailbox, format, size, color_space, usage, context_state, image, memory, requirements.size, vk_format, command_pool)); - if (!pixel_data.empty()) - backing->WritePixels(pixel_data, 0); + if (!pixel_data.empty()) { + backing->WritePixels( + pixel_data.size(), 0, + base::BindOnce([](const void* data, size_t size, + void* buffer) { memcpy(buffer, data, size); }, + pixel_data.data(), pixel_data.size())); + } return backing; } @@ -346,26 +375,24 @@ bool ExternalVkImageBacking::BeginAccess( bool readonly, - std::vector<SemaphoreHandle>* semaphore_handles) { - if (readonly) { - if (reads_in_progress_ == 0 && shared_memory_mapping_.IsValid() && - shared_memory_is_updated_) { - if (!WritePixels( - shared_memory_mapping_.GetMemoryAsSpan<const uint8_t>().subspan( - memory_offset_), - stride_)) - return false; - shared_memory_is_updated_ = false; - } - } + std::vector<SemaphoreHandle>* semaphore_handles, + bool is_gl) { + if (readonly && !reads_in_progress_) + UpdateContent(is_gl ? kInGLTexture : kInVkImage); return BeginAccessInternal(readonly, semaphore_handles); } void ExternalVkImageBacking::EndAccess(bool readonly, - SemaphoreHandle semaphore_handle) { + SemaphoreHandle semaphore_handle, + bool is_gl) { EndAccessInternal(readonly, std::move(semaphore_handle)); - // TODO(penghuang): read pixels back from VkImage to shared memory GMB, if - // this feature is needed. + if (!readonly) { + if (use_separate_gl_texture()) { + latest_content_ = is_gl ? kInGLTexture : kInVkImage; + } else { + latest_content_ = kInVkImage | kInGLTexture; + } + } } bool ExternalVkImageBacking::IsCleared() const { @@ -378,7 +405,7 @@ void ExternalVkImageBacking::Update(std::unique_ptr<gfx::GpuFence> in_fence) { DCHECK(!in_fence); - shared_memory_is_updated_ = true; + latest_content_ = kInSharedMemory; } void ExternalVkImageBacking::Destroy() { @@ -397,8 +424,8 @@ if (texture_) { // Ensure that a context is current before removing the ref and calling // glDeleteTextures. - if (!context_state()->context()->IsCurrent(nullptr)) - context_state()->context()->MakeCurrent(context_state()->surface()); + if (!gl::g_current_gl_context) + context_state()->MakeCurrent(nullptr, true /* need_gl */); texture_->RemoveLightweightRef(have_context()); } } @@ -427,47 +454,50 @@ bool result = backend_texture_.getVkImageInfo(&image_info); DCHECK(result); if (!texture_) { - VkMemoryGetFdInfoKHR get_fd_info; - get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; - get_fd_info.pNext = nullptr; - get_fd_info.memory = image_info.fAlloc.fMemory; - get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + gl::GLApi* api = gl::g_current_gl_context; + GLuint memory_object = 0; + if (!use_separate_gl_texture()) { + VkMemoryGetFdInfoKHR get_fd_info; + get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + get_fd_info.pNext = nullptr; + get_fd_info.memory = image_info.fAlloc.fMemory; + get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; - int memory_fd = -1; - vkGetMemoryFdKHR(device(), &get_fd_info, &memory_fd); - if (memory_fd < 0) { - DLOG(ERROR) - << "Unable to extract file descriptor out of external VkImage"; - return nullptr; + int memory_fd = -1; + vkGetMemoryFdKHR(device(), &get_fd_info, &memory_fd); + if (memory_fd < 0) { + DLOG(ERROR) + << "Unable to extract file descriptor out of external VkImage"; + return nullptr; + } + + api->glCreateMemoryObjectsEXTFn(1, &memory_object); + api->glImportMemoryFdEXTFn(memory_object, image_info.fAlloc.fSize, + GL_HANDLE_TYPE_OPAQUE_FD_EXT, memory_fd); } - gl::GLApi* api = gl::g_current_gl_context; - - constexpr GLenum target = GL_TEXTURE_2D; - constexpr GLenum get_target = GL_TEXTURE_BINDING_2D; GLuint internal_format = viz::TextureStorageFormat(format()); - - GLuint memory_object; - api->glCreateMemoryObjectsEXTFn(1, &memory_object); - api->glImportMemoryFdEXTFn(memory_object, image_info.fAlloc.fSize, - GL_HANDLE_TYPE_OPAQUE_FD_EXT, memory_fd); + GLint old_texture_binding = 0; + api->glGetIntegervFn(GL_TEXTURE_BINDING_2D, &old_texture_binding); GLuint texture_service_id; api->glGenTexturesFn(1, &texture_service_id); - - GLint old_texture_binding = 0; - api->glGetIntegervFn(get_target, &old_texture_binding); - api->glBindTextureFn(target, texture_service_id); - api->glTexParameteriFn(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - api->glTexParameteriFn(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - api->glTexParameteriFn(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - api->glTexParameteriFn(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - api->glTexStorageMem2DEXTFn(GL_TEXTURE_2D, 1, internal_format, - size().width(), size().height(), memory_object, - 0); - + api->glBindTextureFn(GL_TEXTURE_2D, texture_service_id); + api->glTexParameteriFn(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + api->glTexParameteriFn(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + api->glTexParameteriFn(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + api->glTexParameteriFn(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (use_separate_gl_texture()) { + api->glTexStorage2DEXTFn(GL_TEXTURE_2D, 1, internal_format, + size().width(), size().height()); + } else { + DCHECK(memory_object); + api->glTexStorageMem2DEXTFn(GL_TEXTURE_2D, 1, internal_format, + size().width(), size().height(), + memory_object, 0); + } texture_ = new gles2::Texture(texture_service_id); texture_->SetLightweightRef(); - texture_->SetTarget(target, 1); + texture_->SetTarget(GL_TEXTURE_2D, 1); texture_->sampler_state_.min_filter = GL_LINEAR; texture_->sampler_state_.mag_filter = GL_LINEAR; texture_->sampler_state_.wrap_t = GL_CLAMP_TO_EDGE; @@ -479,12 +509,12 @@ GLenum gl_format = viz::GLDataFormat(format()); GLenum gl_type = viz::GLDataType(format()); - texture_->SetLevelInfo(target, 0, internal_format, size().width(), + texture_->SetLevelInfo(GL_TEXTURE_2D, 0, internal_format, size().width(), size().height(), 1, 0, gl_format, gl_type, cleared_rect); texture_->SetImmutable(true); - api->glBindTextureFn(target, old_texture_binding); + api->glBindTextureFn(GL_TEXTURE_2D, old_texture_binding); } return std::make_unique<ExternalVkImageGlRepresentation>( manager, this, tracker, texture_, texture_->service_id()); @@ -526,13 +556,57 @@ Update(nullptr); } -bool ExternalVkImageBacking::WritePixels( - const base::span<const uint8_t>& pixel_data, - size_t stride) { - DCHECK(stride == 0 || size().height() * stride <= pixel_data.size()); +void ExternalVkImageBacking::UpdateContent(uint32_t content_flags) { + // Only support one backing for now. + DCHECK(content_flags == kInVkImage || content_flags == kInGLTexture || + content_flags == kInSharedMemory); + + if ((latest_content_ & content_flags) == content_flags) + return; + + if (content_flags == kInGLTexture && !use_separate_gl_texture()) + content_flags = kInVkImage; + + if (content_flags == kInVkImage) { + if (latest_content_ & kInSharedMemory) { + if (!shared_memory_mapping_.IsValid()) + return; + auto pixel_data = + shared_memory_mapping_.GetMemoryAsSpan<const uint8_t>().subspan( + memory_offset_); + if (!WritePixels( + pixel_data.size(), stride_, + base::BindOnce([](const void* data, size_t size, + void* buffer) { memcpy(buffer, data, size); }, + pixel_data.data(), pixel_data.size()))) { + return; + } + latest_content_ |= + use_separate_gl_texture() ? kInVkImage : kInVkImage | kInGLTexture; + return; + } + if ((latest_content_ & kInGLTexture) && use_separate_gl_texture()) { + CopyPixelsFromGLTexture(); + latest_content_ |= kInVkImage; + return; + } + } else if (content_flags == kInGLTexture) { + // TODO(penghuang): support updating content in gl texture. + NOTIMPLEMENTED_LOG_ONCE(); + } else if (content_flags == kInSharedMemory) { + // TODO(penghuang): read pixels back from VkImage to shared memory GMB, if + // this feature is needed. + NOTIMPLEMENTED_LOG_ONCE(); + } +} + +bool ExternalVkImageBacking::WritePixels(size_t data_size, + size_t stride, + FillBufferCallback callback) { + DCHECK(stride == 0 || size().height() * stride <= data_size); VkBufferCreateInfo buffer_create_info = { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .size = pixel_data.size(), + .size = data_size, .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, }; @@ -576,16 +650,17 @@ return false; } - void* data = nullptr; - result = vkMapMemory(device(), stage_memory, 0 /* memoryOffset */, - pixel_data.size(), 0, &data); + void* buffer = nullptr; + result = vkMapMemory(device(), stage_memory, 0 /* memoryOffset */, data_size, + 0, &buffer); if (result != VK_SUCCESS) { DLOG(ERROR) << "vkMapMemory() failed. " << result; vkDestroyBuffer(device(), stage_buffer, nullptr /* pAllocator */); vkFreeMemory(device(), stage_memory, nullptr /* pAllocator */); return false; } - memcpy(data, pixel_data.data(), pixel_data.size()); + + std::move(callback).Run(buffer); vkUnmapMemory(device(), stage_memory); std::vector<gpu::SemaphoreHandle> handles; @@ -664,6 +739,97 @@ return true; } +void ExternalVkImageBacking::CopyPixelsFromGLTexture() { + DCHECK(use_separate_gl_texture()); + DCHECK(texture_); + + GLenum gl_format = GL_NONE; + GLenum gl_type = GL_NONE; + size_t bytes_per_pixel = 0; + switch (ToVkFormat(format())) { + case VK_FORMAT_R8G8B8A8_UNORM: + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + bytes_per_pixel = 4; + break; + case VK_FORMAT_B8G8R8A8_UNORM: + gl_format = GL_BGRA; + gl_type = GL_UNSIGNED_BYTE; + bytes_per_pixel = 4; + break; + case VK_FORMAT_R8_UNORM: + gl_format = GL_RED; + gl_type = GL_UNSIGNED_BYTE; + bytes_per_pixel = 1; + break; + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_SHORT_4_4_4_4; + bytes_per_pixel = 2; + break; + case VK_FORMAT_R5G6B5_UNORM_PACK16: + gl_format = GL_RGB; + gl_type = GL_UNSIGNED_SHORT_5_6_5; + bytes_per_pixel = 2; + break; + case VK_FORMAT_R16_UNORM: + gl_format = GL_RED; + gl_type = GL_UNSIGNED_SHORT; + bytes_per_pixel = 2; + break; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_INT_2_10_10_10_REV; + bytes_per_pixel = 4; + break; + default: + NOTREACHED() << "Not supported resource format=" << format(); + return; + } + + // Make sure GrContext is not using GL. So we don't need reset GrContext + DCHECK(!context_state_->GrContextIsGL()); + + // Make sure a gl context is current, since textures are shared between all gl + // contexts, we don't care which gl context is current. + if (!gl::g_current_gl_context && + !context_state_->MakeCurrent(nullptr, true /* needs_gl */)) + return; + + gl::GLApi* api = gl::g_current_gl_context; + GLuint framebuffer; + GLint old_framebuffer; + api->glGetIntegervFn(GL_READ_FRAMEBUFFER_BINDING, &old_framebuffer); + api->glGenFramebuffersEXTFn(1, &framebuffer); + api->glBindFramebufferEXTFn(GL_READ_FRAMEBUFFER, framebuffer); + api->glFramebufferTexture2DEXTFn(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture_->service_id(), 0); + GLenum status = api->glCheckFramebufferStatusEXTFn(GL_READ_FRAMEBUFFER); + DCHECK_EQ(status, static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE)) + << "CheckFramebufferStatusEXT() failed."; + + base::CheckedNumeric<size_t> checked_size = bytes_per_pixel; + checked_size *= size().width(); + checked_size *= size().height(); + DCHECK(checked_size.IsValid()); + + ScopedPixelStore pack_row_length(api, GL_PACK_ROW_LENGTH, 0); + ScopedPixelStore pack_skip_pixels(api, GL_PACK_SKIP_PIXELS, 0); + ScopedPixelStore pack_skip_rows(api, GL_PACK_SKIP_ROWS, 0); + ScopedPixelStore pack_aligment(api, GL_PACK_ALIGNMENT, 1); + + WritePixels(checked_size.ValueOrDie(), 0, + base::BindOnce( + [](gl::GLApi* api, const gfx::Size& size, GLenum format, + GLenum type, void* buffer) { + api->glReadPixelsFn(0, 0, size.width(), size.height(), + format, type, buffer); + }, + api, size(), gl_format, gl_type)); + api->glBindFramebufferEXTFn(GL_READ_FRAMEBUFFER, old_framebuffer); + api->glDeleteFramebuffersEXTFn(1, &framebuffer); +} + bool ExternalVkImageBacking::BeginAccessInternal( bool readonly, std::vector<SemaphoreHandle>* semaphore_handles) {
diff --git a/gpu/command_buffer/service/external_vk_image_backing.h b/gpu/command_buffer/service/external_vk_image_backing.h index d02f8b9..54d73b4e 100644 --- a/gpu/command_buffer/service/external_vk_image_backing.h +++ b/gpu/command_buffer/service/external_vk_image_backing.h
@@ -60,19 +60,25 @@ ->GetVulkanDevice(); } bool need_sychronization() const { + if (use_separate_gl_texture()) + return false; return usage() & SHARED_IMAGE_USAGE_GLES2; } + bool use_separate_gl_texture() const { + return !context_state()->support_vulkan_external_object(); + } // Notifies the backing that an access will start. Return false if there is // currently any other conflict access in progress. Otherwise, returns true // and semaphore handles which will be waited on before accessing. bool BeginAccess(bool readonly, - std::vector<SemaphoreHandle>* semaphore_handles); + std::vector<SemaphoreHandle>* semaphore_handles, + bool is_gl); // Notifies the backing that an access has ended. The representation must // provide a semaphore handle that has been signaled at the end of the write // access. - void EndAccess(bool readonly, SemaphoreHandle semaphore_handle); + void EndAccess(bool readonly, SemaphoreHandle semaphore_handle, bool is_gl); // SharedImageBacking implementation. bool IsCleared() const override; @@ -82,6 +88,7 @@ bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) override; protected: + void UpdateContent(uint32_t content_flags); bool BeginAccessInternal(bool readonly, std::vector<SemaphoreHandle>* semaphore_handles); void EndAccessInternal(bool readonly, SemaphoreHandle semaphore_handle); @@ -117,7 +124,11 @@ size_t stride, size_t memory_offset); - bool WritePixels(const base::span<const uint8_t>& pixel_data, size_t stride); + using FillBufferCallback = base::OnceCallback<void(void* buffer)>; + bool WritePixels(size_t data_size, + size_t stride, + FillBufferCallback callback); + void CopyPixelsFromGLTexture(); SharedContextState* const context_state_; GrBackendTexture backend_texture_; @@ -132,11 +143,17 @@ gles2::Texture* texture_ = nullptr; // GMB related stuff. - bool shared_memory_is_updated_ = false; base::WritableSharedMemoryMapping shared_memory_mapping_; size_t stride_ = 0; size_t memory_offset_ = 0; + enum LatestContent { + kInVkImage = 1 << 0, + kInSharedMemory = 1 << 1, + kInGLTexture = 1 << 2, + }; + uint32_t latest_content_ = 0; + DISALLOW_COPY_AND_ASSIGN(ExternalVkImageBacking); };
diff --git a/gpu/command_buffer/service/external_vk_image_gl_representation.cc b/gpu/command_buffer/service/external_vk_image_gl_representation.cc index 1c1155b..cb889f3 100644 --- a/gpu/command_buffer/service/external_vk_image_gl_representation.cc +++ b/gpu/command_buffer/service/external_vk_image_gl_representation.cc
@@ -89,7 +89,7 @@ std::vector<SemaphoreHandle> handles; - if (!backing_impl()->BeginAccess(readonly, &handles)) + if (!backing_impl()->BeginAccess(readonly, &handles, true /* is_gl */)) return false; for (auto& handle : handles) { @@ -124,48 +124,56 @@ (current_access_mode_ == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM); current_access_mode_ = 0; - VkSemaphore semaphore = - vk_implementation()->CreateExternalSemaphore(backing_impl()->device()); - if (semaphore == VK_NULL_HANDLE) { - // TODO(crbug.com/933452): We should be able to handle this failure more - // gracefully rather than shutting down the whole process. - LOG(FATAL) << "Unable to create a VkSemaphore in " - << "ExternalVkImageGlRepresentation for synchronization with " - << "Vulkan"; - return; - } + VkSemaphore semaphore = VK_NULL_HANDLE; + SemaphoreHandle semaphore_handle; + GLuint gl_semaphore = 0; + if (backing_impl()->need_sychronization()) { + semaphore = + vk_implementation()->CreateExternalSemaphore(backing_impl()->device()); + if (semaphore == VK_NULL_HANDLE) { + // TODO(crbug.com/933452): We should be able to handle this failure more + // gracefully rather than shutting down the whole process. + LOG(FATAL) << "Unable to create a VkSemaphore in " + << "ExternalVkImageGlRepresentation for synchronization with " + << "Vulkan"; + return; + } - SemaphoreHandle semaphore_handle = - vk_implementation()->GetSemaphoreHandle(vk_device(), semaphore); - vkDestroySemaphore(backing_impl()->device(), semaphore, nullptr); - if (!semaphore_handle.is_valid()) { - LOG(FATAL) << "Unable to export VkSemaphore into GL in " - << "ExternalVkImageGlRepresentation for synchronization with " - << "Vulkan"; - return; - } + semaphore_handle = + vk_implementation()->GetSemaphoreHandle(vk_device(), semaphore); + vkDestroySemaphore(backing_impl()->device(), semaphore, nullptr); + if (!semaphore_handle.is_valid()) { + LOG(FATAL) << "Unable to export VkSemaphore into GL in " + << "ExternalVkImageGlRepresentation for synchronization with " + << "Vulkan"; + return; + } - SemaphoreHandle dup_semaphore_handle = semaphore_handle.Duplicate(); - GLuint gl_semaphore = - ImportVkSemaphoreIntoGL(std::move(dup_semaphore_handle)); + SemaphoreHandle dup_semaphore_handle = semaphore_handle.Duplicate(); + gl_semaphore = ImportVkSemaphoreIntoGL(std::move(dup_semaphore_handle)); - if (!gl_semaphore) { - // TODO(crbug.com/933452): We should be able to semaphore_handle this - // failure more gracefully rather than shutting down the whole process. - LOG(FATAL) << "Unable to export VkSemaphore into GL in " - << "ExternalVkImageGlRepresentation for synchronization with " - << "Vulkan"; - return; + if (!gl_semaphore) { + // TODO(crbug.com/933452): We should be able to semaphore_handle this + // failure more gracefully rather than shutting down the whole process. + LOG(FATAL) << "Unable to export VkSemaphore into GL in " + << "ExternalVkImageGlRepresentation for synchronization with " + << "Vulkan"; + return; + } } GrVkImageInfo info; auto result = backing_impl()->backend_texture().getVkImageInfo(&info); DCHECK(result); GLenum dst_layout = ToGLImageLayout(info.fImageLayout); - api()->glSignalSemaphoreEXTFn(gl_semaphore, 0, nullptr, 1, - &texture_service_id_, &dst_layout); - api()->glDeleteSemaphoresEXTFn(1, &gl_semaphore); - backing_impl()->EndAccess(readonly, std::move(semaphore_handle)); + if (backing_impl()->need_sychronization()) { + api()->glSignalSemaphoreEXTFn(gl_semaphore, 0, nullptr, 1, + &texture_service_id_, &dst_layout); + api()->glDeleteSemaphoresEXTFn(1, &gl_semaphore); + } + + backing_impl()->EndAccess(readonly, std::move(semaphore_handle), + true /* is_gl */); } GLuint ExternalVkImageGlRepresentation::ImportVkSemaphoreIntoGL(
diff --git a/gpu/command_buffer/service/external_vk_image_skia_representation.cc b/gpu/command_buffer/service/external_vk_image_skia_representation.cc index 572e4d1..d4faa91 100644 --- a/gpu/command_buffer/service/external_vk_image_skia_representation.cc +++ b/gpu/command_buffer/service/external_vk_image_skia_representation.cc
@@ -93,7 +93,7 @@ DCHECK(end_access_semaphore_ == VK_NULL_HANDLE); std::vector<SemaphoreHandle> handles; - if (!backing_impl()->BeginAccess(readonly, &handles)) + if (!backing_impl()->BeginAccess(readonly, &handles, false /* is_gl */)) return nullptr; for (auto& handle : handles) { @@ -137,7 +137,7 @@ DCHECK(end_access_semaphore_ == VK_NULL_HANDLE); } - backing_impl()->EndAccess(readonly, std::move(handle)); + backing_impl()->EndAccess(readonly, std::move(handle), false /* is_gl */); } } // namespace gpu \ No newline at end of file
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc index 2010eb46..061c1ccb 100644 --- a/gpu/command_buffer/service/shared_context_state.cc +++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -223,11 +223,16 @@ context_ = std::move(virtual_context); MakeCurrent(nullptr); } + + // TODO(penghuang): query extension from VulkanInstance. + support_vulkan_external_object_ = + gpu_preferences.use_vulkan == gpu::VulkanImplementationName::kNative; + return true; } -bool SharedContextState::MakeCurrent(gl::GLSurface* surface) { - if (!GrContextIsGL()) +bool SharedContextState::MakeCurrent(gl::GLSurface* surface, bool needs_gl) { + if (!GrContextIsGL() && !needs_gl) return true; if (context_lost_)
diff --git a/gpu/command_buffer/service/shared_context_state.h b/gpu/command_buffer/service/shared_context_state.h index 5c57a62..56b335e 100644 --- a/gpu/command_buffer/service/shared_context_state.h +++ b/gpu/command_buffer/service/shared_context_state.h
@@ -72,7 +72,7 @@ scoped_refptr<gles2::FeatureInfo> feature_info); bool IsGLInitialized() const { return !!feature_info_; } - bool MakeCurrent(gl::GLSurface* surface); + bool MakeCurrent(gl::GLSurface* surface, bool needs_gl = false); void MarkContextLost(); bool IsCurrent(gl::GLSurface* surface); @@ -110,6 +110,9 @@ bool use_virtualized_gl_contexts() const { return use_virtualized_gl_contexts_; } + bool support_vulkan_external_object() const { + return support_vulkan_external_object_; + } // base::trace_event::MemoryDumpProvider implementation. bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, @@ -152,6 +155,7 @@ QueryManager* GetQueryManager() override; bool use_virtualized_gl_contexts_ = false; + bool support_vulkan_external_object_ = false; base::OnceClosure context_lost_callback_; viz::VulkanContextProvider* const vk_context_provider_; viz::MetalContextProvider* const metal_context_provider_;
diff --git a/ios/build/bots/chromium.mac/ios-slimnav.json b/ios/build/bots/chromium.mac/ios-slimnav.json index cae98882..cb53220 100644 --- a/ios/build/bots/chromium.mac/ios-slimnav.json +++ b/ios/build/bots/chromium.mac/ios-slimnav.json
@@ -250,7 +250,7 @@ { "app": "ios_chrome_translate_egtests", "test args": [ - "--enable-features=CompactTranslateInfobarIOS,SlimNavigationManager,OfflineVersionWithoutNativeContent" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "11.4", @@ -372,7 +372,7 @@ { "app": "ios_chrome_translate_egtests", "test args": [ - "--enable-features=CompactTranslateInfobarIOS,SlimNavigationManager,OfflineVersionWithoutNativeContent" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPad Air 2", "os": "12.1", @@ -494,7 +494,7 @@ { "app": "ios_chrome_translate_egtests", "test args": [ - "--enable-features=CompactTranslateInfobarIOS,SlimNavigationManager,OfflineVersionWithoutNativeContent" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "11.4", @@ -616,7 +616,7 @@ { "app": "ios_chrome_translate_egtests", "test args": [ - "--enable-features=CompactTranslateInfobarIOS,SlimNavigationManager,OfflineVersionWithoutNativeContent" + "--enable-features=SlimNavigationManager,OfflineVersionWithoutNativeContent" ], "device type": "iPhone X", "os": "12.1",
diff --git a/ios/build/bots/tests/eg_tests.json b/ios/build/bots/tests/eg_tests.json index 565bc49..6052600c8f 100644 --- a/ios/build/bots/tests/eg_tests.json +++ b/ios/build/bots/tests/eg_tests.json
@@ -20,9 +20,6 @@ }, { "app": "ios_chrome_translate_egtests", - "test args": [ - "--enable-features=CompactTranslateInfobarIOS" - ], "xctest": true, "xcode parallelization": true },
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index a589c02..4577443 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -413,10 +413,6 @@ flag_descriptions::kBreakpadNoDelayInitialUploadDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(crash_report::kBreakpadNoDelayInitialUpload)}, - {"enable-compact-translate-infobar", - flag_descriptions::kCompactTranslateInfobarName, - flag_descriptions::kCompactTranslateInfobarDescription, flags_ui::kOsIos, - FEATURE_VALUE_TYPE(translate::kCompactTranslateInfobarIOS)}, {"non-modal-dialogs", flag_descriptions::kNonModalDialogsName, flag_descriptions::kNonModalDialogsDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(dialogs::kNonModalDialogs)},
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc index f27883c..a351350 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -126,12 +126,6 @@ "Automatically switches to the regular tabs panel in the tab grid after " "closing the last incognito tab"; -const char kCompactTranslateInfobarName[] = - "Enable the compact translate infobar"; -const char kCompactTranslateInfobarDescription[] = - "When enabled, replaces the exisitng translate infobars with a new compact " - "one."; - const char kContextualSearch[] = "Contextual Search"; const char kContextualSearchDescription[] = "Whether or not Contextual Search is enabled.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h index 35b566ae..46e41f1 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -97,10 +97,6 @@ extern const char kClosingLastIncognitoTabName[]; extern const char kClosingLastIncognitoTabDescription[]; -// Title and description for the flag to enable the compact translate infobar. -extern const char kCompactTranslateInfobarName[]; -extern const char kCompactTranslateInfobarDescription[]; - // Title and description for the flag to enable Contextual Search. extern const char kContextualSearch[]; extern const char kContextualSearchDescription[];
diff --git a/ios/chrome/browser/translate/BUILD.gn b/ios/chrome/browser/translate/BUILD.gn index 857141fd..8439b23f 100644 --- a/ios/chrome/browser/translate/BUILD.gn +++ b/ios/chrome/browser/translate/BUILD.gn
@@ -5,18 +5,12 @@ source_set("translate") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "after_translate_infobar_controller.h", - "after_translate_infobar_controller.mm", - "before_translate_infobar_controller.h", - "before_translate_infobar_controller.mm", "chrome_ios_translate_client.h", "chrome_ios_translate_client.mm", "language_selection_context.h", "language_selection_context.mm", "language_selection_delegate.h", "language_selection_handler.h", - "never_translate_infobar_controller.h", - "never_translate_infobar_controller.mm", "translate_accept_languages_factory.cc", "translate_accept_languages_factory.h", "translate_infobar_controller.h", @@ -24,8 +18,6 @@ "translate_infobar_delegate_observer_bridge.h", "translate_infobar_delegate_observer_bridge.mm", "translate_infobar_tags.h", - "translate_message_infobar_controller.h", - "translate_message_infobar_controller.mm", "translate_option_selection_delegate.h", "translate_option_selection_handler.h", "translate_ranker_factory.cc", @@ -131,32 +123,3 @@ ] libs = [ "XCTest.framework" ] } - -source_set("external_url_eg_tests") { - configs += [ "//build/config/compiler:enable_arc" ] - testonly = true - sources = [ - "legacy_translate_infobar_egtest.mm", - ] - deps = [ - ":translate", - "//base", - "//base/test:test_support", - "//components/language/ios/browser", - "//components/strings", - "//components/translate/core/browser", - "//components/translate/core/common", - "//components/translate/ios/browser", - "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/ui/translate:translate_ui", - "//ios/chrome/test/app:test_support", - "//ios/chrome/test/earl_grey:test_support", - "//ios/third_party/earl_grey:earl_grey+link", - "//ios/web:earl_grey_test_support", - "//ios/web/public/test", - "//ios/web/public/test/http_server", - "//net", - "//ui/base", - ] - libs = [ "XCTest.framework" ] -}
diff --git a/ios/chrome/browser/translate/after_translate_infobar_controller.h b/ios/chrome/browser/translate/after_translate_infobar_controller.h deleted file mode 100644 index 57ee824..0000000 --- a/ios/chrome/browser/translate/after_translate_infobar_controller.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_TRANSLATE_AFTER_TRANSLATE_INFOBAR_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_TRANSLATE_AFTER_TRANSLATE_INFOBAR_CONTROLLER_H_ - -#include "ios/chrome/browser/infobars/infobar_controller.h" - -namespace translate { -class TranslateInfoBarDelegate; -} - -@interface AfterTranslateInfoBarController : InfoBarController - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate - NS_DESIGNATED_INITIALIZER; - -@end - -#endif // IOS_CHROME_BROWSER_TRANSLATE_AFTER_TRANSLATE_INFOBAR_CONTROLLER_H_
diff --git a/ios/chrome/browser/translate/after_translate_infobar_controller.mm b/ios/chrome/browser/translate/after_translate_infobar_controller.mm deleted file mode 100644 index 645879e..0000000 --- a/ios/chrome/browser/translate/after_translate_infobar_controller.mm +++ /dev/null
@@ -1,159 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/translate/after_translate_infobar_controller.h" - -#include "base/mac/foundation_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "components/strings/grit/components_strings.h" -#include "components/translate/core/browser/translate_infobar_delegate.h" -#import "ios/chrome/browser/infobars/infobar_controller+protected.h" -#include "ios/chrome/browser/infobars/infobar_controller_delegate.h" -#include "ios/chrome/browser/translate/translate_infobar_tags.h" -#import "ios/chrome/browser/ui/infobars/confirm_infobar_view.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { -enum AlwaysTranslateSwitchState { - ALWAYS_TRANSLATE_SWITCH_NOT_CHANGED, - ALWAYS_TRANSLATE_SWITCH_SET_TO_ENABLED, - ALWAYS_TRANSLATE_SWITCH_SET_TO_DISABLED, -}; -} // namespace - -@interface AfterTranslateInfoBarController () { - AlwaysTranslateSwitchState _alwaysTranslateSwitchState; -} - -// Overrides superclass property. -@property(nonatomic, readonly) - translate::TranslateInfoBarDelegate* infoBarDelegate; - -@end - -@implementation AfterTranslateInfoBarController - -@dynamic infoBarDelegate; - -#pragma mark - -#pragma mark InfoBarControllerProtocol - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate { - return [super initWithInfoBarDelegate:infoBarDelegate]; -} - -- (UIView*)infobarView { - ConfirmInfoBarView* infoBarView = - [[ConfirmInfoBarView alloc] initWithFrame:CGRectZero]; - // Icon - gfx::Image icon = self.infoBarDelegate->GetIcon(); - if (!icon.IsEmpty()) - [infoBarView addLeftIcon:icon.ToUIImage()]; - // Main text. - const bool autodeterminedSourceLanguage = - self.infoBarDelegate->original_language_code() == - translate::kUnknownLanguageCode; - bool swappedLanguageButtons; - std::vector<base::string16> strings; - translate::TranslateInfoBarDelegate::GetAfterTranslateStrings( - &strings, &swappedLanguageButtons, autodeterminedSourceLanguage); - DCHECK_EQ(autodeterminedSourceLanguage ? 2U : 3U, strings.size()); - NSString* label1 = base::SysUTF16ToNSString(strings[0]); - NSString* label2 = base::SysUTF16ToNSString(strings[1]); - NSString* label3 = autodeterminedSourceLanguage - ? @"" - : base::SysUTF16ToNSString(strings[2]); - base::string16 stdOriginal = self.infoBarDelegate->original_language_name(); - NSString* original = base::SysUTF16ToNSString(stdOriginal); - NSString* target = - base::SysUTF16ToNSString(self.infoBarDelegate->target_language_name()); - NSString* label = - [[NSString alloc] initWithFormat:@"%@ %@ %@%@ %@.", label1, original, - label2, label3, target]; - [infoBarView addLabel:label]; - // Close button. - [infoBarView addCloseButtonWithTag:TranslateInfoBarIOSTag::CLOSE - target:self - action:@selector(infoBarButtonDidPress:)]; - // Other buttons. - NSString* buttonRevert = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_REVERT); - NSString* buttonOptions = l10n_util::GetNSString(IDS_DONE); - [infoBarView addButton1:buttonOptions - tag1:TranslateInfoBarIOSTag::AFTER_DONE - button2:buttonRevert - tag2:TranslateInfoBarIOSTag::AFTER_REVERT - target:self - action:@selector(infoBarButtonDidPress:)]; - // Always translate switch. - _alwaysTranslateSwitchState = ALWAYS_TRANSLATE_SWITCH_NOT_CHANGED; - if (self.infoBarDelegate->ShouldShowAlwaysTranslateShortcut()) { - base::string16 alwaysTranslate = l10n_util::GetStringFUTF16( - IDS_TRANSLATE_INFOBAR_ALWAYS_TRANSLATE, stdOriginal); - const BOOL switchValue = self.infoBarDelegate->ShouldAlwaysTranslate(); - [infoBarView - addSwitchWithLabel:base::SysUTF16ToNSString(alwaysTranslate) - isOn:switchValue - tag:TranslateInfoBarIOSTag::ALWAYS_TRANSLATE_SWITCH - target:self - action:@selector(infoBarSwitchDidPress:)]; - } - return infoBarView; -} - -#pragma mark - Handling of User Events - -- (void)infoBarButtonDidPress:(id)sender { - if ([self shouldIgnoreUserInteraction]) - return; - - NSUInteger buttonId = base::mac::ObjCCastStrict<UIButton>(sender).tag; - switch (buttonId) { - case TranslateInfoBarIOSTag::CLOSE: - self.infoBarDelegate->InfoBarDismissed(); - self.delegate->RemoveInfoBar(); - break; - case TranslateInfoBarIOSTag::AFTER_DONE: - [self saveAlwaysTranslateState]; - self.infoBarDelegate->InfoBarDismissed(); - self.delegate->RemoveInfoBar(); - break; - case TranslateInfoBarIOSTag::AFTER_REVERT: - self.infoBarDelegate->RevertTranslation(); - break; - default: - NOTREACHED() << "Unexpected Translate button label"; - break; - } -} - -- (void)infoBarSwitchDidPress:(id)sender { - DCHECK_EQ(TranslateInfoBarIOSTag::ALWAYS_TRANSLATE_SWITCH, [sender tag]); - DCHECK([sender respondsToSelector:@selector(isOn)]); - _alwaysTranslateSwitchState = [sender isOn] - ? ALWAYS_TRANSLATE_SWITCH_SET_TO_ENABLED - : ALWAYS_TRANSLATE_SWITCH_SET_TO_DISABLED; -} - -#pragma mark - Private methods - -- (void)saveAlwaysTranslateState { - if (_alwaysTranslateSwitchState == ALWAYS_TRANSLATE_SWITCH_NOT_CHANGED) - return; - - const bool alwaysTranslate = - _alwaysTranslateSwitchState == ALWAYS_TRANSLATE_SWITCH_SET_TO_ENABLED; - if (alwaysTranslate == self.infoBarDelegate->ShouldAlwaysTranslate()) - return; - - self.infoBarDelegate->ToggleAlwaysTranslate(); -} - -@end
diff --git a/ios/chrome/browser/translate/before_translate_infobar_controller.h b/ios/chrome/browser/translate/before_translate_infobar_controller.h deleted file mode 100644 index 73ac4a1..0000000 --- a/ios/chrome/browser/translate/before_translate_infobar_controller.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_TRANSLATE_BEFORE_TRANSLATE_INFOBAR_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_TRANSLATE_BEFORE_TRANSLATE_INFOBAR_CONTROLLER_H_ - -#include "ios/chrome/browser/infobars/infobar_controller.h" - -@protocol LanguageSelectionHandler; -namespace translate { -class TranslateInfoBarDelegate; -} - -@interface BeforeTranslateInfoBarController : InfoBarController - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate - NS_DESIGNATED_INITIALIZER; - -@property(nonatomic, weak) id<LanguageSelectionHandler> - languageSelectionHandler; - -@end - -#endif // IOS_CHROME_BROWSER_TRANSLATE_BEFORE_TRANSLATE_INFOBAR_CONTROLLER_H_
diff --git a/ios/chrome/browser/translate/before_translate_infobar_controller.mm b/ios/chrome/browser/translate/before_translate_infobar_controller.mm deleted file mode 100644 index 8ace3664..0000000 --- a/ios/chrome/browser/translate/before_translate_infobar_controller.mm +++ /dev/null
@@ -1,201 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/translate/before_translate_infobar_controller.h" - -#include <stddef.h> -#import <UIKit/UIKit.h> - -#include "base/logging.h" -#include "base/mac/foundation_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "components/strings/grit/components_strings.h" -#include "components/translate/core/browser/translate_infobar_delegate.h" -#import "ios/chrome/browser/infobars/infobar_controller+protected.h" -#include "ios/chrome/browser/infobars/infobar_controller_delegate.h" -#include "ios/chrome/browser/translate/language_selection_context.h" -#include "ios/chrome/browser/translate/language_selection_delegate.h" -#include "ios/chrome/browser/translate/language_selection_handler.h" -#include "ios/chrome/browser/translate/translate_infobar_tags.h" -#import "ios/chrome/browser/ui/infobars/confirm_infobar_view.h" -#import "ios/chrome/browser/ui/util/top_view_controller.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface BeforeTranslateInfoBarController ()<LanguageSelectionDelegate> - -// Overrides superclass property. -@property(nonatomic, readonly) - translate::TranslateInfoBarDelegate* infoBarDelegate; - -@end - -@implementation BeforeTranslateInfoBarController { - // Stores whether the user is currently choosing in the UIPickerView the - // original language, or the target language. - TranslateInfoBarIOSTag::Tag _languageSelectionType; - __weak ConfirmInfoBarView* _infoBarView; -} - -@synthesize languageSelectionHandler = _languageSelectionHandler; -@dynamic infoBarDelegate; - -#pragma mark - -#pragma mark InfoBarControllerProtocol - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate { - return [super initWithInfoBarDelegate:infoBarDelegate]; -} - -- (UIView*)infobarView { - ConfirmInfoBarView* infoBarView = - [[ConfirmInfoBarView alloc] initWithFrame:CGRectZero]; - _infoBarView = infoBarView; - // Icon - gfx::Image icon = self.infoBarDelegate->GetIcon(); - if (!icon.IsEmpty()) - [infoBarView addLeftIcon:icon.ToUIImage()]; - - // Main text. - [self updateInfobarLabelOnView:infoBarView]; - - // Close button. - [infoBarView addCloseButtonWithTag:TranslateInfoBarIOSTag::BEFORE_DENY - target:self - action:@selector(infoBarButtonDidPress:)]; - // Other buttons. - NSString* buttonAccept = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_ACCEPT); - NSString* buttonDeny = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_DENY); - [infoBarView addButton1:buttonAccept - tag1:TranslateInfoBarIOSTag::BEFORE_ACCEPT - button2:buttonDeny - tag2:TranslateInfoBarIOSTag::BEFORE_DENY - target:self - action:@selector(infoBarButtonDidPress:)]; - return infoBarView; -} - -- (void)updateInfobarLabelOnView:(ConfirmInfoBarView*)view { - NSString* originalLanguage = - base::SysUTF16ToNSString(self.infoBarDelegate->original_language_name()); - NSString* targetLanguage = - base::SysUTF16ToNSString(self.infoBarDelegate->target_language_name()); - base::string16 originalLanguageWithLink = - base::SysNSStringToUTF16([[view class] - stringAsLink:originalLanguage - tag:TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE]); - base::string16 targetLanguageWithLink = base::SysNSStringToUTF16([[view class] - stringAsLink:targetLanguage - tag:TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE]); - NSString* label = - l10n_util::GetNSStringF(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE_IOS, - originalLanguageWithLink, targetLanguageWithLink); - - __weak BeforeTranslateInfoBarController* weakSelf = self; - [view addLabel:label - action:^(NSUInteger tag) { - [weakSelf infobarLinkDidPress:tag]; - }]; -} - -#pragma mark - Handling of User Events - -- (void)infoBarButtonDidPress:(id)sender { - if ([self shouldIgnoreUserInteraction]) - return; - - NSUInteger buttonId = base::mac::ObjCCastStrict<UIButton>(sender).tag; - switch (buttonId) { - case TranslateInfoBarIOSTag::BEFORE_ACCEPT: - self.infoBarDelegate->Translate(); - break; - case TranslateInfoBarIOSTag::BEFORE_DENY: - self.infoBarDelegate->TranslationDeclined(); - if (self.infoBarDelegate->ShouldShowNeverTranslateShortcut()) - self.infoBarDelegate->ShowNeverTranslateInfobar(); - else - self.delegate->RemoveInfoBar(); - break; - default: - NOTREACHED() << "Unexpected Translate button label"; - break; - } -} - -- (void)infobarLinkDidPress:(NSUInteger)tag { - if ([self shouldIgnoreUserInteraction]) - return; - - _languageSelectionType = static_cast<TranslateInfoBarIOSTag::Tag>(tag); - DCHECK(_languageSelectionType == - TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE || - _languageSelectionType == - TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE); - - size_t selectedRow; - size_t disabledRow; - int originalLanguageIndex = -1; - int targetLanguageIndex = -1; - - for (size_t i = 0; i < self.infoBarDelegate->num_languages(); ++i) { - if (self.infoBarDelegate->language_code_at(i) == - self.infoBarDelegate->original_language_code()) { - originalLanguageIndex = i; - } - if (self.infoBarDelegate->language_code_at(i) == - self.infoBarDelegate->target_language_code()) { - targetLanguageIndex = i; - } - } - DCHECK_GT(originalLanguageIndex, -1); - DCHECK_GT(targetLanguageIndex, -1); - - if (_languageSelectionType == - TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE) { - selectedRow = originalLanguageIndex; - disabledRow = targetLanguageIndex; - } else { - selectedRow = targetLanguageIndex; - disabledRow = originalLanguageIndex; - } - LanguageSelectionContext* context = - [LanguageSelectionContext contextWithLanguageData:self.infoBarDelegate - initialIndex:selectedRow - unavailableIndex:disabledRow]; - DCHECK(self.languageSelectionHandler); - [self.languageSelectionHandler showLanguageSelectorWithContext:context - delegate:self]; -} - -#pragma mark - LanguageSelectionDelegate - -- (void)languageSelectorSelectedLanguage:(std::string)languageCode { - if ([self shouldIgnoreUserInteraction]) - return; - - if (_languageSelectionType == - TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE && - languageCode != self.infoBarDelegate->target_language_code()) { - self.infoBarDelegate->UpdateOriginalLanguage(languageCode); - } - if (_languageSelectionType == - TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE && - languageCode != self.infoBarDelegate->original_language_code()) { - self.infoBarDelegate->UpdateTargetLanguage(languageCode); - } - [self updateInfobarLabelOnView:_infoBarView]; -} - -- (void)languageSelectorClosedWithoutSelection { - // No-op in this implementation, but (for example) metrics for this state - // might be added. -} - -@end
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm index 12e5f257..adc1c35 100644 --- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm +++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -18,7 +18,6 @@ #include "components/translate/core/browser/translate_accept_languages.h" #include "components/translate/core/browser/translate_infobar_delegate.h" #include "components/translate/core/browser/translate_manager.h" -#include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/browser/translate_step.h" #include "components/translate/core/common/language_detection_details.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" @@ -26,13 +25,9 @@ #include "ios/chrome/browser/infobars/infobar_controller.h" #include "ios/chrome/browser/infobars/infobar_manager_impl.h" #include "ios/chrome/browser/language/language_model_manager_factory.h" -#import "ios/chrome/browser/translate/after_translate_infobar_controller.h" -#import "ios/chrome/browser/translate/before_translate_infobar_controller.h" #import "ios/chrome/browser/translate/language_selection_handler.h" -#import "ios/chrome/browser/translate/never_translate_infobar_controller.h" #include "ios/chrome/browser/translate/translate_accept_languages_factory.h" #import "ios/chrome/browser/translate/translate_infobar_controller.h" -#import "ios/chrome/browser/translate/translate_message_infobar_controller.h" #import "ios/chrome/browser/translate/translate_option_selection_handler.h" #include "ios/chrome/browser/translate/translate_ranker_factory.h" #include "ios/chrome/browser/translate/translate_service_ios.h" @@ -96,44 +91,12 @@ std::unique_ptr<infobars::InfoBar> ChromeIOSTranslateClient::CreateInfoBar( std::unique_ptr<translate::TranslateInfoBarDelegate> delegate) const { - if (base::FeatureList::IsEnabled(translate::kCompactTranslateInfobarIOS)) { - TranslateInfoBarController* controller = [[TranslateInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - controller.languageSelectionHandler = language_selection_handler_; - controller.translateOptionSelectionHandler = - translate_option_selection_handler_; - controller.translateNotificationHandler = translate_notification_handler_; - return std::make_unique<InfoBarIOS>(controller, std::move(delegate)); - } - - translate::TranslateStep step = delegate->translate_step(); - - InfoBarController* controller; - switch (step) { - case translate::TRANSLATE_STEP_AFTER_TRANSLATE: - controller = [[AfterTranslateInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - break; - case translate::TRANSLATE_STEP_BEFORE_TRANSLATE: { - BeforeTranslateInfoBarController* beforeController = - [[BeforeTranslateInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - beforeController.languageSelectionHandler = language_selection_handler_; - controller = beforeController; - break; - } - case translate::TRANSLATE_STEP_NEVER_TRANSLATE: - controller = [[NeverTranslateInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - break; - case translate::TRANSLATE_STEP_TRANSLATING: - case translate::TRANSLATE_STEP_TRANSLATE_ERROR: - controller = [[TranslateMessageInfoBarController alloc] - initWithInfoBarDelegate:delegate.get()]; - break; - default: - NOTREACHED(); - } + TranslateInfoBarController* controller = [[TranslateInfoBarController alloc] + initWithInfoBarDelegate:delegate.get()]; + controller.languageSelectionHandler = language_selection_handler_; + controller.translateOptionSelectionHandler = + translate_option_selection_handler_; + controller.translateNotificationHandler = translate_notification_handler_; return std::make_unique<InfoBarIOS>(controller, std::move(delegate)); }
diff --git a/ios/chrome/browser/translate/never_translate_infobar_controller.h b/ios/chrome/browser/translate/never_translate_infobar_controller.h deleted file mode 100644 index 0bf8367..0000000 --- a/ios/chrome/browser/translate/never_translate_infobar_controller.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_TRANSLATE_NEVER_TRANSLATE_INFOBAR_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_TRANSLATE_NEVER_TRANSLATE_INFOBAR_CONTROLLER_H_ - -#include "ios/chrome/browser/infobars/infobar_controller.h" - -namespace translate { -class TranslateInfoBarDelegate; -} - -@interface NeverTranslateInfoBarController : InfoBarController - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate - NS_DESIGNATED_INITIALIZER; - -@end - -#endif // IOS_CHROME_BROWSER_TRANSLATE_NEVER_TRANSLATE_INFOBAR_CONTROLLER_H_
diff --git a/ios/chrome/browser/translate/never_translate_infobar_controller.mm b/ios/chrome/browser/translate/never_translate_infobar_controller.mm deleted file mode 100644 index 9d344a3..0000000 --- a/ios/chrome/browser/translate/never_translate_infobar_controller.mm +++ /dev/null
@@ -1,105 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/translate/never_translate_infobar_controller.h" - -#include "base/mac/foundation_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "components/strings/grit/components_strings.h" -#include "components/translate/core/browser/translate_infobar_delegate.h" -#import "ios/chrome/browser/infobars/infobar_controller+protected.h" -#include "ios/chrome/browser/infobars/infobar_controller_delegate.h" -#include "ios/chrome/browser/translate/translate_infobar_tags.h" -#import "ios/chrome/browser/ui/infobars/confirm_infobar_view.h" -#include "ios/chrome/grit/ios_chromium_strings.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface NeverTranslateInfoBarController () - -// Overrides superclass property. -@property(nonatomic, readonly) - translate::TranslateInfoBarDelegate* infoBarDelegate; - -// Action for any of the user defined buttons. -- (void)infoBarButtonDidPress:(id)sender; - -@end - -@implementation NeverTranslateInfoBarController - -@dynamic infoBarDelegate; - -#pragma mark - -#pragma mark InfoBarControllerProtocol - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate { - return [super initWithInfoBarDelegate:infoBarDelegate]; -} - -- (UIView*)infobarView { - ConfirmInfoBarView* infoBarView = - [[ConfirmInfoBarView alloc] initWithFrame:CGRectZero]; - // Icon - gfx::Image icon = self.infoBarDelegate->GetIcon(); - if (!icon.IsEmpty()) - [infoBarView addLeftIcon:icon.ToUIImage()]; - // Main text. - base::string16 originalLanguage = - self.infoBarDelegate->original_language_name(); - [infoBarView - addLabel:l10n_util::GetNSStringF(IDS_IOS_TRANSLATE_INFOBAR_NEVER_MESSAGE, - originalLanguage)]; - // Close button. - [infoBarView addCloseButtonWithTag:TranslateInfoBarIOSTag::CLOSE - target:self - action:@selector(infoBarButtonDidPress:)]; - // Other buttons. - NSString* buttonLanguage = l10n_util::GetNSStringF( - IDS_TRANSLATE_INFOBAR_NEVER_TRANSLATE, originalLanguage); - NSString* buttonSite = l10n_util::GetNSString( - IDS_TRANSLATE_INFOBAR_OPTIONS_NEVER_TRANSLATE_SITE); - [infoBarView addButton1:buttonLanguage - tag1:TranslateInfoBarIOSTag::DENY_LANGUAGE - button2:buttonSite - tag2:TranslateInfoBarIOSTag::DENY_WEBSITE - target:self - action:@selector(infoBarButtonDidPress:)]; - return infoBarView; -} - -#pragma mark - Handling of User Events - -- (void)infoBarButtonDidPress:(id)sender { - if ([self shouldIgnoreUserInteraction]) - return; - - NSUInteger buttonId = base::mac::ObjCCastStrict<UIButton>(sender).tag; - switch (buttonId) { - case TranslateInfoBarIOSTag::CLOSE: - self.infoBarDelegate->InfoBarDismissed(); - self.delegate->RemoveInfoBar(); - break; - case TranslateInfoBarIOSTag::DENY_LANGUAGE: - self.infoBarDelegate->NeverTranslatePageLanguage(); - self.delegate->RemoveInfoBar(); - break; - case TranslateInfoBarIOSTag::DENY_WEBSITE: - if (!self.infoBarDelegate->IsSiteBlacklisted()) - self.infoBarDelegate->ToggleSiteBlacklist(); - self.delegate->RemoveInfoBar(); - break; - default: - NOTREACHED() << "Unexpected Translate button label"; - break; - } -} - -@end
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm index 950eec5a..e5ac48a 100644 --- a/ios/chrome/browser/translate/translate_egtest.mm +++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -21,7 +21,6 @@ #include "components/translate/core/browser/translate_infobar_delegate.h" #include "components/translate/core/browser/translate_manager.h" #include "components/translate/core/browser/translate_pref_names.h" -#include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/common/language_detection_details.h" #include "components/translate/core/common/translate_constants.h" #include "components/translate/core/common/translate_switches.h" @@ -31,7 +30,6 @@ #import "ios/chrome/browser/chrome_url_util.h" #include "ios/chrome/browser/translate/chrome_ios_translate_client.h" #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h" -#include "ios/chrome/browser/ui/translate/language_selection_view_controller.h" #import "ios/chrome/browser/ui/translate/translate_infobar_coordinator.h" #import "ios/chrome/browser/ui/translate/translate_infobar_view.h" #import "ios/chrome/browser/ui/util/ui_util.h" @@ -437,17 +435,6 @@ @implementation TranslateTestCase -+ (void)setUp { - [super setUp]; - - if (!base::FeatureList::IsEnabled(translate::kCompactTranslateInfobarIOS)) { - // translate::kCompactTranslateInfobarIOS feature is not enabled. You need - // to pass --enable-features=CompactTranslateInfobarIOS command line - // argument in order to run this test. - DCHECK(false); - } -} - - (void)setUp { [super setUp];
diff --git a/ios/chrome/browser/translate/translate_message_infobar_controller.h b/ios/chrome/browser/translate/translate_message_infobar_controller.h deleted file mode 100644 index efdf830f..0000000 --- a/ios/chrome/browser/translate/translate_message_infobar_controller.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_TRANSLATE_TRANSLATE_MESSAGE_INFOBAR_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_TRANSLATE_TRANSLATE_MESSAGE_INFOBAR_CONTROLLER_H_ - -#include "ios/chrome/browser/infobars/infobar_controller.h" - -namespace translate { -class TranslateInfoBarDelegate; -} - -@interface TranslateMessageInfoBarController : InfoBarController - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate - NS_DESIGNATED_INITIALIZER; - -@end - -#endif // IOS_CHROME_BROWSER_TRANSLATE_TRANSLATE_MESSAGE_INFOBAR_CONTROLLER_H_
diff --git a/ios/chrome/browser/translate/translate_message_infobar_controller.mm b/ios/chrome/browser/translate/translate_message_infobar_controller.mm deleted file mode 100644 index a0846c1..0000000 --- a/ios/chrome/browser/translate/translate_message_infobar_controller.mm +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/translate/translate_message_infobar_controller.h" - -#include "base/mac/foundation_util.h" -#include "base/strings/sys_string_conversions.h" -#include "components/translate/core/browser/translate_infobar_delegate.h" -#import "ios/chrome/browser/infobars/infobar_controller+protected.h" -#include "ios/chrome/browser/infobars/infobar_controller_delegate.h" -#include "ios/chrome/browser/translate/translate_infobar_tags.h" -#import "ios/chrome/browser/ui/infobars/confirm_infobar_view.h" -#include "ui/gfx/image/image.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface TranslateMessageInfoBarController () - -// Overrides superclass property. -@property(nonatomic, readonly) - translate::TranslateInfoBarDelegate* infoBarDelegate; - -@end - -@implementation TranslateMessageInfoBarController - -@dynamic infoBarDelegate; - -- (instancetype)initWithInfoBarDelegate: - (translate::TranslateInfoBarDelegate*)infoBarDelegate { - return [super initWithInfoBarDelegate:infoBarDelegate]; -} - -- (UIView*)infobarView { - ConfirmInfoBarView* infoBarView = - [[ConfirmInfoBarView alloc] initWithFrame:CGRectZero]; - // Icon - gfx::Image icon = self.infoBarDelegate->GetIcon(); - if (!icon.IsEmpty()) - [infoBarView addLeftIcon:icon.ToUIImage()]; - // Text. - [infoBarView addLabel:base::SysUTF16ToNSString( - self.infoBarDelegate->GetMessageInfoBarText())]; - // Close button. - [infoBarView addCloseButtonWithTag:TranslateInfoBarIOSTag::CLOSE - target:self - action:@selector(infoBarButtonDidPress:)]; - // Other button. - base::string16 buttonText( - self.infoBarDelegate->GetMessageInfoBarButtonText()); - if (!buttonText.empty()) { - [infoBarView addButton:base::SysUTF16ToNSString(buttonText) - tag:TranslateInfoBarIOSTag::MESSAGE - target:self - action:@selector(infoBarButtonDidPress:)]; - } - return infoBarView; -} - -#pragma mark - Handling of User Events - -- (void)infoBarButtonDidPress:(id)sender { - if ([self shouldIgnoreUserInteraction]) - return; - - NSUInteger buttonId = base::mac::ObjCCastStrict<UIButton>(sender).tag; - switch (buttonId) { - case TranslateInfoBarIOSTag::CLOSE: - self.infoBarDelegate->InfoBarDismissed(); - self.delegate->RemoveInfoBar(); - break; - case TranslateInfoBarIOSTag::MESSAGE: - self.infoBarDelegate->MessageInfoBarButtonPressed(); - break; - default: - NOTREACHED() << "Unexpected Translate button label"; - break; - } -} - -@end
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm index 145d489..66c6e9e7 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -7,7 +7,6 @@ #include <memory> #include "base/scoped_observer.h" -#include "components/translate/core/browser/translate_prefs.h" #import "ios/chrome/browser/app_launcher/app_launcher_abuse_detector.h" #import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h" #import "ios/chrome/browser/autofill/autofill_tab_helper.h" @@ -38,7 +37,6 @@ #import "ios/chrome/browser/ui/reading_list/reading_list_coordinator.h" #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.h" #import "ios/chrome/browser/ui/snackbar/snackbar_coordinator.h" -#import "ios/chrome/browser/ui/translate/language_selection_coordinator.h" #import "ios/chrome/browser/ui/translate/translate_infobar_coordinator.h" #import "ios/chrome/browser/url_loading/url_loading_params.h" #import "ios/chrome/browser/url_loading/url_loading_service.h" @@ -84,10 +82,6 @@ @property(nonatomic, strong) FormInputAccessoryCoordinator* formInputAccessoryCoordinator; -// Coordinator for a language selection UI. -@property(nonatomic, strong) - LanguageSelectionCoordinator* languageSelectionCoordinator; - // Coordinator for Page Info UI. @property(nonatomic, strong) PageInfoLegacyCoordinator* pageInfoCoordinator; @@ -256,19 +250,11 @@ self.formInputAccessoryCoordinator.delegate = self; [self.formInputAccessoryCoordinator start]; - if (base::FeatureList::IsEnabled(translate::kCompactTranslateInfobarIOS)) { - self.translateInfobarCoordinator = [[TranslateInfobarCoordinator alloc] - initWithBaseViewController:self.viewController - browserState:self.browserState - webStateList:self.tabModel.webStateList]; - [self.translateInfobarCoordinator start]; - } else { - self.languageSelectionCoordinator = [[LanguageSelectionCoordinator alloc] - initWithBaseViewController:self.viewController - browserState:self.browserState - webStateList:self.tabModel.webStateList]; - [self.languageSelectionCoordinator start]; - } + self.translateInfobarCoordinator = [[TranslateInfobarCoordinator alloc] + initWithBaseViewController:self.viewController + browserState:self.browserState + webStateList:self.tabModel.webStateList]; + [self.translateInfobarCoordinator start]; self.pageInfoCoordinator = [[PageInfoLegacyCoordinator alloc] initWithBaseViewController:self.viewController @@ -314,9 +300,6 @@ [self.formInputAccessoryCoordinator stop]; self.formInputAccessoryCoordinator = nil; - [self.languageSelectionCoordinator stop]; - self.languageSelectionCoordinator = nil; - [self.pageInfoCoordinator stop]; self.pageInfoCoordinator = nil;
diff --git a/ios/chrome/browser/ui/translate/BUILD.gn b/ios/chrome/browser/ui/translate/BUILD.gn index 5bcf310..11a653e 100644 --- a/ios/chrome/browser/ui/translate/BUILD.gn +++ b/ios/chrome/browser/ui/translate/BUILD.gn
@@ -5,10 +5,6 @@ source_set("translate") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "language_selection_coordinator.h", - "language_selection_coordinator.mm", - "language_selection_mediator.h", - "language_selection_mediator.mm", "translate_infobar_coordinator.h", "translate_infobar_coordinator.mm", "translate_infobar_mediator.h", @@ -37,10 +33,6 @@ source_set("translate_ui") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "language_selection_consumer.h", - "language_selection_provider.h", - "language_selection_view_controller.h", - "language_selection_view_controller.mm", "translate_infobar_language_tab_strip_view.h", "translate_infobar_language_tab_strip_view.mm", "translate_infobar_language_tab_strip_view_delegate.h",
diff --git a/ios/chrome/browser/ui/translate/language_selection_consumer.h b/ios/chrome/browser/ui/translate/language_selection_consumer.h deleted file mode 100644 index 9c884335..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_consumer.h +++ /dev/null
@@ -1,27 +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 IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_CONSUMER_H_ -#define IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_CONSUMER_H_ - -#import <Foundation/Foundation.h> - -@protocol LanguageSelectionProvider; - -// Consumer protocol for a view controller providing a language selection -// interface. -@protocol LanguageSelectionConsumer -// The language provider that the consumer should use to fetch language -// information for display. -@property(nonatomic, weak) id<LanguageSelectionProvider> provider; -// The number of languages available for display in the interface. -@property(nonatomic) int languageCount; -// The index of the initially selected language. -@property(nonatomic) int initialLanguageIndex; -// The index of a language unavailable for selection (because it has already -// been selected, for example). -@property(nonatomic) int disabledLanguageIndex; -@end - -#endif // IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/translate/language_selection_coordinator.h b/ios/chrome/browser/ui/translate/language_selection_coordinator.h deleted file mode 100644 index a83c76db8..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_coordinator.h +++ /dev/null
@@ -1,36 +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 IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_COORDINATOR_H_ -#define IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_COORDINATOR_H_ - -#import <UIKit/UIKit.h> - -#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" - -@protocol ContainedPresenter; -class WebStateList; - -// A coordinator for a language selection UI. This is intended for display as -// a contained, not presented, view controller. -// The methods defined in the LanguageSelectionHandler protocol will be called -// to start the coordinator. -@interface LanguageSelectionCoordinator : ChromeCoordinator - -// Creates a coordinator that uses a |viewController| a |browserState| and -// a |webStateList|. -- (instancetype)initWithBaseViewController:(UIViewController*)viewController - browserState: - (ios::ChromeBrowserState*)browserState - webStateList:(WebStateList*)webStateList; - -// Unavailable, use -initWithBaseViewController:browserState:webStateList:. -- (instancetype)initWithBaseViewController:(UIViewController*)viewController - browserState: - (ios::ChromeBrowserState*)browserState - NS_UNAVAILABLE; - -@end - -#endif // IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/translate/language_selection_coordinator.mm b/ios/chrome/browser/ui/translate/language_selection_coordinator.mm deleted file mode 100644 index 320c9b3a..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_coordinator.mm +++ /dev/null
@@ -1,119 +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. - -#import "ios/chrome/browser/ui/translate/language_selection_coordinator.h" - -#include "base/logging.h" -#import "ios/chrome/browser/translate/language_selection_delegate.h" -#import "ios/chrome/browser/translate/language_selection_handler.h" -#import "ios/chrome/browser/ui/presenters/contained_presenter.h" -#import "ios/chrome/browser/ui/presenters/vertical_animation_container.h" -#import "ios/chrome/browser/ui/translate/language_selection_mediator.h" -#import "ios/chrome/browser/ui/translate/language_selection_view_controller.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface LanguageSelectionCoordinator () < - LanguageSelectionHandler, - LanguageSelectionViewControllerDelegate> - -// The WebStateList being observed. -@property(nonatomic) WebStateList* webStateList; -// Presenter to use to for presenting the view controller. -@property(nonatomic) id<ContainedPresenter> presenter; -// The view controller this coordinator manages. -@property(nonatomic) LanguageSelectionViewController* selectionViewController; -// A mediator to interoperate with the translation model. -@property(nonatomic) LanguageSelectionMediator* selectionMediator; -// A delegate, provided by showLanguageSelectorWithContext:delegate:. -@property(nonatomic, weak) id<LanguageSelectionDelegate> selectionDelegate; -// YES if the coordinator has been started. -@property(nonatomic) BOOL started; - -@end - -@implementation LanguageSelectionCoordinator - -- (instancetype)initWithBaseViewController:(UIViewController*)viewController - browserState: - (ios::ChromeBrowserState*)browserState - webStateList:(WebStateList*)webStateList { - DCHECK(webStateList); - self = [super initWithBaseViewController:viewController - browserState:browserState]; - if (self) { - _webStateList = webStateList; - } - return self; -} - -#pragma mark - private methods - -- (void)start { - if (self.started) - return; - - self.selectionMediator = - [[LanguageSelectionMediator alloc] initWithLanguageSelectionHandler:self]; - self.selectionMediator.webStateList = self.webStateList; - - self.started = YES; -} - -- (void)stop { - if (!self.started) - return; - - [self dismissLanguageSelector]; - [self.selectionMediator disconnect]; - self.selectionMediator = nil; - self.presenter = nil; - self.selectionViewController = nil; - self.selectionDelegate = nil; - - self.started = NO; -} - -#pragma mark - LanguageSelectionHandler - -- (void)showLanguageSelectorWithContext:(LanguageSelectionContext*)context - delegate: - (id<LanguageSelectionDelegate>)delegate { - self.selectionDelegate = delegate; - - self.selectionMediator.context = context; - - self.selectionViewController = [[LanguageSelectionViewController alloc] init]; - self.selectionViewController.delegate = self; - self.selectionMediator.consumer = self.selectionViewController; - - self.presenter = [[VerticalAnimationContainer alloc] init]; - self.presenter.baseViewController = self.baseViewController; - self.presenter.presentedViewController = self.selectionViewController; - [self.presenter prepareForPresentation]; - [self.presenter presentAnimated:YES]; -} - -- (void)dismissLanguageSelector { - [self.selectionDelegate languageSelectorClosedWithoutSelection]; - [self.presenter dismissAnimated:NO]; -} - -#pragma mark - LanguageSelectionViewControllerDelegate - -- (void)languageSelectedAtIndex:(int)index { - [self.selectionDelegate - languageSelectorSelectedLanguage: - [self.selectionMediator languageCodeForLanguageAtIndex:index]]; - [self.presenter dismissAnimated:NO]; -} - -- (void)languageSelectionCanceled { - [self.selectionDelegate languageSelectorClosedWithoutSelection]; - [self.presenter dismissAnimated:NO]; -} - -@end
diff --git a/ios/chrome/browser/ui/translate/language_selection_mediator.h b/ios/chrome/browser/ui/translate/language_selection_mediator.h deleted file mode 100644 index 46154619..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_mediator.h +++ /dev/null
@@ -1,42 +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 IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_MEDIATOR_H_ -#define IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_MEDIATOR_H_ - -#import <Foundation/Foundation.h> -#include <string> - -@protocol LanguageSelectionConsumer; -@class LanguageSelectionContext; -@protocol LanguageSelectionHandler; -class WebStateList; - -// Mediator object to configure and provide data for language selection. -@interface LanguageSelectionMediator : NSObject - -// |handler| presents and dismisses the language selection UI. -- (instancetype)initWithLanguageSelectionHandler: - (id<LanguageSelectionHandler>)handler NS_DESIGNATED_INITIALIZER; -- (instancetype)init NS_UNAVAILABLE; - -// Disconnects the mediator. -- (void)disconnect; - -// The WebStateList being observed. -@property(nonatomic) WebStateList* webStateList; - -// The context object provided for language selection. -@property(nonatomic) LanguageSelectionContext* context; - -// Consumer for this mediator. -@property(nonatomic, weak) id<LanguageSelectionConsumer> consumer; - -// Utility method for the coordinator to map a selected language index to a -// language name. -- (std::string)languageCodeForLanguageAtIndex:(int)index; - -@end - -#endif // IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/translate/language_selection_mediator.mm b/ios/chrome/browser/ui/translate/language_selection_mediator.mm deleted file mode 100644 index 4ac89b5..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_mediator.mm +++ /dev/null
@@ -1,170 +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. - -#import "ios/chrome/browser/ui/translate/language_selection_mediator.h" - -#include <memory> - -#include "base/logging.h" -#include "base/scoped_observer.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "components/translate/core/browser/translate_infobar_delegate.h" -#include "ios/chrome/browser/translate/chrome_ios_translate_client.h" -#import "ios/chrome/browser/translate/language_selection_context.h" -#import "ios/chrome/browser/translate/language_selection_handler.h" -#import "ios/chrome/browser/ui/translate/language_selection_consumer.h" -#import "ios/chrome/browser/ui/translate/language_selection_provider.h" -#import "ios/chrome/browser/web_state_list/web_state_list.h" -#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface LanguageSelectionMediator () <WebStateListObserving, - LanguageSelectionProvider> { - // WebStateList observers. - std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge; - std::unique_ptr<ScopedObserver<WebStateList, WebStateListObserver>> - _scopedWebStateListObserver; -} - -// The language selection handler. -@property(nonatomic, weak) id<LanguageSelectionHandler> - languageSelectionHandler; - -@end - -@implementation LanguageSelectionMediator - -- (instancetype)initWithLanguageSelectionHandler: - (id<LanguageSelectionHandler>)handler { - DCHECK(handler); - if ((self = [super init])) { - _languageSelectionHandler = handler; - } - return self; -} - -#pragma mark - Public methods - -- (void)disconnect { - self.webStateList = nil; -} - -- (std::string)languageCodeForLanguageAtIndex:(int)index { - DCHECK(self.context); - return self.context.languageData->language_code_at(index); -} - -#pragma mark - Properties - -- (void)setConsumer:(id<LanguageSelectionConsumer>)consumer { - _consumer = consumer; - DCHECK(self.context); - self.consumer.languageCount = self.context.languageData->num_languages(); - self.consumer.initialLanguageIndex = self.context.initialLanguageIndex; - self.consumer.disabledLanguageIndex = self.context.unavailableLanguageIndex; - self.consumer.provider = self; -} - -- (void)setWebStateList:(WebStateList*)webStateList { - if (_webStateList == webStateList) - return; - - if (_webStateList) { - [self removeWebStateListObserver]; - - // Uninstall delegates for each WebState in WebStateList. - for (int i = 0; i < self.webStateList->count(); i++) { - [self uninstallDelegatesForWebState:self.webStateList->GetWebStateAt(i)]; - } - } - - _webStateList = webStateList; - - if (_webStateList) { - // Install delegates for each WebState in WebStateList. - for (int i = 0; i < _webStateList->count(); i++) { - [self installDelegatesForWebState:_webStateList->GetWebStateAt(i)]; - } - - [self addWebStateListObserver]; - } -} - -#pragma mark - Private - -// Adds observer for WebStateList. -- (void)addWebStateListObserver { - _webStateListObserverBridge = - std::make_unique<WebStateListObserverBridge>(self); - _scopedWebStateListObserver = - std::make_unique<ScopedObserver<WebStateList, WebStateListObserver>>( - _webStateListObserverBridge.get()); - _scopedWebStateListObserver->Add(self.webStateList); -} - -// Removes observer for WebStateList. -- (void)removeWebStateListObserver { - _scopedWebStateListObserver.reset(); - _webStateListObserverBridge.reset(); -} - -// Installs delegates for |webState|. -- (void)installDelegatesForWebState:(web::WebState*)webState { - if (ChromeIOSTranslateClient::FromWebState(webState)) { - ChromeIOSTranslateClient::FromWebState(webState) - ->set_language_selection_handler(self.languageSelectionHandler); - } -} - -// Uninstalls delegates for |webState|. -- (void)uninstallDelegatesForWebState:(web::WebState*)webState { - if (ChromeIOSTranslateClient::FromWebState(webState)) { - ChromeIOSTranslateClient::FromWebState(webState) - ->set_language_selection_handler(nil); - } -} - -#pragma mark - WebStateListObserving - -- (void)webStateList:(WebStateList*)webStateList - didInsertWebState:(web::WebState*)webState - atIndex:(int)index - activating:(BOOL)activating { - [self installDelegatesForWebState:webState]; -} - -- (void)webStateList:(WebStateList*)webStateList - didReplaceWebState:(web::WebState*)oldWebState - withWebState:(web::WebState*)newWebState - atIndex:(int)index { - [self uninstallDelegatesForWebState:oldWebState]; - [self installDelegatesForWebState:newWebState]; -} - -- (void)webStateList:(WebStateList*)webStateList - didDetachWebState:(web::WebState*)webState - atIndex:(int)index { - [self uninstallDelegatesForWebState:webState]; -} - -#pragma mark - LanguageSelectionProvider - -- (NSString*)languageNameAtIndex:(int)languageIndex { - DCHECK(self.context); - if (languageIndex < 0 || - languageIndex >= - static_cast<int>(self.context.languageData->num_languages())) { - NOTREACHED() << "Language index " << languageIndex - << " out of expected range."; - return nil; - } - return base::SysUTF16ToNSString( - self.context.languageData->language_name_at(languageIndex)); -} - -@end
diff --git a/ios/chrome/browser/ui/translate/language_selection_provider.h b/ios/chrome/browser/ui/translate/language_selection_provider.h deleted file mode 100644 index dc94236..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_provider.h +++ /dev/null
@@ -1,22 +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 IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_PROVIDER_H_ -#define IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_PROVIDER_H_ - -#import <Foundation/Foundation.h> - -// Protocol for a provider that can map indexes to language names. An -// implementer of this protocol should be consistent over its lifetime, always -// returning the same language information for a given index. -@protocol LanguageSelectionProvider - -// The name of the language (in the application's locale) of the language at -// index |languageIndex|, or nil if |languageIndex| is outside of the range -// of indices handled by the implementer. -- (NSString*)languageNameAtIndex:(int)languageIndex; - -@end - -#endif // IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_PROVIDER_H_
diff --git a/ios/chrome/browser/ui/translate/language_selection_view_controller.h b/ios/chrome/browser/ui/translate/language_selection_view_controller.h deleted file mode 100644 index 7ab5d9d..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_view_controller.h +++ /dev/null
@@ -1,43 +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 IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_VIEW_CONTROLLER_H_ -#define IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_VIEW_CONTROLLER_H_ - -#import <UIKit/UIKit.h> - -#import "ios/chrome/browser/ui/translate/language_selection_consumer.h" - -// The accessibility identifier of the cancel button on language picker view. -// NOTE: this should not be used on iOS 9 for testing. -extern NSString* const kLanguagePickerCancelButtonId; - -// The accessibility identifier of the done button on language picker view. -// NOTE: this should not be used on iOS 9 for testing. -extern NSString* const kLanguagePickerDoneButtonId; - -// A delegate for a LanguageSelectionViewController instance, which the view -// controller tells about selection events. -@protocol LanguageSelectionViewControllerDelegate - -// Tells the delegate that a language was selected. |index| will be an index -// in the range provided to the view controller over via the consumer protocol. -- (void)languageSelectedAtIndex:(int)index; - -// Tells the delegate that language selection was cancelled. -- (void)languageSelectionCanceled; - -@end - -// A view controller that displays a picker view for selecting a language from -// a list of provided languages. -@interface LanguageSelectionViewController - : UIViewController<LanguageSelectionConsumer> - -// The delegate for this view controller. -@property(nonatomic, weak) id<LanguageSelectionViewControllerDelegate> delegate; - -@end - -#endif // IOS_CHROME_BROWSER_UI_TRANSLATE_LANGUAGE_SELECTION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/translate/language_selection_view_controller.mm b/ios/chrome/browser/ui/translate/language_selection_view_controller.mm deleted file mode 100644 index c8d8459..0000000 --- a/ios/chrome/browser/ui/translate/language_selection_view_controller.mm +++ /dev/null
@@ -1,152 +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. - -#import "ios/chrome/browser/ui/translate/language_selection_view_controller.h" - -#include "base/logging.h" -#import "base/mac/foundation_util.h" -#import "ios/chrome/browser/ui/translate/language_selection_provider.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -NSString* const kLanguagePickerCancelButtonId = @"LanguagePickerCancelButton"; -NSString* const kLanguagePickerDoneButtonId = @"LanguagePickerDoneButton"; - -namespace { -CGFloat kUIPickerFontSize = 26; -} - -@interface LanguageSelectionViewController ()<UIPickerViewDataSource, - UIPickerViewDelegate> { - // YES if NSLayoutConstraits were added. - BOOL _addedConstraints; -} - -@property(nonatomic, weak) UIPickerView* picker; - -// Action methods for navigation bar buttons. -- (void)languageSelectionDone; -- (void)languageSelectionCancelled; - -@end - -@implementation LanguageSelectionViewController - -// Synthesize properties defined by LanguageSelectionConsumer -@synthesize languageCount = _languageCount; -@synthesize initialLanguageIndex = _initialLanguageIndex; -@synthesize disabledLanguageIndex = _disabledLanguageIndex; -@synthesize provider = _provider; -// Synthesize public properties -@synthesize delegate = _delegate; -// Synthesize private properties -@synthesize picker = _picker; - -#pragma mark - UIViewController - -- (void)viewDidLoad { - DCHECK(_languageCount && _provider); - - UIPickerView* picker = [[UIPickerView alloc] initWithFrame:CGRectZero]; - picker.backgroundColor = UIColor.whiteColor; - picker.translatesAutoresizingMaskIntoConstraints = NO; - picker.showsSelectionIndicator = YES; - picker.dataSource = self; - picker.delegate = self; - [picker selectRow:self.initialLanguageIndex inComponent:0 animated:NO]; - - [self.view addSubview:picker]; - self.picker = picker; - - UINavigationBar* bar = [[UINavigationBar alloc] initWithFrame:CGRectZero]; - bar.translatesAutoresizingMaskIntoConstraints = NO; - - UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem:UIBarButtonSystemItemDone - target:self - action:@selector(languageSelectionDone)]; - [doneButton setAccessibilityIdentifier:kLanguagePickerDoneButtonId]; - - UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem:UIBarButtonSystemItemCancel - target:self - action:@selector(languageSelectionCancelled)]; - [cancelButton setAccessibilityIdentifier:kLanguagePickerCancelButtonId]; - - UINavigationItem* item = [[UINavigationItem alloc] initWithTitle:@""]; - [item setRightBarButtonItem:doneButton]; - [item setLeftBarButtonItem:cancelButton]; - [item setHidesBackButton:YES]; - [bar pushNavigationItem:item animated:NO]; - - [self.view addSubview:bar]; - - // Bar sits on top of the picker, both are full width. Constraints don't - // change. Height is entirely determined by the preferred content sizes of - // the bar and picker. - [NSLayoutConstraint activateConstraints:@[ - [bar.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], - [picker.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], - [bar.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], - [picker.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], - [bar.topAnchor constraintEqualToAnchor:self.view.topAnchor], - [picker.topAnchor constraintEqualToAnchor:bar.bottomAnchor], - [picker.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], - ]]; -} - -- (void)updateViewConstraints { - if (!_addedConstraints) { - [[self.view.superview.widthAnchor - constraintEqualToAnchor:self.view.widthAnchor] setActive:YES]; - _addedConstraints = YES; - } - [super updateViewConstraints]; -} - -#pragma mark - UIPickerViewDataSource - -- (NSInteger)pickerView:(UIPickerView*)pickerView - numberOfRowsInComponent:(NSInteger)component { - return _languageCount; -} - -- (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView { - return 1; -} - -#pragma mark - UIPickerViewDelegate - -- (UIView*)pickerView:(UIPickerView*)pickerView - viewForRow:(NSInteger)row - forComponent:(NSInteger)component - reusingView:(UIView*)view { - DCHECK_EQ(0, component); - UILabel* label = base::mac::ObjCCast<UILabel>(view) ?: [[UILabel alloc] init]; - label.text = [_provider languageNameAtIndex:row]; - label.textAlignment = NSTextAlignmentCenter; - UIFont* font = [UIFont systemFontOfSize:kUIPickerFontSize]; - if (row == _initialLanguageIndex) { - font = [UIFont boldSystemFontOfSize:kUIPickerFontSize]; - } else if (row == _disabledLanguageIndex) { - label.enabled = NO; - } - label.font = font; - return label; -} - -#pragma mark - Navigation buttons - -- (void)languageSelectionDone { - [self.delegate - languageSelectedAtIndex:[self.picker selectedRowInComponent:0]]; -} - -- (void)languageSelectionCancelled { - [self.delegate languageSelectionCanceled]; -} - -@end
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn index 515ca912..eaf4b44c 100644 --- a/ios/chrome/test/earl_grey/BUILD.gn +++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -10,7 +10,6 @@ ":ios_chrome_autofill_automation_egtests", ":ios_chrome_bookmarks_egtests", ":ios_chrome_device_check_egtests", - ":ios_chrome_external_url_egtests", ":ios_chrome_flaky_egtests", ":ios_chrome_integration_egtests", ":ios_chrome_multitasking_egtests", @@ -195,12 +194,6 @@ ] } -chrome_ios_eg_test("ios_chrome_external_url_egtests") { - deps = [ - "//ios/chrome/browser/translate:external_url_eg_tests", - ] -} - source_set("test_support") { defines = [ "CHROME_EARL_GREY_1" ] configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/mojo/public/cpp/bindings/interface_ptr_set.h b/mojo/public/cpp/bindings/interface_ptr_set.h index 8130785..faf91ad 100644 --- a/mojo/public/cpp/bindings/interface_ptr_set.h +++ b/mojo/public/cpp/bindings/interface_ptr_set.h
@@ -21,8 +21,8 @@ namespace internal { -// TODO(blundell): This class should be rewritten to be structured -// similarly to BindingSet if possible, with PtrSet owning its +// TODO(https://crbug.com/965668): This class should be rewritten to be +// structured similarly to BindingSet if possible, with PtrSet owning its // Elements and those Elements calling back into PtrSet on connection // error. template <typename Interface, template <typename> class Ptr>
diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc index 0ed0653..76df73c 100644 --- a/printing/backend/cups_jobs.cc +++ b/printing/backend/cups_jobs.cc
@@ -429,18 +429,18 @@ } } -bool GetPrinterInfo(const std::string& address, - const int port, - const std::string& resource, - bool encrypted, - PrinterInfo* printer_info) { +PrinterQueryResult GetPrinterInfo(const std::string& address, + const int port, + const std::string& resource, + bool encrypted, + PrinterInfo* printer_info) { ScopedHttpPtr http = ScopedHttpPtr(httpConnect2( address.c_str(), port, nullptr, AF_INET, encrypted ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 0, kHttpConnectTimeoutMs, nullptr)); if (!http) { LOG(WARNING) << "Could not connect to host"; - return false; + return PrinterQueryResult::UNREACHABLE; } // TODO(crbug.com/821497): Use a library to canonicalize the URL. @@ -459,10 +459,13 @@ kPrinterInfo.size(), kPrinterInfo.data(), &status); if (status != IPP_STATUS_OK || response.get() == nullptr) { LOG(WARNING) << "Get attributes failure: " << status; - return false; + return PrinterQueryResult::UNKNOWN_FAILURE; } - return ParsePrinterInfo(response.get(), printer_info); + if (ParsePrinterInfo(response.get(), printer_info)) { + return PrinterQueryResult::SUCCESS; + } + return PrinterQueryResult::UNKNOWN_FAILURE; } bool GetPrinterStatus(http_t* http,
diff --git a/printing/backend/cups_jobs.h b/printing/backend/cups_jobs.h index c2606eb..f67359d 100644 --- a/printing/backend/cups_jobs.h +++ b/printing/backend/cups_jobs.h
@@ -143,6 +143,13 @@ PROCESSING // only jobs that are being processed }; +// Specifies query status codes. +enum PRINTING_EXPORT PrinterQueryResult { + UNKNOWN_FAILURE, // catchall error + SUCCESS, // successful + UNREACHABLE, // failed to reach the host +}; + // Extracts structured job information from the |response| for |printer_id|. // Extracted jobs are added to |jobs|. void ParseJobsResponse(ipp_t* response, @@ -155,11 +162,11 @@ // Queries the printer at |address| on |port| with a Get-Printer-Attributes // request to populate |printer_info|. If |encrypted| is true, request is made // using ipps, otherwise, ipp is used. Returns false if the request failed. -bool PRINTING_EXPORT GetPrinterInfo(const std::string& address, - const int port, - const std::string& resource, - bool encrypted, - PrinterInfo* printer_info); +PrinterQueryResult PRINTING_EXPORT GetPrinterInfo(const std::string& address, + const int port, + const std::string& resource, + bool encrypted, + PrinterInfo* printer_info); // Attempts to retrieve printer status using connection |http| for |printer_id|. // Returns true if succcssful and updates the fields in |printer_status| as
diff --git a/sandbox/win/src/process_mitigations_dyncode_unittest.cc b/sandbox/win/src/process_mitigations_dyncode_unittest.cc index df1c24d..59db0b0 100644 --- a/sandbox/win/src/process_mitigations_dyncode_unittest.cc +++ b/sandbox/win/src/process_mitigations_dyncode_unittest.cc
@@ -447,17 +447,12 @@ if (base::win::GetVersion() < base::win::Version::WIN8_1) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); // Expect success, no mitigation. - DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE, true, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE, + true /* expect_success */, + false /* enable_mitigation */); } // This test validates that setting the MITIGATION_DYNAMIC_CODE_DISABLE @@ -466,17 +461,12 @@ if (base::win::GetVersion() < base::win::Version::WIN8_1) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); // Expect failure, with mitigation. - DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE, false, true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE, + false /* expect_success */, + true /* enable_mitigation */); } //------------------------------------------------------------------------------ @@ -534,18 +524,13 @@ if (base::win::GetVersion() < base::win::Version::WIN10_RS1) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); // Expect success, no mitigation (and therefore no thread opt-out). DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT, - true, false, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + true /* expect_success */, + false /* enable_mitigation */, + false /* with_thread_opt_out */); } // This test validates that setting the @@ -555,18 +540,13 @@ if (base::win::GetVersion() < base::win::Version::WIN10_RS1) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); // Expect failure, with mitigation, no thread opt-out. DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT, - false, true, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + false /* expect_success */, + true /* enable_mitigation */, + false /* with_thread_opt_out */); } // This test validates that setting the @@ -577,18 +557,13 @@ if (base::win::GetVersion() < base::win::Version::WIN10_RS1) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); // Expect success, with mitigation, with thread opt-out. DynamicCodeTestHarness(sandbox::MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT, - true, true, true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + true /* expect_success */, + true /* enable_mitigation */, + true /* with_thread_opt_out */); } } // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations_extensionpoints_unittest.cc b/sandbox/win/src/process_mitigations_extensionpoints_unittest.cc index 3c4234f..a9da035 100644 --- a/sandbox/win/src/process_mitigations_extensionpoints_unittest.cc +++ b/sandbox/win/src/process_mitigations_extensionpoints_unittest.cc
@@ -402,16 +402,10 @@ if (base::win::GetVersion() < base::win::Version::WIN8) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_extension_point_test_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_extension_point_test_mutex); - // (is_success_test, global_hook) - TestWin8ExtensionPointHookWrapper(true, true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin8ExtensionPointHookWrapper(true /* is_success_test */, + true /* global hook */); } // This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE @@ -423,16 +417,10 @@ if (base::win::GetVersion() < base::win::Version::WIN8) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_extension_point_test_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_extension_point_test_mutex); - // (is_success_test, global_hook) - TestWin8ExtensionPointHookWrapper(false, true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin8ExtensionPointHookWrapper(false /* is_success_test */, + true /* global hook */); } // This test validates that a "legitimate" hook CAN be set on the sandboxed @@ -443,16 +431,10 @@ if (base::win::GetVersion() < base::win::Version::WIN8) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_extension_point_test_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_extension_point_test_mutex); - // (is_success_test, global_hook) - TestWin8ExtensionPointHookWrapper(true, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin8ExtensionPointHookWrapper(true /* is_success_test */, + false /* global hook */); } // *** Important: MITIGATION_EXTENSION_POINT_DISABLE does NOT prevent @@ -466,16 +448,10 @@ if (base::win::GetVersion() < base::win::Version::WIN8) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_extension_point_test_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_extension_point_test_mutex); - // (is_success_test, global_hook) - TestWin8ExtensionPointHookWrapper(false, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin8ExtensionPointHookWrapper(false /* is_success_test */, + false /* global hook */); } // This test validates that an AppInit Dll CAN be added to a target @@ -487,15 +463,9 @@ if (base::win::GetVersion() < base::win::Version::WIN8) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_extension_point_test_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_extension_point_test_mutex); - TestWin8ExtensionPointAppInitWrapper(true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin8ExtensionPointAppInitWrapper(true /* is_success_test */); } // This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE @@ -507,15 +477,9 @@ if (base::win::GetVersion() < base::win::Version::WIN8) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_extension_point_test_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_extension_point_test_mutex); - TestWin8ExtensionPointAppInitWrapper(false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin8ExtensionPointAppInitWrapper(false /* is_success_test */); } } // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations_imageload_unittest.cc b/sandbox/win/src/process_mitigations_imageload_unittest.cc index f6af3d8..cece245 100644 --- a/sandbox/win/src/process_mitigations_imageload_unittest.cc +++ b/sandbox/win/src/process_mitigations_imageload_unittest.cc
@@ -302,7 +302,7 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - TestWin10ImageLoadRemote(true); + TestWin10ImageLoadRemote(true /* is_success_test */); } // This test validates that setting the MITIGATION_IMAGE_LOAD_NO_REMOTE @@ -314,7 +314,7 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - TestWin10ImageLoadRemote(false); + TestWin10ImageLoadRemote(false /* is_success_test */); } //------------------------------------------------------------------------------ @@ -361,7 +361,7 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - TestWin10ImageLoadLowLabel(true); + TestWin10ImageLoadLowLabel(true /* is_success_test */); } // This test validates that setting the MITIGATION_IMAGE_LOAD_NO_LOW_LABEL @@ -370,7 +370,7 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - TestWin10ImageLoadLowLabel(false); + TestWin10ImageLoadLowLabel(false /* is_success_test */); } //------------------------------------------------------------------------------ @@ -421,16 +421,11 @@ if (base::win::GetVersion() < base::win::Version::WIN10_RS1) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_hijack_dlls_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_hijack_dlls_mutex); // Baseline test, and expect the DLL to NOT be in system32. - TestWin10ImageLoadPreferSys32(true, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin10ImageLoadPreferSys32(true /* baseline_test */, + false /* expect_sys32_path */); } // This test validates that import hijacking succeeds, if the @@ -442,16 +437,11 @@ if (base::win::GetVersion() < base::win::Version::WIN10_RS1) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_hijack_dlls_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_hijack_dlls_mutex); // Not a baseline test, and expect the DLL to be in system32. - TestWin10ImageLoadPreferSys32(false, true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin10ImageLoadPreferSys32(false /* baseline_test */, + true /* expect_sys32_path */); } // This test validates that setting the MITIGATION_IMAGE_LOAD_PREFER_SYS32 @@ -462,16 +452,11 @@ if (base::win::GetVersion() < base::win::Version::WIN10_RS1) return; - HANDLE mutex = ::CreateMutexW(nullptr, false, g_hijack_dlls_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(g_hijack_dlls_mutex); // Not a baseline test, and expect the DLL to NOT be in system32. - TestWin10ImageLoadPreferSys32(false, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin10ImageLoadPreferSys32(false /* baseline_test */, + false /* expect_sys32_path */); } } // namespace sandbox
diff --git a/sandbox/win/src/process_mitigations_unittest.cc b/sandbox/win/src/process_mitigations_unittest.cc index a0cd2790..270cfa1d 100644 --- a/sandbox/win/src/process_mitigations_unittest.cc +++ b/sandbox/win/src/process_mitigations_unittest.cc
@@ -689,7 +689,7 @@ if (base::win::GetVersion() < base::win::Version::WIN10) return; - TestWin10NonSystemFont(true); + TestWin10NonSystemFont(true /* is_success_test */); } // This test validates that setting the MITIGATION_NON_SYSTEM_FONTS_DISABLE @@ -698,7 +698,7 @@ if (base::win::GetVersion() < base::win::Version::WIN10) return; - TestWin10NonSystemFont(false); + TestWin10NonSystemFont(false /* is_success_test */); } //------------------------------------------------------------------------------ @@ -742,17 +742,11 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); - // Expect success; Do not enable mitigation; Use non MS-signed binary. - TestWin10MsSigned(true, false, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin10MsSigned(true /* expect_success */, + false /* enable_mitigation */, + false /* use_ms_signed_binary */); } // This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS @@ -761,17 +755,11 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); - // Expect failure; Enable mitigation; Use non MS-signed binary. - TestWin10MsSigned(false, true, false); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin10MsSigned(false /* expect_success */, + true /* enable_mitigation */, + false /* use_ms_signed_binary */); } // This test validates that we can load a signed Microsoft DLL if the @@ -781,17 +769,11 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); - // Expect success; Do not enable mitigation; Use MS-signed binary. - TestWin10MsSigned(true, false, true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin10MsSigned(true /* expect_success */, + false /* enable_mitigation */, + true /* use_ms_signed_binary */); } // This test validates that setting the MITIGATION_FORCE_MS_SIGNED_BINS @@ -800,17 +782,11 @@ if (base::win::GetVersion() < base::win::Version::WIN10_TH2) return; - HANDLE mutex = - ::CreateMutexW(nullptr, false, hooking_dll::g_hooking_dll_mutex); - EXPECT_TRUE(mutex); - EXPECT_EQ(WAIT_OBJECT_0, - ::WaitForSingleObject(mutex, SboxTestEventTimeout())); + ScopedTestMutex mutex(hooking_dll::g_hooking_dll_mutex); - // Expect success; Enable mitigation; Use MS-signed binary. - TestWin10MsSigned(true, true, true); - - EXPECT_TRUE(::ReleaseMutex(mutex)); - EXPECT_TRUE(::CloseHandle(mutex)); + TestWin10MsSigned(true /* expect_success */, + true /* enable_mitigation */, + true /* use_ms_signed_binary */); } //------------------------------------------------------------------------------
diff --git a/sandbox/win/src/win_utils_unittest.cc b/sandbox/win/src/win_utils_unittest.cc index c814dbb3..507ceaf 100644 --- a/sandbox/win/src/win_utils_unittest.cc +++ b/sandbox/win/src/win_utils_unittest.cc
@@ -20,6 +20,8 @@ #include "sandbox/win/tests/common/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" +namespace sandbox { + namespace { class ScopedTerminateProcess { @@ -252,4 +254,6 @@ EXPECT_TRUE(base::DeleteFileW(temp_path, false)); return; -} \ No newline at end of file +} + +} // namespace sandbox
diff --git a/sandbox/win/tests/common/test_utils.cc b/sandbox/win/tests/common/test_utils.cc index 9c03ac2..53fcc10 100644 --- a/sandbox/win/tests/common/test_utils.cc +++ b/sandbox/win/tests/common/test_utils.cc
@@ -9,6 +9,8 @@ #include "base/numerics/safe_conversions.h" +namespace sandbox { + typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; @@ -145,3 +147,5 @@ return !!::GetTokenInformation(token, information_class, information->data(), return_length, &return_length); } + +} // namespace sandbox
diff --git a/sandbox/win/tests/common/test_utils.h b/sandbox/win/tests/common/test_utils.h index 049321d..2d63047d 100644 --- a/sandbox/win/tests/common/test_utils.h +++ b/sandbox/win/tests/common/test_utils.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SANDBOX_TESTS_COMMON_TEST_UTILS_H_ -#define SANDBOX_TESTS_COMMON_TEST_UTILS_H_ +#ifndef SANDBOX_WIN_TESTS_COMMON_TEST_UTILS_H_ +#define SANDBOX_WIN_TESTS_COMMON_TEST_UTILS_H_ #include <windows.h> @@ -12,6 +12,8 @@ #include "sandbox/win/src/sid.h" +namespace sandbox { + // Sets a reparse point. |source| will now point to |target|. Returns true if // the call succeeds, false otherwise. bool SetReparsePoint(HANDLE source, const wchar_t* target); @@ -48,5 +50,6 @@ TOKEN_INFORMATION_CLASS information_class, std::vector<char>* information); -#endif // SANDBOX_TESTS_COMMON_TEST_UTILS_H_ +} // namespace sandbox +#endif // SANDBOX_WIN_TESTS_COMMON_TEST_UTILS_H_
diff --git a/sandbox/win/tests/integration_tests/integration_tests_common.h b/sandbox/win/tests/integration_tests/integration_tests_common.h index b18bad1a..4093bfa 100644 --- a/sandbox/win/tests/integration_tests/integration_tests_common.h +++ b/sandbox/win/tests/integration_tests/integration_tests_common.h
@@ -7,6 +7,8 @@ #include <windows.h> +#include "testing/gtest/include/gtest/gtest.h" + namespace sandbox { //------------------------------------------------------------------------------ @@ -32,6 +34,28 @@ // Timeout for ::WaitForSingleObject synchronization. DWORD SboxTestEventTimeout(); +// Ensures that a given set of tests specified by |name| never run at the same +// time, as they deal with machine-global data. +class ScopedTestMutex { +public: + explicit ScopedTestMutex(const wchar_t* name) + : mutex_(::CreateMutexW(nullptr, false, name)) { + EXPECT_TRUE(mutex_); + EXPECT_EQ(WAIT_OBJECT_0, + ::WaitForSingleObject(mutex_, SboxTestEventTimeout())); + } + + ~ScopedTestMutex() { + EXPECT_TRUE(::ReleaseMutex(mutex_)); + EXPECT_TRUE(::CloseHandle(mutex_)); + } + +private: + HANDLE mutex_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTestMutex); +}; + } // namespace sandbox #endif // SANDBOX_TESTS_INTEGRATION_TESTS_COMMON_H_
diff --git a/services/network/network_change_manager.cc b/services/network/network_change_manager.cc index 14ce87b..4b9ab32a 100644 --- a/services/network/network_change_manager.cc +++ b/services/network/network_change_manager.cc
@@ -53,7 +53,10 @@ mojom::ConnectionType new_connection_type, bool connection_subtype_changed, mojom::ConnectionSubtype new_connection_subtype) { - DCHECK(network_change_notifier_); + // network_change_notifier_ can be null in unit tests. + if (!network_change_notifier_) + return; + net::NetworkChangeNotifierPosix* notifier = static_cast<net::NetworkChangeNotifierPosix*>( network_change_notifier_.get());
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index fc98e3f..d3c7ff5 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -9,15 +9,6 @@ namespace network { namespace features { -const char kNetworkServiceFeatureName[] = -#if defined(OS_ANDROID) - "NetworkService"; -#else - // Rename the flag so that shortcuts with the old name don't work. - // This codepath doesn't work anymore on desktop. - "NetworkServiceNotSupported"; -#endif - // Enables Expect CT reporting, which sends reports for opted-in sites // that don't serve sufficient Certificate Transparency information. const base::Feature kExpectCTReporting{"ExpectCTReporting", @@ -26,8 +17,14 @@ const base::Feature kNetworkErrorLogging{"NetworkErrorLogging", base::FEATURE_ENABLED_BY_DEFAULT}; // Enables the network service. -const base::Feature kNetworkService{kNetworkServiceFeatureName, - base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kNetworkService { +#if defined(OS_ANDROID) + "NetworkService", +#else + "NetworkServiceNotSupported", +#endif + base::FEATURE_ENABLED_BY_DEFAULT +}; // Out of Blink CORS const base::Feature kOutOfBlinkCors{"OutOfBlinkCors",
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h index 361a088..1fe733d 100644 --- a/services/network/public/cpp/features.h +++ b/services/network/public/cpp/features.h
@@ -12,9 +12,6 @@ namespace features { COMPONENT_EXPORT(NETWORK_CPP) -extern const char kNetworkServiceFeatureName[]; - -COMPONENT_EXPORT(NETWORK_CPP) extern const base::Feature kExpectCTReporting; COMPONENT_EXPORT(NETWORK_CPP) extern const base::Feature kNetworkErrorLogging;
diff --git a/services/tracing/perfetto/json_trace_exporter.cc b/services/tracing/perfetto/json_trace_exporter.cc index f3504332..a647f64 100644 --- a/services/tracing/perfetto/json_trace_exporter.cc +++ b/services/tracing/perfetto/json_trace_exporter.cc
@@ -584,6 +584,11 @@ out_->AppendF(",\"tts\":%" PRId64, thread_timestamp); } +void JSONTraceExporter::ScopedJSONTraceEventAppender::AddThreadInstructionDelta( + int64_t thread_instruction_delta) { + out_->AppendF(",\"tidelta\":%" PRId64, thread_instruction_delta); +} + void JSONTraceExporter::ScopedJSONTraceEventAppender::AddBindId( uint64_t bind_id) { out_->AppendF(",\"bind_id\":\"0x%" PRIx64 "\"",
diff --git a/services/tracing/perfetto/json_trace_exporter.h b/services/tracing/perfetto/json_trace_exporter.h index f14ca24..a1bbb9ed 100644 --- a/services/tracing/perfetto/json_trace_exporter.h +++ b/services/tracing/perfetto/json_trace_exporter.h
@@ -166,6 +166,7 @@ void AddDuration(int64_t duration); void AddThreadDuration(int64_t thread_duration); void AddThreadTimestamp(int64_t thread_timestamp); + void AddThreadInstructionDelta(int64_t thread_instruction_delta); void AddBindId(uint64_t bind_id); // A set of bit flags for this trace event, along with a |scope|. |scope| is // ignored if empty.
diff --git a/services/tracing/perfetto/track_event_json_exporter.cc b/services/tracing/perfetto/track_event_json_exporter.cc index 5c6be7d..33e6c902 100644 --- a/services/tracing/perfetto/track_event_json_exporter.cc +++ b/services/tracing/perfetto/track_event_json_exporter.cc
@@ -522,6 +522,9 @@ if (event.has_thread_duration_us()) { builder.AddThreadDuration(event.thread_duration_us()); } + if (event.has_thread_instruction_delta()) { + builder.AddThreadInstructionDelta(event.thread_instruction_delta()); + } // For flags and ID we need to determine all possible flag bits and set them // correctly.
diff --git a/services/tracing/public/cpp/perfetto/thread_local_event_sink.h b/services/tracing/public/cpp/perfetto/thread_local_event_sink.h index db85b12c..34c719e 100644 --- a/services/tracing/public/cpp/perfetto/thread_local_event_sink.h +++ b/services/tracing/public/cpp/perfetto/thread_local_event_sink.h
@@ -38,9 +38,11 @@ virtual void AddTraceEvent(base::trace_event::TraceEvent* trace_event, base::trace_event::TraceEventHandle* handle) = 0; - virtual void UpdateDuration(base::trace_event::TraceEventHandle handle, - const base::TimeTicks& now, - const base::ThreadTicks& thread_now) = 0; + virtual void UpdateDuration( + base::trace_event::TraceEventHandle handle, + const base::TimeTicks& now, + const base::ThreadTicks& thread_now, + base::trace_event::ThreadInstructionCount thread_instruction_now) = 0; virtual void Flush() = 0;
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc index 56c4fd4..1d34808 100644 --- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc +++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -493,7 +493,8 @@ void TraceEventDataSource::OnUpdateDuration( base::trace_event::TraceEventHandle handle, const base::TimeTicks& now, - const base::ThreadTicks& thread_now) { + const base::ThreadTicks& thread_now, + base::trace_event::ThreadInstructionCount thread_instruction_now) { if (GetThreadIsInTraceEventTLS()->Get()) { return; } @@ -503,7 +504,8 @@ auto* thread_local_event_sink = static_cast<ThreadLocalEventSink*>(ThreadLocalEventSinkSlot()->Get()); if (thread_local_event_sink) { - thread_local_event_sink->UpdateDuration(handle, now, thread_now); + thread_local_event_sink->UpdateDuration(handle, now, thread_now, + thread_instruction_now); } }
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.h b/services/tracing/public/cpp/perfetto/trace_event_data_source.h index de921efc..9d6ab70 100644 --- a/services/tracing/public/cpp/perfetto/trace_event_data_source.h +++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
@@ -147,9 +147,11 @@ static void OnAddTraceEvent(base::trace_event::TraceEvent* trace_event, bool thread_will_flush, base::trace_event::TraceEventHandle* handle); - static void OnUpdateDuration(base::trace_event::TraceEventHandle handle, - const base::TimeTicks& now, - const base::ThreadTicks& thread_now); + static void OnUpdateDuration( + base::trace_event::TraceEventHandle handle, + const base::TimeTicks& now, + const base::ThreadTicks& thread_now, + base::trace_event::ThreadInstructionCount thread_instruction_now); // Extracts UMA histogram names that should be logged in traces and logs their // starting values.
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc index 2efd501..4aab130a 100644 --- a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc +++ b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -17,6 +17,7 @@ #include "base/run_loop.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_id_name_manager.h" +#include "base/trace_event/thread_instruction_count.h" #include "base/trace_event/trace_event.h" #include "components/tracing/common/tracing_switches.h" #include "services/tracing/public/mojom/perfetto_service.mojom.h" @@ -854,7 +855,8 @@ base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDurationExplicit( category_group_enabled, kEventName, handle, base::TimeTicks() + base::TimeDelta::FromMicroseconds(30), - base::ThreadTicks() + base::TimeDelta::FromMicroseconds(50)); + base::ThreadTicks() + base::TimeDelta::FromMicroseconds(50), + base::trace_event::ThreadInstructionCount()); // The call to UpdateTraceEventDurationExplicit should have successfully // updated the duration of the event which was added in the @@ -875,7 +877,8 @@ base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDurationExplicit( category_group_enabled, kEventName, handle, base::TimeTicks() + base::TimeDelta::FromMicroseconds(30), - base::ThreadTicks() + base::TimeDelta::FromMicroseconds(50)); + base::ThreadTicks() + base::TimeDelta::FromMicroseconds(50), + base::trace_event::ThreadInstructionCount()); // No further packets should have been emitted. EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 2u);
diff --git a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc index 7f8ac8e..0516209 100644 --- a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc +++ b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.cc
@@ -344,6 +344,13 @@ legacy_event->set_thread_duration_us(thread_duration); } } + + // TODO(acomminos): Add thread instruction count for BEGIN/END events + if (!trace_event->thread_instruction_count().is_null()) { + int64_t instruction_delta = + trace_event->thread_instruction_delta().ToInternalValue(); + legacy_event->set_thread_instruction_delta(instruction_delta); + } } else if (phase == TRACE_EVENT_PHASE_INSTANT) { switch (flags & TRACE_EVENT_FLAG_SCOPE_MASK) { case TRACE_EVENT_SCOPE_GLOBAL: @@ -473,7 +480,8 @@ void TrackEventThreadLocalEventSink::UpdateDuration( base::trace_event::TraceEventHandle handle, const base::TimeTicks& now, - const base::ThreadTicks& thread_now) { + const base::ThreadTicks& thread_now, + base::trace_event::ThreadInstructionCount thread_instruction_now) { if (!handle.event_index || handle.chunk_index != kMagicChunkIndex || handle.chunk_seq != session_id_) { return; @@ -494,7 +502,8 @@ } current_stack_depth_--; - complete_event_stack_[current_stack_depth_].UpdateDuration(now, thread_now); + complete_event_stack_[current_stack_depth_].UpdateDuration( + now, thread_now, thread_instruction_now); AddTraceEvent(&complete_event_stack_[current_stack_depth_], nullptr); #if defined(OS_ANDROID)
diff --git a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h index 5519857..10ff6f8 100644 --- a/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h +++ b/services/tracing/public/cpp/perfetto/track_event_thread_local_event_sink.h
@@ -46,7 +46,9 @@ base::trace_event::TraceEventHandle* handle) override; void UpdateDuration(base::trace_event::TraceEventHandle handle, const base::TimeTicks& now, - const base::ThreadTicks& thread_now) override; + const base::ThreadTicks& thread_now, + base::trace_event::ThreadInstructionCount + thread_instruction_now) override; void Flush() override; // ThreadIdNameManager::Observer implementation:
diff --git a/services/tracing/public/cpp/tracing_features.cc b/services/tracing/public/cpp/tracing_features.cc index 9a20fc7..50562f9 100644 --- a/services/tracing/public/cpp/tracing_features.cc +++ b/services/tracing/public/cpp/tracing_features.cc
@@ -26,7 +26,7 @@ // Causes Perfetto to run in-process mode for in-process tracing producers. const base::Feature kPerfettoForceOutOfProcessProducer{ - "PerfettoForceOutOfProcessProducer", base::FEATURE_ENABLED_BY_DEFAULT}; + "PerfettoForceOutOfProcessProducer", base::FEATURE_DISABLED_BY_DEFAULT}; // Runs the tracing service as an in-process browser service. const base::Feature kTracingServiceInProcess {
diff --git a/styleguide/c++/c++-dos-and-donts.md b/styleguide/c++/c++-dos-and-donts.md index 2e342677..d88800a 100644 --- a/styleguide/c++/c++-dos-and-donts.md +++ b/styleguide/c++/c++-dos-and-donts.md
@@ -81,7 +81,7 @@ }; class Vexing { public: - explicit Vexing(const std::string& s) { ... }; + explicit Vexing(const std::string& s) { ... }; ... }; void func() { @@ -97,6 +97,34 @@ auto x{1}; // Until C++17, decltype(x) is std::initializer_list<int>, not int! ``` +## Initialize members in the declaration where possible + +If possible, initialize class members in their declarations, except where a +member's value is explicitly set by every constructor. + +This reduces the chance of uninitialized variables, documents default values in +the declaration, and increases the number of constructors that can use +`=default` (see below). + +```cpp +class C { + public: + C() : a_(2) {} + C(int b) : a_(1), b_(b) {} + + private: + int a_; // Not necessary to init this since all constructors set it. + int b_ = 0; // Not all constructors set this. + std::string c_; // No initializer needed due to string's default constructor. + base::WeakPtrFactory<C> factory_{this}; + // {} allows calling of explicit constructors. +}; +``` + +Note that it's possible to call functions or pass `this` and other expressions +in initializers, so even some complex initializations can be done in the +declaration. + ## Prefer structs over pairs/tuples when used repeatedly The Google style guide
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index daf4aa3..b8da67667 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -16064,7 +16064,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16092,7 +16092,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16121,7 +16121,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16147,7 +16147,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16172,7 +16172,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16197,7 +16197,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16219,7 +16219,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16245,7 +16245,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16267,7 +16267,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16303,7 +16303,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16336,7 +16336,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16369,7 +16369,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16402,7 +16402,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16442,7 +16442,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16490,7 +16490,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16524,7 +16524,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16557,7 +16557,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16593,7 +16593,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821", @@ -16628,7 +16628,7 @@ "dimension_sets": [ { "gpu": "8086:0a2e", - "os": "Mac-10.12.6" + "os": "Mac-10.13.6" }, { "gpu": "1002:6821",
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index df04fda..2e154ede 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -1278,9 +1278,6 @@ "type": "raw", }, "ios_chrome_translate_egtests": { - "args": [ - "--enable-features=CompactTranslateInfobarIOS", - ], "label": "//ios/chrome/test/earl_grey:ios_chrome_translate_egtests", "type": "raw", },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 076112d3..92fbc1e7 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -2847,7 +2847,7 @@ # TODO(kbr): figure out how to use mixins for these. { 'gpu': '8086:0a2e', - 'os': 'Mac-10.12.6', + 'os': 'Mac-10.13.6', }, { 'gpu': '1002:6821',
diff --git a/testing/libfuzzer/libprotobuf-mutator.md b/testing/libfuzzer/libprotobuf-mutator.md index 982bf37..51d0a033 100644 --- a/testing/libfuzzer/libprotobuf-mutator.md +++ b/testing/libfuzzer/libprotobuf-mutator.md
@@ -60,7 +60,7 @@ // Assuming the .proto file is path/to/your/proto_file/my_proto.proto. #include "path/to/your/proto_file/my_proto.pb.h" -DEFINE_BINARY_PROTO_FUZZER( +DEFINE_PROTO_FUZZER( const my_proto::MyProtoMessage& my_proto_message) { targeted_function(my_proto_message); } @@ -79,7 +79,7 @@ sources = [ "my_fuzzer.cc" ] deps = [ // The proto library defining the message accepted by - // DEFINE_BINARY_PROTO_FUZZER(). + // DEFINE_PROTO_FUZZER(). ":my_proto", "//third_party/libprotobuf-mutator", @@ -140,7 +140,7 @@ the definition of the Url message. ### Write the Fuzz Target and Conversion Code -Create a new .cc and write a `DEFINE_BINARY_PROTO_FUZZER` function: +Create a new .cc and write a `DEFINE_PROTO_FUZZER` function: ```c++ // Needed since we use getenv(). @@ -158,7 +158,7 @@ // your fuzzing code (or just pass "my_format", if your target accepts // protobufs). -DEFINE_BINARY_PROTO_FUZZER(const my_fuzzer::MyFormat& my_proto_format) { +DEFINE_PROTO_FUZZER(const my_fuzzer::MyFormat& my_proto_format) { // Convert your protobuf to whatever format your targeted code accepts // if it doesn't accept protobufs. std::string native_input = convert_to_native_input(my_proto_format); @@ -299,7 +299,7 @@ // Assuming the .proto file is path/to/your/proto_file/my_fuzzer_input.proto. #include "path/to/your/proto_file/my_proto.pb.h" -DEFINE_BINARY_PROTO_FUZZER( +DEFINE_PROTO_FUZZER( const my_proto::FuzzerInput& fuzzer_input) { if (fuzzer_input.has_arg3()) targeted_function_1(fuzzer_input.arg1(), fuzzer_input.arg2(), fuzzer_input.arg3()); @@ -348,17 +348,21 @@ partially defined by an existing proto definition (if you are writing a grammar fuzzer). -* `DEFINE_TEXT_PROTO_FUZZER` can be used instead of `DEFINE_BINARY_PROTO_FUZZER` -to have a corpus that is human readable and modifiable (ie: not in protobuf's -binary format). However, `DEFINE_TEXT_PROTO_FUZZER` does come with a -performance penalty, so it may be better to only use it during development. - +* `DEFINE_BINARY_PROTO_FUZZER` can be used instead of `DEFINE_PROTO_FUZZER` (or + `DEFINE_TEXT_PROTO_FUZZER`) to use protobuf's binary format for the corpus. + This will make it hard/impossible to modify the corpus manually (i.e. when not + fuzzing). However, protobuf's text format (and by extension + `DEFINE_PROTO_FUZZER`) is believed by some to come with a performance penalty + compared to the binary format. We've never seen a case where this penalty + was important, but if profiling reveals that protobuf deserialization is the + bottleneck in your fuzzer, you may want to consider using the binary format. + This will probably not be the case. [libfuzzer in Chromium]: getting_started.md [Protocol Buffers]: https://developers.google.com/protocol-buffers/docs/cpptutorial [fuzzing@chromium.org]: mailto:fuzzing@chromium.org [this]: https://github.com/google/libprotobuf-mutator/tree/master/examples/libfuzzer/libfuzzer_example.cc -[existing proto fuzzers]: https://cs.chromium.org/search/?q=DEFINE_(BINARY_%7CTEXT_)?PROTO_FUZZER+-file:src/third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h&sq=package:chromium&type=cs +[existing proto fuzzers]: https://cs.chromium.org/search/?q=DEFINE_(BINARY_%7CTEXT_)?PROTO_FUZZER+-file:src/third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h+lang:cpp&sq=package:chromium&type=cs [here]: https://github.com/google/libprotobuf-mutator/blob/master/README.md#utf-8-strings [override_lite_runtime_plugin_test_fuzzer]: https://cs.chromium.org/#search&q=override_lite_runtime_plugin_test_fuzzer+file:%5Esrc/third_party/libprotobuf-mutator/BUILD.gn [mojo_parse_messages_proto_fuzzer]: https://cs.chromium.org/chromium/src/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc?l=25
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 7b45c1d..09c91f8 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -66,6 +66,10 @@ const base::Feature kBlinkGenPropertyTrees{"BlinkGenPropertyTrees", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enable a new CSS property called backdrop-filter. +const base::Feature kCSSBackdropFilter{"CSSBackdropFilter", + base::FEATURE_ENABLED_BY_DEFAULT}; + // Enable Display Locking JavaScript APIs. const base::Feature kDisplayLocking{"DisplayLocking", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index dd21498..0f64ee7 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -27,6 +27,7 @@ BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller; BLINK_COMMON_EXPORT extern const base::Feature kJankTrackingSweepLine; BLINK_COMMON_EXPORT extern const base::Feature kBlinkGenPropertyTrees; +BLINK_COMMON_EXPORT extern const base::Feature kCSSBackdropFilter; BLINK_COMMON_EXPORT extern const base::Feature kDisplayLocking; BLINK_COMMON_EXPORT extern const base::Feature kFastBorderRadius; BLINK_COMMON_EXPORT extern const base::Feature kLayoutNG;
diff --git a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc index 4b6c4e9..2274c0d 100644 --- a/third_party/blink/renderer/core/dom/events/event_dispatcher.cc +++ b/third_party/blink/renderer/core/dom/events/event_dispatcher.cc
@@ -36,6 +36,7 @@ #include "third_party/blink/renderer/core/dom/events/event_path.h" #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h" #include "third_party/blink/renderer/core/dom/events/window_event_context.h" +#include "third_party/blink/renderer/core/events/keyboard_event.h" #include "third_party/blink/renderer/core/events/mouse_event.h" #include "third_party/blink/renderer/core/frame/ad_tracker.h" #include "third_party/blink/renderer/core/frame/deprecation.h" @@ -44,6 +45,8 @@ #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h" +#include "third_party/blink/renderer/core/page/page.h" +#include "third_party/blink/renderer/core/page/spatial_navigation_controller.h" #include "third_party/blink/renderer/core/timing/event_timing.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" @@ -365,6 +368,15 @@ } } + if (Page* page = node_->GetDocument().GetPage()) { + if (page->GetSettings().GetSpatialNavigationEnabled() && + is_trusted_or_click && event_->IsKeyboardEvent() && + ToKeyboardEvent(*event_).key() == "Enter" && + event_->type() == event_type_names::kKeyup) { + page->GetSpatialNavigationController().ResetEnterKeyState(); + } + } + // Track the usage of sending a mousedown event to a select element to force // it to open. This measures a possible breakage of not allowing untrusted // events to open select boxes.
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc index 57005359..cd6943b8 100644 --- a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc +++ b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
@@ -548,6 +548,22 @@ return InsertTextAndMoveCaret(text, relative_caret_position, ime_text_spans); } +bool InputMethodController::ReplaceText(const String& text, + PlainTextRange range) { + EventQueueScope scope; + const PlainTextRange old_selection(GetSelectionOffsets()); + if (!SetSelectionOffsets(range)) + return false; + if (!InsertText(text)) + return false; + wtf_size_t selection_delta = text.length() - range.length(); + wtf_size_t start = old_selection.Start(); + wtf_size_t end = old_selection.End(); + return SetSelectionOffsets( + {start >= range.End() ? start + selection_delta : start, + end >= range.End() ? end + selection_delta : end}); +} + bool InputMethodController::ReplaceComposition(const String& text) { // Verify that the caller is using an EventQueueScope to suppress the input // event from being fired until the proper time (e.g. after applying an IME
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller.h b/third_party/blink/renderer/core/editing/ime/input_method_controller.h index 6bb7ad03..37cde8df 100644 --- a/third_party/blink/renderer/core/editing/ime/input_method_controller.h +++ b/third_party/blink/renderer/core/editing/ime/input_method_controller.h
@@ -78,6 +78,9 @@ const Vector<ImeTextSpan>& ime_text_spans, int relative_caret_position); + // Replaces the text in the specified range without changing the selection. + bool ReplaceText(const String&, PlainTextRange); + // Inserts ongoing composing text; changes the selection to the end of // the inserting text if DoNotKeepSelection, or holds the selection if // KeepSelection.
diff --git a/third_party/blink/renderer/core/editing/layout_selection.cc b/third_party/blink/renderer/core/editing/layout_selection.cc index 1eef465..ea77044e 100644 --- a/third_party/blink/renderer/core/editing/layout_selection.cc +++ b/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -762,13 +762,6 @@ if (!layout_object || !layout_object->CanBeSelectionLeaf()) continue; - if (UNLIKELY(layout_object->NeedsLayout())) { - // TODO(crbug.com/973226): This is a workaround for missing layout on - // |node|. We should eliminate such missing layout eventually. - NOTREACHED() << node; - continue; - } - if (!start_node) { DCHECK(!end_node); start_node = end_node = &node;
diff --git a/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc b/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc index f502778..f70eb17 100644 --- a/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc +++ b/third_party/blink/renderer/core/exported/web_input_method_controller_impl.cc
@@ -122,17 +122,16 @@ relative_caret_position); } - // Select the range to be replaced with the composition later. - if (!replacement_range.IsNull()) { - web_frame_->SelectRange(replacement_range, - WebLocalFrame::kHideSelectionHandle, - blink::mojom::SelectionMenuBehavior::kHide); - } - // TODO(editing-dev): The use of UpdateStyleAndLayout // needs to be audited. See http://crbug.com/590369 for more details. GetFrame()->GetDocument()->UpdateStyleAndLayout(); + if (!replacement_range.IsNull()) { + return GetInputMethodController().ReplaceText( + text, PlainTextRange(replacement_range.StartOffset(), + replacement_range.EndOffset())); + } + return GetInputMethodController().CommitText( text, ImeTextSpanVectorBuilder::Build(ime_text_spans), relative_caret_position);
diff --git a/third_party/blink/renderer/core/html/forms/radio_input_type.cc b/third_party/blink/renderer/core/html/forms/radio_input_type.cc index 730db85..f4f691d 100644 --- a/third_party/blink/renderer/core/html/forms/radio_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/radio_input_type.cc
@@ -151,8 +151,6 @@ event.key() == "Enter")) { DispatchSimulatedClickIfActive(event); } - - DispatchSimulatedClickIfActive(event); } bool RadioInputType::IsKeyboardFocusable() const {
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc index a3f5f49..b6b0f3e 100644 --- a/third_party/blink/renderer/core/html/html_element.cc +++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -1332,6 +1332,8 @@ void HTMLElement::HandleKeypressEvent(KeyboardEvent& event) { if (!IsSpatialNavigationEnabled(GetDocument().GetFrame()) || !SupportsFocus()) return; + if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) + return; GetDocument().UpdateStyleAndLayoutTree(); // if the element is a text form control (like <input type=text> or // <textarea>) or has contentEditable attribute on, we should enter a space or
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css index 07956cd..d4c2d23 100644 --- a/third_party/blink/renderer/core/html/resources/html.css +++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -530,6 +530,11 @@ overflow: hidden; } +input::-internal-input-suggested, +textarea::-internal-input-suggested { + font-family: system-ui !important; +} + input[type="password" i] { -webkit-text-security: disc !important; } @@ -561,7 +566,6 @@ input:-internal-autofill-previewed, textarea:-internal-autofill-previewed, select:-internal-autofill-previewed { - font-family: system-ui !important; background-color: #E8F0FE !important; background-image:none !important; color: #000000 !important;
diff --git a/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/third_party/blink/renderer/core/input/keyboard_event_manager.cc index 06c313c3..100e7a4d 100644 --- a/third_party/blink/renderer/core/input/keyboard_event_manager.cc +++ b/third_party/blink/renderer/core/input/keyboard_event_manager.cc
@@ -352,16 +352,19 @@ frame_->GetEditor().HandleKeyboardEvent(event); if (event->DefaultHandled()) return; - if (event->charCode() == ' ') - DefaultSpaceEventHandler(event, possible_focused_node); - } else if (event->type() == event_type_names::kKeyup) { if (event->key() == "Enter") { DefaultEnterEventHandler(event); - return; + } else if (event->charCode() == ' ') { + DefaultSpaceEventHandler(event, possible_focused_node); } - - if (event->keyCode() == kVKeySpatNavBack) + } else if (event->type() == event_type_names::kKeyup) { + if (event->DefaultHandled()) + return; + if (event->key() == "Enter") { + DefaultEnterEventHandler(event); + } else if (event->keyCode() == kVKeySpatNavBack) { DefaultSpatNavBackEventHandler(event); + } } }
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc index c3b0e50f..d6549af 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
@@ -13,12 +13,6 @@ TextFragmentAnchorMetrics::TextFragmentAnchorMetrics(Document* document) : document_(document) {} -TextFragmentAnchorMetrics::~TextFragmentAnchorMetrics() { -#ifndef NDEBUG - DCHECK(metrics_reported_); -#endif -} - void TextFragmentAnchorMetrics::DidCreateAnchor(int selector_count) { UseCounter::Count(document_, WebFeature::kTextFragmentAnchor); create_time_ = WTF::CurrentTimeTicks();
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h index 5f9c049..baebecf 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
@@ -17,7 +17,6 @@ : public GarbageCollectedFinalized<TextFragmentAnchorMetrics> { public: TextFragmentAnchorMetrics(Document* document); - ~TextFragmentAnchorMetrics(); void DidCreateAnchor(int selector_count);
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc index 5c4f5ee..f00e13e 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc +++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -163,10 +163,18 @@ return false; if (event->type() == event_type_names::kKeydown) { + enter_key_down_seen_ = true; interest_element->SetActive(true); + } else if (event->type() == event_type_names::kKeypress) { + enter_key_press_seen_ = true; } else if (event->type() == event_type_names::kKeyup) { interest_element->SetActive(false); - if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) { + + // Ensure that the enter key has not already been handled by something else, + // or we can end up clicking elements multiple times. Some elements already + // convert the Enter key into click on down and press (and up) events. + if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled() && + enter_key_down_seen_ && enter_key_press_seen_) { interest_element->focus(FocusParams(SelectionBehaviorOnFocus::kReset, kWebFocusTypeSpatialNavigation, nullptr)); @@ -179,6 +187,11 @@ return true; } +void SpatialNavigationController::ResetEnterKeyState() { + enter_key_down_seen_ = false; + enter_key_press_seen_ = false; +} + bool SpatialNavigationController::HandleImeSubmitKeyboardEvent( KeyboardEvent* event) { DCHECK(page_->GetSettings().GetSpatialNavigationEnabled());
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.h b/third_party/blink/renderer/core/page/spatial_navigation_controller.h index d1ac834..e748a5e5 100644 --- a/third_party/blink/renderer/core/page/spatial_navigation_controller.h +++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.h
@@ -32,6 +32,10 @@ bool HandleEscapeKeyboardEvent(KeyboardEvent* event); bool HandleImeSubmitKeyboardEvent(KeyboardEvent* event); + // Called when the enter key is released to clear local state because we don't + // get a consistent event stream when the Enter key is partially handled. + void ResetEnterKeyState(); + // Returns the element that's currently interested. i.e. the Element that's // currently indicated to the user. Element* GetInterestedElement() const; @@ -107,6 +111,11 @@ WeakMember<Element> interest_element_; Member<Page> page_; + // We need to track whether the enter key has been handled in down or press to + // know whether to generate a click on the up. + bool enter_key_down_seen_ = false; + bool enter_key_press_seen_ = false; + mojom::blink::SpatialNavigationStatePtr spatial_navigation_state_; mojom::blink::SpatialNavigationHostPtr spatial_navigation_host_; };
diff --git a/third_party/blink/renderer/devtools/front_end/network/BlockedURLsPane.js b/third_party/blink/renderer/devtools/front_end/network/BlockedURLsPane.js index 21e81fb..3991d919 100644 --- a/third_party/blink/renderer/devtools/front_end/network/BlockedURLsPane.js +++ b/third_party/blink/renderer/devtools/front_end/network/BlockedURLsPane.js
@@ -50,11 +50,9 @@ */ _createEmptyPlaceholder() { const element = this.contentElement.createChild('div', 'no-blocked-urls'); - element.createChild('span').textContent = Common.UIString('Requests are not blocked. '); - const addLink = element.createChild('span', 'link'); - addLink.textContent = Common.UIString('Add pattern.'); - addLink.href = ''; + const addLink = UI.XLink.create('', ls`Add pattern`); addLink.addEventListener('click', this._addButtonClicked.bind(this), false); + element.appendChild(UI.formatLocalized('Requests are not blocked. %s.', [addLink])); return element; }
diff --git a/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp b/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp index 5b75ce6..754e400 100644 --- a/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp +++ b/third_party/blink/renderer/devtools/front_end/network/network_strings.grdp
@@ -84,6 +84,9 @@ <message name="IDS_DEVTOOLS_2537b3e6907e17001b7cdf121cd39dc0" desc=""> (from ServiceWorker) </message> + <message name="IDS_DEVTOOLS_25f77a709e3c31285e8411402420b72d" desc=""> + Requests are not blocked. <ph name="ADDLINK">$1s</ph>. + </message> <message name="IDS_DEVTOOLS_26b6b5ae2c6e2575b2a451c35e94df23" desc=""> Waiting (TTFB) </message> @@ -108,9 +111,6 @@ <message name="IDS_DEVTOOLS_30ad3ea5e350075c1c0a1171c5006ed7" desc=""> Fetching frames... </message> - <message name="IDS_DEVTOOLS_3136ed000d43bebb4ca53a9312fbd32c" desc=""> - Add pattern. - </message> <message name="IDS_DEVTOOLS_31977081ea2c828cc70e6151ab5d7da8" desc=""> view decoded </message> @@ -576,9 +576,6 @@ <message name="IDS_DEVTOOLS_c2cc7082a89c1ad6631a2f66af5f00c0" desc=""> Connection </message> - <message name="IDS_DEVTOOLS_c33fa8b7d663932b656f0f7f53a74e77" desc=""> - Requests are not blocked. ''' - </message> <message name="IDS_DEVTOOLS_c3c14eb17a6cf9c6120f381790ed06eb" desc=""> Copy all as PowerShell </message>
diff --git a/third_party/blink/renderer/devtools/front_end/node_main/NodeConnectionsPanel.js b/third_party/blink/renderer/devtools/front_end/node_main/NodeConnectionsPanel.js index c4d4274..ff9ed37 100644 --- a/third_party/blink/renderer/devtools/front_end/node_main/NodeConnectionsPanel.js +++ b/third_party/blink/renderer/devtools/front_end/node_main/NodeConnectionsPanel.js
@@ -55,11 +55,10 @@ this.element.classList.add('network-discovery-view'); const networkDiscoveryFooter = this.element.createChild('div', 'network-discovery-footer'); - networkDiscoveryFooter.createChild('span').textContent = - Common.UIString('Specify network endpoint and DevTools will connect to it automatically. '); - const link = networkDiscoveryFooter.createChild('span', 'link'); - link.textContent = Common.UIString('Learn more'); - link.addEventListener('click', () => InspectorFrontendHost.openInNewTab('https://nodejs.org/en/docs/inspector/')); + const documentationLink = UI.XLink.create('https://nodejs.org/en/docs/inspector/', ls`Node.js debugging guide`); + networkDiscoveryFooter.appendChild(UI.formatLocalized( + 'Specify network endpoint and DevTools will connect to it automatically. Read %s to learn more.', + [documentationLink])); /** @type {!UI.ListWidget<!Adb.PortForwardingRule>} */ this._list = new UI.ListWidget(this);
diff --git a/third_party/blink/renderer/devtools/front_end/node_main/node_main_strings.grdp b/third_party/blink/renderer/devtools/front_end/node_main/node_main_strings.grdp index 44081351..1241b38 100644 --- a/third_party/blink/renderer/devtools/front_end/node_main/node_main_strings.grdp +++ b/third_party/blink/renderer/devtools/front_end/node_main/node_main_strings.grdp
@@ -6,13 +6,16 @@ <message name="IDS_DEVTOOLS_3fd49f986cbd5dd3148c27c9aaaaa700" desc=""> Network address (e.g. localhost:9229) </message> + <message name="IDS_DEVTOOLS_43d755260901476a60e28982f36b2913" desc=""> + Node.js debugging guide + </message> <message name="IDS_DEVTOOLS_75997049f01ae448c39b8a937c4e2035" desc=""> No connections specified </message> - <message name="IDS_DEVTOOLS_81c731365b52528d7d0fdb477ebc3b1d" desc=""> - Specify network endpoint and DevTools will connect to it automatically. ''' - </message> <message name="IDS_DEVTOOLS_b1f0f05f6f7dcbf25e065bb4c31fec72" desc=""> Node.js: <ph name="TARGETINFO_URL">$1s</ph> </message> + <message name="IDS_DEVTOOLS_ed6b1cccfa7455e9506ff7e5127e1df4" desc=""> + Specify network endpoint and DevTools will connect to it automatically. Read <ph name="DOCUMENTATIONLINK">$1s</ph> to learn more. + </message> </grit-part> \ No newline at end of file
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js index bbfb68d..dcfb44c6 100644 --- a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js +++ b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
@@ -286,9 +286,7 @@ if (wasThrown) { const wrapperElement = createElementWithClass('span', 'error value'); - wrapperElement.createTextChild('[' + Common.UIString('Exception') + ': '); - wrapperElement.appendChild(valueElement); - wrapperElement.createTextChild(']'); + wrapperElement.appendChild(UI.formatLocalized('[Exception: %s]', [valueElement])); return wrapperElement; } valueElement.classList.add('value');
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/object_ui_strings.grdp b/third_party/blink/renderer/devtools/front_end/object_ui/object_ui_strings.grdp index 46d6fa38..83a8248 100644 --- a/third_party/blink/renderer/devtools/front_end/object_ui/object_ui_strings.grdp +++ b/third_party/blink/renderer/devtools/front_end/object_ui/object_ui_strings.grdp
@@ -39,13 +39,13 @@ <message name="IDS_DEVTOOLS_ad921d60486366258809553a3db49a4a" desc=""> unknown </message> - <message name="IDS_DEVTOOLS_b0d4998a26f5b5742ad38c4af8817e32" desc=""> - Exception - </message> <message name="IDS_DEVTOOLS_b46f6ce1cece499f73c9d5c36e4a3de4" desc=""> Invoke property getter </message> <message name="IDS_DEVTOOLS_d50bbea3c85be098dcf221e622cd7718" desc=""> Lexical scope variables </message> + <message name="IDS_DEVTOOLS_ecaa3f03d3f2556acc42a409ae0e00d4" desc=""> + [Exception: <ph name="VALUEELEMENT">$1s</ph>] + </message> </grit-part> \ No newline at end of file
diff --git a/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp b/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp index ca62f1c0..107c2522 100644 --- a/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp +++ b/third_party/blink/renderer/devtools/front_end/sources/sources_strings.grdp
@@ -342,6 +342,9 @@ <message name="IDS_DEVTOOLS_ae76c8d643589ff25d35455a80f12061" desc=""> Do not display variable values inline while debugging </message> + <message name="IDS_DEVTOOLS_b0d4998a26f5b5742ad38c4af8817e32" desc=""> + Exception + </message> <message name="IDS_DEVTOOLS_b16d05636bde9fe84392fd4af198e9c1" desc=""> Quick source </message>
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 6f5b6c4..b330dec2 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -516,7 +516,7 @@ }, { name: "EnterKeyHintAttribute", - status: "experimental", + status: "stable", }, { name: "EventTiming",
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index 618e42a63..a4415607 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -209,7 +209,6 @@ base::test::ScopedFeatureList& scoped_feature_list() { return feature_list_; } - std::unique_ptr<base::FieldTrialList> field_trial_list_; base::test::ScopedFeatureList feature_list_; base::test::ScopedTaskEnvironment task_environment_; std::unique_ptr<MainThreadSchedulerImpl> scheduler_; @@ -1539,7 +1538,6 @@ const char kStudyName[] = "ResourceFetchPriorityExperiment"; const char kGroupName[] = "GroupName1"; - field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); base::AssociateFieldTrialParams(kStudyName, kGroupName, params); base::FieldTrialList::CreateFieldTrial(kStudyName, kGroupName); } @@ -1574,7 +1572,6 @@ const char kStudyName[] = "ResourceFetchPriorityExperiment"; const char kGroupName[] = "GroupName2"; - field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); base::AssociateFieldTrialParams(kStudyName, kGroupName, params); base::FieldTrialList::CreateFieldTrial(kStudyName, kGroupName); } @@ -1748,21 +1745,8 @@ public: ThrottleAndFreezeTaskTypesExperimentTest(const base::FieldTrialParams& params, const char* group_name) { - const char kStudyName[] = "ThrottleAndFreezeTaskTypes"; - - field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr); - - scoped_refptr<base::FieldTrial> trial = - base::FieldTrialList::CreateFieldTrial(kStudyName, group_name); - - base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams( - kStudyName, group_name, params); - - std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - feature_list->RegisterFieldTrialOverride( - kThrottleAndFreezeTaskTypes.name, - base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get()); - scoped_feature_list().InitWithFeatureList(std::move(feature_list)); + scoped_feature_list().InitAndEnableFeatureWithParameters( + kThrottleAndFreezeTaskTypes, params); } };
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc index 3b4e8159..39b78fba 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
@@ -1095,8 +1095,6 @@ ScopedExpensiveBackgroundTimerThrottlingForTest budget_background_throttling_enabler(true); - std::unique_ptr<base::FieldTrialList> field_trial_list = - std::make_unique<base::FieldTrialList>(nullptr); InitializeTrialParams(); page_scheduler_.reset(new PageSchedulerImpl(nullptr, scheduler_.get())); EXPECT_FALSE(page_scheduler_->IsThrottled()); @@ -1160,8 +1158,6 @@ ScopedExpensiveBackgroundTimerThrottlingForTest budget_background_throttling_enabler(true); - std::unique_ptr<base::FieldTrialList> field_trial_list = - std::make_unique<base::FieldTrialList>(nullptr); InitializeTrialParams(); std::unique_ptr<PageSchedulerImpl> page_scheduler( new PageSchedulerImpl(nullptr, scheduler_.get()));
diff --git a/third_party/blink/web_tests/W3CImportExpectations b/third_party/blink/web_tests/W3CImportExpectations index 3f35cc1..629060b 100644 --- a/third_party/blink/web_tests/W3CImportExpectations +++ b/third_party/blink/web_tests/W3CImportExpectations
@@ -466,11 +466,11 @@ external/wpt/client-hints/accept_ch.https.html [ Skip ] # TODO(crbug.com/974254): Remove the following once we can handle spaces in test names. -external/wpt/webdriver/tests/element_click/interactability.py -external/wpt/webdriver/tests/find_element/find.py -external/wpt/webdriver/tests/find_element_from_element/find.py -external/wpt/webdriver/tests/find_elements/find.py -external/wpt/webdriver/tests/find_elements_from_element/find.py -external/wpt/webdriver/tests/new_session/invalid_capabilities.py -external/wpt/webdriver/tests/new_session/response.py -external/wpt/webdriver/tests/send_alert_text/send.py +external/wpt/webdriver/tests/element_click/interactability.py [ Skip ] +external/wpt/webdriver/tests/find_element/find.py [ Skip ] +external/wpt/webdriver/tests/find_element_from_element/find.py [ Skip ] +external/wpt/webdriver/tests/find_elements/find.py [ Skip ] +external/wpt/webdriver/tests/find_elements_from_element/find.py [ Skip ] +external/wpt/webdriver/tests/new_session/invalid_capabilities.py [ Skip ] +external/wpt/webdriver/tests/new_session/response.py [ Skip ] +external/wpt/webdriver/tests/send_alert_text/send.py [ Skip ]
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-expected.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-expected.html deleted file mode 100644 index 18a14ac5..0000000 --- a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-expected.html +++ /dev/null
@@ -1,6 +0,0 @@ -<input id="input" value="hello" style="width: 99px" > -<script> -input.focus(); -input.setSelectionRange(0,0); -internals.setAutofilled(input, true); -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.html deleted file mode 100644 index 0fb8fc3..0000000 --- a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.html +++ /dev/null
@@ -1 +0,0 @@ -<input id="input" value="Springfield"> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.html deleted file mode 100644 index 0fb8fc3..0000000 --- a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.html +++ /dev/null
@@ -1 +0,0 @@ -<input id="input" value="Springfield"> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.html deleted file mode 100644 index 2a9bfb0..0000000 --- a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.html +++ /dev/null
@@ -1,6 +0,0 @@ -<input id="input" maxlength="5" value="Miste"> -<script> -input.focus(); -input.setSelectionRange(0,0); -internals.setAutofilled(input, true); -</script>
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.html deleted file mode 100644 index 6bfd2ec0..0000000 --- a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.html +++ /dev/null
@@ -1,8 +0,0 @@ -<!DOCTYPE html> -<script src="../../../resources/ahem.js"></script> -<input id="input" value="Guy WithAVeryLongLastNameThatCouldWrap" style="width: 99px; font: 20px Ahem" > -<script> -input.focus(); -input.setSelectionRange(0,0); -internals.setAutofilled(input, true); -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.html deleted file mode 100644 index 8d30029..0000000 --- a/third_party/blink/web_tests/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.html +++ /dev/null
@@ -1,4 +0,0 @@ -<input id="input" value="hello" style="width: 99px"> -<script> -internals.setAutofilled(input, true); -</script>
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-offset-size.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-offset-size.html new file mode 100644 index 0000000..7158354 --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/text/input-appearance-offset-size.html
@@ -0,0 +1,35 @@ +<html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<body> +<p>This tests that an input field does not change its size when a value is previewed.</p> + +<div><input id="emptyInput" style="font: 12px Arial"></div> +<div><input id="previewInput" style="font: 12px Arial"></div> + +<div><textarea id="emptyTextArea" style="font: 12px Arial"></textarea></div> +<div><textarea id="previewTextArea" style="font: 12px Arial"></textarea></div> +<script> +test(() => { + var empty = document.getElementById('emptyInput'); + var preview = document.getElementById('previewInput'); + + internals.setSuggestedValue(preview, 'Foooooooooooooooooooooooooooooooooooo'); + + assert_equals(empty.offsetWidth, preview.offsetWidth, 'Elements should have same width'); + assert_equals(empty.offsetHeight, preview.offsetHeight, 'Elements should have same height'); +}, 'Testing that an <input> field does not change its size when a value is previewed.'); + +test(() => { + var empty = document.getElementById('emptyTextArea'); + var preview = document.getElementById('previewTextArea'); + + internals.setSuggestedValue(preview, 'Foooooooooooooooooooooooooooooooooooo'); + + assert_equals(empty.offsetWidth, preview.offsetWidth, 'Elements should have same width'); + assert_equals(empty.offsetHeight, preview.offsetHeight, 'Elements should have same height'); +}, 'Testing that an <textarea> field does not change its size when a value is previewed.'); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/fast/forms/text/input-appearance-scroll-size.html b/third_party/blink/web_tests/fast/forms/text/input-appearance-scroll-size.html new file mode 100644 index 0000000..f927f1a --- /dev/null +++ b/third_party/blink/web_tests/fast/forms/text/input-appearance-scroll-size.html
@@ -0,0 +1,44 @@ +<html> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<body> +<p>An input element can have its scrollWidth/scrollHeight changed while being +temporarily in preview state. This test ensures that these two values do not +depend on the configured font type (the preview always happens with system-ui +font).</p> +<div><input id="referenceInput" style="font: 12px system-ui; width: 10px; height: 6px"></div> +<div><input id="modifiedInput" style="font: 12px Arial; width: 10px; height: 6px"></div> +<div><textarea id="referenceTextArea" style="font: 12px system-ui; width: 10px; height: 6px"></textarea></div> +<div><textarea id="modifiedTextArea" style="font: 12px Arial; width: 10px; height: 6px"></textarea></div> +<script> +test(() => { + var reference = document.getElementById('referenceInput'); + var modified = document.getElementById('modifiedInput'); + + var value = 'Foooooooooooooooooooooooooooooooooooo'; + internals.setSuggestedValue(reference, value); + internals.setSuggestedValue(modified, value); + + assert_equals(reference.scrollWidth, modified.scrollWidth, + 'Elements should have same scrollWidth'); + assert_equals(reference.scrollHeight, modified.scrollHeight, + 'Elements should have same scrollHeight'); +}, 'Testing that <input> elements\' scroll size does not depend on font type.'); + +test(() => { + var reference = document.getElementById('referenceTextArea'); + var modified = document.getElementById('modifiedTextArea'); + + var value = 'Foooooooooooooooooooooooooooooooooooo'; + internals.setSuggestedValue(reference, value); + internals.setSuggestedValue(modified, value); + + assert_equals(reference.scrollWidth, modified.scrollWidth, + 'Elements should have same scrollWidth'); + assert_equals(reference.scrollHeight, modified.scrollHeight, + 'Elements should have same scrollHeight'); +}, 'Testing that <textarea> elements\' scroll size does not depend on font type.'); +</script> +</body> +</html> +
diff --git a/third_party/blink/web_tests/fast/forms/text/password-input-suggested-value-appearance-expected.html b/third_party/blink/web_tests/fast/forms/text/password-input-suggested-value-appearance-expected.html deleted file mode 100644 index 4af5de1..0000000 --- a/third_party/blink/web_tests/fast/forms/text/password-input-suggested-value-appearance-expected.html +++ /dev/null
@@ -1,6 +0,0 @@ -<input id="input" type="password" value="MyPassword" style="width: 99px" > -<script> -input.focus(); -input.setSelectionRange(0,0); -internals.setAutofilled(input, true); -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.html b/third_party/blink/web_tests/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.html deleted file mode 100644 index 7aef426..0000000 --- a/third_party/blink/web_tests/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.html +++ /dev/null
@@ -1,6 +0,0 @@ -<textarea id="textarea" maxlength="5">Miste</textarea> -<script> -textarea.focus(); -textarea.setSelectionRange(0,0); -internals.setAutofilled(textarea, true); -</script>
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-expected.png new file mode 100644 index 0000000..27916cb --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png new file mode 100644 index 0000000..bc6012dd --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png new file mode 100644 index 0000000..bc6012dd --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..54fb80c5 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png new file mode 100644 index 0000000..f8552621 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png new file mode 100644 index 0000000..639ad18 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/password-input-suggested-value-appearance-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/password-input-suggested-value-appearance-expected.png new file mode 100644 index 0000000..c038964f --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/password-input-suggested-value-appearance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/linux/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..7cdc73f --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/linux/images/jpeg-yuv-image-decoding-expected.png index 97a98172..55cd69a8 100644 --- a/third_party/blink/web_tests/platform/linux/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/linux/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png index d2e7d00..b8cdcdf 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png index 97a98172..55cd69a8 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-expected.png new file mode 100644 index 0000000..30ea5b5 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png new file mode 100644 index 0000000..0e61c71 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png new file mode 100644 index 0000000..0e61c71 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..f76879e --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png new file mode 100644 index 0000000..998da681 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png new file mode 100644 index 0000000..4dade790 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/password-input-suggested-value-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/password-input-suggested-value-appearance-expected.png new file mode 100644 index 0000000..f22a1edd --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/password-input-suggested-value-appearance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..d68533d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/images/jpeg-yuv-image-decoding-expected.png index f9c2fe3..20f3f44 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.10/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.10/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png index 6f504d8b4..7e77b7b0 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png index f9c2fe3..20f3f44 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-expected.png new file mode 100644 index 0000000..6c2b505 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png new file mode 100644 index 0000000..0fca354 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png new file mode 100644 index 0000000..0fca354 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..cddd14f4 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png new file mode 100644 index 0000000..ce00c9c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png new file mode 100644 index 0000000..ad30d563 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/password-input-suggested-value-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/password-input-suggested-value-appearance-expected.png new file mode 100644 index 0000000..68eb023 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/password-input-suggested-value-appearance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..7c17f831 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png new file mode 100644 index 0000000..582e8d7 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/text/password-input-suggested-value-appearance-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/text/password-input-suggested-value-appearance-expected.png new file mode 100644 index 0000000..c943b40 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/forms/text/password-input-suggested-value-appearance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-expected.png new file mode 100644 index 0000000..5d14614 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png new file mode 100644 index 0000000..de1589d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png new file mode 100644 index 0000000..de1589d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..edfff76 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png new file mode 100644 index 0000000..655a48e --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png new file mode 100644 index 0000000..690a9708 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/password-input-suggested-value-appearance-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/password-input-suggested-value-appearance-expected.png new file mode 100644 index 0000000..d8b3992 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/password-input-suggested-value-appearance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..6d5471288 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/mac/images/jpeg-yuv-image-decoding-expected.png index 6f1f4ce..99c21b6 100644 --- a/third_party/blink/web_tests/platform/mac/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/mac/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png index db8f44e..80f01a3 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png index 6f1f4ce..99c21b6 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-expected.png new file mode 100644 index 0000000..0b43e7be --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png new file mode 100644 index 0000000..e6de28dc --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggested-value-over-placeholder-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png new file mode 100644 index 0000000..e6de28dc --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggested-value-when-underlying-placeholder-is-removed-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..5429c3d --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png new file mode 100644 index 0000000..df42b059 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png new file mode 100644 index 0000000..14a3face --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/input-appearance-autocomplete-with-initial-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/password-input-suggested-value-appearance-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/password-input-suggested-value-appearance-expected.png new file mode 100644 index 0000000..d59d461 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/password-input-suggested-value-appearance-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png new file mode 100644 index 0000000..3a88be45 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/fast/forms/text/textarea-appearance-autocomplete-suggestion-maxlength-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/win/images/jpeg-yuv-image-decoding-expected.png index adb719c4..0205be9 100644 --- a/third_party/blink/web_tests/platform/win/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/win/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png index f1626ca..6a6b470 100644 --- a/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/exotic-color-space/images/jpeg-yuv-image-decoding-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png b/third_party/blink/web_tests/platform/win7/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png new file mode 100644 index 0000000..a1e8ee0 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/fast/forms/text/input-appearance-autocomplete-very-long-value-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-click-once.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-click-once.html new file mode 100644 index 0000000..7e01c704 --- /dev/null +++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-click-once.html
@@ -0,0 +1,63 @@ +<!DOCTYPE html> +<script src="../../../../../resources/testharness.js"></script> +<script src="../../../../../resources/testharnessreport.js"></script> +<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> +<script src="file:///gen/third_party/blink/public/mojom/page/spatial_navigation.mojom.js"></script> +<script src="../../../../../fast/spatial-navigation/resources/mock-snav-service.js"></script> +<script src="../../../../../fast/spatial-navigation/resources/snav-testharness.js"></script> + +<button type="button" id="button" autofocus> button </button> + +<svg height="100" width="100" id="svg" tabindex="0"> + <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /> +</svg> + +<img src="" height="100" width="100" id="img" tabindex="1" /> + +<script> + let button = document.getElementById("button"); + let svg = document.getElementById("svg"); + let img = document.getElementById("img"); + let buttonClicked = 0; + let svgClicked = 0; + let imgClicked = 0; + + button.addEventListener('click', function() { + console.log('wtf'); + buttonClicked++; + }) + + svg.addEventListener('click', function() { + svgClicked++; + }) + + img.addEventListener('keydown', function(e) { + e.preventDefault(); + }) + img.addEventListener('click', function() { + imgClicked++; + }) + + promise_test(async () => { + await snav.rAF(); + eventSender.keyDown('Enter'); + await snav.rAF(); + assert_equals(buttonClicked, + 1, + "button should have been clicked once."); + + svg.focus(); + eventSender.keyDown('Enter'); + await snav.rAF(); + assert_equals(svgClicked, + 1, + "svg should have been clicked once."); + + img.focus(); + eventSender.keyDown('Enter'); + await snav.rAF(); + assert_equals(imgClicked, + 0, + "img should not have been clicked."); + }, 'Spat Nav doesn\'t click multiple times.'); +</script>
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt index dc22bfa4..fe2505f 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -59,6 +59,7 @@ property dir property dispatchEvent property draggable + property enterKeyHint property firstChild property firstElementChild property focus
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index 5afccc46..0b8d2e66 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -2195,6 +2195,7 @@ getter dataset getter dir getter draggable + getter enterKeyHint getter hidden getter innerText getter inputMode @@ -2302,6 +2303,7 @@ setter contentEditable setter dir setter draggable + setter enterKeyHint setter hidden setter innerText setter inputMode
diff --git a/third_party/closure_compiler/externs/bluetooth_private.js b/third_party/closure_compiler/externs/bluetooth_private.js index 0ba0571..d53aff1 100644 --- a/third_party/closure_compiler/externs/bluetooth_private.js +++ b/third_party/closure_compiler/externs/bluetooth_private.js
@@ -173,6 +173,14 @@ chrome.bluetoothPrivate.recordReconnection = function(success) {}; /** + * Record that a user selected a device to connect to. + * @param {number} selectionDurationMs + * @param {boolean} wasPaired + * @param {!chrome.bluetooth.Transport} transport + */ +chrome.bluetoothPrivate.recordDeviceSelection = function(selectionDurationMs, wasPaired, transport) {}; + +/** * Fired when a pairing event occurs. * @type {!ChromeEvent} */
diff --git a/third_party/webxr_test_pages/webxr-samples/index.html b/third_party/webxr_test_pages/webxr-samples/index.html index db4d01e..57d1a8e 100644 --- a/third_party/webxr_test_pages/webxr-samples/index.html +++ b/third_party/webxr_test_pages/webxr-samples/index.html
@@ -100,6 +100,13 @@ <script> let pages = [ + { title: 'Barebones', category: 'Basics', + path: 'xr-barebones.html', + description: 'Extremely simple use of WebXR with no library dependencies. Doesn\'t render anything exciting.' }, + + { tag: 'hr' }, + { tag: 'br' }, + { title: 'XR Presentation', category: 'Basics', path: 'xr-presentation.html', description: 'Demonstrates how to present a simple WebGL scene to a XRDevice.' }, @@ -154,22 +161,17 @@ { title: 'Spectator Mode', category: 'Advanced Techniques', path: 'spectator-mode.html', description: 'Demonstrates rendering a 3rd person view of the scene to an external monitor.' }, - - { tag: 'hr' }, - { tag: 'br' }, - - { title: 'Barebones', category: 'WIN32_LEAN_AND_MEAN', - path: 'xr-barebones.html', - description: 'Extremely simple use of WebXR with no library dependencies. Doesn\'t render anything exciting.' }, ]; let mainElement = document.getElementById("main"); // Append an element for every item in the pages list. + let tag_count = 0; for (var i = 0; i < pages.length; ++i) { var page = pages[i]; if (page.tag) { + tag_count++; mainElement.appendChild(document.createElement(page.tag)); continue; } @@ -177,7 +179,7 @@ let article = document.createElement('article'); let title = document.createElement('h3'); - title.setAttribute('data-index', i + 1); + title.setAttribute('data-index', i + 1 - tag_count); let titleLink = document.createElement('a'); titleLink.href = page.path;
diff --git a/third_party/webxr_test_pages/webxr-samples/xr-barebones.html b/third_party/webxr_test_pages/webxr-samples/xr-barebones.html index 0120898..94f2f94 100644 --- a/third_party/webxr_test_pages/webxr-samples/xr-barebones.html +++ b/third_party/webxr_test_pages/webxr-samples/xr-barebones.html
@@ -30,9 +30,7 @@ <meta http-equiv="origin-trial" data-feature="WebXR Device API (For Chrome M76+)" data-expires="2019-07-24" content="Ap6io/uhkGK7vXCD+golNnQfj8wJ4so790EzZoqb8YOljMXIBTvBEQFPTHYIz5d/BgtuwZTKOLrmHAOt30f38g8AAABxeyJvcmlnaW4iOiJodHRwczovL3N0b3JhZ2UuZ29vZ2xlYXBpcy5jb206NDQzIiwiZmVhdHVyZSI6IldlYlhSRGV2aWNlTTc2IiwiZXhwaXJ5IjoxNTY0MDA5MzU2LCJpc1N1YmRvbWFpbiI6dHJ1ZX0="> <title>Barebones WebXR</title> - <link href='css/common.css' rel='stylesheet'></link> - </head> <body> <header> @@ -60,32 +58,36 @@ let gl = null; function checkSupportedState() { - // If the device allows creation of exclusive sessions enable the - // button. If the supportsSession request is rejected, then - // disable the button because it means that XR is not supported. - navigator.xr.supportsSession('immersive-vr').then(() => { - // Updates the button to start an XR session when clicked. - xrButton.innerHTML = 'Enter XR'; - xrButton.disabled = false; - }, () => { - xrButton.innerHTML = 'XR not found'; - xrButton.disabled = true; - }); + // If the device allows creation of immersive VR sessions, enable the + // button. If the supportsSession request is rejected, then + // disable the button because it means that the desired session mode is + // not supported. + navigator.xr.supportsSession('immersive-vr').then(() => { + // Updates the button to start an XR session when clicked. + xrButton.innerHTML = 'Enter XR'; + xrButton.disabled = false; + }, () => { + xrButton.innerHTML = 'XR not found'; + xrButton.disabled = true; + }); } - // Checks to see if WebXR is available and, if so, requests an XRDevice - // that is connected to the system and tests it to ensure it supports the - // desired session options. + // Checks to see if WebXR is available. If it is, checks if the desired + // session options are supported both right now and whenever a device is + // added or removed. function initXR() { - // Is WebXR available on this UA? + // If WebXR is available on this UA, check if any devices are connected + // that would support an immersive VR session. if (navigator.xr) { - // Register our click handler + // Register our click handler. + // In the other WebXR samples, most of the button details are handled + // by XRDeviceButton from js/webxr-button.js. xrButton.addEventListener('click', onButtonClicked); - // Register for device change events, this indicates that a device has - // been added or removed and that whether or not XR is supported has - // likely changed. - navigator.xr.addEventListener('devicechange',checkSupportedState); + // Register for device change events. This indicates that a device has + // been added or removed, which means that whether or not XR is + // supported has likely changed. + navigator.xr.addEventListener('devicechange', checkSupportedState); // Just in case the devicechange event has already fired, call it now // as well. @@ -97,7 +99,9 @@ // session already we'll request one, and if we do we'll end it. function onButtonClicked() { if (!xrSession) { - navigator.xr.requestSession('immersive-vr').then(onSessionStarted); + navigator.xr.requestSession('immersive-vr').then( + onSessionStarted, + onRequestSessionError); } else { xrSession.end(); } @@ -106,7 +110,6 @@ // Called when we've successfully acquired a XRSession. In response we // will set up the necessary session state and kick off the frame loop. function onSessionStarted(session) { - session.mode = 'immersive-vr'; xrSession = session; xrButton.innerHTML = 'Exit XR'; @@ -123,12 +126,13 @@ // Use the new WebGL context to create a XRWebGLLayer and set it as the // sessions baseLayer. This allows any content rendered to the layer to - // be displayed on the XRDevice. + // be displayed on the XR Device. session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) }); - // Get a frame of reference, which is required for querying poses. In - // this case an 'eye-level' frame of reference means that all poses will - // be relative to the location where the XRDevice was first detected. + // Get a reference space, which is required for querying poses. In + // this case a 'local' reference space means that all poses will be + // relative to the location of the user's head at the time this + // reference space is first created. session.requestReferenceSpace('local').then((refSpace) => { xrRefSpace = refSpace; @@ -137,6 +141,12 @@ }); } + // Called when the requestSession promise was rejected with an exception. + function onRequestSessionError(ex) { + alert("Failed to start immersive VR session."); + console.error(ex.message); + } + // Called when the user clicks the 'Exit XR' button. In response we end // the session. function onEndSession(session) { @@ -160,22 +170,26 @@ function onXRFrame(t, frame) { let session = frame.session; - // Inform the session that we're ready for the next frame. + // There are a few advantages to requesting the next frame immediately + // instead of at the end of this function. + // 1) It's less likely to forget to call requestAnimationFrame in cases + // when onXRFrame has more complicated control flow. + // 2) If an exception is thrown later in this function, the render loop + // will still continue. session.requestAnimationFrame(onXRFrame); - // Get the XRDevice pose relative to the Frame of Reference we created + // Get the viewer pose relative to the reference space we created // earlier. let pose = frame.getViewerPose(xrRefSpace); // Getting the pose may fail if, for example, tracking is lost. So we // have to check to make sure that we got a valid pose before attempting - // to render with it. If not in this case we'll just leave the + // to render with it. If not, in this case we'll just leave the // framebuffer cleared, so tracking loss means the scene will simply - // dissapear. + // disappear. if (pose) { - // If we do have a valid pose, bind the WebGL layer's framebuffer, - // which is where any content to be displayed on the XRDevice must be + // which is where any content to be displayed on the XR Device must be // rendered. gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer); @@ -195,7 +209,6 @@ let viewport = session.renderState.baseLayer.getViewport(view); gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); - // Draw something. }*/ }
diff --git a/tools/OWNERS b/tools/OWNERS index 9796621..d771315 100644 --- a/tools/OWNERS +++ b/tools/OWNERS
@@ -43,10 +43,6 @@ per-file remove_stale_pyc_files.py=dtu@chromium.org -per-file roll_angle.py=kbr@chromium.org -per-file roll_angle.py=geofflang@chromium.org -per-file roll_swiftshader.py=capn@chromium.org -per-file roll_swiftshader.py=sugoi@chromium.org per-file roll_webgl_conformance.py=bajones@chromium.org per-file roll_webgl_conformance.py=kbr@chromium.org per-file roll_webgl_conformance.py=geofflang@chromium.org
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index b91d0e6..90ef0f71 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -12885,6 +12885,12 @@ <description>Please enter the description of this user action.</description> </action> +<action name="MobileToolbarIdentityDiscTap"> + <owner>pavely@chromium.org</owner> + <owner>chrome-android-app@chromium.org</owner> + <description>User tapped on IdentityDisc button on toolbar.</description> +</action> + <action name="MobileToolbarNewTab"> <obsolete>Deprecated as of 5/2015</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 0e0318a1..998be5c3 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -17222,6 +17222,7 @@ <int value="567" label="RelaunchHeadsUpPeriod"/> <int value="568" label="StartupBrowserWindowLaunchSuppressed"/> <int value="569" label="DeviceWebUsbAllowDevicesForUrls"/> + <int value="570" label="UserFeedbackAllowed"/> </enum> <enum name="EnterprisePolicyInvalidations"> @@ -19717,6 +19718,7 @@ <int value="1342" label="LOGINSCREENUI_CLOSE"/> <int value="1343" label="DECLARATIVENETREQUEST_GETMATCHEDRULES"/> <int value="1344" label="DECLARATIVENETREQUEST_SETACTIONCOUNTASBADGETEXT"/> + <int value="1345" label="BLUETOOTHPRIVATE_RECORDDEVICESELECTION"/> </enum> <enum name="ExtensionIconState"> @@ -33427,6 +33429,7 @@ <int value="-1937077699" label="http-form-warning"/> <int value="-1934661084" label="ForceUnifiedConsentBump:disabled"/> <int value="-1933425042" label="OfflinePreviews:enabled"/> + <int value="-1932609987" label="CSSBackdropFilter:disabled"/> <int value="-1932379839" label="OmniboxUIExperimentHideSteadyStateUrlTrivialSubdomains:enabled"/> <int value="-1930720286" label="nacl-debug-mask"/> @@ -34392,6 +34395,7 @@ <int value="-557742250" label="ContentSuggestionsCategories:disabled"/> <int value="-548082154" label="protect-sync-credential:disabled"/> <int value="-547301855" label="SyncPseudoUSSSupervisedUsers:enabled"/> + <int value="-544629557" label="CSSBackdropFilter:enabled"/> <int value="-541611402" label="OfflinePagesPrefetching:enabled"/> <int value="-540150399" label="TapVisualizerApp:enabled"/> <int value="-539105193" label="SendTabToSelfBroadcast:disabled"/> @@ -34770,6 +34774,7 @@ <int value="5654819" label="CrostiniGpuSupport:disabled"/> <int value="7444737" label="NTPSuggestionsStandaloneUI:disabled"/> <int value="7533886" label="disable-offer-store-unmasked-wallet-cards"/> + <int value="8891567" label="CaptionSettings:enabled"/> <int value="10458238" label="disable-print-preview-simplify"/> <int value="11698808" label="enable-dom-distiller-button-animation"/> <int value="15614295" label="Portals:enabled"/> @@ -35813,6 +35818,7 @@ <int value="1597880096" label="FocusMode:disabled"/> <int value="1600850069" label="MobileIdentityConsistency:disabled"/> <int value="1600926040" label="TranslateCompactUI:enabled"/> + <int value="1603578716" label="CaptionSettings:disabled"/> <int value="1605398303" label="MacSystemMediaPermissionsInfoUI:enabled"/> <int value="1605611615" label="enable-webrtc-srtp-aes-gcm"/> <int value="1611522475" label="AutofillPrimaryInfoStyleExperiment:disabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 8e85ebc..bf3fd024 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -14331,6 +14331,20 @@ </summary> </histogram> +<histogram name="Bluetooth.ChromeOS.DeviceSelectionDuration" units="ms" + expires_after="2020-06-13"> +<!-- Name completed by histogram_suffixes name="BluetoothUISurfaces", + name="BluetoothPairingStates", and name="BluetoothTransportTypes" --> + + <owner>hansberry@chromium.org</owner> + <owner>jlklein@chromium.org</owner> + <summary> + Records how long it takes for the user to select a device either after they + open the UI and Bluetooth is on, or after Bluetooth turns on while the UI is + open. + </summary> +</histogram> + <histogram name="Bluetooth.ChromeOS.Pairing.Duration.Failure" units="ms" expires_after="2020-06-06"> <!-- Name completed by histogram_suffixes name="BluetoothTransportTypes" --> @@ -39143,6 +39157,9 @@ <histogram name="Extensions.HostedAppUnlimitedStorageUsage" units="KB" expires_after="2018-08-30"> + <obsolete> + Expired 2018-08-30 + </obsolete> <owner>rdevlin.cronin@chromium.org</owner> <summary> The usage (in kilobytes) of a hosted app with the unlimitedStorage api @@ -149051,10 +149068,23 @@ <affected-histogram name="Blink.VisibleLoadTime.LazyLoadImages.BelowTheFold"/> </histogram_suffixes> +<histogram_suffixes name="BluetoothPairedStates" separator="."> + <suffix name="NotPaired"/> + <suffix name="Paired"/> + <affected-histogram + name="Bluetooth.ChromeOS.DeviceSelectionDuration.Settings"/> + <affected-histogram + name="Bluetooth.ChromeOS.DeviceSelectionDuration.SystemTray"/> +</histogram_suffixes> + <histogram_suffixes name="BluetoothTransportTypes" separator="."> <suffix name="BLE"/> <suffix name="Classic"/> <suffix name="Dual"/> + <affected-histogram + name="Bluetooth.ChromeOS.DeviceSelectionDuration.Settings.NotPaired"/> + <affected-histogram + name="Bluetooth.ChromeOS.DeviceSelectionDuration.SystemTray.NotPaired"/> <affected-histogram name="Bluetooth.ChromeOS.Pairing.Duration.Failure"/> <affected-histogram name="Bluetooth.ChromeOS.Pairing.Duration.Success"/> <affected-histogram name="Bluetooth.ChromeOS.Pairing.Result"/> @@ -149063,6 +149093,7 @@ <histogram_suffixes name="BluetoothUISurfaces" separator="."> <suffix name="Settings"/> <suffix name="SystemTray"/> + <affected-histogram name="Bluetooth.ChromeOS.DeviceSelectionDuration"/> <affected-histogram name="Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result"/> </histogram_suffixes>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv index e49b146..cad8206b 100644 --- a/tools/perf/benchmark.csv +++ b/tools/perf/benchmark.csv
@@ -27,8 +27,8 @@ load_library_perf_tests,"xhwang@chromium.org, crouleau@chromium.org",Internals>Media>Encrypted,, loading.desktop,"kouhei@chromium.org, ksakamoto@chromium.org",Blink>Loader,https://bit.ly/loading-benchmarks,"cache_temperature_cold,cache_temperature_warm,international,intl_ar_fa_he,intl_es_fr_pt_BR,intl_hi_ru,intl_ja_zh,intl_ko_th_vi,typical" loading.mobile,"kouhei@chromium.org, ksakamoto@chromium.org",Blink>Loader,https://bit.ly/loading-benchmarks,"cache_temperature_cold,cache_temperature_hot,cache_temperature_warm,easy_ttfmp,easy_tti,global,pwa,tough_ttfmp,tough_tti" -media.desktop,dalecurtis@chromium.org,Internals>Media,,"aac,audio_only,audio_video,av1,background,beginning_to_end,busyjs,cns,h264,is_4k,is_50fps,mp3,mse,opus,pcm,seek,src,video_only,vorbis,vp8,vp9" -media.mobile,dalecurtis@chromium.org,Internals>Media,,"aac,audio_only,audio_video,background,beginning_to_end,busyjs,cns,h264,mp3,mse,opus,pcm,seek,src,video_only,vorbis,vp9" +media.desktop,dalecurtis@chromium.org,Internals>Media,,"aac,audio_only,audio_video,av1,background,beginning_to_end,busyjs,cns,h264,is_4k,is_50fps,mp3,mse,opus,seek,src,video_only,vorbis,vp8,vp9" +media.mobile,dalecurtis@chromium.org,Internals>Media,,"aac,audio_only,audio_video,background,beginning_to_end,busyjs,cns,h264,mp3,mse,opus,seek,src,video_only,vorbis,vp9" media_perftests,"crouleau@chromium.org, dalecurtis@chromium.org",Internals>Media,, memory.desktop,erikchen@chromium.org,,, memory.top_10_mobile,perezju@chromium.org,,,
diff --git a/tools/perf/page_sets/media_cases.py b/tools/perf/page_sets/media_cases.py index 5f213b8..6e39f55 100644 --- a/tools/perf/page_sets/media_cases.py +++ b/tools/perf/page_sets/media_cases.py
@@ -224,83 +224,70 @@ def _GetCrossPlatformMediaPages(page_set): return [ - _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=crowd.ogg&type=audio', - page_set=page_set, - tags=['vorbis', 'audio_only']), + # 1080p 50fps crowd test cases. High non-60fps frame rate is good for + # finding rendering and efficiency regressions. _BeginningToEndPlayPage( url=_URL_BASE + 'video.html?src=crowd1080.webm', page_set=page_set, tags=['is_50fps', 'vp8', 'vorbis', 'audio_video']), _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio', - page_set=page_set, - tags=['vorbis', 'audio_only']), - _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio', - page_set=page_set, - tags=['pcm', 'audio_only']), - _BeginningToEndPlayPage( url=_URL_BASE + 'video.html?src=crowd1080.mp4', page_set=page_set, tags=['is_50fps', 'h264', 'aac', 'audio_video']), _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm', + page_set=page_set, + tags=['is_50fps', 'vp9', 'video_only']), + + # Audio only test cases. MP3 and OGG are important to test since they are + # unstructured containers and thus are prone to efficiency regressions. + _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio', + page_set=page_set, + tags=['vorbis', 'audio_only']), + _BeginningToEndPlayPage( url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio', page_set=page_set, tags=['mp3', 'audio_only']), _BeginningToEndPlayPage( + url=_URL_BASE + 'video.html?src=tulip2.m4a&type=audio', + page_set=page_set, + tags=['aac', 'audio_only']), + + # Baseline + busyjs test. + _BeginningToEndPlayPage( url=_URL_BASE + 'video.html?src=tulip2.mp4', page_set=page_set, tags=['h264', 'aac', 'audio_video']), _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=tulip2.m4a&type=audio', + url=_URL_BASE + 'video.html?src=tulip2.mp4&busyjs', page_set=page_set, - tags=['aac', 'audio_only']), - _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=garden2_10s.webm', - page_set=page_set, - tags=['is_4k', 'vp8', 'vorbis', 'audio_video']), - _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=garden2_10s.mp4', - page_set=page_set, - tags=['is_4k', 'h264', 'aac', 'audio_video']), - _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=tulip2.vp9.webm', - page_set=page_set, - tags=['vp9', 'opus', 'audio_video'], - traffic_setting=traffic_setting_module.WIFI), + tags=['h264', 'aac', 'audio_video', 'busyjs']), + + # Baseline + WiFi test. _BeginningToEndPlayPage( url=_URL_BASE + 'video.html?src=tulip2.vp9.webm', page_set=page_set, tags=['vp9', 'opus', 'audio_video']), _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm', + url=_URL_BASE + 'video.html?src=tulip2.vp9.webm', page_set=page_set, - tags=['vp9', 'video_only']), - _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=crowd720_vp9.webm', - page_set=page_set, - tags=['vp9', 'video_only']), - _BeginningToEndPlayPage( - url=_URL_BASE + 'video.html?src=tulip2.mp4&busyjs', - page_set=page_set, - tags=['h264', 'aac', 'audio_video', 'busyjs']), + tags=['vp9', 'opus', 'audio_video'], + traffic_setting=traffic_setting_module.WIFI), + + # Seek tests in MP3 and OGG are important since they don't have seek + # indices and thus show off efficiency regressions easily. _SeekPage( url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio&seek', page_set=page_set, tags=['vorbis', 'audio_only']), _SeekPage( - url=_URL_BASE + 'video.html?src=tulip2.wav&type=audio&seek', - page_set=page_set, - tags=['pcm', 'audio_only']), - _SeekPage( url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio&seek', page_set=page_set, tags=['mp3', 'audio_only']), - _SeekPage( - url=_URL_BASE + 'video.html?src=tulip2.mp4&seek', - page_set=page_set, - tags=['h264', 'aac', 'audio_video']), + + # High resolution seek test cases which will exaggerate any decoding + # efficiency or buffering regressions. _SeekPage( url=_URL_BASE + 'video.html?src=garden2_10s.webm&seek', page_set=page_set, @@ -310,32 +297,27 @@ page_set=page_set, tags=['is_4k', 'h264', 'aac', 'audio_video']), _SeekPage( - url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&seek', - page_set=page_set, - tags=['vp9', 'opus', 'audio_video']), - _SeekPage( - url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm&seek', - page_set=page_set, - tags=['vp9', 'video_only', 'seek']), - _SeekPage( url=(_URL_BASE + 'video.html?src=' 'smpte_3840x2160_60fps_vp9.webm&seek'), page_set=page_set, tags=['is_4k', 'vp9', 'video_only'], action_timeout_in_seconds=120), + + # Basic test that ensures background playback works properly. _BackgroundPlaybackPage( url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&background', page_set=page_set, tags=['vp9', 'opus', 'audio_video']), + + # Basic MSE test pages for common configurations. _MSEPage( url=_URL_BASE + 'mse.html?media=aac_audio.mp4,h264_video.mp4', page_set=page_set, tags=['h264', 'aac', 'audio_video']), _MSEPage( - url=(_URL_BASE + 'mse.html?' - 'media=aac_audio.mp4,h264_video.mp4&waitForPageLoaded=true'), + url=_URL_BASE + 'mse.html?media=tulip2.vp9.webm', page_set=page_set, - tags=['h264', 'aac', 'audio_video']), + tags=['vp9', 'opus', 'audio_video']), _MSEPage( url=_URL_BASE + 'mse.html?media=aac_audio.mp4', page_set=page_set,
diff --git a/tools/perf/page_sets/media_cases/mse.js b/tools/perf/page_sets/media_cases/mse.js index 6a097f8..794315f5 100644 --- a/tools/perf/page_sets/media_cases/mse.js +++ b/tools/perf/page_sets/media_cases/mse.js
@@ -13,6 +13,7 @@ "aac_audio.mp4": "audio/mp4; codecs=\"mp4a.40.2\"", "h264_video.mp4": "video/mp4; codecs=\"avc1.640028\"", "tulip0.av1.mp4": "video/mp4; codecs=\"av01.0.05M.08\"", + "tulip2.vp9.webm": "video/webm; codecs=\"opus,vp9\"", }; const testParams = {}
diff --git a/tools/roll_swiftshader.py b/tools/roll_swiftshader.py deleted file mode 100755 index 785e9c28..0000000 --- a/tools/roll_swiftshader.py +++ /dev/null
@@ -1,405 +0,0 @@ -#!/usr/bin/env python -# Copyright 2015 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import argparse -import collections -import logging -import os -import re -import subprocess -import sys -import time - -extra_cq_trybots = [ - { - "mastername": "luci.chromium.try", - "buildernames": ["win_optional_gpu_tests_rel"] - }, - { - "mastername": "luci.chromium.try", - "buildernames": ["mac_optional_gpu_tests_rel"] - }, - { - "mastername": "luci.chromium.try", - "buildernames": ["linux_optional_gpu_tests_rel"] - }, - { - "mastername": "luci.chromium.try", - "buildernames": ["android_optional_gpu_tests_rel"] - } -] - -SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) -SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir)) -sys.path.insert(0, os.path.join(SRC_DIR, 'build')) -import find_depot_tools -find_depot_tools.add_depot_tools_to_path() -import roll_dep_svn -from third_party import upload - -# Avoid depot_tools/third_party/upload.py print verbose messages. -upload.verbosity = 0 # Errors only. - -CHROMIUM_GIT_URL = 'https://chromium.googlesource.com/chromium/src.git' -CL_ISSUE_RE = re.compile('^Issue number: ([0-9]+) \((.*)\)$') -REVIEW_URL_RE = re.compile('^https?://(.*)/(.*)') -ROLL_BRANCH_NAME = 'special_swiftshader_roll_branch' -TRYJOB_STATUS_SLEEP_SECONDS = 30 - -# Use a shell for subcommands on Windows to get a PATH search. -IS_WIN = sys.platform.startswith('win') -SWIFTSHADER_PATH = os.path.join('third_party', 'swiftshader') - -CommitInfo = collections.namedtuple('CommitInfo', ['git_commit', - 'git_repo_url']) -CLInfo = collections.namedtuple('CLInfo', ['issue', 'url', 'review_server']) - -def _VarLookup(local_scope): - return lambda var_name: local_scope['vars'][var_name] - -def _PosixPath(path): - """Convert a possibly-Windows path to a posix-style path.""" - (_, path) = os.path.splitdrive(path) - return path.replace(os.sep, '/') - -def _ParseGitCommitHash(description): - for line in description.splitlines(): - if line.startswith('commit '): - return line.split()[1] - logging.error('Failed to parse git commit id from:\n%s\n', description) - sys.exit(-1) - return None - - -def _ParseDepsFile(filename): - with open(filename, 'rb') as f: - deps_content = f.read() - return _ParseDepsDict(deps_content) - - -def _ParseDepsDict(deps_content): - local_scope = {} - global_scope = { - 'Var': _VarLookup(local_scope), - 'deps_os': {}, - } - exec(deps_content, global_scope, local_scope) - return local_scope - - -def _GenerateCLDescriptionCommand(swiftshader_current, swiftshader_new, bugs, - tbr): - def GetChangeString(current_hash, new_hash): - return '%s..%s' % (current_hash[0:7], new_hash[0:7]); - - def GetChangeLogURL(git_repo_url, change_string): - return '%s/+log/%s' % (git_repo_url, change_string) - - def GetBugString(bugs): - bug_str = 'BUG=' - for bug in bugs: - bug_str += bug + ',' - return bug_str.rstrip(',') - - if swiftshader_current.git_commit != swiftshader_new.git_commit: - change_str = GetChangeString(swiftshader_current.git_commit, - swiftshader_new.git_commit) - changelog_url = GetChangeLogURL(swiftshader_current.git_repo_url, - change_str) - - def GetExtraCQTrybotString(): - s = '' - for t in extra_cq_trybots: - if s: - s += ';' - s += t['mastername'] + ':' + ','.join(t['buildernames']) - return s - - def GetTBRString(tbr): - if not tbr: - return '' - return 'TBR=' + tbr - - extra_trybot_args = [] - if extra_cq_trybots: - extra_trybot_string = GetExtraCQTrybotString() - extra_trybot_args = ['-m', 'CQ_INCLUDE_TRYBOTS=' + extra_trybot_string] - - return [ - '-m', 'Roll SwiftShader ' + change_str, - '-m', '%s' % changelog_url, - '-m', GetBugString(bugs), - '-m', GetTBRString(tbr), - '-m', 'TEST=bots', - ] + extra_trybot_args - - -class AutoRoller(object): - def __init__(self, chromium_src): - self._chromium_src = chromium_src - - def _RunCommand(self, command, working_dir=None, ignore_exit_code=False, - extra_env=None): - """Runs a command and returns the stdout from that command. - - If the command fails (exit code != 0), the function will exit the process. - """ - working_dir = working_dir or self._chromium_src - logging.debug('cmd: %s cwd: %s', ' '.join(command), working_dir) - env = os.environ.copy() - if extra_env: - logging.debug('extra env: %s', extra_env) - env.update(extra_env) - p = subprocess.Popen(command, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, shell=IS_WIN, env=env, - cwd=working_dir, universal_newlines=True) - output = p.stdout.read() - p.wait() - p.stdout.close() - p.stderr.close() - - if not ignore_exit_code and p.returncode != 0: - logging.error('Command failed: %s\n%s', str(command), output) - sys.exit(p.returncode) - return output - - def _GetCommitInfo(self, path_below_src, git_hash=None, git_repo_url=None): - working_dir = os.path.join(self._chromium_src, path_below_src) - self._RunCommand(['git', 'fetch', 'origin'], working_dir=working_dir) - revision_range = git_hash or 'origin' - ret = self._RunCommand( - ['git', '--no-pager', 'log', revision_range, - '--no-abbrev-commit', '--pretty=full', '-1'], - working_dir=working_dir) - return CommitInfo(_ParseGitCommitHash(ret), git_repo_url) - - def _GetDepsCommitInfo(self, deps_dict, path_below_src): - entry = deps_dict['deps'][_PosixPath('src/%s' % path_below_src)] - at_index = entry.find('@') - git_repo_url = entry[:at_index] - git_hash = entry[at_index + 1:] - return self._GetCommitInfo(path_below_src, git_hash, git_repo_url) - - def _GetCLInfo(self): - cl_output = self._RunCommand(['git', 'cl', 'issue']) - m = CL_ISSUE_RE.match(cl_output.strip()) - if not m: - logging.error('Cannot find any CL info. Output was:\n%s', cl_output) - sys.exit(-1) - issue_number = int(m.group(1)) - url = m.group(2) - - # Parse the codereview host from the URL. - m = REVIEW_URL_RE.match(url) - if not m: - logging.error('Cannot parse codereview host from URL: %s', url) - sys.exit(-1) - review_server = m.group(1) - return CLInfo(issue_number, url, review_server) - - def _GetCurrentBranchName(self): - return self._RunCommand( - ['git', 'rev-parse', '--abbrev-ref', 'HEAD']).splitlines()[0] - - def _IsTreeClean(self): - lines = self._RunCommand( - ['git', 'status', '--porcelain', '-uno']).splitlines() - if len(lines) == 0: - return True - - logging.debug('Dirty/unversioned files:\n%s', '\n'.join(lines)) - return False - - def _GetBugList(self, path_below_src, swiftshader_current, swiftshader_new): - working_dir = os.path.join(self._chromium_src, path_below_src) - lines = self._RunCommand( - ['git','log', - '%s..%s' % (swiftshader_current.git_commit, - swiftshader_new.git_commit)], - working_dir=working_dir).split('\n') - ignored_projects = set(['swiftshader']) - bugs = set() - for line in lines: - line = line.strip() - bug_prefix = 'BUG=' - if line.startswith(bug_prefix): - bugs_strings = line[len(bug_prefix):].split(',') - for bug_string in bugs_strings: - ignore_bug = False - for ignored_project in ignored_projects: - if bug_string.startswith(ignored_project + ':'): - ignore_bug = True - break - if not ignore_bug: - bugs.add(bug_string) - return bugs - - def _UpdateReadmeFile(self, readme_path, new_revision): - readme = open(os.path.join(self._chromium_src, readme_path), 'r+') - txt = readme.read() - m = re.sub(re.compile('.*^Revision\: ([0-9]*).*', re.MULTILINE), - ('Revision: %s' % new_revision), txt) - readme.seek(0) - readme.write(m) - readme.truncate() - - def _TriggerExtraTrybots(self, trybots): - for trybot in trybots: - for builder in trybot['buildernames']: - self._RunCommand([ - 'git', 'cl', 'try', - '-m', trybot['mastername'], - '-b', builder]) - - def PrepareRoll(self, ignore_checks, tbr, should_commit): - # TODO(kjellander): use os.path.normcase, os.path.join etc for all paths for - # cross platform compatibility. - - if not ignore_checks: - if self._GetCurrentBranchName() != 'master': - logging.error('Please checkout the master branch.') - return -1 - if not self._IsTreeClean(): - logging.error('Please make sure you don\'t have any modified files.') - return -1 - - # Always clean up any previous roll. - self.Abort() - - logging.debug('Pulling latest changes') - if not ignore_checks: - self._RunCommand(['git', 'pull']) - - self._RunCommand(['git', 'checkout', '-b', ROLL_BRANCH_NAME]) - - # Modify Chromium's DEPS file. - - # Parse current hashes. - deps_filename = os.path.join(self._chromium_src, 'DEPS') - deps = _ParseDepsFile(deps_filename) - swiftshader_current = self._GetDepsCommitInfo(deps, SWIFTSHADER_PATH) - - # Find ToT revisions. - swiftshader_latest = self._GetCommitInfo(SWIFTSHADER_PATH) - - if IS_WIN: - # Make sure the roll script doesn't use windows line endings - self._RunCommand(['git', 'config', 'core.autocrlf', 'true']) - - self._UpdateDep(deps_filename, SWIFTSHADER_PATH, swiftshader_latest) - - if self._IsTreeClean(): - logging.debug('Tree is clean - no changes detected.') - self._DeleteRollBranch() - else: - bugs = self._GetBugList(SWIFTSHADER_PATH, swiftshader_current, - swiftshader_latest) - description = _GenerateCLDescriptionCommand( - swiftshader_current, swiftshader_latest, bugs, tbr) - logging.debug('Committing changes locally.') - self._RunCommand(['git', 'add', '--update', '.']) - self._RunCommand(['git', 'commit'] + description) - logging.debug('Uploading changes...') - self._RunCommand(['git', 'cl', 'upload'], - extra_env={'EDITOR': 'true'}) - - # Kick off tryjobs. - base_try_cmd = ['git', 'cl', 'try'] - self._RunCommand(base_try_cmd) - - # Mark the CL to be committed if requested - if should_commit: - self._RunCommand(['git', 'cl', 'set-commit']) - - cl_info = self._GetCLInfo() - print 'Issue: %d URL: %s' % (cl_info.issue, cl_info.url) - - # Checkout master again. - self._RunCommand(['git', 'checkout', 'master']) - print 'Roll branch left as ' + ROLL_BRANCH_NAME - return 0 - - def _UpdateDep(self, deps_filename, dep_relative_to_src, commit_info): - dep_name = _PosixPath(os.path.join('src', dep_relative_to_src)) - - # roll_dep_svn.py relies on cwd being the Chromium checkout, so let's - # temporarily change the working directory and then change back. - cwd = os.getcwd() - os.chdir(os.path.dirname(deps_filename)) - roll_dep_svn.update_deps(deps_filename, dep_relative_to_src, dep_name, - commit_info.git_commit, '') - os.chdir(cwd) - - def _DeleteRollBranch(self): - self._RunCommand(['git', 'checkout', 'master']) - self._RunCommand(['git', 'branch', '-D', ROLL_BRANCH_NAME]) - logging.debug('Deleted the local roll branch (%s)', ROLL_BRANCH_NAME) - - - def _GetBranches(self): - """Returns a tuple of active,branches. - - The 'active' is the name of the currently active branch and 'branches' is a - list of all branches. - """ - lines = self._RunCommand(['git', 'branch']).split('\n') - branches = [] - active = '' - for l in lines: - if '*' in l: - # The assumption is that the first char will always be the '*'. - active = l[1:].strip() - branches.append(active) - else: - b = l.strip() - if b: - branches.append(b) - return (active, branches) - - def Abort(self): - active_branch, branches = self._GetBranches() - if active_branch == ROLL_BRANCH_NAME: - active_branch = 'master' - if ROLL_BRANCH_NAME in branches: - print 'Aborting pending roll.' - self._RunCommand(['git', 'checkout', ROLL_BRANCH_NAME]) - # Ignore an error here in case an issue wasn't created for some reason. - self._RunCommand(['git', 'cl', 'set_close'], ignore_exit_code=True) - self._RunCommand(['git', 'checkout', active_branch]) - self._RunCommand(['git', 'branch', '-D', ROLL_BRANCH_NAME]) - return 0 - - -def main(): - parser = argparse.ArgumentParser( - description='Auto-generates a CL containing a SwiftShader roll.') - parser.add_argument('--abort', - help=('Aborts a previously prepared roll. ' - 'Closes any associated issues and deletes the roll branches'), - action='store_true') - parser.add_argument('--ignore-checks', action='store_true', default=False, - help=('Skips checks for being on the master branch, dirty workspaces and ' - 'the updating of the checkout. Will still delete and create local ' - 'Git branches.')) - parser.add_argument('--tbr', help='Add a TBR to the commit message.') - parser.add_argument('--commit', action='store_true', default=False, - help='Submit the roll to the CQ after uploading.') - parser.add_argument('-v', '--verbose', action='store_true', default=False, - help='Be extra verbose in printing of log messages.') - args = parser.parse_args() - - if args.verbose: - logging.basicConfig(level=logging.DEBUG) - else: - logging.basicConfig(level=logging.ERROR) - - autoroller = AutoRoller(SRC_DIR) - if args.abort: - return autoroller.Abort() - else: - return autoroller.PrepareRoll(args.ignore_checks, args.tbr, args.commit) - -if __name__ == '__main__': - sys.exit(main())
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn index f51fbc2..7bedfd47 100644 --- a/ui/android/BUILD.gn +++ b/ui/android/BUILD.gn
@@ -379,6 +379,7 @@ "junit/src/org/chromium/ui/modaldialog/ModalDialogManagerTest.java", "junit/src/org/chromium/ui/modelutil/LazyConstructionPropertyMcpTest.java", "junit/src/org/chromium/ui/modelutil/ListModelBaseTest.java", + "junit/src/org/chromium/ui/modelutil/ModelListAdapterTest.java", "junit/src/org/chromium/ui/modelutil/PropertyListModelTest.java", "junit/src/org/chromium/ui/modelutil/PropertyModelTest.java", "junit/src/org/chromium/ui/modelutil/SimpleListObservableTest.java",
diff --git a/ui/android/java/res/values/ids.xml b/ui/android/java/res/values/ids.xml index efb2f14..4a6b138e 100644 --- a/ui/android/java/res/values/ids.xml +++ b/ui/android/java/res/values/ids.xml
@@ -6,4 +6,5 @@ <!-- Model Utils --> <item type="id" name="view_model" /> <item type="id" name="view_type" /> + <item type="id" name="view_mcp" /> </resources> \ No newline at end of file
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java b/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java index c45003d4..13eab2d 100644 --- a/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java +++ b/ui/android/java/src/org/chromium/ui/modelutil/ModelListAdapter.java
@@ -4,20 +4,18 @@ package org.chromium.ui.modelutil; -import android.content.Context; +import android.support.annotation.Nullable; import android.util.Pair; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; +import org.chromium.base.VisibleForTesting; import org.chromium.ui.R; -import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableFloatPropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableIntPropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -35,15 +33,10 @@ T buildView(); } - private final Context mContext; private final List<Pair<Integer, PropertyModel>> mModelList = new ArrayList<>(); private final SparseArray<Pair<ViewBuilder, PropertyModelChangeProcessor.ViewBinder>> mViewBuilderMap = new SparseArray<>(); - public ModelListAdapter(Context context) { - mContext = context; - } - /** * Update the visible models (list items). */ @@ -94,6 +87,15 @@ @SuppressWarnings("unchecked") @Override public View getView(int position, View convertView, ViewGroup parent) { + // 1. Destroy the old PropertyModelChangeProcessor if it exists. + if (convertView != null && convertView.getTag(R.id.view_mcp) != null) { + PropertyModelChangeProcessor propertyModelChangeProcessor = + (PropertyModelChangeProcessor) convertView.getTag(R.id.view_mcp); + propertyModelChangeProcessor.destroy(); + } + + // 2. Build a new view if needed. Otherwise, fetch the old model from the convertView. + PropertyModel oldModel = null; if (convertView == null || convertView.getTag(R.id.view_type) == null || (int) convertView.getTag(R.id.view_type) != getItemViewType(position)) { int modelTypeId = mModelList.get(position).first; @@ -104,45 +106,62 @@ // and identify what type the view is. This should allow lists that aren't necessarily // recycler views to work correctly with heterogeneous lists. convertView.setTag(R.id.view_type, modelTypeId); + } else { + oldModel = (PropertyModel) convertView.getTag(R.id.view_model); } PropertyModel model = mModelList.get(position).second; - PropertyModel viewModel = - getOrCreateModelFromExisting(convertView, mModelList.get(position)); - for (PropertyKey key : model.getAllSetProperties()) { - if (key instanceof WritableIntPropertyKey) { - WritableIntPropertyKey intKey = (WritableIntPropertyKey) key; - viewModel.set(intKey, model.get(intKey)); - } else if (key instanceof WritableBooleanPropertyKey) { - WritableBooleanPropertyKey booleanKey = (WritableBooleanPropertyKey) key; - viewModel.set(booleanKey, model.get(booleanKey)); - } else if (key instanceof WritableFloatPropertyKey) { - WritableFloatPropertyKey floatKey = (WritableFloatPropertyKey) key; - viewModel.set(floatKey, model.get(floatKey)); - } else if (key instanceof WritableObjectPropertyKey<?>) { - @SuppressWarnings({"unchecked", "rawtypes"}) - WritableObjectPropertyKey objectKey = (WritableObjectPropertyKey) key; - viewModel.set(objectKey, model.get(objectKey)); - } else { - assert false : "Unexpected key received"; - } - } + PropertyModelChangeProcessor.ViewBinder binder = + mViewBuilderMap.get(mModelList.get(position).first).second; + + // 3. Attach a PropertyModelChangeProcessor and PropertyModel to the view (for #1/2 above + // when re-using a view). + convertView.setTag(R.id.view_mcp, + PropertyModelChangeProcessor.create( + model, convertView, binder, /* performInitialBind = */ false)); + convertView.setTag(R.id.view_model, model); + + // 4. Bind properties to the convertView. + bindNewModel(model, oldModel, convertView, binder); + // TODO(tedchoc): Investigate whether this is still needed. convertView.jumpDrawablesToCurrentState(); return convertView; } - @SuppressWarnings("unchecked") - private PropertyModel getOrCreateModelFromExisting( - View view, Pair<Integer, PropertyModel> item) { - PropertyModel model = (PropertyModel) view.getTag(R.id.view_model); - if (model == null) { - model = new PropertyModel(item.second.getAllProperties()); - PropertyModelChangeProcessor.create( - model, view, mViewBuilderMap.get(item.first).second); - view.setTag(R.id.view_model, model); + /** + * Binds all set properties to the view. If oldModel is not null, binds properties that were + * previously set in the oldModel but are not set in the new model. + * + * @param newModel The new model to bind to {@code view}. + * @param oldModel The old model previously bound to {@code view}. May be null. + * @param view The view to bind. + * @param binder The ViewBinder that will bind model properties to {@code view}. + */ + @VisibleForTesting + static void bindNewModel(PropertyModel newModel, @Nullable PropertyModel oldModel, View view, + PropertyModelChangeProcessor.ViewBinder binder) { + Collection<PropertyKey> setProperties = newModel.getAllSetProperties(); + for (PropertyKey key : newModel.getAllProperties()) { + if (oldModel != null) { + // Skip binding properties that haven't changed. + if (newModel.compareValue(oldModel, key)) { + continue; + } else { + // When rebinding a view, if the value has changed it should be writable as + // views reasonably may not expect read-only keys not to change or be rebound. + assert key instanceof PropertyModel.WritableObjectPropertyKey + || key instanceof PropertyModel.WritableIntPropertyKey + || key instanceof PropertyModel.WritableBooleanPropertyKey + || key instanceof PropertyModel.WritableFloatPropertyKey; + } + } else if (!setProperties.contains(key)) { + // If there is no previous model, skip binding properties that haven't been set. + continue; + } + + binder.bind(newModel, view, key); } - return model; } }
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java index 093d3b17..4496aaf 100644 --- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java +++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModel.java
@@ -368,6 +368,26 @@ } /** + * Determines whether the value for the provided key is the same in this model and a different + * model. + * @param otherModel The other {@link PropertyModel} to check. + * @param key The {@link PropertyKey} to check. + * @return Whether this model and {@code otherModel} have the same value set for {@code key}. + */ + public boolean compareValue(PropertyModel otherModel, PropertyKey key) { + validateKey(key); + otherModel.validateKey(key); + if (!mData.containsKey(key) || !otherModel.mData.containsKey(key)) return false; + + if (key instanceof WritableObjectPropertyKey + && ((WritableObjectPropertyKey) key).mSkipEquality) { + return false; + } + + return ObjectsCompat.equals(mData.get(key), otherModel.mData.get(key)); + } + + /** * Allows constructing a new {@link PropertyModel} with read-only properties. */ public static class Builder { @@ -481,6 +501,12 @@ public String toString() { return value + " in " + super.toString(); } + + @Override + public boolean equals(Object other) { + return other != null && other instanceof FloatContainer + && ((FloatContainer) other).value == value; + } } private static class IntContainer extends ValueContainer { @@ -490,6 +516,12 @@ public String toString() { return value + " in " + super.toString(); } + + @Override + public boolean equals(Object other) { + return other != null && other instanceof IntContainer + && ((IntContainer) other).value == value; + } } private static class BooleanContainer extends ValueContainer { @@ -499,6 +531,12 @@ public String toString() { return value + " in " + super.toString(); } + + @Override + public boolean equals(Object other) { + return other != null && other instanceof BooleanContainer + && ((BooleanContainer) other).value == value; + } } private static class ObjectContainer<T> extends ValueContainer { @@ -508,5 +546,11 @@ public String toString() { return value + " in " + super.toString(); } + + @Override + public boolean equals(Object other) { + return other != null && other instanceof ObjectContainer + && ObjectsCompat.equals(((ObjectContainer) other).value, value); + } } }
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java index 69ac149f..623bc1a 100644 --- a/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java +++ b/ui/android/java/src/org/chromium/ui/modelutil/PropertyModelChangeProcessor.java
@@ -34,26 +34,45 @@ * @param model The model containing the data to be bound. * @param view The view to which data will be bound. * @param viewBinder A class that binds the model to the view. + * @param performInitialBind Whether all set model properties should be immediately bound. */ - private PropertyModelChangeProcessor(M model, V view, ViewBinder<M, V, P> viewBinder) { + private PropertyModelChangeProcessor( + M model, V view, ViewBinder<M, V, P> viewBinder, boolean performInitialBind) { mModel = model; mView = view; mViewBinder = viewBinder; - for (P property : model.getAllSetProperties()) { - onPropertyChanged(model, property); + + if (performInitialBind) { + for (P property : model.getAllSetProperties()) { + onPropertyChanged(model, property); + } } + model.addObserver(mPropertyObserver); } /** + * Creates a new PropertyModelChangeProcessor observing the given {@code model}. All set model + * properties will be bound. + * @param model The model containing the data to be bound. + * @param view The view to which data will be bound. + * @param viewBinder A class that binds the model to the view. + */ + public static <M extends PropertyObservable<P>, V, P> PropertyModelChangeProcessor<M, V, P> + create(M model, V view, ViewBinder<M, V, P> viewBinder) { + return create(model, view, viewBinder, true); + } + + /** * Creates a new PropertyModelChangeProcessor observing the given {@code model}. * @param model The model containing the data to be bound. * @param view The view to which data will be bound. * @param viewBinder A class that binds the model to the view. + * @param performInitialBind Whether all set model properties should be immediately bound. */ public static <M extends PropertyObservable<P>, V, P> PropertyModelChangeProcessor<M, V, P> - create(M model, V view, ViewBinder<M, V, P> viewBinder) { - return new PropertyModelChangeProcessor<>(model, view, viewBinder); + create(M model, V view, ViewBinder<M, V, P> viewBinder, boolean performInitialBind) { + return new PropertyModelChangeProcessor<>(model, view, viewBinder, performInitialBind); } /**
diff --git a/ui/android/junit/src/org/chromium/ui/modelutil/ModelListAdapterTest.java b/ui/android/junit/src/org/chromium/ui/modelutil/ModelListAdapterTest.java new file mode 100644 index 0000000..f57326f --- /dev/null +++ b/ui/android/junit/src/org/chromium/ui/modelutil/ModelListAdapterTest.java
@@ -0,0 +1,338 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.ui.modelutil; + +import android.text.TextUtils; +import android.util.Pair; +import android.view.View; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.ui.R; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeoutException; + +/** + * Tests to ensure/validate ModelListAdapter behavior. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class ModelListAdapterTest { + private static final Integer VIEW_TYPE_1 = 0; + private static final Integer VIEW_TYPE_2 = 1; + + private static final PropertyModel.WritableBooleanPropertyKey BOOLEAN_PROPERTY = + new PropertyModel.WritableBooleanPropertyKey(); + private static final PropertyModel.WritableFloatPropertyKey FLOAT_PROPERTY = + new PropertyModel.WritableFloatPropertyKey(); + private static final PropertyModel.WritableIntPropertyKey INT_PROPERTY = + new PropertyModel.WritableIntPropertyKey(); + private static final PropertyModel.WritableObjectPropertyKey OBJECT_PROPERTY = + new PropertyModel.WritableObjectPropertyKey(); + private static final PropertyModel.ReadableBooleanPropertyKey READONLY_BOOLEAN_PROPERTY = + new PropertyModel.ReadableBooleanPropertyKey(); + + private class TestViewBinder implements PropertyModelChangeProcessor.ViewBinder { + @Override + public void bind(Object model, Object view, Object propertyKey) { + if (propertyKey.equals(BOOLEAN_PROPERTY)) { + mBindBooleanCallbackHelper.notifyCalled(); + } else if (propertyKey.equals(FLOAT_PROPERTY)) { + mBindFloatCallbackHelper.notifyCalled(); + } else if (propertyKey.equals(INT_PROPERTY)) { + mBindIntCallbackHelper.notifyCalled(); + } else if (propertyKey.equals(OBJECT_PROPERTY)) { + mBindObjectCallbackHelper.notifyCalled(); + } + } + } + + private class TestViewBuilder implements ModelListAdapter.ViewBuilder<View> { + @Override + public View buildView() { + return new View(RuntimeEnvironment.application); + } + } + + private class TestObject { + private String mId; + public TestObject(String id) { + mId = id; + } + + @Override + public boolean equals(Object other) { + return other == this + || (other != null && other instanceof TestObject + && TextUtils.equals(((TestObject) other).mId, mId)); + } + } + + private PropertyModel mModel; + private ModelListAdapter mModelListAdapter; + private final CallbackHelper mBindBooleanCallbackHelper = new CallbackHelper(); + private final CallbackHelper mBindFloatCallbackHelper = new CallbackHelper(); + private final CallbackHelper mBindIntCallbackHelper = new CallbackHelper(); + private final CallbackHelper mBindObjectCallbackHelper = new CallbackHelper(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mModelListAdapter = new ModelListAdapter(); + mModelListAdapter.registerType(VIEW_TYPE_1, new TestViewBuilder(), new TestViewBinder()); + mModelListAdapter.registerType(VIEW_TYPE_2, new TestViewBuilder(), new TestViewBinder()); + + mModel = new PropertyModel(BOOLEAN_PROPERTY, FLOAT_PROPERTY, INT_PROPERTY, OBJECT_PROPERTY); + + List<Pair<Integer, PropertyModel>> testData = new ArrayList<>(); + testData.add(new Pair(VIEW_TYPE_1, mModel)); + + mModelListAdapter.updateModels(testData); + } + + @Test + public void testNullConvertView() throws TimeoutException, InterruptedException { + // Set a property to test that it gets bound. + mModel.set(BOOLEAN_PROPERTY, true); + + View view = mModelListAdapter.getView(0, null, null); + + mBindBooleanCallbackHelper.waitForCallback(0); + + Assert.assertEquals("Incorrect view type", VIEW_TYPE_1, view.getTag(R.id.view_type)); + Assert.assertEquals("Incorrect model", mModel, view.getTag(R.id.view_model)); + Assert.assertNotNull("MCP not set", view.getTag(R.id.view_mcp)); + + // Check that the MCP is hooked up. + mModel.set(BOOLEAN_PROPERTY, false); + mBindBooleanCallbackHelper.waitForCallback(1); + } + + @Test + public void testNullTypeConvertView() throws TimeoutException, InterruptedException { + // Set a property to test that it gets bound. + mModel.set(BOOLEAN_PROPERTY, true); + + View nullTypeView = new View(RuntimeEnvironment.application); + View view = mModelListAdapter.getView(0, nullTypeView, null); + + mBindBooleanCallbackHelper.waitForCallback(0); + Assert.assertEquals("Incorrect view type", VIEW_TYPE_1, view.getTag(R.id.view_type)); + Assert.assertNotEquals("nullTypeView incorrectly reused", nullTypeView, view); + } + + @Test + public void testSameTypeConvertView_SameProperties() + throws TimeoutException, InterruptedException { + // Construct a test model for the convertView. + PropertyModel convertViewModel = + new PropertyModel(BOOLEAN_PROPERTY, FLOAT_PROPERTY, INT_PROPERTY, OBJECT_PROPERTY); + + // Set a property to the same value for both models. + convertViewModel.set(BOOLEAN_PROPERTY, true); + mModel.set(BOOLEAN_PROPERTY, true); + + // Set up a convertView with the same type, the test model, and a test MCP. + View convertView = new View(RuntimeEnvironment.application); + PropertyModelChangeProcessor convertViewMcp = + Mockito.spy(PropertyModelChangeProcessor.create( + convertViewModel, convertView, new TestViewBinder(), false)); + convertView.setTag(R.id.view_type, VIEW_TYPE_1); + convertView.setTag(R.id.view_model, convertViewModel); + convertView.setTag(R.id.view_mcp, convertViewMcp); + + View view = mModelListAdapter.getView(0, convertView, null); + + Assert.assertEquals("Incorrect callback count for boolean property", 0, + mBindBooleanCallbackHelper.getCallCount()); + Assert.assertEquals("convertView not reused", convertView, view); + Assert.assertEquals("Incorrect view type", VIEW_TYPE_1, view.getTag(R.id.view_type)); + Assert.assertEquals("Incorrect model", mModel, view.getTag(R.id.view_model)); + Assert.assertNotNull("MCP not set", view.getTag(R.id.view_mcp)); + Assert.assertNotEquals( + "MCP not properly switched", convertViewMcp, view.getTag(R.id.view_mcp)); + Mockito.verify(convertViewMcp).destroy(); + + // Set a property on the new view's model and assert the ViewBinder is invoked. + mModel.set(BOOLEAN_PROPERTY, false); + mBindBooleanCallbackHelper.waitForCallback(0); + Assert.assertEquals("Incorrect callback count for boolean property", 1, + mBindBooleanCallbackHelper.getCallCount()); + + // Set a property on the convertView's model and assert the ViewBinder is not invoked. + convertViewModel.set(BOOLEAN_PROPERTY, true); + Assert.assertEquals("Incorrect callback count for boolean property", 1, + mBindBooleanCallbackHelper.getCallCount()); + } + + @Test + public void testSameTypeConvertView_DifferentProperties() + throws TimeoutException, InterruptedException { + // Construct a test model for the convertView. + PropertyModel convertViewModel = + new PropertyModel(BOOLEAN_PROPERTY, FLOAT_PROPERTY, INT_PROPERTY, OBJECT_PROPERTY); + + // Set a property to a different value for each model. + convertViewModel.set(BOOLEAN_PROPERTY, true); + mModel.set(BOOLEAN_PROPERTY, false); + + View convertView = new View(RuntimeEnvironment.application); + convertView.setTag(R.id.view_type, VIEW_TYPE_1); + convertView.setTag(R.id.view_model, convertViewModel); + + View view = mModelListAdapter.getView(0, convertView, null); + + mBindBooleanCallbackHelper.waitForCallback(0); + Assert.assertEquals("convertView not reused", convertView, view); + } + + @Test + public void testDifferentTypeConvertView() throws TimeoutException, InterruptedException { + // Construct a test model for the convertView. + PropertyModel convertViewModel = + new PropertyModel(BOOLEAN_PROPERTY, FLOAT_PROPERTY, INT_PROPERTY, OBJECT_PROPERTY); + + // Set a property to the same value for each model. + convertViewModel.set(BOOLEAN_PROPERTY, true); + mModel.set(BOOLEAN_PROPERTY, true); + + View convertView = new View(RuntimeEnvironment.application); + convertView.setTag(R.id.view_type, VIEW_TYPE_2); + convertView.setTag(R.id.view_model, convertViewModel); + + View view = mModelListAdapter.getView(0, convertView, null); + + mBindBooleanCallbackHelper.waitForCallback(0); + Assert.assertEquals("Incorrect view type", VIEW_TYPE_1, view.getTag(R.id.view_type)); + Assert.assertNotEquals("convertView incorrectly reused", convertView, view); + } + + @Test + public void testBindNewModel_NullOldModel_SetPropertyValues() + throws TimeoutException, InterruptedException { + mModel.set(BOOLEAN_PROPERTY, true); + mModel.set(FLOAT_PROPERTY, 1.2f); + mModel.set(INT_PROPERTY, 3); + mModel.set(OBJECT_PROPERTY, new TestObject("Test")); + + ModelListAdapter.bindNewModel( + mModel, null, new View(RuntimeEnvironment.application), new TestViewBinder()); + + mBindBooleanCallbackHelper.waitForCallback(0); + mBindFloatCallbackHelper.waitForCallback(0); + mBindIntCallbackHelper.waitForCallback(0); + mBindObjectCallbackHelper.waitForCallback(0); + } + + @Test + public void testBindNewModel_NullOldModel_UnsetPropertyValues() { + ModelListAdapter.bindNewModel( + mModel, null, new View(RuntimeEnvironment.application), new TestViewBinder()); + + Assert.assertEquals("Incorrect callback count for boolean property", 0, + mBindBooleanCallbackHelper.getCallCount()); + Assert.assertEquals("Incorrect callback count for float property", 0, + mBindFloatCallbackHelper.getCallCount()); + Assert.assertEquals("Incorrect callback count for int property", 0, + mBindIntCallbackHelper.getCallCount()); + Assert.assertEquals("Incorrect callback count for object property", 0, + mBindObjectCallbackHelper.getCallCount()); + } + + @Test + public void testBindNewModel_NonNullOldModel_SamePropertyValues() { + PropertyModel oldModel = + new PropertyModel(BOOLEAN_PROPERTY, FLOAT_PROPERTY, INT_PROPERTY, OBJECT_PROPERTY); + + oldModel.set(BOOLEAN_PROPERTY, true); + mModel.set(BOOLEAN_PROPERTY, true); + oldModel.set(FLOAT_PROPERTY, 1.2f); + mModel.set(FLOAT_PROPERTY, 1.2f); + oldModel.set(INT_PROPERTY, 3); + mModel.set(INT_PROPERTY, 3); + oldModel.set(OBJECT_PROPERTY, new TestObject("Test")); + mModel.set(OBJECT_PROPERTY, new TestObject("Test")); + + ModelListAdapter.bindNewModel( + mModel, oldModel, new View(RuntimeEnvironment.application), new TestViewBinder()); + + Assert.assertEquals("Incorrect callback count for boolean property", 0, + mBindBooleanCallbackHelper.getCallCount()); + Assert.assertEquals("Incorrect callback count for float property", 0, + mBindFloatCallbackHelper.getCallCount()); + Assert.assertEquals("Incorrect callback count for int property", 0, + mBindIntCallbackHelper.getCallCount()); + Assert.assertEquals("Incorrect callback count for object property", 0, + mBindObjectCallbackHelper.getCallCount()); + } + + @Test + public void testBindNewModel_NonNullOldModel_DifferentPropertyValues() + throws TimeoutException, InterruptedException { + PropertyModel oldModel = + new PropertyModel(BOOLEAN_PROPERTY, FLOAT_PROPERTY, INT_PROPERTY, OBJECT_PROPERTY); + + oldModel.set(BOOLEAN_PROPERTY, true); + mModel.set(BOOLEAN_PROPERTY, false); + oldModel.set(FLOAT_PROPERTY, 1.2f); + mModel.set(FLOAT_PROPERTY, 1.21f); + oldModel.set(INT_PROPERTY, 3); + mModel.set(INT_PROPERTY, 4); + oldModel.set(OBJECT_PROPERTY, new TestObject("Test")); + mModel.set(OBJECT_PROPERTY, new TestObject("Test1")); + + ModelListAdapter.bindNewModel( + mModel, oldModel, new View(RuntimeEnvironment.application), new TestViewBinder()); + + mBindBooleanCallbackHelper.waitForCallback(0); + mBindFloatCallbackHelper.waitForCallback(0); + mBindIntCallbackHelper.waitForCallback(0); + mBindObjectCallbackHelper.waitForCallback(0); + } + + @Test + public void testBindNewModel_NonNullOldModel_UnsetPropertyValues() + throws TimeoutException, InterruptedException { + PropertyModel oldModel = + new PropertyModel(BOOLEAN_PROPERTY, FLOAT_PROPERTY, INT_PROPERTY, OBJECT_PROPERTY); + + oldModel.set(BOOLEAN_PROPERTY, true); + oldModel.set(FLOAT_PROPERTY, 1.2f); + oldModel.set(INT_PROPERTY, 3); + oldModel.set(OBJECT_PROPERTY, new TestObject("Test")); + + ModelListAdapter.bindNewModel( + mModel, oldModel, new View(RuntimeEnvironment.application), new TestViewBinder()); + + mBindBooleanCallbackHelper.waitForCallback(0); + mBindFloatCallbackHelper.waitForCallback(0); + mBindIntCallbackHelper.waitForCallback(0); + mBindObjectCallbackHelper.waitForCallback(0); + } + + @Test(expected = AssertionError.class) + public void testBindNewModel_RewriteReadOnlyProperty() { + PropertyModel oldModel = new PropertyModel.Builder(READONLY_BOOLEAN_PROPERTY) + .with(READONLY_BOOLEAN_PROPERTY, false) + .build(); + PropertyModel newModel = new PropertyModel.Builder(READONLY_BOOLEAN_PROPERTY) + .with(READONLY_BOOLEAN_PROPERTY, true) + .build(); + ModelListAdapter.bindNewModel( + newModel, oldModel, new View(RuntimeEnvironment.application), new TestViewBinder()); + } +}
diff --git a/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java b/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java index 4f68cf4..9c7b127 100644 --- a/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java +++ b/ui/android/junit/src/org/chromium/ui/modelutil/PropertyModelTest.java
@@ -9,6 +9,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.mockito.Mockito.verify; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -54,6 +55,8 @@ new WritableObjectPropertyKey<>(); public static WritableObjectPropertyKey<List<Integer>> OBJECT_PROPERTY_C = new WritableObjectPropertyKey<>(); + public static WritableObjectPropertyKey<Object> OBJECT_PROPERTY_SKIP_EQUALITY = + new WritableObjectPropertyKey<>(true); @Test public void getAllSetProperties() { @@ -216,4 +219,106 @@ public void preventsDuplicateKeys() { new PropertyModel(BOOLEAN_PROPERTY_A, BOOLEAN_PROPERTY_A); } + + @Test + public void testCompareValue_Boolean() { + PropertyModel model1 = + new PropertyModel(BOOLEAN_PROPERTY_A, BOOLEAN_PROPERTY_B, BOOLEAN_PROPERTY_C); + model1.set(BOOLEAN_PROPERTY_A, true); + model1.set(BOOLEAN_PROPERTY_B, true); + model1.set(BOOLEAN_PROPERTY_C, false); + + PropertyModel model2 = + new PropertyModel(BOOLEAN_PROPERTY_A, BOOLEAN_PROPERTY_B, BOOLEAN_PROPERTY_C); + model2.set(BOOLEAN_PROPERTY_A, true); + model2.set(BOOLEAN_PROPERTY_B, false); + + Assert.assertTrue("BOOLEAN_PROPERTY_A should be equal", + model1.compareValue(model2, BOOLEAN_PROPERTY_A)); + Assert.assertFalse("BOOLEAN_PROPERTY_B should not be equal", + model1.compareValue(model2, BOOLEAN_PROPERTY_B)); + Assert.assertFalse("BOOLEAN_PROPERTY_C should not be equal", + model1.compareValue(model2, BOOLEAN_PROPERTY_C)); + } + + @Test + public void testCompareValue_Integer() { + PropertyModel model1 = new PropertyModel(INT_PROPERTY_A, INT_PROPERTY_B, INT_PROPERTY_C); + model1.set(INT_PROPERTY_A, 1); + model1.set(INT_PROPERTY_B, 2); + model1.set(INT_PROPERTY_C, 3); + + PropertyModel model2 = new PropertyModel(INT_PROPERTY_A, INT_PROPERTY_B, INT_PROPERTY_C); + model2.set(INT_PROPERTY_A, 1); + model2.set(INT_PROPERTY_B, 3); + + Assert.assertTrue( + "INT_PROPERTY_A should be equal", model1.compareValue(model2, INT_PROPERTY_A)); + Assert.assertFalse( + "INT_PROPERTY_B should not be equal", model1.compareValue(model2, INT_PROPERTY_B)); + Assert.assertFalse( + "INT_PROPERTY_C should not be equal", model1.compareValue(model2, INT_PROPERTY_C)); + } + + @Test + public void testCompareValue_Float() { + PropertyModel model1 = + new PropertyModel(FLOAT_PROPERTY_A, FLOAT_PROPERTY_B, FLOAT_PROPERTY_C); + model1.set(FLOAT_PROPERTY_A, 1.2f); + model1.set(FLOAT_PROPERTY_B, 2.2f); + model1.set(FLOAT_PROPERTY_C, 3.2f); + + PropertyModel model2 = + new PropertyModel(FLOAT_PROPERTY_A, FLOAT_PROPERTY_B, FLOAT_PROPERTY_C); + model2.set(FLOAT_PROPERTY_A, 1.2f); + model2.set(FLOAT_PROPERTY_B, 3.2f); + + Assert.assertTrue( + "FLOAT_PROPERTY_A should be equal", model1.compareValue(model2, FLOAT_PROPERTY_A)); + Assert.assertFalse("FLOAT_PROPERTY_B should not be equal", + model1.compareValue(model2, FLOAT_PROPERTY_B)); + Assert.assertFalse("FLOAT_PROPERTY_C should not be equal", + model1.compareValue(model2, FLOAT_PROPERTY_C)); + } + + @Test + public void testCompareValue_Object() { + Object sharedObject = new Object(); + + PropertyModel model1 = + new PropertyModel(OBJECT_PROPERTY_A, OBJECT_PROPERTY_B, OBJECT_PROPERTY_C); + model1.set(OBJECT_PROPERTY_A, sharedObject); + model1.set(OBJECT_PROPERTY_B, "Test"); + model1.set(OBJECT_PROPERTY_C, new ArrayList<>()); + + PropertyModel model2 = + new PropertyModel(OBJECT_PROPERTY_A, OBJECT_PROPERTY_B, OBJECT_PROPERTY_C); + model2.set(OBJECT_PROPERTY_A, sharedObject); + model2.set(OBJECT_PROPERTY_B, "Test"); + + Assert.assertTrue("OBJECT_PROPERTY_A should be equal", + model1.compareValue(model2, OBJECT_PROPERTY_A)); + Assert.assertTrue("OBJECT_PROPERTY_B should be equal", + model1.compareValue(model2, OBJECT_PROPERTY_B)); + Assert.assertFalse("OBJECT_PROPERTY_C should not be equal", + model1.compareValue(model2, OBJECT_PROPERTY_C)); + + model2.set(OBJECT_PROPERTY_B, "Test2"); + Assert.assertFalse("OBJECT_PROPERTY_B should not be equal", + model1.compareValue(model2, OBJECT_PROPERTY_B)); + } + + @Test + public void testCompareValue_Object_SkipEquality() { + Object sharedObject = new Object(); + + PropertyModel model1 = new PropertyModel(OBJECT_PROPERTY_SKIP_EQUALITY); + model1.set(OBJECT_PROPERTY_SKIP_EQUALITY, sharedObject); + + PropertyModel model2 = new PropertyModel(OBJECT_PROPERTY_SKIP_EQUALITY); + model2.set(OBJECT_PROPERTY_SKIP_EQUALITY, sharedObject); + + Assert.assertFalse("OBJECT_PROPERTY_A should not be equal", + model1.compareValue(model2, OBJECT_PROPERTY_SKIP_EQUALITY)); + } }
diff --git a/ui/base/accelerators/global_media_keys_listener_win.h b/ui/base/accelerators/global_media_keys_listener_win.h index 4b95a20..8de4946 100644 --- a/ui/base/accelerators/global_media_keys_listener_win.h +++ b/ui/base/accelerators/global_media_keys_listener_win.h
@@ -32,6 +32,7 @@ // MediaKeysListener implementation. bool StartWatchingMediaKey(KeyboardCode key_code) override; void StopWatchingMediaKey(KeyboardCode key_code) override; + void SetIsMediaPlaying(bool is_playing) override {} private: // Called by SingletonHwndObserver.
diff --git a/ui/base/accelerators/media_keys_listener.h b/ui/base/accelerators/media_keys_listener.h index 9072523c..997718d 100644 --- a/ui/base/accelerators/media_keys_listener.h +++ b/ui/base/accelerators/media_keys_listener.h
@@ -49,6 +49,13 @@ virtual bool StartWatchingMediaKey(KeyboardCode key_code) = 0; // Stop listening for a given media key. virtual void StopWatchingMediaKey(KeyboardCode key_code) = 0; + + // Informs the listener whether or not media is currently playing. In some + // implementations this will prevent us from calling PlayPause unnecessarily. + // TODO(https://crbug.com/974035): Once the MediaKeysListenerManager has been + // refactored to work with system media controls this should no longer be + // needed and should be deleted. + virtual void SetIsMediaPlaying(bool is_playing) = 0; }; } // namespace ui
diff --git a/ui/base/accelerators/media_keys_listener_mac.mm b/ui/base/accelerators/media_keys_listener_mac.mm index 71b417ee..f4e3126 100644 --- a/ui/base/accelerators/media_keys_listener_mac.mm +++ b/ui/base/accelerators/media_keys_listener_mac.mm
@@ -46,6 +46,7 @@ // MediaKeysListener: bool StartWatchingMediaKey(KeyboardCode key_code) override; void StopWatchingMediaKey(KeyboardCode key_code) override; + void SetIsMediaPlaying(bool is_playing) override {} private: // Callback on media key event.
diff --git a/ui/base/accelerators/mpris_media_keys_listener.cc b/ui/base/accelerators/mpris_media_keys_listener.cc index 7edd491..81653849 100644 --- a/ui/base/accelerators/mpris_media_keys_listener.cc +++ b/ui/base/accelerators/mpris_media_keys_listener.cc
@@ -88,6 +88,10 @@ } } +void MprisMediaKeysListener::SetIsMediaPlaying(bool is_playing) { + is_media_playing_ = is_playing; +} + void MprisMediaKeysListener::OnNext() { MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK); } @@ -97,7 +101,8 @@ } void MprisMediaKeysListener::OnPause() { - MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); + if (is_media_playing_) + MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); } void MprisMediaKeysListener::OnPlayPause() { @@ -109,7 +114,8 @@ } void MprisMediaKeysListener::OnPlay() { - MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); + if (!is_media_playing_) + MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); } void MprisMediaKeysListener::MaybeSendKeyCode(KeyboardCode key_code) {
diff --git a/ui/base/accelerators/mpris_media_keys_listener.h b/ui/base/accelerators/mpris_media_keys_listener.h index 166b249..ff95808 100644 --- a/ui/base/accelerators/mpris_media_keys_listener.h +++ b/ui/base/accelerators/mpris_media_keys_listener.h
@@ -35,6 +35,7 @@ // MediaKeysListener implementation. bool StartWatchingMediaKey(KeyboardCode key_code) override; void StopWatchingMediaKey(KeyboardCode key_code) override; + void SetIsMediaPlaying(bool is_playing) override; // mpris::MprisServiceObserver implementation. void OnNext() override; @@ -57,6 +58,7 @@ MediaKeysListener::Delegate* delegate_; base::flat_set<KeyboardCode> key_codes_; mpris::MprisService* service_ = nullptr; + bool is_media_playing_ = false; DISALLOW_COPY_AND_ASSIGN(MprisMediaKeysListener); };
diff --git a/ui/base/accelerators/mpris_media_keys_listener_unittest.cc b/ui/base/accelerators/mpris_media_keys_listener_unittest.cc index 29b570e..5f4eb42 100644 --- a/ui/base/accelerators/mpris_media_keys_listener_unittest.cc +++ b/ui/base/accelerators/mpris_media_keys_listener_unittest.cc
@@ -118,4 +118,32 @@ listener()->OnPrevious(); } +TEST_F(MprisMediaKeysListenerTest, DoesNotFirePlayPauseOnPauseEventWhenPaused) { + // Should be set to true when we start listening for the key. + EXPECT_CALL(mock_mpris_service(), SetCanPlay(true)); + EXPECT_CALL(mock_mpris_service(), SetCanPause(true)); + EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0); + + listener()->Initialize(); + listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE); + listener()->SetIsMediaPlaying(false); + + // Simulate media key press. + listener()->OnPause(); +} + +TEST_F(MprisMediaKeysListenerTest, DoesNotFirePlayPauseOnPlayEventWhenPlaying) { + // Should be set to true when we start listening for the key. + EXPECT_CALL(mock_mpris_service(), SetCanPlay(true)); + EXPECT_CALL(mock_mpris_service(), SetCanPause(true)); + EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0); + + listener()->Initialize(); + listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE); + listener()->SetIsMediaPlaying(true); + + // Simulate media key press. + listener()->OnPlay(); +} + } // namespace ui
diff --git a/ui/base/accelerators/remote_command_media_keys_listener_mac.h b/ui/base/accelerators/remote_command_media_keys_listener_mac.h index e077175..192c921 100644 --- a/ui/base/accelerators/remote_command_media_keys_listener_mac.h +++ b/ui/base/accelerators/remote_command_media_keys_listener_mac.h
@@ -37,6 +37,7 @@ // MediaKeysListener implementation. bool StartWatchingMediaKey(KeyboardCode key_code) override; void StopWatchingMediaKey(KeyboardCode key_code) override; + void SetIsMediaPlaying(bool is_playing) override; // now_playing::RemoteCommandCenterDelegateObserver implementation. void OnNext() override; @@ -61,6 +62,7 @@ base::flat_set<KeyboardCode> key_codes_; now_playing::RemoteCommandCenterDelegate* remote_command_center_delegate_ = nullptr; + bool is_media_playing_ = false; DISALLOW_COPY_AND_ASSIGN(RemoteCommandMediaKeysListenerMac); };
diff --git a/ui/base/accelerators/remote_command_media_keys_listener_mac.mm b/ui/base/accelerators/remote_command_media_keys_listener_mac.mm index ddcc5442..0f7265d6 100644 --- a/ui/base/accelerators/remote_command_media_keys_listener_mac.mm +++ b/ui/base/accelerators/remote_command_media_keys_listener_mac.mm
@@ -91,6 +91,10 @@ } } +void RemoteCommandMediaKeysListenerMac::SetIsMediaPlaying(bool is_playing) { + is_media_playing_ = is_playing; +} + void RemoteCommandMediaKeysListenerMac::OnNext() { MaybeSend(VKEY_MEDIA_NEXT_TRACK); } @@ -100,7 +104,8 @@ } void RemoteCommandMediaKeysListenerMac::OnPause() { - MaybeSend(VKEY_MEDIA_PLAY_PAUSE); + if (is_media_playing_) + MaybeSend(VKEY_MEDIA_PLAY_PAUSE); } void RemoteCommandMediaKeysListenerMac::OnPlayPause() { @@ -112,7 +117,8 @@ } void RemoteCommandMediaKeysListenerMac::OnPlay() { - MaybeSend(VKEY_MEDIA_PLAY_PAUSE); + if (!is_media_playing_) + MaybeSend(VKEY_MEDIA_PLAY_PAUSE); } void RemoteCommandMediaKeysListenerMac::MaybeSend(KeyboardCode key_code) {
diff --git a/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm b/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm index 123b3f00..c5860602 100644 --- a/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm +++ b/ui/base/accelerators/remote_command_media_keys_listener_mac_unittest.mm
@@ -118,4 +118,50 @@ } } +TEST_F(RemoteCommandMediaKeysListenerMacTest, + DoesNotFirePlayPauseOnPauseEventWhenPaused) { + if (@available(macOS 10.12.2, *)) { + now_playing::MockRemoteCommandCenterDelegate rcc_delegate; + MockMediaKeysListenerDelegate delegate; + RemoteCommandMediaKeysListenerMac listener(&delegate); + listener.SetRemoteCommandCenterDelegateForTesting(&rcc_delegate); + + EXPECT_CALL(rcc_delegate, AddObserver(&listener)); + EXPECT_CALL(rcc_delegate, SetCanPlayPause(true)); + EXPECT_CALL(rcc_delegate, SetCanPlay(true)); + EXPECT_CALL(rcc_delegate, SetCanPause(true)); + EXPECT_CALL(delegate, OnMediaKeysAccelerator(_)).Times(0); + + listener.Initialize(); + listener.StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE); + listener.SetIsMediaPlaying(false); + + // Simulate media key press. + listener.OnPause(); + } +} + +TEST_F(RemoteCommandMediaKeysListenerMacTest, + DoesNotFirePlayPauseOnPlayEventWhenPlaying) { + if (@available(macOS 10.12.2, *)) { + now_playing::MockRemoteCommandCenterDelegate rcc_delegate; + MockMediaKeysListenerDelegate delegate; + RemoteCommandMediaKeysListenerMac listener(&delegate); + listener.SetRemoteCommandCenterDelegateForTesting(&rcc_delegate); + + EXPECT_CALL(rcc_delegate, AddObserver(&listener)); + EXPECT_CALL(rcc_delegate, SetCanPlayPause(true)); + EXPECT_CALL(rcc_delegate, SetCanPlay(true)); + EXPECT_CALL(rcc_delegate, SetCanPause(true)); + EXPECT_CALL(delegate, OnMediaKeysAccelerator(_)).Times(0); + + listener.Initialize(); + listener.StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE); + listener.SetIsMediaPlaying(true); + + // Simulate media key press. + listener.OnPlay(); + } +} + } // namespace ui
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener.cc b/ui/base/accelerators/system_media_controls_media_keys_listener.cc index a07e0eb..f4de72a 100644 --- a/ui/base/accelerators/system_media_controls_media_keys_listener.cc +++ b/ui/base/accelerators/system_media_controls_media_keys_listener.cc
@@ -104,6 +104,10 @@ } } +void SystemMediaControlsMediaKeysListener::SetIsMediaPlaying(bool is_playing) { + is_media_playing_ = is_playing; +} + void SystemMediaControlsMediaKeysListener::OnNext() { MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK); } @@ -113,7 +117,8 @@ } void SystemMediaControlsMediaKeysListener::OnPause() { - MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); + if (is_media_playing_) + MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); } void SystemMediaControlsMediaKeysListener::OnStop() { @@ -121,7 +126,8 @@ } void SystemMediaControlsMediaKeysListener::OnPlay() { - MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); + if (!is_media_playing_) + MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE); } void SystemMediaControlsMediaKeysListener::MaybeSendKeyCode(
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener.h b/ui/base/accelerators/system_media_controls_media_keys_listener.h index c900d841..1bc133b7 100644 --- a/ui/base/accelerators/system_media_controls_media_keys_listener.h +++ b/ui/base/accelerators/system_media_controls_media_keys_listener.h
@@ -35,6 +35,7 @@ // MediaKeysListener implementation. bool StartWatchingMediaKey(KeyboardCode key_code) override; void StopWatchingMediaKey(KeyboardCode key_code) override; + void SetIsMediaPlaying(bool is_playing) override; // system_media_controls::SystemMediaControlsServiceObserver implementation. void OnNext() override; @@ -61,6 +62,8 @@ system_media_controls::SystemMediaControlsService* service_ = nullptr; + bool is_media_playing_ = false; + DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsMediaKeysListener); };
diff --git a/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc b/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc index b07c9a59..f4d20b0 100644 --- a/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc +++ b/ui/base/accelerators/system_media_controls_media_keys_listener_unittest.cc
@@ -132,4 +132,36 @@ listener()->OnPrevious(); } +TEST_F(SystemMediaControlsMediaKeysListenerTest, + DoesNotFirePlayPauseOnPauseEventWhenPaused) { + // Should be set to true when we start listening for the key. + EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true)); + EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true)); + + EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0); + + ASSERT_TRUE(listener()->Initialize()); + listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE); + listener()->SetIsMediaPlaying(false); + + // Simulate media key press. + listener()->OnPause(); +} + +TEST_F(SystemMediaControlsMediaKeysListenerTest, + DoesNotFirePlayPauseOnPlayEventWhenPlaying) { + // Should be set to true when we start listening for the key. + EXPECT_CALL(mock_system_media_controls_service(), SetIsPlayEnabled(true)); + EXPECT_CALL(mock_system_media_controls_service(), SetIsPauseEnabled(true)); + + EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0); + + ASSERT_TRUE(listener()->Initialize()); + listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE); + listener()->SetIsMediaPlaying(true); + + // Simulate media key press. + listener()->OnPlay(); +} + } // namespace ui
diff --git a/ui/base/clipboard/clipboard_format_type.h b/ui/base/clipboard/clipboard_format_type.h index 07d8e08..98c06de 100644 --- a/ui/base/clipboard/clipboard_format_type.h +++ b/ui/base/clipboard/clipboard_format_type.h
@@ -26,6 +26,7 @@ namespace ui { // Platform neutral holder for native data representation of a clipboard type. +// Copyable and assignable, since this is an opaque value type. struct COMPONENT_EXPORT(BASE_CLIPBOARD_TYPES) ClipboardFormatType { ClipboardFormatType(); ~ClipboardFormatType(); @@ -93,7 +94,7 @@ friend struct ClipboardFormatType; // Platform-specific glue used internally by the ClipboardFormatType struct. - // Each platform should define,at least one of each of the following: + // Each platform should define at least one of each of the following: // 1. A constructor that wraps that native clipboard format descriptor. // 2. An accessor to retrieve the wrapped descriptor. // 3. A data member to hold the wrapped descriptor. @@ -125,8 +126,6 @@ #else #error No ClipboardFormatType definition. #endif - - // Copyable and assignable, since this is essentially an opaque value type. }; } // namespace ui
diff --git a/ui/base/clipboard/clipboard_format_type_win.cc b/ui/base/clipboard/clipboard_format_type_win.cc index 5d300923..e5210b9e3 100644 --- a/ui/base/clipboard/clipboard_format_type_win.cc +++ b/ui/base/clipboard/clipboard_format_type_win.cc
@@ -56,7 +56,7 @@ return data_.cfFormat == other.data_.cfFormat; } -// Various predefined ClipboardFormatTypes. +// Predefined ClipboardFormatTypes. // static ClipboardFormatType ClipboardFormatType::GetType( @@ -207,9 +207,6 @@ LONG index) { auto& index_to_type_map = GetFileContentTypeMap(); - // Use base::WrapUnique instead of std::make_unique here since - // ClipboardFormatType constructor is private. See - // https://chromium.googlesource.com/chromium/src/+/HEAD/styleguide/c++/c++-dos-and-donts.md. auto insert_or_assign_result = index_to_type_map.insert( {index, ClipboardFormatType(::RegisterClipboardFormat(CFSTR_FILECONTENTS), index,
diff --git a/ui/base/clipboard/clipboard_types.h b/ui/base/clipboard/clipboard_types.h index 8929d92..dc12e88 100644 --- a/ui/base/clipboard/clipboard_types.h +++ b/ui/base/clipboard/clipboard_types.h
@@ -7,13 +7,11 @@ namespace ui { -// This type designates which clipboard the action should be applied to. -// Only platforms that use the X Window System support the selection buffer. -// Drag type is only supported on Mac OS X. +// |ClipboardType| designates which clipboard the action should be applied to. enum ClipboardType { CLIPBOARD_TYPE_COPY_PASTE, - CLIPBOARD_TYPE_SELECTION, - CLIPBOARD_TYPE_DRAG, + CLIPBOARD_TYPE_SELECTION, // Only supported on systems running X11. + CLIPBOARD_TYPE_DRAG, // Only supported on Mac OS X. CLIPBOARD_TYPE_LAST = CLIPBOARD_TYPE_DRAG };
diff --git a/ui/base/clipboard/clipboard_util_win.h b/ui/base/clipboard/clipboard_util_win.h index bfcea85c..0a02c28 100644 --- a/ui/base/clipboard/clipboard_util_win.h +++ b/ui/base/clipboard/clipboard_util_win.h
@@ -1,8 +1,6 @@ // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// -// Some helper functions for working with the clipboard and IDataObjects. #ifndef UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_WIN_H_ #define UI_BASE_CLIPBOARD_CLIPBOARD_UTIL_WIN_H_ @@ -22,6 +20,7 @@ namespace ui { +// Contains helper functions for working with the clipboard and IDataObjects. class COMPONENT_EXPORT(BASE_CLIPBOARD) ClipboardUtil { public: /////////////////////////////////////////////////////////////////////////////
diff --git a/ui/base/clipboard/custom_data_helper.h b/ui/base/clipboard/custom_data_helper.h index 7d980f0..fc1bf96 100644 --- a/ui/base/clipboard/custom_data_helper.h +++ b/ui/base/clipboard/custom_data_helper.h
@@ -1,11 +1,6 @@ // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// -// Due to restrictions of most operating systems, we don't directly map each -// type of custom data to a native data transfer type. Instead, we serialize -// each key-value pair into the pickle as a pair of string objects, and then -// write the binary data in the pickle to the native data transfer object. #ifndef UI_BASE_CLIPBOARD_CUSTOM_DATA_HELPER_H_ #define UI_BASE_CLIPBOARD_CUSTOM_DATA_HELPER_H_ @@ -20,6 +15,10 @@ #include "base/strings/string16.h" #include "build/build_config.h" +// Due to restrictions of most operating systems, we don't directly map each +// type of custom data to a native data transfer type. Instead, we serialize +// each key-value pair into the pickle as a pair of string objects, and then +// write the binary data in the pickle to the native data transfer object. namespace base { class Pickle; }
diff --git a/ui/base/clipboard/scoped_clipboard_writer.cc b/ui/base/clipboard/scoped_clipboard_writer.cc index 6e11dab..b41c7095 100644 --- a/ui/base/clipboard/scoped_clipboard_writer.cc +++ b/ui/base/clipboard/scoped_clipboard_writer.cc
@@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file implements the ScopedClipboardWriter class. Documentation on its -// purpose can be found in our header. Documentation on the format of the -// parameters for each clipboard target can be found in clipboard.h. - #include "ui/base/clipboard/scoped_clipboard_writer.h" #include "base/pickle.h" @@ -14,6 +10,8 @@ #include "ui/base/clipboard/clipboard_format_type.h" #include "ui/gfx/geometry/size.h" +// Documentation on the format of the parameters for each clipboard target can +// be found in clipboard.h. namespace ui { ScopedClipboardWriter::ScopedClipboardWriter(ClipboardType type) : type_(type) {
diff --git a/ui/base/clipboard/scoped_clipboard_writer.h b/ui/base/clipboard/scoped_clipboard_writer.h index 084d5fe1..178833f3 100644 --- a/ui/base/clipboard/scoped_clipboard_writer.h +++ b/ui/base/clipboard/scoped_clipboard_writer.h
@@ -2,12 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file declares the ScopedClipboardWriter class, a wrapper around -// the Clipboard class which simplifies writing data to the system clipboard. -// Upon deletion the class atomically writes all data to the clipboard, -// avoiding any potential race condition with other processes that are also -// writing to the system clipboard. - #ifndef UI_BASE_CLIPBOARD_SCOPED_CLIPBOARD_WRITER_H_ #define UI_BASE_CLIPBOARD_SCOPED_CLIPBOARD_WRITER_H_ @@ -25,8 +19,14 @@ namespace ui { -// This class is a wrapper for |Clipboard| that handles packing data -// into a Clipboard::ObjectMap. +// |ScopedClipboardWriter|: +// - is a wrapper for |Clipboard|. +// - simplifies writing data to the system clipboard. +// - handles packing data into a Clipboard::ObjectMap. +// +// Upon deletion, the class atomically writes all data to the clipboard, +// avoiding any potential race condition with other processes that are also +// writing to the system clipboard. class COMPONENT_EXPORT(BASE_CLIPBOARD) ScopedClipboardWriter { public: // Create an instance that is a simple wrapper around the clipboard of the
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc index 29635eab..90a54d5 100644 --- a/ui/views/controls/label.cc +++ b/ui/views/controls/label.cc
@@ -414,6 +414,11 @@ return base::string16(); } +void Label::OnHandlePropertyChangeEffects(PropertyEffects property_effects) { + if (property_effects & kPropertyEffectsLayout) + ResetLayout(); +} + std::unique_ptr<gfx::RenderText> Label::CreateRenderText() const { // Multi-line labels only support NO_ELIDE and ELIDE_TAIL for now. // TODO(warx): Investigate more elide text support.
diff --git a/ui/views/controls/label.h b/ui/views/controls/label.h index 4d9c4a4..36117ce 100644 --- a/ui/views/controls/label.h +++ b/ui/views/controls/label.h
@@ -235,6 +235,7 @@ WordLookupClient* GetWordLookupClient() override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; base::string16 GetTooltipText(const gfx::Point& p) const override; + void OnHandlePropertyChangeEffects(PropertyEffects property_effects) override; protected: // Create a single RenderText instance to actually be painted.
diff --git a/ui/views/view.cc b/ui/views/view.cc index f0d165b..5df93cb 100644 --- a/ui/views/view.cc +++ b/ui/views/view.cc
@@ -1955,6 +1955,7 @@ InvalidateLayout(); if (effects & kPropertyEffectsPaint) SchedulePaint(); + OnHandlePropertyChangeEffects(effects); } PropertyChangedSubscription View::AddPropertyChangedCallback(
diff --git a/ui/views/view.h b/ui/views/view.h index 94dcf00d..78b42e0 100644 --- a/ui/views/view.h +++ b/ui/views/view.h
@@ -1572,6 +1572,11 @@ void OnPropertyChanged(PropertyKey property, PropertyEffects property_effects); + // Empty function called in HandlePropertyChangeEffects to be overridden in + // subclasses if they have custom functions for property changes. + virtual void OnHandlePropertyChangeEffects(PropertyEffects property_effects) { + } + private: friend class internal::PreEventDispatchHandler; friend class internal::PostEventDispatchHandler;
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn index af9dbbf..d551ea4f 100644 --- a/ui/webui/resources/cr_elements/BUILD.gn +++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -7,8 +7,6 @@ group("closure_compile") { deps = [ ":cr_elements_resources", - "chromeos/cr_picture:closure_compile", - "chromeos/network:closure_compile", "cr_action_menu:closure_compile", "cr_button:closure_compile", "cr_checkbox:closure_compile", @@ -21,7 +19,6 @@ "cr_profile_avatar_selector:closure_compile", "cr_radio_button:closure_compile", "cr_radio_group:closure_compile", - "cr_searchable_drop_down:closure_compile", "cr_slider:closure_compile", "cr_tabs:closure_compile", "cr_toast:closure_compile", @@ -29,6 +26,16 @@ "cr_view_manager:closure_compile", "policy:closure_compile", ] + + if (is_chromeos) { + deps += [ + "chromeos:closure_compile", + + # cr-searchable-drop-down is only used in smb and cups dialogs, both of + # which are chromeos only. + "cr_searchable_drop_down:closure_compile", + ] + } } js_type_check("cr_elements_resources") {
diff --git a/ui/webui/resources/cr_elements/chromeos/BUILD.gn b/ui/webui/resources/cr_elements/chromeos/BUILD.gn new file mode 100644 index 0000000..b73e6bf5 --- /dev/null +++ b/ui/webui/resources/cr_elements/chromeos/BUILD.gn
@@ -0,0 +1,15 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +assert(is_chromeos, "Only ChromeOS components belong here.") + +group("closure_compile") { + deps = [ + "cr_picture:closure_compile", + "fingerprint:closure_compile", + "network:closure_compile", + ] +}
diff --git a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn index c70cdd8e..92effd9 100644 --- a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn +++ b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
@@ -4,63 +4,71 @@ import("//third_party/closure_compiler/compile_js.gni") +# Note: This file is referenced in settings_ui for :cr_onc_types. + js_type_check("closure_compile") { deps = [ - ":cr_network_icon", - ":cr_network_list", - ":cr_network_list_item", - ":cr_network_list_types", - ":cr_network_listener_behavior", - ":cr_network_select", ":cr_onc_types", ] + if (is_chromeos) { + deps += [ + ":cr_network_icon", + ":cr_network_list", + ":cr_network_list_item", + ":cr_network_list_types", + ":cr_network_listener_behavior", + ":cr_network_select", + ] + } } -js_library("cr_network_icon") { - deps = [ - ":cr_onc_types", - "//ui/webui/resources/js:assert", - ] -} +if (is_chromeos) { + js_library("cr_network_icon") { + deps = [ + ":cr_onc_types", + "//ui/webui/resources/js:assert", + ] + } -js_library("cr_network_list") { - deps = [ - ":cr_network_list_types", - ":cr_onc_types", - "//ui/webui/resources/cr_elements:cr_scrollable_behavior", - ] -} + js_library("cr_network_list") { + deps = [ + ":cr_network_list_types", + ":cr_onc_types", + "//ui/webui/resources/cr_elements:cr_scrollable_behavior", + ] + } -js_library("cr_network_list_item") { - deps = [ - ":cr_network_list_types", - ":cr_onc_types", - "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior", - "//ui/webui/resources/js:assert", - ] -} + js_library("cr_network_list_item") { + deps = [ + ":cr_network_list_types", + ":cr_onc_types", + "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior", + "//ui/webui/resources/js:assert", + ] + } -js_library("cr_network_list_types") { - deps = [ - ":cr_onc_types", - ] -} + js_library("cr_network_list_types") { + deps = [ + ":cr_onc_types", + ] + } -js_library("cr_network_listener_behavior") { - deps = [ - "//ui/webui/resources/js:assert", - ] - externs_list = [ "$externs_path/networking_private.js" ] - extra_sources = [ "$interfaces_path/networking_private_interface.js" ] -} + js_library("cr_network_listener_behavior") { + deps = [ + "//ui/webui/resources/js:assert", + ] + externs_list = [ "$externs_path/networking_private.js" ] + extra_sources = [ "$interfaces_path/networking_private_interface.js" ] + } -js_library("cr_network_select") { - deps = [ - ":cr_network_list_types", - ":cr_onc_types", - "//ui/webui/resources/js:util", - ] - externs_list = [ "$externs_path/networking_private.js" ] + js_library("cr_network_select") { + deps = [ + ":cr_network_list_types", + ":cr_onc_types", + "//ui/webui/resources/js:util", + ] + externs_list = [ "$externs_path/networking_private.js" ] + } } js_library("cr_onc_types") {
diff --git a/ui/webui/resources/cr_elements/cr_button/cr_button.html b/ui/webui/resources/cr_elements/cr_button/cr_button.html index ae6392de..58c3d13 100644 --- a/ui/webui/resources/cr_elements/cr_button/cr_button.html +++ b/ui/webui/resources/cr_elements/cr_button/cr_button.html
@@ -12,7 +12,7 @@ <style include="cr-hidden-style"> :host { --active-shadow-rgb: var(--google-grey-800-rgb); - --active-shadow-action-rgb: var(--google-blue-500-rgb); + --active-shadow-action-rgb: var(--google-blue-refresh-500-rgb); --bg-action: var(--google-blue-600); --border-color: var(--google-grey-refresh-300); --disabled-bg-action: var(--google-grey-refresh-100); @@ -20,7 +20,9 @@ --disabled-border-color: var(--google-grey-refresh-100); --focus-shadow-color: rgba(var(--google-blue-600-rgb), .4); --hover-bg-action: rgba(var(--google-blue-600-rgb), .9); - --hover-bg-color: rgba(var(--google-blue-500-rgb), .04); + --hover-bg-color: rgba(var(--google-blue-refresh-500-rgb), .04); + --hover-border-color: var(--google-blue-refresh-100); + --hover-shadow-action-rgb: var(--google-blue-refresh-500-rgb); --ink-color-action: white; /* Blue-ish color used either as a background or as a text color, * depending on the type of button. */ @@ -95,7 +97,7 @@ @media (prefers-color-scheme: light) { :host(:hover) { - border-color: var(--google-blue-refresh-100); + border-color: var(--hover-border-color); } } @@ -117,10 +119,11 @@ background: var(--hover-bg-action); } - @media (prefers-color-scheme: dark) { - :host(.action-button:hover) { - box-shadow: 0 1px 2px 0 rgba(var(--google-blue-500-rgb), .3), - 0 1px 3px 1px rgba(var(--google-blue-500-rgb), .15); + @media (prefers-color-scheme: light) { + :host(.action-button:not(:active):hover) { + box-shadow: + 0 1px 2px 0 rgba(var(--hover-shadow-action-rgb), .3), + 0 1px 3px 1px rgba(var(--hover-shadow-action-rgb), .15); } }
diff --git a/ui/webui/resources/cr_elements/policy/BUILD.gn b/ui/webui/resources/cr_elements/policy/BUILD.gn index 743f989..e758d2e 100644 --- a/ui/webui/resources/cr_elements/policy/BUILD.gn +++ b/ui/webui/resources/cr_elements/policy/BUILD.gn
@@ -8,12 +8,16 @@ deps = [ ":cr_policy_indicator", ":cr_policy_indicator_behavior", - ":cr_policy_network_behavior", - ":cr_policy_network_indicator", ":cr_policy_pref_behavior", ":cr_policy_pref_indicator", ":cr_tooltip_icon", ] + if (is_chromeos) { + deps += [ + ":cr_policy_network_behavior", + ":cr_policy_network_indicator", + ] + } } js_library("cr_policy_indicator") { @@ -43,20 +47,22 @@ externs_list = [ "$externs_path/settings_private.js" ] } -js_library("cr_policy_network_behavior") { - deps = [ - ":cr_policy_indicator_behavior", - "../chromeos/network:cr_onc_types", - ] -} +if (is_chromeos) { + js_library("cr_policy_network_behavior") { + deps = [ + ":cr_policy_indicator_behavior", + "../chromeos/network:cr_onc_types", + ] + } -js_library("cr_policy_network_indicator") { - deps = [ - ":cr_policy_indicator_behavior", - ":cr_policy_network_behavior", - ":cr_tooltip_icon", - "../chromeos/network:cr_onc_types", - ] + js_library("cr_policy_network_indicator") { + deps = [ + ":cr_policy_indicator_behavior", + ":cr_policy_network_behavior", + ":cr_tooltip_icon", + "../chromeos/network:cr_onc_types", + ] + } } js_library("cr_tooltip_icon") {
diff --git a/url/gurl.cc b/url/gurl.cc index 84e7bf1..91b0f24 100644 --- a/url/gurl.cc +++ b/url/gurl.cc
@@ -8,6 +8,7 @@ #include <algorithm> #include <ostream> +#include <utility> #include "base/lazy_instance.h" #include "base/logging.h" @@ -339,16 +340,11 @@ } bool GURL::IsAboutBlank() const { - if (!SchemeIs(url::kAboutScheme)) - return false; + return IsAboutUrl(url::kAboutBlankPath); +} - if (has_host() || has_username() || has_password() || has_port()) - return false; - - if (path() != url::kAboutBlankPath && path() != url::kAboutBlankWithHashPath) - return false; - - return true; +bool GURL::IsAboutSrcdoc() const { + return IsAboutUrl(url::kAboutSrcdocPath); } bool GURL::SchemeIs(base::StringPiece lower_ascii_scheme) const { @@ -487,6 +483,30 @@ (parsed_.inner_parsed() ? sizeof(url::Parsed) : 0); } +bool GURL::IsAboutUrl(base::StringPiece allowed_path) const { + if (!SchemeIs(url::kAboutScheme)) + return false; + + if (has_host() || has_username() || has_password() || has_port()) + return false; + + if (!path_piece().starts_with(allowed_path)) + return false; + + if (path_piece().size() == allowed_path.size()) { + DCHECK_EQ(path_piece(), allowed_path); + return true; + } + + if ((path_piece().size() == allowed_path.size() + 1) && + path_piece().back() == '/') { + DCHECK_EQ(path_piece(), allowed_path.as_string() + '/'); + return true; + } + + return false; +} + std::ostream& operator<<(std::ostream& out, const GURL& url) { return out << url.possibly_invalid_spec(); }
diff --git a/url/gurl.h b/url/gurl.h index 1b0669e..9c680e0 100644 --- a/url/gurl.h +++ b/url/gurl.h
@@ -217,6 +217,10 @@ // about:blank/#foo. bool IsAboutBlank() const; + // Returns true when the url is of the form about:srcdoc, about:srcdoc?foo or + // about:srcdoc/#foo. + bool IsAboutSrcdoc() const; + // Returns true if the given parameter (should be lower-case ASCII to match // the canonicalized scheme) is the scheme for this URL. Do not include a // colon. @@ -445,6 +449,9 @@ void InitializeFromCanonicalSpec(); + // Helper used by IsAboutBlank and IsAboutSrcdoc. + bool IsAboutUrl(base::StringPiece allowed_path) const; + // Returns the substring of the input identified by the given component. std::string ComponentString(const url::Component& comp) const { if (comp.len <= 0)
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc index 379c04f..0d7b65b 100644 --- a/url/gurl_unittest.cc +++ b/url/gurl_unittest.cc
@@ -863,11 +863,34 @@ const std::string kNotAboutBlankUrls[] = { "http:blank", "about:blan", "about://blank", "about:blank/foo", "about://:8000/blank", "about://foo:foo@/blank", - "foo@about:blank", "foo:bar@about:blank", "about:blank:8000"}; + "foo@about:blank", "foo:bar@about:blank", "about:blank:8000", + "about:blANk"}; for (const auto& url : kNotAboutBlankUrls) EXPECT_FALSE(GURL(url).IsAboutBlank()) << url; } +TEST(GURLTest, IsAboutSrcdoc) { + const std::string kAboutSrcdocUrls[] = { + "about:srcdoc", "about:srcdoc/", "about:srcdoc?foo", "about:srcdoc/#foo", + "about:srcdoc?foo#foo"}; + for (const auto& url : kAboutSrcdocUrls) + EXPECT_TRUE(GURL(url).IsAboutSrcdoc()) << url; + + const std::string kNotAboutSrcdocUrls[] = {"http:srcdoc", + "about:srcdo", + "about://srcdoc", + "about://srcdoc\\", + "about:srcdoc/foo", + "about://:8000/srcdoc", + "about://foo:foo@/srcdoc", + "foo@about:srcdoc", + "foo:bar@about:srcdoc", + "about:srcdoc:8000", + "about:srCDOc"}; + for (const auto& url : kNotAboutSrcdocUrls) + EXPECT_FALSE(GURL(url).IsAboutSrcdoc()) << url; +} + TEST(GURLTest, EqualsIgnoringRef) { const struct { const char* url_a;
diff --git a/url/url_constants.cc b/url/url_constants.cc index 110c6a7b..38f86bbb 100644 --- a/url/url_constants.cc +++ b/url/url_constants.cc
@@ -9,7 +9,7 @@ const char kAboutBlankURL[] = "about:blank"; const char kAboutBlankPath[] = "blank"; -const char kAboutBlankWithHashPath[] = "blank/"; +const char kAboutSrcdocPath[] = "srcdoc"; const char kAboutScheme[] = "about"; const char kBlobScheme[] = "blob";
diff --git a/url/url_constants.h b/url/url_constants.h index 38a0e38..7f322f89 100644 --- a/url/url_constants.h +++ b/url/url_constants.h
@@ -14,7 +14,7 @@ COMPONENT_EXPORT(URL) extern const char kAboutBlankURL[]; COMPONENT_EXPORT(URL) extern const char kAboutBlankPath[]; -COMPONENT_EXPORT(URL) extern const char kAboutBlankWithHashPath[]; +COMPONENT_EXPORT(URL) extern const char kAboutSrcdocPath[]; COMPONENT_EXPORT(URL) extern const char kAboutScheme[]; COMPONENT_EXPORT(URL) extern const char kBlobScheme[];